Repository: sinajia/Downloader Branch: main Commit: b9fd6e5f1910 Files: 197 Total size: 2.7 MB Directory structure: gitextract_1xa6jjjt/ ├── .gitignore ├── LICENSE ├── Microsoft_VC++2022.sln ├── README-zh.md ├── README.md ├── WTL/ │ ├── atlapp.h │ ├── atlcrack.h │ ├── atlctrls.h │ ├── atlctrlw.h │ ├── atlctrlx.h │ ├── atlddx.h │ ├── atldlgs.h │ ├── atldwm.h │ ├── atlfind.h │ ├── atlframe.h │ ├── atlgdi.h │ ├── atlmisc.h │ ├── atlprint.h │ ├── atlres.h │ ├── atlresce.h │ ├── atlribbon.h │ ├── atlscrl.h │ ├── atlsplit.h │ ├── atltheme.h │ ├── atluser.h │ ├── atlwince.h │ └── atlwinx.h ├── bin/ │ └── upx-4.1.0-win32/ │ ├── COPYING │ ├── LICENSE │ ├── NEWS │ ├── README │ ├── THANKS.txt │ ├── upx-doc.html │ ├── upx-doc.txt │ └── upx.1 ├── common/ │ ├── jsoncpp/ │ │ ├── json/ │ │ │ ├── autolink.h │ │ │ ├── config.h │ │ │ ├── features.h │ │ │ ├── forwards.h │ │ │ ├── json.h │ │ │ ├── reader.h │ │ │ ├── value.h │ │ │ └── writer.h │ │ ├── json_batchallocator.h │ │ ├── json_valueiterator.inl │ │ ├── reader.cpp │ │ ├── value.cpp │ │ └── writer.cpp │ ├── util/ │ │ ├── base.cpp │ │ ├── base.h │ │ ├── def.h │ │ ├── md5.cpp │ │ ├── md5.h │ │ ├── system.cpp │ │ ├── system.h │ │ ├── util_tools.cpp │ │ └── util_tools.h │ ├── xml/ │ │ ├── tinystr.cpp │ │ ├── tinystr.h │ │ ├── tinyxml.cpp │ │ ├── tinyxml.h │ │ ├── tinyxmlerror.cpp │ │ ├── tinyxmlparser.cpp │ │ ├── xmlhelper.cpp │ │ └── xmlhelper.h │ └── xzip/ │ ├── XUnzip.cpp │ └── XUnzip.h └── src/ ├── .gitignore ├── App.vcxproj ├── App.vcxproj.filters ├── DirectUI/ │ ├── DUIButton.cpp │ ├── DUIButton.h │ ├── DUICheckBox.cpp │ ├── DUICheckBox.h │ ├── DUIDef.h │ ├── DUIElement.cpp │ ├── DUIElement.h │ ├── DUIElementsMgr.cpp │ ├── DUIElementsMgr.h │ ├── DUIGDIResource.cpp │ ├── DUIGDIResource.h │ ├── DUIHyperLink.cpp │ ├── DUIHyperLink.h │ ├── DUILayeredEdit.cpp │ ├── DUILayeredEdit.h │ ├── DUIOptionLine.cpp │ ├── DUIOptionLine.h │ ├── DUIPanel.cpp │ ├── DUIPanel.h │ ├── DUIProgress.cpp │ ├── DUIProgress.h │ ├── DUIRadioButton.cpp │ ├── DUIRadioButton.h │ ├── DUIStatic.cpp │ ├── DUIStatic.h │ ├── DUITab.cpp │ ├── DUITab.h │ ├── DUITabList.cpp │ ├── DUITabList.h │ ├── DUITransWindow.cpp │ ├── DUITransWindow.h │ ├── DUITransWindowEx.cpp │ ├── DUITransWindowEx.h │ ├── DUIWindowStyle.cpp │ ├── DUIWindowStyle.h │ ├── Draw.cpp │ ├── Draw.h │ ├── EventHandler.h │ ├── UpdateWindowBase.cpp │ ├── UpdateWindowBase.h │ ├── UpdateWindowBaseEx.cpp │ └── UpdateWindowBaseEx.h ├── DownLoader/ │ ├── DownloadDelegate.cpp │ ├── DownloadDelegate.h │ ├── fetcherurl.cpp │ ├── fetcherurl.h │ ├── fetchfile.cpp │ └── fetchfile.h ├── Downloader.rc ├── Event/ │ ├── WaitableEvent.cc │ └── WaitableEvent.h ├── Global.cpp ├── Global.h ├── Language/ │ ├── Language.cpp │ └── Language.h ├── LogAssist/ │ ├── LogAssist.cpp │ └── LogAssist.h ├── Main.cpp ├── StdAfx.cpp ├── StdAfx.h ├── UI/ │ ├── FrameShowState.cpp │ ├── FrameShowState.h │ ├── UIAgreement.cpp │ ├── UIAgreement.h │ ├── UICannotDown.cpp │ ├── UICannotDown.h │ ├── UIMainWindowEx.cpp │ ├── UIMainWindowEx.h │ ├── UtilityWindow.cpp │ └── UtilityWindow.h ├── Util/ │ ├── UtilApi.cpp │ └── UtilApi.h ├── base/ │ ├── FastDelegate.h │ ├── FastDelegateImpl.h │ ├── MessageLoop.cc │ ├── MessageLoop.h │ ├── MessagePump.h │ ├── MessagePumpDefault.cc │ ├── MessagePumpDefault.h │ ├── MessagePumpWin.cc │ ├── MessagePumpWin.h │ ├── PendingTask.cpp │ ├── PendingTask.h │ ├── Thread.cc │ ├── Thread.h │ ├── WeakPtr.cc │ ├── WeakPtr.h │ ├── WrapperObj.h │ ├── aligned_memory.h │ ├── at_exist.cc │ ├── at_exist.h │ ├── common_threads.cc │ ├── common_threads.h │ ├── lazy_instance.cc │ ├── lazy_instance.h │ ├── macros.h │ ├── notification_details.h │ ├── notification_observer.h │ ├── notification_registrar.cc │ ├── notification_registrar.h │ ├── notification_service.cc │ ├── notification_service.h │ ├── notification_source.h │ ├── notification_types.h │ ├── observer_list.h │ ├── ref_counted.cc │ ├── ref_counted.h │ ├── scoped_handle.h │ ├── string_util_win.h │ ├── stringprintf.cc │ ├── stringprintf.h │ ├── thread_local.cc │ └── thread_local.h ├── base.h ├── net/ │ ├── url_fetcher.cc │ └── url_fetcher.h ├── res/ │ └── xml/ │ ├── EngUIAgreement.xml │ ├── EngUICannotDown.xml │ ├── EngUIContent.xml │ ├── EngUIMainWindow.xml │ ├── UIAgreement.xml │ ├── UICannotDown.xml │ ├── UIContent.xml │ └── UIMainWindow.xml ├── resource.h └── time/ ├── time.cc └── time.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Compiled Static libraries .vs/ 0utPut/ Debug/ Release/ *.aps *.vcxproj.user *.vcproj.user ================================================ FILE: LICENSE ================================================ Copyright (c) 996 License Version 1.0 (Draft) Permission is hereby granted to any individual or legal entity obtaining a copy of this licensed work (including the source code, documentation and/or related items, hereinafter collectively referred to as the "licensed work"), free of charge, to deal with the licensed work for any purpose, including without limitation, the rights to use, reproduce, prepare derivative works of, distribute and sublicense the licensed work, subject to the following conditions: 1. The individual or the legal entity must conspicuously display, without modification, this License on each redistributed or derivative copy of the Licensed Work. 2. The individual or the legal entity must strictly comply with all applicable laws, regulations, rules and standards of the jurisdiction relating to labor and employment where the individual is physically located or where the individual was born or naturalized; or where the legal entity is registered or is operating (whichever is stricter). In case that the jurisdiction has no such laws, regulations, rules and standards or its laws, regulations, rules and standards are unenforceable, the individual or the legal entity are required to comply with Core International Labor Standards. 3. The individual or the legal entity shall not induce or force its employee(s), whether full-time or part-time, or its independent contractor(s), in any methods, to agree in oral or written form, to directly or indirectly restrict, weaken or relinquish his or her rights or remedies under such laws, regulations, rules and standards relating to labor and employment as mentioned above, no matter whether such written or oral agreement are enforceable under the laws of the said jurisdiction, nor shall such individual or the legal entity limit, in any methods, the rights of its employee(s) or independent contractor(s) from reporting or complaining to the copyright holder or relevant authorities monitoring the compliance of the license about its violation(s) of the said license. THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK. ================================================ FILE: Microsoft_VC++2022.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Downloader", "src\App.vcxproj", "{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Debug|x86.ActiveCfg = Debug|Win32 {D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Debug|x86.Build.0 = Debug|Win32 {D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Release|x86.ActiveCfg = Release|Win32 {D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8F0590AF-8B95-4D3A-B92B-2D153EA34AB5} EndGlobalSection EndGlobal ================================================ FILE: README-zh.md ================================================ # 当必火🔥——Windows 平台的下载器 🚀 当必火🔥——让程序下载和安装变得简单! ![](./assets/20240525104340.png) ## 特点: - Windows C++ 原生代码(std:c++14) - 超小体积——Release 版本只有 400kb 左右 - 使用 WTL,不依赖其他库 - 只需修改一个文件,就可以编译成自己的下载器 - 自绘界面,对懂 C++ 的高度可定制 - 下载一个 Zip 文件,解压然后安装到指定目录,并创建桌面快捷方式 ## 编译 Visual Studio 2022 ## 使用: 代码上,只需改一个 cpp 文件,重新编译即可。 编辑 src/Global.cpp。如果用 VC++ 打开,查看 Source Files/Global.cpp。 ```c++ /// /// Set the following string and then compile // Query zip download link std::string CGlobal::downloadurl_ = "http://127.0.0.1:5001/download-url"; // directory name std::string CGlobal::appDirName_ = "MyeXeAppDir"; // Exe file name such as eXeScope.exe or a relative path such as bin\\eXeScope.exe std::string CGlobal::appname_ = "eXeScope.exe"; // shortcut file name std::string CGlobal::shortcutname_ = "eXeScope"; // Link to open after installation std::string CGlobal::openurl_ = "https://github.com/sinajia/Downloader"; /// ``` 需要修改上面五个变量。它们代表的意义如下: downloadurl_,Get 请求地址。获取真正的 Zip 文件地址。 appDirName_,代表程序安装的文件夹的名称,这个文件夹由本下载器自动创建。 appname_,exe 文件的名称。例如 eXeScope.exe 或者 bin\\eXeScope.exe。 shortcutname_,桌面快捷方式的名称。 openurl_,可选。安装过程中,自动调用系统默认浏览器打开的网址,可以是空字符串""。如果为空字符串,则没有打开动作。 使用本下载器,需要有一个服务器端,必须实现上述的 Get 请求。以下代码是用 node.js 写的示例代码: ```js const express = require('express') const app = express() app.get('/download-url', (req, res) => { res.json({ downloadUrl: 'http://xxxx.com/zipfile.zip', }) }) const server = require('http').createServer(app) server.listen(5001, '0.0.0.0', function (err) { console.log('running') }) ``` 本下载器会自动解析这个 Get 请求返回的 Json 字符串。字段 downloadUrl 是必须的,表示真正的 Zip 文件的地址。Zip 文件就是程序的压缩包。 关于程序压缩包,可以参看 example\eXeScope.zip。 你还应该替换 App.ico,这个文件在 src\res。将 App.ico 替换为你自己程序的 ico 文件。当然,文件名必须还是 App.ico。 除此之外,你需要将 src\res\png 里面 1.png, 2.png, 3.png, 4.png, 5.png, 6.png 替换一下。这六张 png 图片是六张轮播图,替换成自己的。要求图片尺寸都是 480 × 240,png 格式。 做完这些,重新编译,然后启动! ## Star 一下 本程序的创作耗费了很多精力,请动动发财的小手点个 Star ~~~///(^v^)\\\~~~ ## 赞助 本程序的创作耗费了我很多时间和精力,如果也帮到了你,请动动发财的小手,支持一下,让我更有动力更新 ❤️ USDT(TRC20) TYWsj6oBb1zqkhMvYhXBuFYJD21dVWzXFL ================================================ FILE: README.md ================================================ # Win32 Native Downloader 🚀 A fast, tiny, native win32 downloader & installer for Windows platform. ![](./assets/20240525104340.png) [中文介绍](./README-zh.md) ## Features: - Pure C++ (std:c++14). - Tiny, the release version is only 414kb. - Without any other dependencies. - Just modify a little, very easy to use. - Very beautiful UI framework, highly customizable. - Download a zip file and install it to the specified directory. ## Compile and Build Visual Studio 2022 ## How to use: You only need to modify one file and recompile it to get a customized downloader. Edit file src/Global.cpp (Source Files/Global.cpp in VC++). ```c++ /// /// Set the following string and then compile // Query zip download link std::string CGlobal::downloadurl_ = "http://127.0.0.1:5001/download-url"; // directory name std::string CGlobal::appDirName_ = "MyeXeAppDir"; // Exe file name such as eXeScope.exe or a relative path such as bin\\eXeScope.exe std::string CGlobal::appname_ = "eXeScope.exe"; // shortcut file name std::string CGlobal::shortcutname_ = "eXeScope"; // Link to open after installation std::string CGlobal::openurl_ = "https://github.com/sinajia/Downloader"; /// ``` You should modify the values of the above five variables. The program will first request a json string from a specified resource. The get request url is stored in CGlobal::downloadurl_. Your server side needs to give the real download link. Here is an example of a server side (Node.js) ```js const express = require('express') const app = express() app.get('/download-url', (req, res) => { res.json({ downloadUrl: 'http://xxxx.com/zipfile.zip', }) }) const server = require('http').createServer(app) server.listen(5001, '0.0.0.0', function (err) { console.log('running') }) ``` "downloadUrl" is the real installation package link. `The package must be a zip file.` You should also replace App.ico in src/res and six PNG images (1.png, 2.png, 3.png, 4.png, 5.png, 6.png) in src/res/png. If you have done the above, please recompile it. Start now ! ## Support Help support the development and maintenance of the software ❤️ USDT(TRC20) TYWsj6oBb1zqkhMvYhXBuFYJD21dVWzXFL ================================================ FILE: WTL/atlapp.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLAPP_H__ #define __ATLAPP_H__ #pragma once #ifndef __cplusplus #error WTL requires C++ compilation (use a .cpp suffix) #endif #ifndef __ATLBASE_H__ #error atlapp.h requires atlbase.h to be included first #endif #ifndef _WIN32_WCE #if (WINVER < 0x0400) #error WTL requires Windows version 4.0 or higher #endif #if (_WIN32_IE < 0x0300) #error WTL requires IE version 3.0 or higher #endif #endif #ifdef _ATL_NO_COMMODULE #error WTL requires that _ATL_NO_COMMODULE is not defined #endif #if (_ATL_VER >= 0x0900) && defined(_ATL_MIN_CRT) #error _ATL_MIN_CRT is not supported with ATL 9.0 and higher #endif #if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT) #pragma message("Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT") #endif #include #if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) #include // for _beginthreadex #endif #if (_ATL_VER < 0x0800) && !defined(_DEBUG) #include #endif #include #ifndef _WIN32_WCE #pragma comment(lib, "comctl32.lib") #endif #if defined(_SYSINFOAPI_H_) && defined(NOT_BUILD_WINDOWS_DEPRECATE) && (_WIN32_WINNT >= 0x0501) #include #endif #ifndef _WIN32_WCE #include "atlres.h" #else // CE specific #include "atlresce.h" #endif // _WIN32_WCE // We need to disable this warning because of template class arguments #pragma warning(disable: 4127) #if (_ATL_VER >= 0x0900) && !defined(_SECURE_ATL) #define _SECURE_ATL 1 #endif /////////////////////////////////////////////////////////////////////////////// // WTL version number #define _WTL_VER 0x0910 /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CMessageFilter // CIdleHandler // CMessageLoop // // CAppModule // CServerAppModule // // CRegKeyEx // // Global functions: // AtlGetDefaultGuiFont() // AtlCreateControlFont() // AtlCreateBoldFont() // AtlInitCommonControls() /////////////////////////////////////////////////////////////////////////////// // Global support for Windows CE #ifdef _WIN32_WCE #ifndef SW_SHOWDEFAULT #define SW_SHOWDEFAULT SW_SHOWNORMAL #endif // !SW_SHOWDEFAULT // These get's OR-ed in a constant and will have no effect. // Defining them reduces the number of #ifdefs required for CE. #define LR_DEFAULTSIZE 0 #define LR_LOADFROMFILE 0 #ifndef SM_CXCURSOR #define SM_CXCURSOR 13 #endif #ifndef SM_CYCURSOR #define SM_CYCURSOR 14 #endif inline BOOL IsMenu(HMENU hMenu) { MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; ::SetLastError(0); BOOL bRet = ::GetMenuItemInfo(hMenu, 0, TRUE, &mii); if(!bRet) bRet = (::GetLastError() != ERROR_INVALID_MENU_HANDLE) ? TRUE : FALSE; return bRet; } #if (_WIN32_WCE >= 410) extern "C" void WINAPI ListView_SetItemSpacing(HWND hwndLV, int iHeight); #endif // (_WIN32_WCE >= 410) inline int MulDiv(IN int nNumber, IN int nNumerator, IN int nDenominator) { __int64 multiple = nNumber * nNumerator; return static_cast(multiple / nDenominator); } #if (_ATL_VER >= 0x0800) #ifndef _WTL_KEEP_WS_OVERLAPPEDWINDOW #ifdef WS_OVERLAPPEDWINDOW #undef WS_OVERLAPPEDWINDOW #define WS_OVERLAPPEDWINDOW 0 #endif // WS_OVERLAPPEDWINDOW #endif // !_WTL_KEEP_WS_OVERLAPPEDWINDOW #ifndef RDW_FRAME #define RDW_FRAME 0 #endif // !RDW_FRAME #ifndef WM_WINDOWPOSCHANGING #define WM_WINDOWPOSCHANGING 0 #endif // !WM_WINDOWPOSCHANGING #define FreeResource(x) #define UnlockResource(x) namespace ATL { inline HRESULT CComModule::RegisterClassObjects(DWORD /*dwClsContext*/, DWORD /*dwFlags*/) throw() { return E_NOTIMPL; } inline HRESULT CComModule::RevokeClassObjects() throw() { return E_NOTIMPL; } }; // namespace ATL #ifndef lstrlenW #define lstrlenW (int)ATL::lstrlenW #endif // lstrlenW inline int WINAPI lstrlenA(LPCSTR lpszString) { return ATL::lstrlenA(lpszString); } #ifdef lstrcpyn #undef lstrcpyn #define lstrcpyn ATL::lstrcpynW #endif // lstrcpyn #ifndef SetWindowLongPtrW inline LONG_PTR tmp_SetWindowLongPtrW( HWND hWnd, int nIndex, LONG_PTR dwNewLong ) { return( ::SetWindowLongW( hWnd, nIndex, LONG( dwNewLong ) ) ); } #define SetWindowLongPtrW tmp_SetWindowLongPtrW #endif #ifndef GetWindowLongPtrW inline LONG_PTR tmp_GetWindowLongPtrW( HWND hWnd, int nIndex ) { return( ::GetWindowLongW( hWnd, nIndex ) ); } #define GetWindowLongPtrW tmp_GetWindowLongPtrW #endif #ifndef LongToPtr #define LongToPtr(x) ((void*)x) #endif #ifndef PtrToInt #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) #endif #else // !(_ATL_VER >= 0x0800) #ifdef lstrlenW #undef lstrlenW #define lstrlenW (int)::wcslen #endif // lstrlenW #define lstrlenA (int)strlen #ifndef lstrcpyn inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength) { if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) return NULL; int nLen = __min(lstrlen(lpstrSrc), nLength - 1); LPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR)); lpstrDest[nLen] = 0; return lpstrRet; } #endif // !lstrcpyn #ifndef lstrcpynW inline LPWSTR lstrcpynW(LPWSTR lpstrDest, LPCWSTR lpstrSrc, int nLength) { return lstrcpyn(lpstrDest, lpstrSrc, nLength); // WinCE is Unicode only } #endif // !lstrcpynW #ifndef lstrcpynA inline LPSTR lstrcpynA(LPSTR lpstrDest, LPCSTR lpstrSrc, int nLength) { if(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0) return NULL; int nLen = __min(lstrlenA(lpstrSrc), nLength - 1); LPSTR lpstrRet = (LPSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(char)); lpstrDest[nLen] = 0; return lpstrRet; } #endif // !lstrcpyn #ifdef TrackPopupMenu #undef TrackPopupMenu #endif // TrackPopupMenu #define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \ static CWndClassInfo& GetWndClassInfo() \ { \ static CWndClassInfo wc = \ { \ { style, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \ }; \ return wc; \ } #ifndef _MAX_FNAME #define _MAX_FNAME _MAX_PATH #endif // _MAX_FNAME #if (_WIN32_WCE < 400) #define MAKEINTATOM(i) (LPTSTR)((ULONG_PTR)((WORD)(i))) #endif // (_WIN32_WCE < 400) #if (_WIN32_WCE < 410) #define WHEEL_PAGESCROLL (UINT_MAX) #define WHEEL_DELTA 120 #endif // (_WIN32_WCE < 410) #ifdef DrawIcon #undef DrawIcon #endif #ifndef VARCMP_LT #define VARCMP_LT 0 #endif #ifndef VARCMP_EQ #define VARCMP_EQ 1 #endif #ifndef VARCMP_GT #define VARCMP_GT 2 #endif #ifndef VARCMP_NULL #define VARCMP_NULL 3 #endif #ifndef RDW_ALLCHILDREN #define RDW_ALLCHILDREN 0 #endif #endif // !(_ATL_VER >= 0x0800) #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // Global support for using original VC++ 6.0 headers with WTL #if (_MSC_VER < 1300) && !defined(_WIN32_WCE) #ifndef REG_QWORD #define REG_QWORD 11 #endif #ifndef BS_PUSHBOX #define BS_PUSHBOX 0x0000000AL #endif struct __declspec(uuid("000214e6-0000-0000-c000-000000000046")) IShellFolder; struct __declspec(uuid("000214f9-0000-0000-c000-000000000046")) IShellLinkW; struct __declspec(uuid("000214ee-0000-0000-c000-000000000046")) IShellLinkA; #endif // (_MSC_VER < 1300) && !defined(_WIN32_WCE) #ifndef _ATL_NO_OLD_HEADERS_WIN64 #if !defined(_WIN64) && (_ATL_VER < 0x0700) #ifndef PSM_INSERTPAGE #define PSM_INSERTPAGE (WM_USER + 119) #endif // !PSM_INSERTPAGE #ifndef GetClassLongPtr #define GetClassLongPtrA GetClassLongA #define GetClassLongPtrW GetClassLongW #ifdef UNICODE #define GetClassLongPtr GetClassLongPtrW #else #define GetClassLongPtr GetClassLongPtrA #endif // !UNICODE #endif // !GetClassLongPtr #ifndef GCLP_HICONSM #define GCLP_HICONSM (-34) #endif // !GCLP_HICONSM #ifndef GetWindowLongPtr #define GetWindowLongPtrA GetWindowLongA #define GetWindowLongPtrW GetWindowLongW #ifdef UNICODE #define GetWindowLongPtr GetWindowLongPtrW #else #define GetWindowLongPtr GetWindowLongPtrA #endif // !UNICODE #endif // !GetWindowLongPtr #ifndef SetWindowLongPtr #define SetWindowLongPtrA SetWindowLongA #define SetWindowLongPtrW SetWindowLongW #ifdef UNICODE #define SetWindowLongPtr SetWindowLongPtrW #else #define SetWindowLongPtr SetWindowLongPtrA #endif // !UNICODE #endif // !SetWindowLongPtr #ifndef GWLP_WNDPROC #define GWLP_WNDPROC (-4) #endif #ifndef GWLP_HINSTANCE #define GWLP_HINSTANCE (-6) #endif #ifndef GWLP_HWNDPARENT #define GWLP_HWNDPARENT (-8) #endif #ifndef GWLP_USERDATA #define GWLP_USERDATA (-21) #endif #ifndef GWLP_ID #define GWLP_ID (-12) #endif #ifndef DWLP_MSGRESULT #define DWLP_MSGRESULT 0 #endif typedef long LONG_PTR; typedef unsigned long ULONG_PTR; typedef ULONG_PTR DWORD_PTR; #ifndef HandleToUlong #define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) ) #endif #ifndef HandleToLong #define HandleToLong( h ) ((LONG)(LONG_PTR) (h) ) #endif #ifndef LongToHandle #define LongToHandle( h) ((HANDLE)(LONG_PTR) (h)) #endif #ifndef PtrToUlong #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) ) #endif #ifndef PtrToLong #define PtrToLong( p ) ((LONG)(LONG_PTR) (p) ) #endif #ifndef PtrToUint #define PtrToUint( p ) ((UINT)(UINT_PTR) (p) ) #endif #ifndef PtrToInt #define PtrToInt( p ) ((INT)(INT_PTR) (p) ) #endif #ifndef PtrToUshort #define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) ) #endif #ifndef PtrToShort #define PtrToShort( p ) ((short)(LONG_PTR)(p) ) #endif #ifndef IntToPtr #define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i)) #endif #ifndef UIntToPtr #define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui)) #endif #ifndef LongToPtr #define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l)) #endif #ifndef ULongToPtr #define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul)) #endif #endif // !defined(_WIN64) && (_ATL_VER < 0x0700) #endif // !_ATL_NO_OLD_HEADERS_WIN64 /////////////////////////////////////////////////////////////////////////////// // Global support for using original VC++ 7.x headers with WTL #if (_MSC_VER >= 1300) && (_MSC_VER < 1400) #ifndef BS_PUSHBOX #define BS_PUSHBOX 0x0000000AL #endif #pragma warning(disable: 4244) // conversion from 'type1' to 'type2', possible loss of data #endif // (_MSC_VER >= 1300) && (_MSC_VER < 1400) /////////////////////////////////////////////////////////////////////////////// // Global support for old SDK headers #ifndef BTNS_BUTTON #define BTNS_BUTTON TBSTYLE_BUTTON #endif #ifndef BTNS_SEP #define BTNS_SEP TBSTYLE_SEP #endif #ifndef BTNS_CHECK #define BTNS_CHECK TBSTYLE_CHECK #endif #ifndef BTNS_GROUP #define BTNS_GROUP TBSTYLE_GROUP #endif #ifndef BTNS_CHECKGROUP #define BTNS_CHECKGROUP TBSTYLE_CHECKGROUP #endif #if (_WIN32_IE >= 0x0300) #ifndef BTNS_DROPDOWN #define BTNS_DROPDOWN TBSTYLE_DROPDOWN #endif #endif #if (_WIN32_IE >= 0x0400) #ifndef BTNS_AUTOSIZE #define BTNS_AUTOSIZE TBSTYLE_AUTOSIZE #endif #ifndef BTNS_NOPREFIX #define BTNS_NOPREFIX TBSTYLE_NOPREFIX #endif #endif /////////////////////////////////////////////////////////////////////////////// // Global support for SecureHelper functions #ifndef _TRUNCATE #define _TRUNCATE ((size_t)-1) #endif #ifndef _ERRCODE_DEFINED #define _ERRCODE_DEFINED typedef int errno_t; #endif #ifndef _SECURECRT_ERRCODE_VALUES_DEFINED #define _SECURECRT_ERRCODE_VALUES_DEFINED #define EINVAL 22 #define STRUNCATE 80 #endif #ifndef _countof #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) #endif /////////////////////////////////////////////////////////////////////////////// // Miscellaneous global support // define useful macros from winuser.h #ifndef IS_INTRESOURCE #define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0) #endif // IS_INTRESOURCE // protect template members from windowsx.h macros #ifdef _INC_WINDOWSX #undef SubclassWindow #endif // _INC_WINDOWSX // define useful macros from windowsx.h #ifndef GET_X_LPARAM #define GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam)) #endif #ifndef GET_Y_LPARAM #define GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam)) #endif // Dummy structs for compiling with /CLR #if (_MSC_VER >= 1300) && defined(_MANAGED) __if_not_exists(_IMAGELIST::_IMAGELIST) { struct _IMAGELIST { }; } __if_not_exists(_TREEITEM::_TREEITEM) { struct _TREEITEM { }; } __if_not_exists(_PSP::_PSP) { struct _PSP { }; } #endif // Define ATLVERIFY macro for ATL3 #if (_ATL_VER < 0x0700) #ifndef ATLVERIFY #ifdef _DEBUG #define ATLVERIFY(expr) ATLASSERT(expr) #else #define ATLVERIFY(expr) (expr) #endif // DEBUG #endif // ATLVERIFY #endif // (_ATL_VER < 0x0700) // Forward declaration for ATL3 and ATL11 fix #if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE) namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); }; #endif #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E #endif namespace WTL { #if (_ATL_VER >= 0x0700) DECLARE_TRACE_CATEGORY(atlTraceUI); #ifdef _DEBUG __declspec(selectany) ATL::CTraceCategory atlTraceUI(_T("atlTraceUI")); #endif // _DEBUG #else // !(_ATL_VER >= 0x0700) enum wtlTraceFlags { atlTraceUI = 0x10000000 }; #endif // !(_ATL_VER >= 0x0700) // Windows version helper inline bool AtlIsOldWindows() { #ifdef _versionhelpers_H_INCLUDED_ return !::IsWindowsVersionOrGreater(4, 90, 0); #else // !_versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; BOOL bRet = ::GetVersionEx(&ovi); return (!bRet || !((ovi.dwMajorVersion >= 5) || (ovi.dwMajorVersion == 4 && ovi.dwMinorVersion >= 90))); #endif // _versionhelpers_H_INCLUDED_ } // Default GUI font helper - "MS Shell Dlg" stock font inline HFONT AtlGetDefaultGuiFont() { #ifndef _WIN32_WCE return (HFONT)::GetStockObject(DEFAULT_GUI_FONT); #else // CE specific return (HFONT)::GetStockObject(SYSTEM_FONT); #endif // _WIN32_WCE } // Control font helper - default font for controls not in a dialog // (NOTE: Caller owns the font, and should destroy it when it's no longer needed) inline HFONT AtlCreateControlFont() { #ifndef _WIN32_WCE LOGFONT lf = { 0 }; ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); HFONT hFont = ::CreateFontIndirect(&lf); ATLASSERT(hFont != NULL); return hFont; #else // CE specific return (HFONT)::GetStockObject(SYSTEM_FONT); #endif // _WIN32_WCE } // Bold font helper // (NOTE: Caller owns the font, and should destroy it when it's no longer needed) inline HFONT AtlCreateBoldFont(HFONT hFont = NULL) { LOGFONT lf = { 0 }; #ifndef _WIN32_WCE if(hFont == NULL) ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); else ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); #else // CE specific if(hFont == NULL) hFont = (HFONT)::GetStockObject(SYSTEM_FONT); ATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT)); #endif // _WIN32_WCE lf.lfWeight = FW_BOLD; HFONT hFontBold = ::CreateFontIndirect(&lf); ATLASSERT(hFontBold != NULL); return hFontBold; } // Common Controls initialization helper inline BOOL AtlInitCommonControls(DWORD dwFlags) { INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX), dwFlags }; BOOL bRet = ::InitCommonControlsEx(&iccx); ATLASSERT(bRet); return bRet; } /////////////////////////////////////////////////////////////////////////////// // RunTimeHelper - helper functions for Windows version and structure sizes // Not for Windows CE #if defined(_WIN32_WCE) && !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) #define _WTL_NO_RUNTIME_STRUCT_SIZE #endif #ifndef _WTL_NO_RUNTIME_STRUCT_SIZE #ifndef _SIZEOF_STRUCT #define _SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) #endif #if (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) #define REBARBANDINFO_V6_SIZE _SIZEOF_STRUCT(REBARBANDINFO, cxHeader) #endif // (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE) #if (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) #define LVGROUP_V5_SIZE _SIZEOF_STRUCT(LVGROUP, uAlign) #endif // (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE) #if (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) #define LVTILEINFO_V5_SIZE _SIZEOF_STRUCT(LVTILEINFO, puColumns) #endif // (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE) #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) #define MCHITTESTINFO_V1_SIZE _SIZEOF_STRUCT(MCHITTESTINFO, st) #endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE) #if !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) #define NONCLIENTMETRICS_V1_SIZE _SIZEOF_STRUCT(NONCLIENTMETRICS, lfMessageFont) #endif // !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE) #if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE) #define TTTOOLINFO_V2_SIZE _SIZEOF_STRUCT(TTTOOLINFO, lParam) #endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE) #endif // !_WTL_NO_RUNTIME_STRUCT_SIZE namespace RunTimeHelper { #ifndef _WIN32_WCE inline bool IsCommCtrl6() { DWORD dwMajor = 0, dwMinor = 0; HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); return (SUCCEEDED(hRet) && (dwMajor >= 6)); } inline bool IsVista() { #ifdef _versionhelpers_H_INCLUDED_ return ::IsWindowsVistaOrGreater(); #else // !_versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; BOOL bRet = ::GetVersionEx(&ovi); return ((bRet != FALSE) && (ovi.dwMajorVersion >= 6)); #endif // _versionhelpers_H_INCLUDED_ } inline bool IsThemeAvailable() { bool bRet = false; if(IsCommCtrl6()) { HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); if(hThemeDLL != NULL) { typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)(); PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive"); ATLASSERT(pfnIsThemeActive != NULL); bRet = (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE); if(bRet) { typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)(); PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed"); ATLASSERT(pfnIsAppThemed != NULL); bRet = (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE); } ::FreeLibrary(hThemeDLL); } } return bRet; } inline bool IsWin7() { #ifdef _versionhelpers_H_INCLUDED_ return ::IsWindows7OrGreater(); #else // !_versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; BOOL bRet = ::GetVersionEx(&ovi); return ((bRet != FALSE) && (ovi.dwMajorVersion == 6) && (ovi.dwMinorVersion >= 1)); #endif // _versionhelpers_H_INCLUDED_ } inline bool IsRibbonUIAvailable() { static INT iRibbonUI = -1; #if defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) if (iRibbonUI == -1) { HMODULE hRibbonDLL = ::LoadLibrary(_T("propsys.dll")); if (hRibbonDLL != NULL) { const GUID CLSID_UIRibbonFramework = { 0x926749fa, 0x2615, 0x4987, { 0x88, 0x45, 0xc3, 0x3e, 0x65, 0xf2, 0xb9, 0x57 } }; // block - create instance { ATL::CComPtr pIUIFramework; iRibbonUI = SUCCEEDED(pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework)) ? 1 : 0; } ::FreeLibrary(hRibbonDLL); } else { iRibbonUI = 0; } } #endif // defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7) return (iRibbonUI == 1); } #endif // !_WIN32_WCE inline UINT SizeOf_REBARBANDINFO() { UINT uSize = sizeof(REBARBANDINFO); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) if(!(IsVista() && IsCommCtrl6())) uSize = REBARBANDINFO_V6_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) return uSize; } #if (_WIN32_WINNT >= 0x501) inline UINT SizeOf_LVGROUP() { UINT uSize = sizeof(LVGROUP); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) if(!IsVista()) uSize = LVGROUP_V5_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) return uSize; } inline UINT SizeOf_LVTILEINFO() { UINT uSize = sizeof(LVTILEINFO); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) if(!IsVista()) uSize = LVTILEINFO_V5_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600) return uSize; } #endif // (_WIN32_WINNT >= 0x501) inline UINT SizeOf_MCHITTESTINFO() { UINT uSize = sizeof(MCHITTESTINFO); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) if(!(IsVista() && IsCommCtrl6())) uSize = MCHITTESTINFO_V1_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) return uSize; } #ifndef _WIN32_WCE inline UINT SizeOf_NONCLIENTMETRICS() { UINT uSize = sizeof(NONCLIENTMETRICS); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) if(!IsVista()) uSize = NONCLIENTMETRICS_V1_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600) return uSize; } inline UINT SizeOf_TOOLINFO() { UINT uSize = sizeof(TOOLINFO); #if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501) if(!IsVista()) uSize = TTTOOLINFO_V2_SIZE; #endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501) return uSize; } #endif // !_WIN32_WCE }; /////////////////////////////////////////////////////////////////////////////// // ModuleHelper - helper functions for ATL3 and ATL7 module classes namespace ModuleHelper { inline HINSTANCE GetModuleInstance() { #if (_ATL_VER >= 0x0700) return ATL::_AtlBaseModule.GetModuleInstance(); #else // !(_ATL_VER >= 0x0700) return ATL::_pModule->GetModuleInstance(); #endif // !(_ATL_VER >= 0x0700) } inline HINSTANCE GetResourceInstance() { #if (_ATL_VER >= 0x0700) return ATL::_AtlBaseModule.GetResourceInstance(); #else // !(_ATL_VER >= 0x0700) return ATL::_pModule->GetResourceInstance(); #endif // !(_ATL_VER >= 0x0700) } inline void AddCreateWndData(ATL::_AtlCreateWndData* pData, void* pObject) { #if (_ATL_VER >= 0x0700) ATL::_AtlWinModule.AddCreateWndData(pData, pObject); #else // !(_ATL_VER >= 0x0700) ATL::_pModule->AddCreateWndData(pData, pObject); #endif // !(_ATL_VER >= 0x0700) } inline void* ExtractCreateWndData() { #if (_ATL_VER >= 0x0700) return ATL::_AtlWinModule.ExtractCreateWndData(); #else // !(_ATL_VER >= 0x0700) return ATL::_pModule->ExtractCreateWndData(); #endif // !(_ATL_VER >= 0x0700) } }; /////////////////////////////////////////////////////////////////////////////// // SecureHelper - helper functions for VS2005 secure CRT namespace SecureHelper { inline void strcpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) { #if _SECURE_ATL ATL::Checked::strcpy_s(lpstrDest, cchDest, lpstrSrc); #else if(cchDest > (size_t)lstrlenA(lpstrSrc)) ATLVERIFY(lstrcpyA(lpstrDest, lpstrSrc) != NULL); else ATLASSERT(FALSE); #endif } inline void strcpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) { #if _SECURE_ATL ATL::Checked::wcscpy_s(lpstrDest, cchDest, lpstrSrc); #else if(cchDest > (size_t)lstrlenW(lpstrSrc)) ATLVERIFY(lstrcpyW(lpstrDest, lpstrSrc) != NULL); else ATLASSERT(FALSE); #endif } inline void strcpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) { #ifdef _UNICODE strcpyW_x(lpstrDest, cchDest, lpstrSrc); #else strcpyA_x(lpstrDest, cchDest, lpstrSrc); #endif } inline errno_t strncpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc, size_t cchCount) { #if _SECURE_ATL return ATL::Checked::strncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); #else errno_t nRet = 0; if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) { nRet = EINVAL; } else if(cchCount == _TRUNCATE) { cchCount = __min(cchDest - 1, size_t(lstrlenA(lpstrSrc))); nRet = STRUNCATE; } else if(cchDest <= cchCount) { lpstrDest[0] = 0; nRet = EINVAL; } if(nRet == 0 || nRet == STRUNCATE) nRet = (lstrcpynA(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; ATLASSERT(nRet == 0 || nRet == STRUNCATE); return nRet; #endif } inline errno_t strncpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc, size_t cchCount) { #if _SECURE_ATL return ATL::Checked::wcsncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount); #else errno_t nRet = 0; if(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL) { nRet = EINVAL; } else if(cchCount == _TRUNCATE) { cchCount = __min(cchDest - 1, size_t(lstrlenW(lpstrSrc))); nRet = STRUNCATE; } else if(cchDest <= cchCount) { lpstrDest[0] = 0; nRet = EINVAL; } if(nRet == 0 || nRet == STRUNCATE) nRet = (lstrcpynW(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL; ATLASSERT(nRet == 0 || nRet == STRUNCATE); return nRet; #endif } inline errno_t strncpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc, size_t cchCount) { #ifdef _UNICODE return strncpyW_x(lpstrDest, cchDest, lpstrSrc, cchCount); #else return strncpyA_x(lpstrDest, cchDest, lpstrSrc, cchCount); #endif } inline void strcatA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc) { #if _SECURE_ATL ATL::Checked::strcat_s(lpstrDest, cchDest, lpstrSrc); #else if(cchDest > (size_t)lstrlenA(lpstrSrc)) ATLVERIFY(lstrcatA(lpstrDest, lpstrSrc) != NULL); else ATLASSERT(FALSE); #endif } inline void strcatW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc) { #if _SECURE_ATL ATL::Checked::wcscat_s(lpstrDest, cchDest, lpstrSrc); #else if(cchDest > (size_t)lstrlenW(lpstrSrc)) ATLVERIFY(lstrcatW(lpstrDest, lpstrSrc) != NULL); else ATLASSERT(FALSE); #endif } inline void strcat_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc) { #ifdef _UNICODE strcatW_x(lpstrDest, cchDest, lpstrSrc); #else strcatA_x(lpstrDest, cchDest, lpstrSrc); #endif } inline void memcpy_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) { #if _SECURE_ATL ATL::Checked::memcpy_s(pDest, cbDest, pSrc, cbSrc); #else if(cbDest >= cbSrc) memcpy(pDest, pSrc, cbSrc); else ATLASSERT(FALSE); #endif } inline void memmove_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc) { #if _SECURE_ATL ATL::Checked::memmove_s(pDest, cbDest, pSrc, cbSrc); #else if(cbDest >= cbSrc) memmove(pDest, pSrc, cbSrc); else ATLASSERT(FALSE); #endif } inline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) { #if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); #else cchBuff; // Avoid unused argument warning #pragma warning(push) #pragma warning(disable: 4996) return _vstprintf(lpstrBuff, lpstrFormat, args); #pragma warning(pop) #endif } inline int wvsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args) { #if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE) return _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args); #else cchBuff; // Avoid unused argument warning return ::wvsprintf(lpstrBuff, lpstrFormat, args); #endif } inline int sprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) { va_list args; va_start(args, lpstrFormat); int nRes = vsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); va_end(args); return nRes; } inline int wsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...) { va_list args; va_start(args, lpstrFormat); int nRes = wvsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args); va_end(args); return nRes; } }; // namespace SecureHelper /////////////////////////////////////////////////////////////////////////////// // MinCrtHelper - helper functions for using _ATL_MIN_CRT namespace MinCrtHelper { inline int _isspace(TCHAR ch) { #ifndef _ATL_MIN_CRT return _istspace(ch); #else // _ATL_MIN_CRT WORD type = 0; ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); return (type & C1_SPACE) == C1_SPACE; #endif // _ATL_MIN_CRT } inline int _isdigit(TCHAR ch) { #ifndef _ATL_MIN_CRT return _istdigit(ch); #else // _ATL_MIN_CRT WORD type = 0; ::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type); return (type & C1_DIGIT) == C1_DIGIT; #endif // _ATL_MIN_CRT } inline int _atoi(LPCTSTR str) { #ifndef _ATL_MIN_CRT return _ttoi(str); #else // _ATL_MIN_CRT while(_isspace(*str) != 0) ++str; TCHAR ch = *str++; TCHAR sign = ch; // save sign indication if(ch == _T('-') || ch == _T('+')) ch = *str++; // skip sign int total = 0; while(_isdigit(ch) != 0) { total = 10 * total + (ch - '0'); // accumulate digit ch = *str++; // get next char } return (sign == '-') ? -total : total; // return result, negated if necessary #endif // _ATL_MIN_CRT } inline LPCTSTR _strrchr(LPCTSTR str, TCHAR ch) { #ifndef _ATL_MIN_CRT return _tcsrchr(str, ch); #else // _ATL_MIN_CRT LPCTSTR lpsz = NULL; while(*str != 0) { if(*str == ch) lpsz = str; str = ::CharNext(str); } return lpsz; #endif // _ATL_MIN_CRT } inline LPTSTR _strrchr(LPTSTR str, TCHAR ch) { #ifndef _ATL_MIN_CRT return _tcsrchr(str, ch); #else // _ATL_MIN_CRT LPTSTR lpsz = NULL; while(*str != 0) { if(*str == ch) lpsz = str; str = ::CharNext(str); } return lpsz; #endif // _ATL_MIN_CRT } }; // namespace MinCrtHelper /////////////////////////////////////////////////////////////////////////////// // GenericWndClass - generic window class usable for subclassing // Use in dialog templates to specify a placeholder to be subclassed // Specify as a custom control with class name WTL_GenericWindow // Call Rregister() before creating dialog (for example, in WinMain) namespace GenericWndClass { inline LPCTSTR GetName() { return _T("WTL_GenericWindow"); } inline ATOM Register() { #ifndef _WIN32_WCE WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; #else WNDCLASS wc = { 0 }; #endif wc.lpfnWndProc = ::DefWindowProc; wc.hInstance = ModuleHelper::GetModuleInstance(); wc.hCursor = ::LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = GetName(); #ifndef _WIN32_WCE ATOM atom = ::RegisterClassEx(&wc); #else ATOM atom = ::RegisterClass(&wc); #endif ATLASSERT(atom != 0); return atom; } inline BOOL Unregister() // only needed for DLLs or tmp use { return ::UnregisterClass(GetName(), ModuleHelper::GetModuleInstance()); } }; // namespace GenericWndClass /////////////////////////////////////////////////////////////////////////////// // CMessageFilter - Interface for message filter support class CMessageFilter { public: virtual BOOL PreTranslateMessage(MSG* pMsg) = 0; }; /////////////////////////////////////////////////////////////////////////////// // CIdleHandler - Interface for idle processing class CIdleHandler { public: virtual BOOL OnIdle() = 0; }; #ifndef _ATL_NO_OLD_NAMES // for compatilibility with old names only typedef CIdleHandler CUpdateUIObject; #define DoUpdate OnIdle #endif // !_ATL_NO_OLD_NAMES /////////////////////////////////////////////////////////////////////////////// // CMessageLoop - message loop implementation class CMessageLoop { public: ATL::CSimpleArray m_aMsgFilter; ATL::CSimpleArray m_aIdleHandler; MSG m_msg; // Message filter operations BOOL AddMessageFilter(CMessageFilter* pMessageFilter) { return m_aMsgFilter.Add(pMessageFilter); } BOOL RemoveMessageFilter(CMessageFilter* pMessageFilter) { return m_aMsgFilter.Remove(pMessageFilter); } // Idle handler operations BOOL AddIdleHandler(CIdleHandler* pIdleHandler) { return m_aIdleHandler.Add(pIdleHandler); } BOOL RemoveIdleHandler(CIdleHandler* pIdleHandler) { return m_aIdleHandler.Remove(pIdleHandler); } #ifndef _ATL_NO_OLD_NAMES // for compatilibility with old names only BOOL AddUpdateUI(CIdleHandler* pIdleHandler) { ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and AddUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); return AddIdleHandler(pIdleHandler); } BOOL RemoveUpdateUI(CIdleHandler* pIdleHandler) { ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIObject and RemoveUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\n")); return RemoveIdleHandler(pIdleHandler); } #endif // !_ATL_NO_OLD_NAMES // message loop int Run() { BOOL bDoIdle = TRUE; int nIdleCount = 0; BOOL bRet; for(;;) { while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE)) { if(!OnIdle(nIdleCount++)) bDoIdle = FALSE; } bRet = ::GetMessage(&m_msg, NULL, 0, 0); if(bRet == -1) { ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)\n")); continue; // error, don't process } else if(!bRet) { ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting\n")); break; // WM_QUIT, exit message loop } if(!PreTranslateMessage(&m_msg)) { ::TranslateMessage(&m_msg); ::DispatchMessage(&m_msg); } if(IsIdleMessage(&m_msg)) { bDoIdle = TRUE; nIdleCount = 0; } } return (int)m_msg.wParam; } static BOOL IsIdleMessage(MSG* pMsg) { // These messages should NOT cause idle processing switch(pMsg->message) { case WM_MOUSEMOVE: #ifndef _WIN32_WCE case WM_NCMOUSEMOVE: #endif // !_WIN32_WCE case WM_PAINT: case 0x0118: // WM_SYSTIMER (caret blink) return FALSE; } return TRUE; } // Overrideables // Override to change message filtering virtual BOOL PreTranslateMessage(MSG* pMsg) { // loop backwards for(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--) { CMessageFilter* pMessageFilter = m_aMsgFilter[i]; if(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg)) return TRUE; } return FALSE; // not translated } // override to change idle processing virtual BOOL OnIdle(int /*nIdleCount*/) { for(int i = 0; i < m_aIdleHandler.GetSize(); i++) { CIdleHandler* pIdleHandler = m_aIdleHandler[i]; if(pIdleHandler != NULL) pIdleHandler->OnIdle(); } return FALSE; // don't continue } }; /////////////////////////////////////////////////////////////////////////////// // CStaticDataInitCriticalSectionLock and CWindowCreateCriticalSectionLock // internal classes to manage critical sections for both ATL3 and ATL7 class CStaticDataInitCriticalSectionLock { public: #if (_ATL_VER >= 0x0700) ATL::CComCritSecLock m_cslock; CStaticDataInitCriticalSectionLock() : m_cslock(ATL::_pAtlModule->m_csStaticDataInitAndTypeInfo, false) { } #endif // (_ATL_VER >= 0x0700) HRESULT Lock() { #if (_ATL_VER >= 0x0700) return m_cslock.Lock(); #else // !(_ATL_VER >= 0x0700) ::EnterCriticalSection(&ATL::_pModule->m_csStaticDataInit); return S_OK; #endif // !(_ATL_VER >= 0x0700) } void Unlock() { #if (_ATL_VER >= 0x0700) m_cslock.Unlock(); #else // !(_ATL_VER >= 0x0700) ::LeaveCriticalSection(&ATL::_pModule->m_csStaticDataInit); #endif // !(_ATL_VER >= 0x0700) } }; class CWindowCreateCriticalSectionLock { public: #if (_ATL_VER >= 0x0700) ATL::CComCritSecLock m_cslock; CWindowCreateCriticalSectionLock() : m_cslock(ATL::_AtlWinModule.m_csWindowCreate, false) { } #endif // (_ATL_VER >= 0x0700) HRESULT Lock() { #if (_ATL_VER >= 0x0700) return m_cslock.Lock(); #else // !(_ATL_VER >= 0x0700) ::EnterCriticalSection(&ATL::_pModule->m_csWindowCreate); return S_OK; #endif // !(_ATL_VER >= 0x0700) } void Unlock() { #if (_ATL_VER >= 0x0700) m_cslock.Unlock(); #else // !(_ATL_VER >= 0x0700) ::LeaveCriticalSection(&ATL::_pModule->m_csWindowCreate); #endif // !(_ATL_VER >= 0x0700) } }; /////////////////////////////////////////////////////////////////////////////// // CTempBuffer - helper class for stack allocations for ATL3 #ifndef _WTL_STACK_ALLOC_THRESHOLD #define _WTL_STACK_ALLOC_THRESHOLD 512 #endif #if (_ATL_VER >= 0x0700) using ATL::CTempBuffer; #else // !(_ATL_VER >= 0x0700) #ifndef SIZE_MAX #ifdef _WIN64 #define SIZE_MAX _UI64_MAX #else #define SIZE_MAX UINT_MAX #endif #endif #pragma warning(push) #pragma warning(disable: 4284) // warning for operator -> template class CTempBuffer { public: CTempBuffer() : m_p(NULL) { } CTempBuffer(size_t nElements) : m_p(NULL) { Allocate(nElements); } ~CTempBuffer() { if(m_p != reinterpret_cast(m_abFixedBuffer)) free(m_p); } operator T*() const { return m_p; } T* operator ->() const { ATLASSERT(m_p != NULL); return m_p; } T* Allocate(size_t nElements) { ATLASSERT(nElements <= (SIZE_MAX / sizeof(T))); return AllocateBytes(nElements * sizeof(T)); } T* AllocateBytes(size_t nBytes) { ATLASSERT(m_p == NULL); if(nBytes > t_nFixedBytes) m_p = static_cast(malloc(nBytes)); else m_p = reinterpret_cast(m_abFixedBuffer); return m_p; } private: T* m_p; BYTE m_abFixedBuffer[t_nFixedBytes]; }; #pragma warning(pop) #endif // !(_ATL_VER >= 0x0700) /////////////////////////////////////////////////////////////////////////////// // CAppModule - module class for an application class CAppModule : public ATL::CComModule { public: DWORD m_dwMainThreadID; ATL::CSimpleMap* m_pMsgLoopMap; ATL::CSimpleArray* m_pSettingChangeNotify; // Overrides of CComModule::Init and Term HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) { HRESULT hRet = CComModule::Init(pObjMap, hInstance, pLibID); if(FAILED(hRet)) return hRet; m_dwMainThreadID = ::GetCurrentThreadId(); typedef ATL::CSimpleMap _mapClass; m_pMsgLoopMap = NULL; ATLTRY(m_pMsgLoopMap = new _mapClass); if(m_pMsgLoopMap == NULL) return E_OUTOFMEMORY; m_pSettingChangeNotify = NULL; return hRet; } void Term() { TermSettingChangeNotify(); delete m_pMsgLoopMap; CComModule::Term(); } // Message loop map methods BOOL AddMessageLoop(CMessageLoop* pMsgLoop) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\n")); ATLASSERT(FALSE); return FALSE; } ATLASSERT(pMsgLoop != NULL); ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL); // not in map yet BOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop); lock.Unlock(); return bRet; } BOOL RemoveMessageLoop() { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\n")); ATLASSERT(FALSE); return FALSE; } BOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId()); lock.Unlock(); return bRet; } CMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\n")); ATLASSERT(FALSE); return NULL; } CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID); lock.Unlock(); return pLoop; } // Setting change notify methods // Note: Call this from the main thread for MSDI apps BOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\n")); ATLASSERT(FALSE); return FALSE; } if(m_pSettingChangeNotify == NULL) { typedef ATL::CSimpleArray _notifyClass; ATLTRY(m_pSettingChangeNotify = new _notifyClass); ATLASSERT(m_pSettingChangeNotify != NULL); } BOOL bRet = (m_pSettingChangeNotify != NULL); if(bRet && m_pSettingChangeNotify->GetSize() == 0) { // init everything _ATL_EMPTY_DLGTEMPLATE templ; HWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc); ATLASSERT(::IsWindow(hNtfWnd)); if(::IsWindow(hNtfWnd)) { // need conditional code because types don't match in winuser.h #ifdef _WIN64 ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this); #else ::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this)); #endif bRet = m_pSettingChangeNotify->Add(hNtfWnd); } else { bRet = FALSE; } } lock.Unlock(); return bRet; } void TermSettingChangeNotify() { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\n")); ATLASSERT(FALSE); return; } if(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0) ::DestroyWindow((*m_pSettingChangeNotify)[0]); delete m_pSettingChangeNotify; m_pSettingChangeNotify = NULL; lock.Unlock(); } BOOL AddSettingChangeNotify(HWND hWnd) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\n")); ATLASSERT(FALSE); return FALSE; } ATLASSERT(::IsWindow(hWnd)); BOOL bRet = FALSE; if(InitSettingChangeNotify() != FALSE) bRet = m_pSettingChangeNotify->Add(hWnd); lock.Unlock(); return bRet; } BOOL RemoveSettingChangeNotify(HWND hWnd) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\n")); ATLASSERT(FALSE); return FALSE; } BOOL bRet = FALSE; if(m_pSettingChangeNotify != NULL) bRet = m_pSettingChangeNotify->Remove(hWnd); lock.Unlock(); return bRet; } // Implementation - setting change notify dialog template and dialog procedure struct _ATL_EMPTY_DLGTEMPLATE : DLGTEMPLATE { _ATL_EMPTY_DLGTEMPLATE() { memset(this, 0, sizeof(_ATL_EMPTY_DLGTEMPLATE)); style = WS_POPUP; } WORD wMenu, wClass, wTitle; }; #ifdef _WIN64 static INT_PTR CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #else static BOOL CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #endif { if(uMsg == WM_SETTINGCHANGE) { // need conditional code because types don't match in winuser.h #ifdef _WIN64 CAppModule* pModule = (CAppModule*)::GetWindowLongPtr(hWnd, GWLP_USERDATA); #else CAppModule* pModule = (CAppModule*)LongToPtr(::GetWindowLongPtr(hWnd, GWLP_USERDATA)); #endif ATLASSERT(pModule != NULL); ATLASSERT(pModule->m_pSettingChangeNotify != NULL); const UINT uTimeout = 1500; // ms for(int i = 1; i < pModule->m_pSettingChangeNotify->GetSize(); i++) { #if !defined(_WIN32_WCE) ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_ABORTIFHUNG, uTimeout, NULL); #elif(_WIN32_WCE >= 400) // CE specific ::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_NORMAL, uTimeout, NULL); #else // _WIN32_WCE < 400 specific uTimeout; ::SendMessage((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam); #endif } return TRUE; } return FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CServerAppModule - module class for a COM server application class CServerAppModule : public CAppModule { public: HANDLE m_hEventShutdown; bool m_bActivity; DWORD m_dwTimeOut; DWORD m_dwPause; // Override of CAppModule::Init HRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL) { m_dwTimeOut = 5000; m_dwPause = 1000; return CAppModule::Init(pObjMap, hInstance, pLibID); } void Term() { if(m_hEventShutdown != NULL && ::CloseHandle(m_hEventShutdown)) m_hEventShutdown = NULL; CAppModule::Term(); } // COM Server methods #if (_MSC_VER >= 1300) LONG Unlock() throw() #else LONG Unlock() #endif { LONG lRet = CComModule::Unlock(); if(lRet == 0) { m_bActivity = true; ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero } return lRet; } void MonitorShutdown() { for(;;) { ::WaitForSingleObject(m_hEventShutdown, INFINITE); DWORD dwWait = 0; do { m_bActivity = false; dwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); } while(dwWait == WAIT_OBJECT_0); // timed out if(!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail { #if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) && defined(_ATL_FREE_THREADED) && !defined(_WIN32_WCE) ::CoSuspendClassObjects(); if(!m_bActivity && m_nLockCnt == 0) #endif break; } } // This handle should be valid now. If it isn't, // check if _Module.Term was called first (it shouldn't) if(::CloseHandle(m_hEventShutdown)) m_hEventShutdown = NULL; ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); } bool StartMonitor() { m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL); if(m_hEventShutdown == NULL) return false; DWORD dwThreadID = 0; #if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE) HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))MonitorProc, this, 0, (UINT*)&dwThreadID); #else HANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); #endif bool bRet = (hThread != NULL); if(bRet) ::CloseHandle(hThread); return bRet; } static DWORD WINAPI MonitorProc(void* pv) { CServerAppModule* p = (CServerAppModule*)pv; p->MonitorShutdown(); return 0; } #if (_ATL_VER < 0x0700) // search for an occurence of string p2 in string p1 static LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) { while(p1 != NULL && *p1 != NULL) { LPCTSTR p = p2; while(p != NULL && *p != NULL) { if(*p1 == *p) return ::CharNext(p1); p = ::CharNext(p); } p1 = ::CharNext(p1); } return NULL; } #endif // (_ATL_VER < 0x0700) }; /////////////////////////////////////////////////////////////////////////////// // CRegKeyEx - adds type-specific methods to ATL3 CRegKey #if (_ATL_VER < 0x0700) class CRegKeyEx : public ATL::CRegKey { public: // Constructors and operators CRegKeyEx(HKEY hKey = NULL) { m_hKey = hKey; } CRegKeyEx(CRegKeyEx& key) { Attach(key.Detach()); } CRegKeyEx& operator =(CRegKeyEx& key) { Close(); Attach(key.Detach()); return *this; } // Methods LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) { ATLASSERT(m_hKey != NULL); return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast(pValue), nBytes); } LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) { ATLASSERT(m_hKey != NULL); OLECHAR szGUID[64] = { 0 }; ::StringFromGUID2(guidValue, szGUID, 64); USES_CONVERSION; LPCTSTR lpstr = OLE2CT(szGUID); #ifndef _UNICODE if(lpstr == NULL) return E_OUTOFMEMORY; #endif return SetStringValue(pszValueName, lpstr); } LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) { ATLASSERT(m_hKey != NULL); return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast(pValue), nBytes); } LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) { ATLASSERT(m_hKey != NULL); return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast(&dwValue), sizeof(DWORD)); } #ifndef _WIN32_WCE LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) { ATLASSERT(m_hKey != NULL); return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast(&qwValue), sizeof(ULONGLONG)); } #endif LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) { ATLASSERT(m_hKey != NULL); if(pszValue == NULL) { ATLASSERT(FALSE); return ERROR_INVALID_DATA; } ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)); return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast(pszValue), (lstrlen(pszValue) + 1) * sizeof(TCHAR)); } LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) { ATLASSERT(m_hKey != NULL); if(pszValue == NULL) { ATLASSERT(FALSE); return ERROR_INVALID_DATA; } ULONG nBytes = 0; ULONG nLength = 0; LPCTSTR pszTemp = pszValue; do { nLength = lstrlen(pszTemp) + 1; pszTemp += nLength; nBytes += nLength * sizeof(TCHAR); } while (nLength != 1); return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast(pszValue), nBytes); } LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) { ATLASSERT(m_hKey != NULL); return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast(pData), pnBytes); } LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) { ATLASSERT(m_hKey != NULL); guidValue = GUID_NULL; TCHAR szGUID[64] = { 0 }; ULONG nCount = 64; LONG lRes = QueryStringValue(pszValueName, szGUID, &nCount); if (lRes != ERROR_SUCCESS) return lRes; if(szGUID[0] != _T('{')) return ERROR_INVALID_DATA; USES_CONVERSION; LPOLESTR lpstr = T2OLE(szGUID); #ifndef _UNICODE if(lpstr == NULL) return E_OUTOFMEMORY; #endif HRESULT hr = ::CLSIDFromString(lpstr, &guidValue); if (FAILED(hr)) return ERROR_INVALID_DATA; return ERROR_SUCCESS; } LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) { ATLASSERT(pnBytes != NULL); ATLASSERT(m_hKey != NULL); DWORD dwType = 0; LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pValue), pnBytes); if (lRes != ERROR_SUCCESS) return lRes; if (dwType != REG_BINARY) return ERROR_INVALID_DATA; return ERROR_SUCCESS; } LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) { ATLASSERT(m_hKey != NULL); ULONG nBytes = sizeof(DWORD); DWORD dwType = 0; LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&dwValue), &nBytes); if (lRes != ERROR_SUCCESS) return lRes; if (dwType != REG_DWORD) return ERROR_INVALID_DATA; return ERROR_SUCCESS; } #ifndef _WIN32_WCE LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) { ATLASSERT(m_hKey != NULL); ULONG nBytes = sizeof(ULONGLONG); DWORD dwType = 0; LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&qwValue), &nBytes); if (lRes != ERROR_SUCCESS) return lRes; if (dwType != REG_QWORD) return ERROR_INVALID_DATA; return ERROR_SUCCESS; } #endif LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) { ATLASSERT(m_hKey != NULL); ATLASSERT(pnChars != NULL); ULONG nBytes = (*pnChars) * sizeof(TCHAR); DWORD dwType = 0; *pnChars = 0; LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); if (lRes != ERROR_SUCCESS) { return lRes; } if(dwType != REG_SZ && dwType != REG_EXPAND_SZ) { return ERROR_INVALID_DATA; } if (pszValue != NULL) { if(nBytes != 0) { if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0)) return ERROR_INVALID_DATA; } else { pszValue[0] = _T('\0'); } } *pnChars = nBytes / sizeof(TCHAR); return ERROR_SUCCESS; } LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) { ATLASSERT(m_hKey != NULL); ATLASSERT(pnChars != NULL); if (pszValue != NULL && *pnChars < 2) return ERROR_INSUFFICIENT_BUFFER; ULONG nBytes = (*pnChars) * sizeof(TCHAR); DWORD dwType = 0; *pnChars = 0; LONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), &nBytes); if (lRes != ERROR_SUCCESS) return lRes; if (dwType != REG_MULTI_SZ) return ERROR_INVALID_DATA; if (pszValue != NULL && (nBytes % sizeof(TCHAR) != 0 || nBytes / sizeof(TCHAR) < 1 || pszValue[nBytes / sizeof(TCHAR) - 1] != 0 || ((nBytes / sizeof(TCHAR)) > 1 && pszValue[nBytes / sizeof(TCHAR) - 2] != 0))) return ERROR_INVALID_DATA; *pnChars = nBytes / sizeof(TCHAR); return ERROR_SUCCESS; } }; #else // !(_ATL_VER < 0x0700) typedef ATL::CRegKey CRegKeyEx; #endif // !(_ATL_VER < 0x0700) /////////////////////////////////////////////////////////////////////////////// // CString forward reference (enables CString use in atluser.h and atlgdi.h) #if defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) #define _WTL_USE_CSTRING #endif // defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING) #ifdef _WTL_USE_CSTRING class CString; // forward declaration (include atlmisc.h for the whole class) #endif // _WTL_USE_CSTRING // CString namespace #ifndef _CSTRING_NS #ifdef __ATLSTR_H__ #define _CSTRING_NS ATL #else #define _CSTRING_NS WTL #endif #endif // _CSTRING_NS // Type classes namespace #ifndef _WTYPES_NS #ifdef __ATLTYPES_H__ #define _WTYPES_NS #else #define _WTYPES_NS WTL #endif #endif // _WTYPES_NS }; // namespace WTL /////////////////////////////////////////////////////////////////////////////// // General DLL version helpers // (ATL3: excluded from atlbase.h if _ATL_DLL is defined; ATL11: removed) #if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE) namespace ATL { inline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo) { ATLASSERT(pDllVersionInfo != NULL); if(pDllVersionInfo == NULL) return E_INVALIDARG; // We must get this function explicitly because some DLLs don't implement it. DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, "DllGetVersion"); if(pfnDllGetVersion == NULL) return E_NOTIMPL; return (*pfnDllGetVersion)(pDllVersionInfo); } inline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo) { HINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName); if(hInstDLL == NULL) return E_FAIL; HRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo); ::FreeLibrary(hInstDLL); return hRet; } // Common Control Versions: // Win95/WinNT 4.0 maj=4 min=00 // IE 3.x maj=4 min=70 // IE 4.0 maj=4 min=71 inline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) { ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); if(pdwMajor == NULL || pdwMinor == NULL) return E_INVALIDARG; DLLVERSIONINFO dvi; ::ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); HRESULT hRet = AtlGetDllVersion(_T("comctl32.dll"), &dvi); if(SUCCEEDED(hRet)) { *pdwMajor = dvi.dwMajorVersion; *pdwMinor = dvi.dwMinorVersion; } else if(hRet == E_NOTIMPL) { // If DllGetVersion is not there, then the DLL is a version // previous to the one shipped with IE 3.x *pdwMajor = 4; *pdwMinor = 0; hRet = S_OK; } return hRet; } // Shell Versions: // Win95/WinNT 4.0 maj=4 min=00 // IE 3.x, IE 4.0 without Web Integrated Desktop maj=4 min=00 // IE 4.0 with Web Integrated Desktop maj=4 min=71 // IE 4.01 with Web Integrated Desktop maj=4 min=72 inline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) { ATLASSERT(pdwMajor != NULL && pdwMinor != NULL); if(pdwMajor == NULL || pdwMinor == NULL) return E_INVALIDARG; DLLVERSIONINFO dvi; ::ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); HRESULT hRet = AtlGetDllVersion(_T("shell32.dll"), &dvi); if(SUCCEEDED(hRet)) { *pdwMajor = dvi.dwMajorVersion; *pdwMinor = dvi.dwMinorVersion; } else if(hRet == E_NOTIMPL) { // If DllGetVersion is not there, then the DLL is a version // previous to the one shipped with IE 4.x *pdwMajor = 4; *pdwMinor = 0; hRet = S_OK; } return hRet; } }; // namespace ATL #endif // (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE) // These are always included #include "atlwinx.h" #include "atluser.h" #include "atlgdi.h" #ifndef _WTL_NO_AUTOMATIC_NAMESPACE using namespace WTL; #endif // !_WTL_NO_AUTOMATIC_NAMESPACE #endif // __ATLAPP_H__ ================================================ FILE: WTL/atlcrack.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLCRACK_H__ #define __ATLCRACK_H__ #pragma once #ifndef __ATLAPP_H__ #error atlcrack.h requires atlapp.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Message map macro for cracked handlers // Note about message maps with cracked handlers: // For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX. // For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes, // but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl. #define BEGIN_MSG_MAP_EX(theClass) \ public: \ BOOL m_bMsgHandled; \ /* "handled" management for cracked handlers */ \ BOOL IsMsgHandled() const \ { \ return m_bMsgHandled; \ } \ void SetMsgHandled(BOOL bHandled) \ { \ m_bMsgHandled = bHandled; \ } \ BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \ { \ BOOL bOldMsgHandled = m_bMsgHandled; \ BOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \ m_bMsgHandled = bOldMsgHandled; \ return bRet; \ } \ BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \ { \ BOOL bHandled = TRUE; \ (hWnd); \ (uMsg); \ (wParam); \ (lParam); \ (lResult); \ (bHandled); \ switch(dwMsgMapID) \ { \ case 0: /////////////////////////////////////////////////////////////////////////////// // Standard Windows message macros // int OnCreate(LPCREATESTRUCT lpCreateStruct) #define MSG_WM_CREATE(func) \ if (uMsg == WM_CREATE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam) #define MSG_WM_INITDIALOG(func) \ if (uMsg == WM_INITDIALOG) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct) #define MSG_WM_COPYDATA(func) \ if (uMsg == WM_COPYDATA) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDestroy() #define MSG_WM_DESTROY(func) \ if (uMsg == WM_DESTROY) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMove(CPoint ptPos) #define MSG_WM_MOVE(func) \ if (uMsg == WM_MOVE) \ { \ SetMsgHandled(TRUE); \ func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSize(UINT nType, CSize size) #define MSG_WM_SIZE(func) \ if (uMsg == WM_SIZE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther) #define MSG_WM_ACTIVATE(func) \ if (uMsg == WM_ACTIVATE) \ { \ SetMsgHandled(TRUE); \ func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSetFocus(CWindow wndOld) #define MSG_WM_SETFOCUS(func) \ if (uMsg == WM_SETFOCUS) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnKillFocus(CWindow wndFocus) #define MSG_WM_KILLFOCUS(func) \ if (uMsg == WM_KILLFOCUS) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnEnable(BOOL bEnable) #define MSG_WM_ENABLE(func) \ if (uMsg == WM_ENABLE) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPaint(CDCHandle dc) #define MSG_WM_PAINT(func) \ if (uMsg == WM_PAINT) \ { \ SetMsgHandled(TRUE); \ func((HDC)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnClose() #define MSG_WM_CLOSE(func) \ if (uMsg == WM_CLOSE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnQueryEndSession(UINT nSource, UINT uLogOff) #define MSG_WM_QUERYENDSESSION(func) \ if (uMsg == WM_QUERYENDSESSION) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnQueryOpen() #define MSG_WM_QUERYOPEN(func) \ if (uMsg == WM_QUERYOPEN) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(); \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnEraseBkgnd(CDCHandle dc) #define MSG_WM_ERASEBKGND(func) \ if (uMsg == WM_ERASEBKGND) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysColorChange() #define MSG_WM_SYSCOLORCHANGE(func) \ if (uMsg == WM_SYSCOLORCHANGE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnEndSession(BOOL bEnding, UINT uLogOff) #define MSG_WM_ENDSESSION(func) \ if (uMsg == WM_ENDSESSION) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam, (UINT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnShowWindow(BOOL bShow, UINT nStatus) #define MSG_WM_SHOWWINDOW(func) \ if (uMsg == WM_SHOWWINDOW) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam, (int)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit) #define MSG_WM_CTLCOLOREDIT(func) \ if (uMsg == WM_CTLCOLOREDIT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox) #define MSG_WM_CTLCOLORLISTBOX(func) \ if (uMsg == WM_CTLCOLORLISTBOX) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button) #define MSG_WM_CTLCOLORBTN(func) \ if (uMsg == WM_CTLCOLORBTN) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd) #define MSG_WM_CTLCOLORDLG(func) \ if (uMsg == WM_CTLCOLORDLG) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) #define MSG_WM_CTLCOLORSCROLLBAR(func) \ if (uMsg == WM_CTLCOLORSCROLLBAR) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic) #define MSG_WM_CTLCOLORSTATIC(func) \ if (uMsg == WM_CTLCOLORSTATIC) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSettingChange(UINT uFlags, LPCTSTR lpszSection) #define MSG_WM_SETTINGCHANGE(func) \ if (uMsg == WM_SETTINGCHANGE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPCTSTR)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDevModeChange(LPCTSTR lpDeviceName) #define MSG_WM_DEVMODECHANGE(func) \ if (uMsg == WM_DEVMODECHANGE) \ { \ SetMsgHandled(TRUE); \ func((LPCTSTR)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnActivateApp(BOOL bActive, DWORD dwThreadID) #define MSG_WM_ACTIVATEAPP(func) \ if (uMsg == WM_ACTIVATEAPP) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam, (DWORD)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnFontChange() #define MSG_WM_FONTCHANGE(func) \ if (uMsg == WM_FONTCHANGE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnTimeChange() #define MSG_WM_TIMECHANGE(func) \ if (uMsg == WM_TIMECHANGE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCancelMode() #define MSG_WM_CANCELMODE(func) \ if (uMsg == WM_CANCELMODE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message) #define MSG_WM_SETCURSOR(func) \ if (uMsg == WM_SETCURSOR) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ if(IsMsgHandled()) \ return TRUE; \ } // int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message) #define MSG_WM_MOUSEACTIVATE(func) \ if (uMsg == WM_MOUSEACTIVATE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnChildActivate() #define MSG_WM_CHILDACTIVATE(func) \ if (uMsg == WM_CHILDACTIVATE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnGetMinMaxInfo(LPMINMAXINFO lpMMI) #define MSG_WM_GETMINMAXINFO(func) \ if (uMsg == WM_GETMINMAXINFO) \ { \ SetMsgHandled(TRUE); \ func((LPMINMAXINFO)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnIconEraseBkgnd(CDCHandle dc) #define MSG_WM_ICONERASEBKGND(func) \ if (uMsg == WM_ICONERASEBKGND) \ { \ SetMsgHandled(TRUE); \ func((HDC)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSpoolerStatus(UINT nStatus, UINT nJobs) #define MSG_WM_SPOOLERSTATUS(func) \ if (uMsg == WM_SPOOLERSTATUS) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (UINT)LOWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) #define MSG_WM_DRAWITEM(func) \ if (uMsg == WM_DRAWITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) #define MSG_WM_MEASUREITEM(func) \ if (uMsg == WM_MEASUREITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) #define MSG_WM_DELETEITEM(func) \ if (uMsg == WM_DELETEITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } //int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox) #define MSG_WM_CHARTOITEM(func) \ if (uMsg == WM_CHARTOITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) #define MSG_WM_VKEYTOITEM(func) \ if (uMsg == WM_VKEYTOITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HCURSOR OnQueryDragIcon() #define MSG_WM_QUERYDRAGICON(func) \ if (uMsg == WM_QUERYDRAGICON) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(); \ if(IsMsgHandled()) \ return TRUE; \ } // int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) #define MSG_WM_COMPAREITEM(func) \ if (uMsg == WM_COMPAREITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCompacting(UINT nCpuTime) #define MSG_WM_COMPACTING(func) \ if (uMsg == WM_COMPACTING) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct) #define MSG_WM_NCCREATE(func) \ if (uMsg == WM_NCCREATE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcDestroy() #define MSG_WM_NCDESTROY(func) \ if (uMsg == WM_NCDESTROY) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam) #define MSG_WM_NCCALCSIZE(func) \ if (uMsg == WM_NCCALCSIZE) \ { \ SetMsgHandled(TRUE); \ lResult = func((BOOL)wParam, lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // UINT OnNcHitTest(CPoint point) #define MSG_WM_NCHITTEST(func) \ if (uMsg == WM_NCHITTEST) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcPaint(CRgnHandle rgn) #define MSG_WM_NCPAINT(func) \ if (uMsg == WM_NCPAINT) \ { \ SetMsgHandled(TRUE); \ func((HRGN)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnNcActivate(BOOL bActive) #define MSG_WM_NCACTIVATE(func) \ if (uMsg == WM_NCACTIVATE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((BOOL)wParam); \ if(IsMsgHandled()) \ return TRUE; \ } // UINT OnGetDlgCode(LPMSG lpMsg) #define MSG_WM_GETDLGCODE(func) \ if (uMsg == WM_GETDLGCODE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPMSG)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcMouseMove(UINT nHitTest, CPoint point) #define MSG_WM_NCMOUSEMOVE(func) \ if (uMsg == WM_NCMOUSEMOVE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcLButtonDown(UINT nHitTest, CPoint point) #define MSG_WM_NCLBUTTONDOWN(func) \ if (uMsg == WM_NCLBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcLButtonUp(UINT nHitTest, CPoint point) #define MSG_WM_NCLBUTTONUP(func) \ if (uMsg == WM_NCLBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcLButtonDblClk(UINT nHitTest, CPoint point) #define MSG_WM_NCLBUTTONDBLCLK(func) \ if (uMsg == WM_NCLBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcRButtonDown(UINT nHitTest, CPoint point) #define MSG_WM_NCRBUTTONDOWN(func) \ if (uMsg == WM_NCRBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcRButtonUp(UINT nHitTest, CPoint point) #define MSG_WM_NCRBUTTONUP(func) \ if (uMsg == WM_NCRBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcRButtonDblClk(UINT nHitTest, CPoint point) #define MSG_WM_NCRBUTTONDBLCLK(func) \ if (uMsg == WM_NCRBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcMButtonDown(UINT nHitTest, CPoint point) #define MSG_WM_NCMBUTTONDOWN(func) \ if (uMsg == WM_NCMBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcMButtonUp(UINT nHitTest, CPoint point) #define MSG_WM_NCMBUTTONUP(func) \ if (uMsg == WM_NCMBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNcMButtonDblClk(UINT nHitTest, CPoint point) #define MSG_WM_NCMBUTTONDBLCLK(func) \ if (uMsg == WM_NCMBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_KEYDOWN(func) \ if (uMsg == WM_KEYDOWN) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_KEYUP(func) \ if (uMsg == WM_KEYUP) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_CHAR(func) \ if (uMsg == WM_CHAR) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_DEADCHAR(func) \ if (uMsg == WM_DEADCHAR) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_SYSKEYDOWN(func) \ if (uMsg == WM_SYSKEYDOWN) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_SYSKEYUP(func) \ if (uMsg == WM_SYSKEYUP) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_SYSCHAR(func) \ if (uMsg == WM_SYSCHAR) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_SYSDEADCHAR(func) \ if (uMsg == WM_SYSDEADCHAR) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSysCommand(UINT nID, CPoint point) #define MSG_WM_SYSCOMMAND(func) \ if (uMsg == WM_SYSCOMMAND) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnTCard(UINT idAction, DWORD dwActionData) #define MSG_WM_TCARD(func) \ if (uMsg == WM_TCARD) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (DWORD)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnTimer(UINT_PTR nIDEvent) #define MSG_WM_TIMER(func) \ if (uMsg == WM_TIMER) \ { \ SetMsgHandled(TRUE); \ func((UINT_PTR)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) #define MSG_WM_HSCROLL(func) \ if (uMsg == WM_HSCROLL) \ { \ SetMsgHandled(TRUE); \ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) #define MSG_WM_VSCROLL(func) \ if (uMsg == WM_VSCROLL) \ { \ SetMsgHandled(TRUE); \ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnInitMenu(CMenuHandle menu) #define MSG_WM_INITMENU(func) \ if (uMsg == WM_INITMENU) \ { \ SetMsgHandled(TRUE); \ func((HMENU)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnInitMenuPopup(CMenuHandle menuPopup, UINT nIndex, BOOL bSysMenu) #define MSG_WM_INITMENUPOPUP(func) \ if (uMsg == WM_INITMENUPOPUP) \ { \ SetMsgHandled(TRUE); \ func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMenuSelect(UINT nItemID, UINT nFlags, CMenuHandle menu) #define MSG_WM_MENUSELECT(func) \ if (uMsg == WM_MENUSELECT) \ { \ SetMsgHandled(TRUE); \ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenuHandle menu) #define MSG_WM_MENUCHAR(func) \ if (uMsg == WM_MENUCHAR) \ { \ SetMsgHandled(TRUE); \ lResult = func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotify(int idCtrl, LPNMHDR pnmh) #define MSG_WM_NOTIFY(func) \ if (uMsg == WM_NOTIFY) \ { \ SetMsgHandled(TRUE); \ lResult = func((int)wParam, (LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnEnterIdle(UINT nWhy, CWindow wndWho) #define MSG_WM_ENTERIDLE(func) \ if (uMsg == WM_ENTERIDLE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMouseMove(UINT nFlags, CPoint point) #define MSG_WM_MOUSEMOVE(func) \ if (uMsg == WM_MOUSEMOVE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) #define MSG_WM_MOUSEWHEEL(func) \ if (uMsg == WM_MOUSEWHEEL) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnLButtonDown(UINT nFlags, CPoint point) #define MSG_WM_LBUTTONDOWN(func) \ if (uMsg == WM_LBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnLButtonUp(UINT nFlags, CPoint point) #define MSG_WM_LBUTTONUP(func) \ if (uMsg == WM_LBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnLButtonDblClk(UINT nFlags, CPoint point) #define MSG_WM_LBUTTONDBLCLK(func) \ if (uMsg == WM_LBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRButtonDown(UINT nFlags, CPoint point) #define MSG_WM_RBUTTONDOWN(func) \ if (uMsg == WM_RBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRButtonUp(UINT nFlags, CPoint point) #define MSG_WM_RBUTTONUP(func) \ if (uMsg == WM_RBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRButtonDblClk(UINT nFlags, CPoint point) #define MSG_WM_RBUTTONDBLCLK(func) \ if (uMsg == WM_RBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMButtonDown(UINT nFlags, CPoint point) #define MSG_WM_MBUTTONDOWN(func) \ if (uMsg == WM_MBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMButtonUp(UINT nFlags, CPoint point) #define MSG_WM_MBUTTONUP(func) \ if (uMsg == WM_MBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMButtonDblClk(UINT nFlags, CPoint point) #define MSG_WM_MBUTTONDBLCLK(func) \ if (uMsg == WM_MBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam) #define MSG_WM_PARENTNOTIFY(func) \ if (uMsg == WM_PARENTNOTIFY) \ { \ SetMsgHandled(TRUE); \ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate) #define MSG_WM_MDIACTIVATE(func) \ if (uMsg == WM_MDIACTIVATE) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRenderFormat(UINT nFormat) #define MSG_WM_RENDERFORMAT(func) \ if (uMsg == WM_RENDERFORMAT) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRenderAllFormats() #define MSG_WM_RENDERALLFORMATS(func) \ if (uMsg == WM_RENDERALLFORMATS) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDestroyClipboard() #define MSG_WM_DESTROYCLIPBOARD(func) \ if (uMsg == WM_DESTROYCLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDrawClipboard() #define MSG_WM_DRAWCLIPBOARD(func) \ if (uMsg == WM_DRAWCLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct) #define MSG_WM_PAINTCLIPBOARD(func) \ if (uMsg == WM_PAINTCLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \ ::GlobalUnlock((HGLOBAL)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) #define MSG_WM_VSCROLLCLIPBOARD(func) \ if (uMsg == WM_VSCROLLCLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnContextMenu(CWindow wnd, CPoint point) #define MSG_WM_CONTEXTMENU(func) \ if (uMsg == WM_CONTEXTMENU) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect) #define MSG_WM_SIZECLIPBOARD(func) \ if (uMsg == WM_SIZECLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \ ::GlobalUnlock((HGLOBAL)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString) #define MSG_WM_ASKCBFORMATNAME(func) \ if (uMsg == WM_ASKCBFORMATNAME) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPTSTR)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter) #define MSG_WM_CHANGECBCHAIN(func) \ if (uMsg == WM_CHANGECBCHAIN) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos) #define MSG_WM_HSCROLLCLIPBOARD(func) \ if (uMsg == WM_HSCROLLCLIPBOARD) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnQueryNewPalette() #define MSG_WM_QUERYNEWPALETTE(func) \ if (uMsg == WM_QUERYNEWPALETTE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPaletteChanged(CWindow wndFocus) #define MSG_WM_PALETTECHANGED(func) \ if (uMsg == WM_PALETTECHANGED) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPaletteIsChanging(CWindow wndPalChg) #define MSG_WM_PALETTEISCHANGING(func) \ if (uMsg == WM_PALETTEISCHANGING) \ { \ SetMsgHandled(TRUE); \ func((HWND)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDropFiles(HDROP hDropInfo) #define MSG_WM_DROPFILES(func) \ if (uMsg == WM_DROPFILES) \ { \ SetMsgHandled(TRUE); \ func((HDROP)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnWindowPosChanging(LPWINDOWPOS lpWndPos) #define MSG_WM_WINDOWPOSCHANGING(func) \ if (uMsg == WM_WINDOWPOSCHANGING) \ { \ SetMsgHandled(TRUE); \ func((LPWINDOWPOS)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnWindowPosChanged(LPWINDOWPOS lpWndPos) #define MSG_WM_WINDOWPOSCHANGED(func) \ if (uMsg == WM_WINDOWPOSCHANGED) \ { \ SetMsgHandled(TRUE); \ func((LPWINDOWPOS)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnExitMenuLoop(BOOL fIsTrackPopupMenu) #define MSG_WM_EXITMENULOOP(func) \ if (uMsg == WM_EXITMENULOOP) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnEnterMenuLoop(BOOL fIsTrackPopupMenu) #define MSG_WM_ENTERMENULOOP(func) \ if (uMsg == WM_ENTERMENULOOP) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct) #define MSG_WM_STYLECHANGED(func) \ if (uMsg == WM_STYLECHANGED) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct) #define MSG_WM_STYLECHANGING(func) \ if (uMsg == WM_STYLECHANGING) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSizing(UINT fwSide, LPRECT pRect) #define MSG_WM_SIZING(func) \ if (uMsg == WM_SIZING) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPRECT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMoving(UINT fwSide, LPRECT pRect) #define MSG_WM_MOVING(func) \ if (uMsg == WM_MOVING) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPRECT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCaptureChanged(CWindow wnd) #define MSG_WM_CAPTURECHANGED(func) \ if (uMsg == WM_CAPTURECHANGED) \ { \ SetMsgHandled(TRUE); \ func((HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData) #define MSG_WM_DEVICECHANGE(func) \ if (uMsg == WM_DEVICECHANGE) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam, (DWORD_PTR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) #define MSG_WM_COMMAND(func) \ if (uMsg == WM_COMMAND) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDisplayChange(UINT uBitsPerPixel, CSize sizeScreen) #define MSG_WM_DISPLAYCHANGE(func) \ if (uMsg == WM_DISPLAYCHANGE) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnEnterSizeMove() #define MSG_WM_ENTERSIZEMOVE(func) \ if (uMsg == WM_ENTERSIZEMOVE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnExitSizeMove() #define MSG_WM_EXITSIZEMOVE(func) \ if (uMsg == WM_EXITSIZEMOVE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // HFONT OnGetFont() #define MSG_WM_GETFONT(func) \ if (uMsg == WM_GETFONT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnGetHotKey() #define MSG_WM_GETHOTKEY(func) \ if (uMsg == WM_GETHOTKEY) \ { \ SetMsgHandled(TRUE); \ lResult = func(); \ if(IsMsgHandled()) \ return TRUE; \ } // HICON OnGetIcon() #define MSG_WM_GETICON(func) \ if (uMsg == WM_GETICON) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam); \ if(IsMsgHandled()) \ return TRUE; \ } // int OnGetText(int cchTextMax, LPTSTR lpszText) #define MSG_WM_GETTEXT(func) \ if (uMsg == WM_GETTEXT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // int OnGetTextLength() #define MSG_WM_GETTEXTLENGTH(func) \ if (uMsg == WM_GETTEXTLENGTH) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func(); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnHelp(LPHELPINFO lpHelpInfo) #define MSG_WM_HELP(func) \ if (uMsg == WM_HELP) \ { \ SetMsgHandled(TRUE); \ func((LPHELPINFO)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey) #define MSG_WM_HOTKEY(func) \ if (uMsg == WM_HOTKEY) \ { \ SetMsgHandled(TRUE); \ func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout) #define MSG_WM_INPUTLANGCHANGE(func) \ if (uMsg == WM_INPUTLANGCHANGE) \ { \ SetMsgHandled(TRUE); \ func((DWORD)wParam, (HKL)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout) #define MSG_WM_INPUTLANGCHANGEREQUEST(func) \ if (uMsg == WM_INPUTLANGCHANGEREQUEST) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam, (HKL)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus) #define MSG_WM_NEXTDLGCTL(func) \ if (uMsg == WM_NEXTDLGCTL) \ { \ SetMsgHandled(TRUE); \ func((BOOL)LOWORD(lParam), wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu) #define MSG_WM_NEXTMENU(func) \ if (uMsg == WM_NEXTMENU) \ { \ SetMsgHandled(TRUE); \ func((int)wParam, (LPMDINEXTMENU)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // int OnNotifyFormat(CWindow wndFrom, int nCommand) #define MSG_WM_NOTIFYFORMAT(func) \ if (uMsg == WM_NOTIFYFORMAT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, (int)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD_PTR dwData) #define MSG_WM_POWERBROADCAST(func) \ if (uMsg == WM_POWERBROADCAST) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((DWORD)wParam, (DWORD_PTR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPrint(CDCHandle dc, UINT uFlags) #define MSG_WM_PRINT(func) \ if (uMsg == WM_PRINT) \ { \ SetMsgHandled(TRUE); \ func((HDC)wParam, (UINT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPrintClient(CDCHandle dc, UINT uFlags) #define MSG_WM_PRINTCLIENT(func) \ if (uMsg == WM_PRINTCLIENT) \ { \ SetMsgHandled(TRUE); \ func((HDC)wParam, (UINT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError) #define MSG_WM_RASDIALEVENT(func) \ if (uMsg == WM_RASDIALEVENT) \ { \ SetMsgHandled(TRUE); \ func((RASCONNSTATE)wParam, (DWORD)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSetFont(CFontHandle font, BOOL bRedraw) #define MSG_WM_SETFONT(func) \ if (uMsg == WM_SETFONT) \ { \ SetMsgHandled(TRUE); \ func((HFONT)wParam, (BOOL)LOWORD(lParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // int OnSetHotKey(int nVirtKey, UINT uFlags) #define MSG_WM_SETHOTKEY(func) \ if (uMsg == WM_SETHOTKEY) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), (UINT)HIBYTE(LOWORD(wParam))); \ if(IsMsgHandled()) \ return TRUE; \ } // HICON OnSetIcon(UINT uType, HICON hIcon) #define MSG_WM_SETICON(func) \ if (uMsg == WM_SETICON) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnSetRedraw(BOOL bRedraw) #define MSG_WM_SETREDRAW(func) \ if (uMsg == WM_SETREDRAW) \ { \ SetMsgHandled(TRUE); \ func((BOOL)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // int OnSetText(LPCTSTR lpstrText) #define MSG_WM_SETTEXT(func) \ if (uMsg == WM_SETTEXT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPCTSTR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnUserChanged() #define MSG_WM_USERCHANGED(func) \ if (uMsg == WM_USERCHANGED) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // New NT4 & NT5 messages #if (_WIN32_WINNT >= 0x0400) // void OnMouseHover(WPARAM wParam, CPoint ptPos) #define MSG_WM_MOUSEHOVER(func) \ if (uMsg == WM_MOUSEHOVER) \ { \ SetMsgHandled(TRUE); \ func(wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMouseLeave() #define MSG_WM_MOUSELEAVE(func) \ if (uMsg == WM_MOUSELEAVE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } #endif // _WIN32_WINNT >= 0x0400 #if (WINVER >= 0x0500) // void OnMenuRButtonUp(WPARAM wParam, CMenuHandle menu) #define MSG_WM_MENURBUTTONUP(func) \ if (uMsg == WM_MENURBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func(wParam, (HMENU)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnMenuDrag(WPARAM wParam, CMenuHandle menu) #define MSG_WM_MENUDRAG(func) \ if (uMsg == WM_MENUDRAG) \ { \ SetMsgHandled(TRUE); \ lResult = func(wParam, (HMENU)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info) #define MSG_WM_MENUGETOBJECT(func) \ if (uMsg == WM_MENUGETOBJECT) \ { \ SetMsgHandled(TRUE); \ lResult = func((PMENUGETOBJECTINFO)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnUnInitMenuPopup(UINT nID, CMenuHandle menu) #define MSG_WM_UNINITMENUPOPUP(func) \ if (uMsg == WM_UNINITMENUPOPUP) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(lParam), (HMENU)wParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnMenuCommand(WPARAM nIndex, CMenuHandle menu) #define MSG_WM_MENUCOMMAND(func) \ if (uMsg == WM_MENUCOMMAND) \ { \ SetMsgHandled(TRUE); \ func(wParam, (HMENU)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } #endif // WINVER >= 0x0500 #if (_WIN32_WINNT >= 0x0500) // BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys) #define MSG_WM_APPCOMMAND(func) \ if (uMsg == WM_APPCOMMAND) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos) #define MSG_WM_NCXBUTTONDOWN(func) \ if (uMsg == WM_NCXBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos) #define MSG_WM_NCXBUTTONUP(func) \ if (uMsg == WM_NCXBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos) #define MSG_WM_NCXBUTTONDBLCLK(func) \ if (uMsg == WM_NCXBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos) #define MSG_WM_XBUTTONDOWN(func) \ if (uMsg == WM_XBUTTONDOWN) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos) #define MSG_WM_XBUTTONUP(func) \ if (uMsg == WM_XBUTTONUP) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos) #define MSG_WM_XBUTTONDBLCLK(func) \ if (uMsg == WM_XBUTTONDBLCLK) \ { \ SetMsgHandled(TRUE); \ func(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnChangeUIState(WORD nAction, WORD nState) #define MSG_WM_CHANGEUISTATE(func) \ if (uMsg == WM_CHANGEUISTATE) \ { \ SetMsgHandled(TRUE); \ func(LOWORD(wParam), HIWORD(wParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnUpdateUIState(WORD nAction, WORD nState) #define MSG_WM_UPDATEUISTATE(func) \ if (uMsg == WM_UPDATEUISTATE) \ { \ SetMsgHandled(TRUE); \ func(LOWORD(wParam), HIWORD(wParam)); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnQueryUIState() #define MSG_WM_QUERYUISTATE(func) \ if (uMsg == WM_QUERYUISTATE) \ { \ SetMsgHandled(TRUE); \ lResult = func(); \ if(IsMsgHandled()) \ return TRUE; \ } #endif // (_WIN32_WINNT >= 0x0500) #if(_WIN32_WINNT >= 0x0501) // void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput) #define MSG_WM_INPUT(func) \ if (uMsg == WM_INPUT) \ { \ SetMsgHandled(TRUE); \ func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags) #define MSG_WM_UNICHAR(func) \ if (uMsg == WM_UNICHAR) \ { \ SetMsgHandled(TRUE); \ func((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \ if(IsMsgHandled()) \ { \ lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \ return TRUE; \ } \ } // void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION nSessionID) #define MSG_WM_WTSSESSION_CHANGE(func) \ if (uMsg == WM_WTSSESSION_CHANGE) \ { \ SetMsgHandled(TRUE); \ func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnThemeChanged() #define MSG_WM_THEMECHANGED(func) \ if (uMsg == WM_THEMECHANGED) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } #endif // _WIN32_WINNT >= 0x0501 #if (_WIN32_WINNT >= 0x0600) // BOOL OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt) #define MSG_WM_MOUSEHWHEEL(func) \ if (uMsg == WM_MOUSEHWHEEL) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \ if(IsMsgHandled()) \ return TRUE; \ } #endif // (_WIN32_WINNT >= 0x0600) /////////////////////////////////////////////////////////////////////////////// // ATL defined messages // BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData) #define MSG_WM_FORWARDMSG(func) \ if (uMsg == WM_FORWARDMSG) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Dialog specific messages // LRESULT OnDMGetDefID() #define MSG_DM_GETDEFID(func) \ if (uMsg == DM_GETDEFID) \ { \ SetMsgHandled(TRUE); \ lResult = func(); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDMSetDefID(UINT DefID) #define MSG_DM_SETDEFID(func) \ if (uMsg == DM_SETDEFID) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnDMReposition() #define MSG_DM_REPOSITION(func) \ if (uMsg == DM_REPOSITION) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Reflected messages // void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl) #define MSG_OCM_COMMAND(func) \ if (uMsg == OCM_COMMAND) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh) #define MSG_OCM_NOTIFY(func) \ if (uMsg == OCM_NOTIFY) \ { \ SetMsgHandled(TRUE); \ lResult = func((int)wParam, (LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam) #define MSG_OCM_PARENTNOTIFY(func) \ if (uMsg == OCM_PARENTNOTIFY) \ { \ SetMsgHandled(TRUE); \ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) #define MSG_OCM_DRAWITEM(func) \ if (uMsg == OCM_DRAWITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) #define MSG_OCM_MEASUREITEM(func) \ if (uMsg == OCM_MEASUREITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct) #define MSG_OCM_COMPAREITEM(func) \ if (uMsg == OCM_COMPAREITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct) #define MSG_OCM_DELETEITEM(func) \ if (uMsg == OCM_DELETEITEM) \ { \ SetMsgHandled(TRUE); \ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \ lResult = TRUE; \ if(IsMsgHandled()) \ return TRUE; \ } // int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox) #define MSG_OCM_VKEYTOITEM(func) \ if (uMsg == OCM_VKEYTOITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } //int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox) #define MSG_OCM_CHARTOITEM(func) \ if (uMsg == OCM_CHARTOITEM) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) #define MSG_OCM_HSCROLL(func) \ if (uMsg == OCM_HSCROLL) \ { \ SetMsgHandled(TRUE); \ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar) #define MSG_OCM_VSCROLL(func) \ if (uMsg == OCM_VSCROLL) \ { \ SetMsgHandled(TRUE); \ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit) #define MSG_OCM_CTLCOLOREDIT(func) \ if (uMsg == OCM_CTLCOLOREDIT) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox) #define MSG_OCM_CTLCOLORLISTBOX(func) \ if (uMsg == OCM_CTLCOLORLISTBOX) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button) #define MSG_OCM_CTLCOLORBTN(func) \ if (uMsg == OCM_CTLCOLORBTN) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd) #define MSG_OCM_CTLCOLORDLG(func) \ if (uMsg == OCM_CTLCOLORDLG) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar) #define MSG_OCM_CTLCOLORSCROLLBAR(func) \ if (uMsg == OCM_CTLCOLORSCROLLBAR) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic) #define MSG_OCM_CTLCOLORSTATIC(func) \ if (uMsg == OCM_CTLCOLORSTATIC) \ { \ SetMsgHandled(TRUE); \ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Edit specific messages // void OnClear() #define MSG_WM_CLEAR(func) \ if (uMsg == WM_CLEAR) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCopy() #define MSG_WM_COPY(func) \ if (uMsg == WM_COPY) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCut() #define MSG_WM_CUT(func) \ if (uMsg == WM_CUT) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnPaste() #define MSG_WM_PASTE(func) \ if (uMsg == WM_PASTE) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnUndo() #define MSG_WM_UNDO(func) \ if (uMsg == WM_UNDO) \ { \ SetMsgHandled(TRUE); \ func(); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Generic message handlers // LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) #define MESSAGE_HANDLER_EX(msg, func) \ if(uMsg == msg) \ { \ SetMsgHandled(TRUE); \ lResult = func(uMsg, wParam, lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam) #define MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \ if(uMsg >= msgFirst && uMsg <= msgLast) \ { \ SetMsgHandled(TRUE); \ lResult = func(uMsg, wParam, lParam); \ if(IsMsgHandled()) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Commands and notifications // void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define COMMAND_HANDLER_EX(id, code, func) \ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define COMMAND_ID_HANDLER_EX(id, func) \ if (uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define COMMAND_CODE_HANDLER_EX(code, func) \ if (uMsg == WM_COMMAND && code == HIWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotifyHandlerEX(LPNMHDR pnmh) #define NOTIFY_HANDLER_EX(id, cd, func) \ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh) #define NOTIFY_ID_HANDLER_EX(id, func) \ if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh) #define NOTIFY_CODE_HANDLER_EX(cd, func) \ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh) #define NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh) #define NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define REFLECTED_COMMAND_HANDLER_EX(id, code, func) \ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \ if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \ if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh) #define REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh) #define REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \ if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh) #define REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \ if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl) #define REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \ if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ SetMsgHandled(TRUE); \ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \ lResult = 0; \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh) #define REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \ if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } // LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh) #define REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ SetMsgHandled(TRUE); \ lResult = func((LPNMHDR)lParam); \ if(IsMsgHandled()) \ return TRUE; \ } #endif // __ATLCRACK_H__ ================================================ FILE: WTL/atlctrls.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLCTRLS_H__ #define __ATLCTRLS_H__ #pragma once #ifndef __ATLAPP_H__ #error atlctrls.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlctrls.h requires atlwin.h to be included first #endif #ifndef _WIN32_WCE #include #include #elif defined(WIN32_PLATFORM_WFSP) && !defined(_WINUSERM_H_) #include #endif // !_WIN32_WCE // protect template members from windowsx.h macros #ifdef _INC_WINDOWSX #undef GetNextSibling #undef GetPrevSibling #endif // _INC_WINDOWSX /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CStaticT - CStatic // CButtonT - CButton // CListBoxT - CListBox // CComboBoxT - CComboBox // CEditT - CEdit // CEditCommands // CScrollBarT - CScrollBar // // CImageListT - CImageList, CImageListManaged // CListViewCtrlT - CListViewCtrl // CTreeViewCtrlT - CTreeViewCtrl // CTreeItemT - CTreeItem // CTreeViewCtrlExT - CTreeViewCtrlEx // CHeaderCtrlT - CHeaderCtrl // CToolBarCtrlT - CToolBarCtrl // CStatusBarCtrlT - CStatusBarCtrl // CTabCtrlT - CTabCtrl // CToolInfo // CToolTipCtrlT - CToolTipCtrl // CTrackBarCtrlT - CTrackBarCtrl // CUpDownCtrlT - CUpDownCtrl // CProgressBarCtrlT - CProgressBarCtrl // CHotKeyCtrlT - CHotKeyCtrl // CAnimateCtrlT - CAnimateCtrl // CRichEditCtrlT - CRichEditCtrl // CRichEditCommands // CDragListBoxT - CDragListBox // CDragListNotifyImpl // CReBarCtrlT - CReBarCtrl // CComboBoxExT - CComboBoxEx // CDateTimePickerCtrlT - CDateTimePickerCtrl // CMonthCalendarCtrlT - CMonthCalendarCtrl // CFlatScrollBarImpl // CFlatScrollBarT - CFlatScrollBar // CIPAddressCtrlT - CIPAddressCtrl // CPagerCtrlT - CPagerCtrl // CLinkCtrlT - CLinkCtrl // // CCustomDraw // // CCECommandBarCtrlT - CCECommandBarCtrl // CCECommandBandsCtrlT - CCECommandBandsCtrl namespace WTL { // These are wrapper classes for Windows standard and common controls. // To implement a window based on a control, use following: // Example: Implementing a window based on a list box // // class CMyListBox : CWindowImpl // { // public: // BEGIN_MSG_MAP(CMyListBox) // // put your message handler entries here // END_MSG_MAP() // }; // --- Standard Windows controls --- /////////////////////////////////////////////////////////////////////////////// // CStatic - client side for a Windows STATIC control template class CStaticT : public TBase { public: // Constructors CStaticT(HWND hWnd = NULL) : TBase(hWnd) { } CStaticT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("STATIC"); } #ifndef _WIN32_WCE HICON GetIcon() const { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, STM_GETICON, 0, 0L); } HICON SetIcon(HICON hIcon) { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, STM_SETICON, (WPARAM)hIcon, 0L); } HENHMETAFILE GetEnhMetaFile() const { ATLASSERT(::IsWindow(m_hWnd)); return (HENHMETAFILE)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ENHMETAFILE, 0L); } HENHMETAFILE SetEnhMetaFile(HENHMETAFILE hMetaFile) { ATLASSERT(::IsWindow(m_hWnd)); return (HENHMETAFILE)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)hMetaFile); } #else // CE specific HICON GetIcon() const { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ICON, 0L); } HICON SetIcon(HICON hIcon) { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); } #endif // _WIN32_WCE CBitmapHandle GetBitmap() const { ATLASSERT(::IsWindow(m_hWnd)); return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0L)); } CBitmapHandle SetBitmap(HBITMAP hBitmap) { ATLASSERT(::IsWindow(m_hWnd)); return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); } HCURSOR GetCursor() const { ATLASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_CURSOR, 0L); } HCURSOR SetCursor(HCURSOR hCursor) { ATLASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor); } }; typedef CStaticT CStatic; /////////////////////////////////////////////////////////////////////////////// // CButton - client side for a Windows BUTTON control template class CButtonT : public TBase { public: // Constructors CButtonT(HWND hWnd = NULL) : TBase(hWnd) { } CButtonT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("BUTTON"); } UINT GetState() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L); } void SetState(BOOL bHighlight) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L); } int GetCheck() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0L); } void SetCheck(int nCheck) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0L); } UINT GetButtonStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::GetWindowLong(m_hWnd, GWL_STYLE) & 0xFFFF; } void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw); } #ifndef _WIN32_WCE HICON GetIcon() const { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L); } HICON SetIcon(HICON hIcon) { ATLASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); } CBitmapHandle GetBitmap() const { ATLASSERT(::IsWindow(m_hWnd)); return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L)); } CBitmapHandle SetBitmap(HBITMAP hBitmap) { ATLASSERT(::IsWindow(m_hWnd)); return CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap)); } #endif // !_WIN32_WCE #if (_WIN32_WINNT >= 0x0501) BOOL GetIdealSize(LPSIZE lpSize) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, BCM_GETIDEALSIZE, 0, (LPARAM)lpSize); } BOOL GetImageList(PBUTTON_IMAGELIST pButtonImagelist) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, BCM_GETIMAGELIST, 0, (LPARAM)pButtonImagelist); } BOOL SetImageList(PBUTTON_IMAGELIST pButtonImagelist) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, BCM_SETIMAGELIST, 0, (LPARAM)pButtonImagelist); } BOOL GetTextMargin(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, BCM_GETTEXTMARGIN, 0, (LPARAM)lpRect); } BOOL SetTextMargin(LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, BCM_SETTEXTMARGIN, 0, (LPARAM)lpRect); } #endif // (_WIN32_WINNT >= 0x0501) #if (WINVER >= 0x0600) void SetDontClick(BOOL bDontClick) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETDONTCLICK, (WPARAM)bDontClick, 0L); } #endif // (WINVER >= 0x0600) #if (_WIN32_WINNT >= 0x0600) BOOL SetDropDownState(BOOL bDropDown) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); return (BOOL)::SendMessage(m_hWnd, BCM_SETDROPDOWNSTATE, (WPARAM)bDropDown, 0L); } BOOL GetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); return (BOOL)::SendMessage(m_hWnd, BCM_GETSPLITINFO, 0, (LPARAM)pSplitInfo); } BOOL SetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0); return (BOOL)::SendMessage(m_hWnd, BCM_SETSPLITINFO, 0, (LPARAM)pSplitInfo); } int GetNoteLength() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); return (int)::SendMessage(m_hWnd, BCM_GETNOTELENGTH, 0, 0L); } BOOL GetNote(LPWSTR lpstrNoteText, int cchNoteText) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); return (BOOL)::SendMessage(m_hWnd, BCM_GETNOTE, cchNoteText, (LPARAM)lpstrNoteText); } BOOL SetNote(LPCWSTR lpstrNoteText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0); return (BOOL)::SendMessage(m_hWnd, BCM_SETNOTE, 0, (LPARAM)lpstrNoteText); } LRESULT SetElevationRequiredState(BOOL bSet) { ATLASSERT(::IsWindow(m_hWnd)); return ::SendMessage(m_hWnd, BCM_SETSHIELD, 0, (LPARAM)bSet); } #endif // (_WIN32_WINNT >= 0x0600) // Operations void Click() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_CLICK, 0, 0L); } }; typedef CButtonT CButton; /////////////////////////////////////////////////////////////////////////////// // CListBox - client side for a Windows LISTBOX control template class CListBoxT : public TBase { public: // Constructors CListBoxT(HWND hWnd = NULL) : TBase(hWnd) { } CListBoxT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("LISTBOX"); } // for entire listbox int GetCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETCOUNT, 0, 0L); } #ifndef _WIN32_WCE int SetCount(int cItems) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(((GetStyle() & LBS_NODATA) != 0) && ((GetStyle() & LBS_HASSTRINGS) == 0)); return (int)::SendMessage(m_hWnd, LB_SETCOUNT, cItems, 0L); } #endif // !_WIN32_WCE int GetHorizontalExtent() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETHORIZONTALEXTENT, 0, 0L); } void SetHorizontalExtent(int cxExtent) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LB_SETHORIZONTALEXTENT, cxExtent, 0L); } int GetTopIndex() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETTOPINDEX, 0, 0L); } int SetTopIndex(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_SETTOPINDEX, nIndex, 0L); } LCID GetLocale() const { ATLASSERT(::IsWindow(m_hWnd)); return (LCID)::SendMessage(m_hWnd, LB_GETLOCALE, 0, 0L); } LCID SetLocale(LCID nNewLocale) { ATLASSERT(::IsWindow(m_hWnd)); return (LCID)::SendMessage(m_hWnd, LB_SETLOCALE, (WPARAM)nNewLocale, 0L); } #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) DWORD GetListBoxInfo() const { ATLASSERT(::IsWindow(m_hWnd)); #if (_WIN32_WINNT >= 0x0501) return (DWORD)::SendMessage(m_hWnd, LB_GETLISTBOXINFO, 0, 0L); #else // !(_WIN32_WINNT >= 0x0501) return ::GetListBoxInfo(m_hWnd); #endif // !(_WIN32_WINNT >= 0x0501) } #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) // for single-selection listboxes int GetCurSel() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); return (int)::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L); } int SetCurSel(int nSelect) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); return (int)::SendMessage(m_hWnd, LB_SETCURSEL, nSelect, 0L); } // for multiple-selection listboxes int GetSel(int nIndex) const // also works for single-selection { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETSEL, nIndex, 0L); } int SetSel(int nIndex, BOOL bSelect = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); return (int)::SendMessage(m_hWnd, LB_SETSEL, bSelect, nIndex); } int GetSelCount() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); return (int)::SendMessage(m_hWnd, LB_GETSELCOUNT, 0, 0L); } int GetSelItems(int nMaxItems, LPINT rgIndex) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); return (int)::SendMessage(m_hWnd, LB_GETSELITEMS, nMaxItems, (LPARAM)rgIndex); } int GetAnchorIndex() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); return (int)::SendMessage(m_hWnd, LB_GETANCHORINDEX, 0, 0L); } void SetAnchorIndex(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); ::SendMessage(m_hWnd, LB_SETANCHORINDEX, nIndex, 0L); } int GetCaretIndex() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETCARETINDEX, 0, 0); } int SetCaretIndex(int nIndex, BOOL bScroll = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_SETCARETINDEX, nIndex, MAKELONG(bScroll, 0)); } // for listbox items DWORD_PTR GetItemData(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD_PTR)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); } int SetItemData(int nIndex, DWORD_PTR dwItemData) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_SETITEMDATA, nIndex, (LPARAM)dwItemData); } void* GetItemDataPtr(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (void*)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L); } int SetItemDataPtr(int nIndex, void* pData) { ATLASSERT(::IsWindow(m_hWnd)); return SetItemData(nIndex, (DWORD_PTR)pData); } int GetItemRect(int nIndex, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETITEMRECT, nIndex, (LPARAM)lpRect); } int GetText(int nIndex, LPTSTR lpszBuffer) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETTEXT, nIndex, (LPARAM)lpszBuffer); } #ifndef _ATL_NO_COM #ifdef _OLEAUTO_H_ BOOL GetTextBSTR(int nIndex, BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); int nLen = GetTextLen(nIndex); if(nLen == LB_ERR) return FALSE; CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(nLen + 1); if(lpstrText == NULL) return FALSE; if(GetText(nIndex, lpstrText) == LB_ERR) return FALSE; bstrText = ::SysAllocString(T2OLE(lpstrText)); return (bstrText != NULL) ? TRUE : FALSE; } #endif // _OLEAUTO_H_ #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetText(int nIndex, _CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); int cchLen = GetTextLen(nIndex); if(cchLen == LB_ERR) return LB_ERR; int nRet = LB_ERR; LPTSTR lpstr = strText.GetBufferSetLength(cchLen); if(lpstr != NULL) { nRet = GetText(nIndex, lpstr); strText.ReleaseBuffer(); } return nRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetTextLen(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETTEXTLEN, nIndex, 0L); } int GetItemHeight(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_GETITEMHEIGHT, nIndex, 0L); } int SetItemHeight(int nIndex, UINT cyItemHeight) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); } // Settable only attributes void SetColumnWidth(int cxWidth) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LB_SETCOLUMNWIDTH, cxWidth, 0L); } BOOL SetTabStops(int nTabStops, LPINT rgTabStops) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); } BOOL SetTabStops() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 0, 0L); } BOOL SetTabStops(const int& cxEachStop) // takes an 'int' { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0); return (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); } // Operations int InitStorage(int nItems, UINT nBytes) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_INITSTORAGE, (WPARAM)nItems, nBytes); } void ResetContent() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LB_RESETCONTENT, 0, 0L); } UINT ItemFromPoint(POINT pt, BOOL& bOutside) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dw = (DWORD)::SendMessage(m_hWnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); bOutside = (BOOL)HIWORD(dw); return (UINT)LOWORD(dw); } // manipulating listbox items int AddString(LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszItem); } int DeleteString(UINT nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_DELETESTRING, nIndex, 0L); } int InsertString(int nIndex, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_INSERTSTRING, nIndex, (LPARAM)lpszItem); } #ifndef _WIN32_WCE int Dir(UINT attr, LPCTSTR lpszWildCard) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_DIR, attr, (LPARAM)lpszWildCard); } int AddFile(LPCTSTR lpstrFileName) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_ADDFILE, 0, (LPARAM)lpstrFileName); } #endif // !_WIN32_WCE // selection helpers int FindString(int nStartAfter, LPCTSTR lpszItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_FINDSTRING, nStartAfter, (LPARAM)lpszItem); } int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); } int SelectString(int nStartAfter, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LB_SELECTSTRING, nStartAfter, (LPARAM)lpszItem); } int SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0); ATLASSERT(nFirstItem <= nLastItem); return bSelect ? (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nFirstItem, nLastItem) : (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nLastItem, nFirstItem); } #ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages DWORD GetInputMode(BOOL bCurrentMode = TRUE) { return SendMessage(LB_GETINPUTMODE, 0, (LPARAM)bCurrentMode); } BOOL SetInputMode(DWORD dwMode) { return SendMessage(LB_SETINPUTMODE, 0, (LPARAM)dwMode); } #endif // WIN32_PLATFORM_WFSP }; typedef CListBoxT CListBox; /////////////////////////////////////////////////////////////////////////////// // CComboBox - client side for a Windows COMBOBOX control #ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones template class CComboBoxT : public TBase { public: // Constructors CComboBoxT(HWND hWnd = NULL) : TBase(hWnd) { } CComboBoxT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("COMBOBOX"); } // for entire combo box int GetCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0L); } int GetCurSel() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0L); } int SetCurSel(int nSelect) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0L); } LCID GetLocale() const { ATLASSERT(::IsWindow(m_hWnd)); return (LCID)::SendMessage(m_hWnd, CB_GETLOCALE, 0, 0L); } LCID SetLocale(LCID nNewLocale) { ATLASSERT(::IsWindow(m_hWnd)); return (LCID)::SendMessage(m_hWnd, CB_SETLOCALE, (WPARAM)nNewLocale, 0L); } int GetTopIndex() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETTOPINDEX, 0, 0L); } int SetTopIndex(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETTOPINDEX, nIndex, 0L); } UINT GetHorizontalExtent() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, CB_GETHORIZONTALEXTENT, 0, 0L); } void SetHorizontalExtent(UINT nExtent) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, CB_SETHORIZONTALEXTENT, nExtent, 0L); } int GetDroppedWidth() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETDROPPEDWIDTH, 0, 0L); } int SetDroppedWidth(UINT nWidth) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETDROPPEDWIDTH, nWidth, 0L); } #if ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) BOOL GetComboBoxInfo(PCOMBOBOXINFO pComboBoxInfo) const { ATLASSERT(::IsWindow(m_hWnd)); #if ((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) return (BOOL)::SendMessage(m_hWnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)pComboBoxInfo); #else // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) return ::GetComboBoxInfo(m_hWnd, pComboBoxInfo); #endif // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) } #endif // ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420)) // for edit control DWORD GetEditSel() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0L); } BOOL SetEditSel(int nStartChar, int nEndChar) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar)); } // for combobox item DWORD_PTR GetItemData(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD_PTR)::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0L); } int SetItemData(int nIndex, DWORD_PTR dwItemData) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData); } void* GetItemDataPtr(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (void*)GetItemData(nIndex); } int SetItemDataPtr(int nIndex, void* pData) { ATLASSERT(::IsWindow(m_hWnd)); return SetItemData(nIndex, (DWORD_PTR)pData); } int GetLBText(int nIndex, LPTSTR lpszText) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETLBTEXT, nIndex, (LPARAM)lpszText); } #ifndef _ATL_NO_COM BOOL GetLBTextBSTR(int nIndex, BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); int nLen = GetLBTextLen(nIndex); if(nLen == CB_ERR) return FALSE; CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(nLen + 1); if(lpstrText == NULL) return FALSE; if(GetLBText(nIndex, lpstrText) == CB_ERR) return FALSE; bstrText = ::SysAllocString(T2OLE(lpstrText)); return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetLBText(int nIndex, _CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); int cchLen = GetLBTextLen(nIndex); if(cchLen == CB_ERR) return CB_ERR; int nRet = CB_ERR; LPTSTR lpstr = strText.GetBufferSetLength(cchLen); if(lpstr != NULL) { nRet = GetLBText(nIndex, lpstr); strText.ReleaseBuffer(); } return nRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetLBTextLen(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETLBTEXTLEN, nIndex, 0L); } int GetItemHeight(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETITEMHEIGHT, nIndex, 0L); } int SetItemHeight(int nIndex, UINT cyItemHeight) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0)); } BOOL GetExtendedUI() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_GETEXTENDEDUI, 0, 0L); } int SetExtendedUI(BOOL bExtended = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETEXTENDEDUI, bExtended, 0L); } void GetDroppedControlRect(LPRECT lprect) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)lprect); } BOOL GetDroppedState() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_GETDROPPEDSTATE, 0, 0L); } #if (_WIN32_WINNT >= 0x0501) int GetMinVisible() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETMINVISIBLE, 0, 0L); } BOOL SetMinVisible(int nMinVisible) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_SETMINVISIBLE, nMinVisible, 0L); } // Vista only BOOL GetCueBannerText(LPWSTR lpwText, int cchText) const { #ifndef CB_GETCUEBANNER const UINT CB_GETCUEBANNER = (CBM_FIRST + 4); #endif ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_GETCUEBANNER, (WPARAM)lpwText, cchText); } // Vista only BOOL SetCueBannerText(LPCWSTR lpcwText) { #ifndef CB_SETCUEBANNER const UINT CB_SETCUEBANNER = (CBM_FIRST + 3); #endif ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_SETCUEBANNER, 0, (LPARAM)lpcwText); } #endif // (_WIN32_WINNT >= 0x0501) // Operations int InitStorage(int nItems, UINT nBytes) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_INITSTORAGE, (WPARAM)nItems, nBytes); } void ResetContent() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, CB_RESETCONTENT, 0, 0L); } // for edit control BOOL LimitText(int nMaxChars) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0L); } // for drop-down combo boxes void ShowDropDown(BOOL bShowIt = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, CB_SHOWDROPDOWN, bShowIt, 0L); } // manipulating listbox items int AddString(LPCTSTR lpszString) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0, (LPARAM)lpszString); } int DeleteString(UINT nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_DELETESTRING, nIndex, 0L); } int InsertString(int nIndex, LPCTSTR lpszString) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_INSERTSTRING, nIndex, (LPARAM)lpszString); } #ifndef _WIN32_WCE int Dir(UINT attr, LPCTSTR lpszWildCard) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_DIR, attr, (LPARAM)lpszWildCard); } #endif // !_WIN32_WCE // selection helpers int FindString(int nStartAfter, LPCTSTR lpszString) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_FINDSTRING, nStartAfter, (LPARAM)lpszString); } int FindStringExact(int nIndexStart, LPCTSTR lpszFind) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind); } int SelectString(int nStartAfter, LPCTSTR lpszString) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SELECTSTRING, nStartAfter, (LPARAM)lpszString); } // Clipboard operations void Clear() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); } void Copy() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_COPY, 0, 0L); } void Cut() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CUT, 0, 0L); } void Paste() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); } }; typedef CComboBoxT CComboBox; #endif // !WIN32_PLATFORM_WFSP /////////////////////////////////////////////////////////////////////////////// // CEdit - client side for a Windows EDIT control template class CEditT : public TBase { public: // Constructors CEditT(HWND hWnd = NULL) : TBase(hWnd) { } CEditT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("EDIT"); } BOOL CanUndo() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); } int GetLineCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); } BOOL GetModify() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); } void SetModify(BOOL bModified = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); } void GetRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); } DWORD GetSel() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); } void GetSel(int& nStartChar, int& nEndChar) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); } #ifndef _WIN32_WCE HLOCAL GetHandle() const { ATLASSERT(::IsWindow(m_hWnd)); return (HLOCAL)::SendMessage(m_hWnd, EM_GETHANDLE, 0, 0L); } void SetHandle(HLOCAL hBuffer) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETHANDLE, (WPARAM)hBuffer, 0L); } #endif // !_WIN32_WCE DWORD GetMargins() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L); } void GetMargins(UINT& nLeft, UINT& nRight) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L); nLeft = LOWORD(dwRet); nRight = HIWORD(dwRet); } void SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight)); } UINT GetLimitText() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); } void SetLimitText(UINT nMax) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETLIMITTEXT, nMax, 0L); } POINT PosFromChar(UINT nChar) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_POSFROMCHAR, nChar, 0); POINT point = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; return point; } int CharFromPos(POINT pt, int* pLine = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y)); if(pLine != NULL) *pLine = (int)(short)HIWORD(dwRet); return (int)(short)LOWORD(dwRet); } // NOTE: first word in lpszBuffer must contain the size of the buffer! int GetLine(int nIndex, LPTSTR lpszBuffer) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); } int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const { ATLASSERT(::IsWindow(m_hWnd)); *(LPWORD)lpszBuffer = (WORD)nMaxLength; return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); } TCHAR GetPasswordChar() const { ATLASSERT(::IsWindow(m_hWnd)); return (TCHAR)::SendMessage(m_hWnd, EM_GETPASSWORDCHAR, 0, 0L); } void SetPasswordChar(TCHAR ch) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETPASSWORDCHAR, ch, 0L); } #ifndef _WIN32_WCE EDITWORDBREAKPROC GetWordBreakProc() const { ATLASSERT(::IsWindow(m_hWnd)); return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L); } void SetWordBreakProc(EDITWORDBREAKPROC ewbprc) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc); } #endif // !_WIN32_WCE int GetFirstVisibleLine() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); } #ifndef _WIN32_WCE int GetThumb() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & ES_MULTILINE) != 0); return (int)::SendMessage(m_hWnd, EM_GETTHUMB, 0, 0L); } #endif // !_WIN32_WCE BOOL SetReadOnly(BOOL bReadOnly = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); } #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) UINT GetImeStatus(UINT uStatus) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETIMESTATUS, uStatus, 0L); } UINT SetImeStatus(UINT uStatus, UINT uData) { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_SETIMESTATUS, uStatus, uData); } #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) BOOL GetCueBannerText(LPCWSTR lpstrText, int cchText) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETCUEBANNER, (WPARAM)lpstrText, cchText); } // bKeepWithFocus - Vista only BOOL SetCueBannerText(LPCWSTR lpstrText, BOOL bKeepWithFocus = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETCUEBANNER, (WPARAM)bKeepWithFocus, (LPARAM)(lpstrText)); } #endif // (_WIN32_WINNT >= 0x0501) // Operations void EmptyUndoBuffer() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); } BOOL FmtLines(BOOL bAddEOL) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_FMTLINES, bAddEOL, 0L); } void LimitText(int nChars = 0) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_LIMITTEXT, nChars, 0L); } int LineFromChar(int nIndex = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_LINEFROMCHAR, nIndex, 0L); } int LineIndex(int nLine = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); } int LineLength(int nLine = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); } void LineScroll(int nLines, int nChars = 0) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines); } void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); } void SetRect(LPCRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); } void SetRectNP(LPCRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect); } void SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection)); if(!bNoScroll) ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); } void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); if(!bNoScroll) ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); } void SetSelAll(BOOL bNoScroll = FALSE) { SetSel(0, -1, bNoScroll); } void SetSelNone(BOOL bNoScroll = FALSE) { SetSel(-1, 0, bNoScroll); } BOOL SetTabStops(int nTabStops, LPINT rgTabStops) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); } BOOL SetTabStops() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); } BOOL SetTabStops(const int& cxEachStop) // takes an 'int' { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); } void ScrollCaret() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); } int Scroll(int nScrollAction) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & ES_MULTILINE) != 0); LRESULT lRet = ::SendMessage(m_hWnd, EM_SCROLL, nScrollAction, 0L); if(!(BOOL)HIWORD(lRet)) return -1; // failed return (int)(short)LOWORD(lRet); } void InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) { SetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll); ReplaceSel(lpstrText, bCanUndo); } void AppendText(LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE) { InsertText(GetWindowTextLength(), lpstrText, bNoScroll, bCanUndo); } #if (_WIN32_WINNT >= 0x0501) BOOL ShowBalloonTip(PEDITBALLOONTIP pEditBaloonTip) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SHOWBALLOONTIP, 0, (LPARAM)pEditBaloonTip); } BOOL HideBalloonTip() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_HIDEBALLOONTIP, 0, 0L); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) DWORD GetHilite() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); } void GetHilite(int& nStartChar, int& nEndChar) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L); nStartChar = (int)(short)LOWORD(dwRet); nEndChar = (int)(short)HIWORD(dwRet); } void SetHilite(int nStartChar, int nEndChar) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETHILITE, nStartChar, nEndChar); } #endif // (_WIN32_WINNT >= 0x0600) // Clipboard operations BOOL Undo() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); } void Clear() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); } void Copy() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_COPY, 0, 0L); } void Cut() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CUT, 0, 0L); } void Paste() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); } #ifdef WIN32_PLATFORM_WFSP // SmartPhone only messages DWORD GetExtendedStyle() { return SendMessage(EM_GETEXTENDEDSTYLE); } DWORD SetExtendedStyle(DWORD dwMask, DWORD dwExStyle) { return SendMessage(EM_SETEXTENDEDSTYLE, (WPARAM)dwMask, (LPARAM)dwExStyle); } DWORD GetInputMode(BOOL bCurrentMode = TRUE) { return SendMessage(EM_GETINPUTMODE, 0, (LPARAM)bCurrentMode); } BOOL SetInputMode(DWORD dwMode) { return SendMessage(EM_SETINPUTMODE, 0, (LPARAM)dwMode); } BOOL SetSymbols(LPCTSTR szSymbols) { return SendMessage(EM_SETSYMBOLS, 0, (LPARAM)szSymbols); } BOOL ResetSymbols() { return SendMessage(EM_SETSYMBOLS); } #endif // WIN32_PLATFORM_WFSP }; typedef CEditT CEdit; /////////////////////////////////////////////////////////////////////////////// // CEditCommands - message handlers for standard EDIT commands // Chain to CEditCommands message map. Your class must also derive from CEdit. // Example: // class CMyEdit : public CWindowImpl, // public CEditCommands // { // public: // BEGIN_MSG_MAP(CMyEdit) // // your handlers... // CHAIN_MSG_MAP_ALT(CEditCommands, 1) // END_MSG_MAP() // // other stuff... // }; template class CEditCommands { public: BEGIN_MSG_MAP(CEditCommands< T >) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear) COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll) COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy) COMMAND_ID_HANDLER(ID_EDIT_CUT, OnEditCut) COMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste) COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll) COMMAND_ID_HANDLER(ID_EDIT_UNDO, OnEditUndo) END_MSG_MAP() LRESULT OnEditClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Clear(); return 0; } LRESULT OnEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->SetSel(0, -1); pT->Clear(); return 0; } LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Copy(); return 0; } LRESULT OnEditCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Cut(); return 0; } LRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Paste(); return 0; } LRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->SetSel(0, -1); return 0; } LRESULT OnEditUndo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Undo(); return 0; } // State (update UI) helpers BOOL CanCut() const { return HasSelection(); } BOOL CanCopy() const { return HasSelection(); } BOOL CanClear() const { return HasSelection(); } BOOL CanSelectAll() const { return HasText(); } BOOL CanFind() const { return HasText(); } BOOL CanRepeat() const { return HasText(); } BOOL CanReplace() const { return HasText(); } BOOL CanClearAll() const { return HasText(); } // Implementation BOOL HasSelection() const { const T* pT = static_cast(this); int nMin = 0, nMax = 0; ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nMin, (LPARAM)&nMax); return (nMin != nMax); } BOOL HasText() const { const T* pT = static_cast(this); return (pT->GetWindowTextLength() > 0); } }; /////////////////////////////////////////////////////////////////////////////// // CScrollBar - client side for a Windows SCROLLBAR control template class CScrollBarT : public TBase { public: // Constructors CScrollBarT(HWND hWnd = NULL) : TBase(hWnd) { } CScrollBarT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return _T("SCROLLBAR"); } #ifndef _WIN32_WCE int GetScrollPos() const { ATLASSERT(::IsWindow(m_hWnd)); return ::GetScrollPos(m_hWnd, SB_CTL); } #endif // !_WIN32_WCE int SetScrollPos(int nPos, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ::SetScrollPos(m_hWnd, SB_CTL, nPos, bRedraw); } #ifndef _WIN32_WCE void GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const { ATLASSERT(::IsWindow(m_hWnd)); ::GetScrollRange(m_hWnd, SB_CTL, lpMinPos, lpMaxPos); } #endif // !_WIN32_WCE void SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SetScrollRange(m_hWnd, SB_CTL, nMinPos, nMaxPos, bRedraw); } BOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return ::GetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo); } int SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ::SetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo, bRedraw); } #ifndef _WIN32_WCE int GetScrollLimit() const { SCROLLINFO info = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE }; ::GetScrollInfo(m_hWnd, SB_CTL, &info); if(info.nPage > 1) info.nMax -= info.nPage - 1; return info.nMax; } #if (WINVER >= 0x0500) BOOL GetScrollBarInfo(PSCROLLBARINFO pScrollBarInfo) const { ATLASSERT(::IsWindow(m_hWnd)); #if (_WIN32_WINNT >= 0x0501) return (BOOL)::SendMessage(m_hWnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)pScrollBarInfo); #else // !(_WIN32_WINNT >= 0x0501) return ::GetScrollBarInfo(m_hWnd, OBJID_CLIENT, pScrollBarInfo); #endif // !(_WIN32_WINNT >= 0x0501) } #endif // (WINVER >= 0x0500) // Operations void ShowScrollBar(BOOL bShow = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::ShowScrollBar(m_hWnd, SB_CTL, bShow); } BOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH) { ATLASSERT(::IsWindow(m_hWnd)); return ::EnableScrollBar(m_hWnd, SB_CTL, nArrowFlags); } #endif // !_WIN32_WCE }; typedef CScrollBarT CScrollBar; // --- Windows Common Controls --- /////////////////////////////////////////////////////////////////////////////// // CImageList // forward declarations template class CImageListT; typedef CImageListT CImageList; typedef CImageListT CImageListManaged; template class CImageListT { public: // Data members HIMAGELIST m_hImageList; // Constructor/destructor/operators CImageListT(HIMAGELIST hImageList = NULL) : m_hImageList(hImageList) { } ~CImageListT() { if(t_bManaged && (m_hImageList != NULL)) Destroy(); } CImageListT& operator =(HIMAGELIST hImageList) { Attach(hImageList); return *this; } void Attach(HIMAGELIST hImageList) { if(t_bManaged && (m_hImageList != NULL) && (m_hImageList != hImageList)) ImageList_Destroy(m_hImageList); m_hImageList = hImageList; } HIMAGELIST Detach() { HIMAGELIST hImageList = m_hImageList; m_hImageList = NULL; return hImageList; } operator HIMAGELIST() const { return m_hImageList; } bool IsNull() const { return (m_hImageList == NULL); } // Attributes int GetImageCount() const { ATLASSERT(m_hImageList != NULL); return ImageList_GetImageCount(m_hImageList); } COLORREF GetBkColor() const { ATLASSERT(m_hImageList != NULL); return ImageList_GetBkColor(m_hImageList); } COLORREF SetBkColor(COLORREF cr) { ATLASSERT(m_hImageList != NULL); return ImageList_SetBkColor(m_hImageList, cr); } BOOL GetImageInfo(int nImage, IMAGEINFO* pImageInfo) const { ATLASSERT(m_hImageList != NULL); return ImageList_GetImageInfo(m_hImageList, nImage, pImageInfo); } HICON GetIcon(int nIndex, UINT uFlags = ILD_NORMAL) const { ATLASSERT(m_hImageList != NULL); return ImageList_GetIcon(m_hImageList, nIndex, uFlags); } BOOL GetIconSize(int& cx, int& cy) const { ATLASSERT(m_hImageList != NULL); return ImageList_GetIconSize(m_hImageList, &cx, &cy); } BOOL GetIconSize(SIZE& size) const { ATLASSERT(m_hImageList != NULL); return ImageList_GetIconSize(m_hImageList, (int*)&size.cx, (int*)&size.cy); } BOOL SetIconSize(int cx, int cy) { ATLASSERT(m_hImageList != NULL); return ImageList_SetIconSize(m_hImageList, cx, cy); } BOOL SetIconSize(SIZE size) { ATLASSERT(m_hImageList != NULL); return ImageList_SetIconSize(m_hImageList, size.cx, size.cy); } BOOL SetImageCount(UINT uNewCount) { ATLASSERT(m_hImageList != NULL); return ImageList_SetImageCount(m_hImageList, uNewCount); } BOOL SetOverlayImage(int nImage, int nOverlay) { ATLASSERT(m_hImageList != NULL); return ImageList_SetOverlayImage(m_hImageList, nImage, nOverlay); } // Operations BOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow) { ATLASSERT(m_hImageList == NULL); m_hImageList = ImageList_Create(cx, cy, nFlags, nInitial, nGrow); return (m_hImageList != NULL) ? TRUE : FALSE; } BOOL Create(ATL::_U_STRINGorID bitmap, int cx, int nGrow, COLORREF crMask) { ATLASSERT(m_hImageList == NULL); m_hImageList = ImageList_LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, cx, nGrow, crMask); return (m_hImageList != NULL) ? TRUE : FALSE; } BOOL CreateFromImage(ATL::_U_STRINGorID image, int cx, int nGrow, COLORREF crMask, UINT uType, UINT uFlags = LR_DEFAULTCOLOR | LR_DEFAULTSIZE) { ATLASSERT(m_hImageList == NULL); m_hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, cx, nGrow, crMask, uType, uFlags); return (m_hImageList != NULL) ? TRUE : FALSE; } BOOL Merge(HIMAGELIST hImageList1, int nImage1, HIMAGELIST hImageList2, int nImage2, int dx, int dy) { ATLASSERT(m_hImageList == NULL); m_hImageList = ImageList_Merge(hImageList1, nImage1, hImageList2, nImage2, dx, dy); return (m_hImageList != NULL) ? TRUE : FALSE; } #ifndef _WIN32_WCE #ifdef __IStream_INTERFACE_DEFINED__ BOOL CreateFromStream(LPSTREAM lpStream) { ATLASSERT(m_hImageList == NULL); m_hImageList = ImageList_Read(lpStream); return (m_hImageList != NULL) ? TRUE : FALSE; } #endif // __IStream_INTERFACE_DEFINED__ #endif // !_WIN32_WCE BOOL Destroy() { if (m_hImageList == NULL) return FALSE; BOOL bRet = ImageList_Destroy(m_hImageList); if(bRet) m_hImageList = NULL; return bRet; } int Add(HBITMAP hBitmap, HBITMAP hBitmapMask = NULL) { ATLASSERT(m_hImageList != NULL); return ImageList_Add(m_hImageList, hBitmap, hBitmapMask); } int Add(HBITMAP hBitmap, COLORREF crMask) { ATLASSERT(m_hImageList != NULL); return ImageList_AddMasked(m_hImageList, hBitmap, crMask); } BOOL Remove(int nImage) { ATLASSERT(m_hImageList != NULL); return ImageList_Remove(m_hImageList, nImage); } BOOL RemoveAll() { ATLASSERT(m_hImageList != NULL); return ImageList_RemoveAll(m_hImageList); } BOOL Replace(int nImage, HBITMAP hBitmap, HBITMAP hBitmapMask) { ATLASSERT(m_hImageList != NULL); return ImageList_Replace(m_hImageList, nImage, hBitmap, hBitmapMask); } int AddIcon(HICON hIcon) { ATLASSERT(m_hImageList != NULL); return ImageList_AddIcon(m_hImageList, hIcon); } int ReplaceIcon(int nImage, HICON hIcon) { ATLASSERT(m_hImageList != NULL); return ImageList_ReplaceIcon(m_hImageList, nImage, hIcon); } HICON ExtractIcon(int nImage) { ATLASSERT(m_hImageList != NULL); return ImageList_ExtractIcon(NULL, m_hImageList, nImage); } BOOL Draw(HDC hDC, int nImage, int x, int y, UINT nStyle) { ATLASSERT(m_hImageList != NULL); ATLASSERT(hDC != NULL); return ImageList_Draw(m_hImageList, nImage, hDC, x, y, nStyle); } BOOL Draw(HDC hDC, int nImage, POINT pt, UINT nStyle) { ATLASSERT(m_hImageList != NULL); ATLASSERT(hDC != NULL); return ImageList_Draw(m_hImageList, nImage, hDC, pt.x, pt.y, nStyle); } BOOL DrawEx(int nImage, HDC hDC, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) { ATLASSERT(m_hImageList != NULL); ATLASSERT(hDC != NULL); return ImageList_DrawEx(m_hImageList, nImage, hDC, x, y, dx, dy, rgbBk, rgbFg, fStyle); } BOOL DrawEx(int nImage, HDC hDC, RECT& rect, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle) { ATLASSERT(m_hImageList != NULL); ATLASSERT(hDC != NULL); return ImageList_DrawEx(m_hImageList, nImage, hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rgbBk, rgbFg, fStyle); } static BOOL DrawIndirect(IMAGELISTDRAWPARAMS* pimldp) { return ImageList_DrawIndirect(pimldp); } BOOL Copy(int nSrc, int nDst, UINT uFlags = ILCF_MOVE) { ATLASSERT(m_hImageList != NULL); return ImageList_Copy(m_hImageList, nDst, m_hImageList, nSrc, uFlags); } #ifdef __IStream_INTERFACE_DEFINED__ #ifndef _WIN32_WCE static HIMAGELIST Read(LPSTREAM lpStream) { return ImageList_Read(lpStream); } BOOL Write(LPSTREAM lpStream) { ATLASSERT(m_hImageList != NULL); return ImageList_Write(m_hImageList, lpStream); } #endif // !_WIN32_WCE #if (_WIN32_WINNT >= 0x0501) static HRESULT ReadEx(DWORD dwFlags, LPSTREAM lpStream, REFIID riid, PVOID* ppv) { return ImageList_ReadEx(dwFlags, lpStream, riid, ppv); } HRESULT WriteEx(DWORD dwFlags, LPSTREAM lpStream) { ATLASSERT(m_hImageList != NULL); return ImageList_WriteEx(m_hImageList, dwFlags, lpStream); } #endif // (_WIN32_WINNT >= 0x0501) #endif // __IStream_INTERFACE_DEFINED__ // Drag operations BOOL BeginDrag(int nImage, POINT ptHotSpot) { ATLASSERT(m_hImageList != NULL); return ImageList_BeginDrag(m_hImageList, nImage, ptHotSpot.x, ptHotSpot.y); } BOOL BeginDrag(int nImage, int xHotSpot, int yHotSpot) { ATLASSERT(m_hImageList != NULL); return ImageList_BeginDrag(m_hImageList, nImage, xHotSpot, yHotSpot); } static void EndDrag() { ImageList_EndDrag(); } static BOOL DragMove(POINT pt) { return ImageList_DragMove(pt.x, pt.y); } static BOOL DragMove(int x, int y) { return ImageList_DragMove(x, y); } BOOL SetDragCursorImage(int nDrag, POINT ptHotSpot) { ATLASSERT(m_hImageList != NULL); return ImageList_SetDragCursorImage(m_hImageList, nDrag, ptHotSpot.x, ptHotSpot.y); } BOOL SetDragCursorImage(int nDrag, int xHotSpot, int yHotSpot) { ATLASSERT(m_hImageList != NULL); return ImageList_SetDragCursorImage(m_hImageList, nDrag, xHotSpot, yHotSpot); } static BOOL DragShowNolock(BOOL bShow = TRUE) { return ImageList_DragShowNolock(bShow); } static CImageList GetDragImage(LPPOINT lpPoint, LPPOINT lpPointHotSpot) { return CImageList(ImageList_GetDragImage(lpPoint, lpPointHotSpot)); } static BOOL DragEnter(HWND hWnd, POINT point) { return ImageList_DragEnter(hWnd, point.x, point.y); } static BOOL DragEnter(HWND hWnd, int x, int y) { return ImageList_DragEnter(hWnd, x, y); } static BOOL DragLeave(HWND hWnd) { return ImageList_DragLeave(hWnd); } #if (_WIN32_IE >= 0x0400) CImageList Duplicate() const { ATLASSERT(m_hImageList != NULL); return CImageList(ImageList_Duplicate(m_hImageList)); } static CImageList Duplicate(HIMAGELIST hImageList) { ATLASSERT(hImageList != NULL); return CImageList(ImageList_Duplicate(hImageList)); } #endif // (_WIN32_IE >= 0x0400) }; /////////////////////////////////////////////////////////////////////////////// // CToolTipCtrl #ifndef _WIN32_WCE class CToolInfo : public TOOLINFO { public: CToolInfo(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) { Init(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam); } operator LPTOOLINFO() { return this; } operator LPARAM() { return (LPARAM)this; } void Init(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL) { ATLASSERT(::IsWindow(hWnd)); memset(this, 0, sizeof(TOOLINFO)); cbSize = RunTimeHelper::SizeOf_TOOLINFO(); uFlags = nFlags; if(nIDTool == 0) { hwnd = ::GetParent(hWnd); uFlags |= TTF_IDISHWND; uId = (UINT_PTR)hWnd; } else { hwnd = hWnd; uId = nIDTool; } if(lpRect != NULL) rect = *lpRect; hinst = ModuleHelper::GetResourceInstance(); lpszText = lpstrText; lParam = lUserParam; } }; template class CToolTipCtrlT : public TBase { public: // Constructors CToolTipCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CToolTipCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return TOOLTIPS_CLASS; } void GetText(LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&lpToolInfo); } void GetText(LPTSTR lpstrText, HWND hWnd, UINT_PTR nIDTool = 0) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); ::SendMessage(m_hWnd, TTM_GETTEXT, 0, ti); } BOOL GetToolInfo(LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo); } BOOL GetToolInfo(HWND hWnd, UINT_PTR nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); ATLASSERT(puFlags != NULL); ATLASSERT(lpRect != NULL); CToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText); BOOL bRet = (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, ti); if(bRet != FALSE) { *puFlags = ti.uFlags; *lpRect = ti.rect; } return bRet; } void SetToolInfo(LPTOOLINFO lpToolInfo) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo); } void SetToolRect(LPTOOLINFO lpToolInfo) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo); } void SetToolRect(HWND hWnd, UINT_PTR nIDTool, LPCRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); ATLASSERT(nIDTool != 0); CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, NULL); ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, ti); } int GetToolCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TTM_GETTOOLCOUNT, 0, 0L); } int GetDelayTime(DWORD dwType) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TTM_GETDELAYTIME, dwType, 0L); } void SetDelayTime(DWORD dwType, int nTime) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0)); } void GetMargin(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_GETMARGIN, 0, (LPARAM)lpRect); } void SetMargin(LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)lpRect); } int GetMaxTipWidth() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TTM_GETMAXTIPWIDTH, 0, 0L); } int SetMaxTipWidth(int nWidth) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, nWidth); } COLORREF GetTipBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPBKCOLOR, 0, 0L); } void SetTipBkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L); } COLORREF GetTipTextColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPTEXTCOLOR, 0, 0L); } void SetTipTextColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L); } BOOL GetCurrentTool(LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo); } #if (_WIN32_IE >= 0x0500) SIZE GetBubbleSize(LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo); SIZE size = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) }; return size; } BOOL SetTitle(UINT_PTR uIcon, LPCTSTR lpstrTitle) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle); } BOOL SetTitle(HICON hIcon, LPCTSTR lpstrTitle) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, (WPARAM)hIcon, (LPARAM)lpstrTitle); } #endif // (_WIN32_IE >= 0x0500) #if (_WIN32_WINNT >= 0x0501) void GetTitle(PTTGETTITLE pTTGetTitle) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_GETTITLE, 0, (LPARAM)pTTGetTitle); } void SetWindowTheme(LPCWSTR lpstrTheme) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); } #endif // (_WIN32_WINNT >= 0x0501) // Operations void Activate(BOOL bActivate) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L); } BOOL AddTool(LPTOOLINFO lpToolInfo) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)lpToolInfo); } BOOL AddTool(HWND hWnd, ATL::_U_STRINGorID text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT_PTR nIDTool = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); // the toolrect and toolid must both be zero or both valid ATLASSERT((lpRectTool != NULL && nIDTool != 0) || (lpRectTool == NULL && nIDTool == 0)); CToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text.m_lpstr); return (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, ti); } void DelTool(LPTOOLINFO lpToolInfo) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)lpToolInfo); } void DelTool(HWND hWnd, UINT_PTR nIDTool = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); CToolInfo ti(0, hWnd, nIDTool, NULL, NULL); ::SendMessage(m_hWnd, TTM_DELTOOL, 0, ti); } BOOL HitTest(LPTTHITTESTINFO lpHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)lpHitTestInfo); } BOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); ATLASSERT(lpToolInfo != NULL); TTHITTESTINFO hti = { 0 }; hti.ti.cbSize = RunTimeHelper::SizeOf_TOOLINFO(); hti.hwnd = hWnd; hti.pt.x = pt.x; hti.pt.y = pt.y; if((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti) != FALSE) { *lpToolInfo = hti.ti; return TRUE; } return FALSE; } void RelayEvent(LPMSG lpMsg) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_RELAYEVENT, 0, (LPARAM)lpMsg); } void UpdateTipText(LPTOOLINFO lpToolInfo) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo); } void UpdateTipText(ATL::_U_STRINGorID text, HWND hWnd, UINT_PTR nIDTool = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); CToolInfo ti(0, hWnd, nIDTool, NULL, (LPTSTR)text.m_lpstr); ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, ti); } BOOL EnumTools(UINT_PTR nTool, LPTOOLINFO lpToolInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo); } void Pop() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_POP, 0, 0L); } void TrackActivate(LPTOOLINFO lpToolInfo, BOOL bActivate) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, (LPARAM)lpToolInfo); } void TrackActivate(HWND hWnd, UINT_PTR nIDTool, BOOL bActivate) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hWnd != NULL); CToolInfo ti(0, hWnd, nIDTool); ::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, ti); } void TrackPosition(int xPos, int yPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos)); } #if (_WIN32_IE >= 0x0400) void Update() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_UPDATE, 0, 0L); } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) BOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect); } #endif // (_WIN32_IE >= 0x0500) #if (_WIN32_WINNT >= 0x0501) void Popup() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TTM_POPUP, 0, 0L); } #endif // (_WIN32_WINNT >= 0x0501) }; typedef CToolTipCtrlT CToolTipCtrl; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CHeaderCtrl template class CHeaderCtrlT : public TBase { public: // Constructors CHeaderCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CHeaderCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_HEADER; } int GetItemCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_GETITEMCOUNT, 0, 0L); } BOOL GetItem(int nIndex, LPHDITEM pHeaderItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETITEM, nIndex, (LPARAM)pHeaderItem); } BOOL SetItem(int nIndex, LPHDITEM pHeaderItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_SETITEM, nIndex, (LPARAM)pHeaderItem); } CImageList GetImageList() const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_GETIMAGELIST, 0, 0L)); } CImageList SetImageList(HIMAGELIST hImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_SETIMAGELIST, 0, (LPARAM)hImageList)); } BOOL GetOrderArray(int nSize, int* lpnArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETORDERARRAY, nSize, (LPARAM)lpnArray); } BOOL SetOrderArray(int nSize, int* lpnArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_SETORDERARRAY, nSize, (LPARAM)lpnArray); } BOOL GetItemRect(int nIndex, LPRECT lpItemRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMRECT, nIndex, (LPARAM)lpItemRect); } int SetHotDivider(BOOL bPos, DWORD dwInputValue) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_SETHOTDIVIDER, bPos, dwInputValue); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) int GetBitmapMargin() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_GETBITMAPMARGIN, 0, 0L); } int SetBitmapMargin(int nWidth) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_SETBITMAPMARGIN, nWidth, 0L); } int SetFilterChangeTimeout(DWORD dwTimeOut) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, dwTimeOut); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0600) BOOL GetItemDropDownRect(int nIndex, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect); } BOOL GetOverflowRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_GETOVERFLOWRECT, 0, (LPARAM)lpRect); } int GetFocusedItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_GETFOCUSEDITEM, 0, 0L); } BOOL SetFocusedItem(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_SETFOCUSEDITEM, 0, nIndex); } #endif // (_WIN32_WINNT >= 0x0600) // Operations int InsertItem(int nIndex, LPHDITEM phdi) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_INSERTITEM, nIndex, (LPARAM)phdi); } int AddItem(LPHDITEM phdi) { return InsertItem(GetItemCount(), phdi); } BOOL DeleteItem(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_DELETEITEM, nIndex, 0L); } BOOL Layout(HD_LAYOUT* pHeaderLayout) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, HDM_LAYOUT, 0, (LPARAM)pHeaderLayout); } int HitTest(LPHDHITTESTINFO lpHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)lpHitTestInfo); } int OrderToIndex(int nOrder) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_ORDERTOINDEX, nOrder, 0L); } CImageList CreateDragImage(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_CREATEDRAGIMAGE, nIndex, 0L)); } #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) int EditFilter(int nColumn, BOOL bDiscardChanges) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_EDITFILTER, nColumn, MAKELPARAM(bDiscardChanges, 0)); } int ClearFilter(int nColumn) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, nColumn, 0L); } int ClearAllFilters() { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, (WPARAM)-1, 0L); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) }; typedef CHeaderCtrlT CHeaderCtrl; /////////////////////////////////////////////////////////////////////////////// // CListViewCtrl template class CListViewCtrlT : public TBase { public: // Constructors CListViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CListViewCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_LISTVIEW; } COLORREF GetBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_GETBKCOLOR, 0, 0L); } BOOL SetBkColor(COLORREF cr) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETBKCOLOR, 0, cr); } CImageList GetImageList(int nImageListType) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, nImageListType, 0L)); } CImageList SetImageList(HIMAGELIST hImageList, int nImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, nImageList, (LPARAM)hImageList)); } int GetItemCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0L); } BOOL SetItemCount(int nItems) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, 0L); } BOOL GetItem(LPLVITEM pItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); } BOOL SetItem(const LVITEM* pItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)pItem); } BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, int nImage, UINT nState, UINT nStateMask, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.mask = nMask; lvi.iItem = nItem; lvi.iSubItem = nSubItem; lvi.stateMask = nStateMask; lvi.state = nState; lvi.pszText = (LPTSTR) lpszItem; lvi.iImage = nImage; lvi.lParam = lParam; return (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi); } UINT GetItemState(int nItem, UINT nMask) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, LVM_GETITEMSTATE, nItem, nMask); } BOOL SetItemState(int nItem, UINT nState, UINT nStateMask) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.state = nState; lvi.stateMask = nStateMask; return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi); } BOOL SetItemState(int nItem, LPLVITEM pItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)pItem); } #ifndef _ATL_NO_COM BOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); LVITEM lvi = { 0 }; lvi.iSubItem = nSubItem; LPTSTR lpstrText = NULL; int nRes = 0; for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrText = new TCHAR[nLen]); if(lpstrText == NULL) break; lpstrText[0] = NULL; lvi.cchTextMax = nLen; lvi.pszText = lpstrText; nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); if(nRes < nLen - 1) break; delete [] lpstrText; lpstrText = NULL; } if(lpstrText != NULL) { if(nRes != 0) bstrText = ::SysAllocString(T2OLE(lpstrText)); delete [] lpstrText; } return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetItemText(int nItem, int nSubItem, _CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.iSubItem = nSubItem; strText.Empty(); int nRes = 0; for(int nLen = 256; ; nLen *= 2) { lvi.cchTextMax = nLen; lvi.pszText = strText.GetBufferSetLength(nLen); if(lvi.pszText == NULL) { nRes = 0; break; } nRes = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); if(nRes < nLen - 1) break; } strText.ReleaseBuffer(); return nRes; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.iSubItem = nSubItem; lvi.cchTextMax = nLen; lvi.pszText = lpszText; return (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi); } BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(nItem, nSubItem, LVIF_TEXT, lpszText, 0, 0, 0, 0); } DWORD_PTR GetItemData(int nItem) const { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.iItem = nItem; lvi.mask = LVIF_PARAM; BOOL bRet = (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi); return (DWORD_PTR)(bRet ? lvi.lParam : NULL); } BOOL SetItemData(int nItem, DWORD_PTR dwData) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(nItem, 0, LVIF_PARAM, NULL, 0, 0, 0, (LPARAM)dwData); } UINT GetCallbackMask() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, LVM_GETCALLBACKMASK, 0, 0L); } BOOL SetCallbackMask(UINT nMask) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETCALLBACKMASK, nMask, 0L); } BOOL GetItemPosition(int nItem, LPPOINT lpPoint) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)lpPoint); } BOOL SetItemPosition(int nItem, POINT pt) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); } BOOL SetItemPosition(int nItem, int x, int y) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON)); POINT pt = { x, y }; return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt); } int GetStringWidth(LPCTSTR lpsz) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETSTRINGWIDTH, 0, (LPARAM)lpsz); } CEdit GetEditControl() const { ATLASSERT(::IsWindow(m_hWnd)); return CEdit((HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L)); } BOOL GetColumn(int nCol, LVCOLUMN* pColumn) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMN, nCol, (LPARAM)pColumn); } BOOL SetColumn(int nCol, const LVCOLUMN* pColumn) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMN, nCol, (LPARAM)pColumn); } int GetColumnWidth(int nCol) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETCOLUMNWIDTH, nCol, 0L); } BOOL SetColumnWidth(int nCol, int cx) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNWIDTH, nCol, MAKELPARAM(cx, 0)); } BOOL GetViewRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETVIEWRECT, 0, (LPARAM)lpRect); } COLORREF GetTextColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTCOLOR, 0, 0L); } BOOL SetTextColor(COLORREF cr) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTCOLOR, 0, cr); } COLORREF GetTextBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTBKCOLOR, 0, 0L); } BOOL SetTextBkColor(COLORREF cr) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTBKCOLOR, 0, cr); } int GetTopIndex() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0L); } int GetCountPerPage() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETCOUNTPERPAGE, 0, 0L); } BOOL GetOrigin(LPPOINT lpPoint) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETORIGIN, 0, (LPARAM)lpPoint); } UINT GetSelectedCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, LVM_GETSELECTEDCOUNT, 0, 0L); } BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const { ATLASSERT(::IsWindow(m_hWnd)); lpRect->left = nCode; return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)lpRect); } #ifndef _WIN32_WCE HCURSOR GetHotCursor() const { ATLASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, LVM_GETHOTCURSOR, 0, 0L); } HCURSOR SetHotCursor(HCURSOR hHotCursor) { ATLASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, LVM_SETHOTCURSOR, 0, (LPARAM)hHotCursor); } int GetHotItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETHOTITEM, 0, 0L); } int SetHotItem(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SETHOTITEM, nIndex, 0L); } #endif // !_WIN32_WCE BOOL GetColumnOrderArray(int nCount, int* lpnArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); } BOOL SetColumnOrderArray(int nCount, int* lpnArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray); } CHeaderCtrl GetHeader() const { ATLASSERT(::IsWindow(m_hWnd)); return CHeaderCtrl((HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0L)); } BOOL GetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT); ATLASSERT(lpRect != NULL); lpRect->top = nSubItem; lpRect->left = nFlag; return (BOOL)::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, nItem, (LPARAM)lpRect); } DWORD SetIconSpacing(int cx, int cy) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_ICON); return (DWORD)::SendMessage(m_hWnd, LVM_SETICONSPACING, 0, MAKELPARAM(cx, cy)); } int GetISearchString(LPTSTR lpstr) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); } void GetItemSpacing(SIZE& sizeSpacing, BOOL bSmallIconView = FALSE) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, LVM_GETITEMSPACING, bSmallIconView, 0L); sizeSpacing.cx = GET_X_LPARAM(dwRet); sizeSpacing.cy = GET_Y_LPARAM(dwRet); } #if (_WIN32_WCE >= 410) void SetItemSpacing(INT cySpacing) { ATLASSERT(::IsWindow(m_hWnd)); ListView_SetItemSpacing(m_hWnd, cySpacing); } #endif // (_WIN32_WCE >= 410) // single-selection only int GetSelectedIndex() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); } BOOL GetSelectedItem(LPLVITEM pItem) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & LVS_SINGLESEL) != 0); ATLASSERT(pItem != NULL); pItem->iItem = (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0)); if(pItem->iItem == -1) return FALSE; return (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem); } // extended list view styles DWORD GetExtendedListViewStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0L); } // dwExMask = 0 means all styles DWORD SetExtendedListViewStyle(DWORD dwExStyle, DWORD dwExMask = 0) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExMask, dwExStyle); } // checkboxes only BOOL GetCheckState(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExtendedListViewStyle() & LVS_EX_CHECKBOXES) != 0); UINT uRet = GetItemState(nIndex, LVIS_STATEIMAGEMASK); return (uRet >> 12) - 1; } BOOL SetCheckState(int nItem, BOOL bCheck) { int nCheck = bCheck ? 2 : 1; // one based index return SetItemState(nItem, INDEXTOSTATEIMAGEMASK(nCheck), LVIS_STATEIMAGEMASK); } // view type DWORD GetViewType() const { ATLASSERT(::IsWindow(m_hWnd)); return (GetStyle() & LVS_TYPEMASK); } DWORD SetViewType(DWORD dwType) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(dwType == LVS_ICON || dwType == LVS_SMALLICON || dwType == LVS_LIST || dwType == LVS_REPORT); DWORD dwOldType = GetViewType(); if(dwType != dwOldType) ModifyStyle(LVS_TYPEMASK, (dwType & LVS_TYPEMASK)); return dwOldType; } #if (_WIN32_IE >= 0x0400) #ifndef _WIN32_WCE BOOL GetBkImage(LPLVBKIMAGE plvbki) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETBKIMAGE, 0, (LPARAM)plvbki); } BOOL SetBkImage(LPLVBKIMAGE plvbki) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETBKIMAGE, 0, (LPARAM)plvbki); } #endif // !_WIN32_WCE int GetSelectionMark() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETSELECTIONMARK, 0, 0L); } int SetSelectionMark(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SETSELECTIONMARK, 0, nIndex); } #ifndef _WIN32_WCE BOOL GetWorkAreas(int nWorkAreas, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETWORKAREAS, nWorkAreas, (LPARAM)lpRect); } BOOL SetWorkAreas(int nWorkAreas, LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETWORKAREAS, nWorkAreas, (LPARAM)lpRect); } DWORD GetHoverTime() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); return (DWORD)::SendMessage(m_hWnd, LVM_GETHOVERTIME, 0, 0L); } DWORD SetHoverTime(DWORD dwHoverTime) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0); return (DWORD)::SendMessage(m_hWnd, LVM_SETHOVERTIME, 0, dwHoverTime); } BOOL GetNumberOfWorkAreas(int* pnWorkAreas) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETNUMBEROFWORKAREAS, 0, (LPARAM)pnWorkAreas); } #endif // !_WIN32_WCE BOOL SetItemCountEx(int nItems, DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(((GetStyle() & LVS_OWNERDATA) != 0) && (((GetStyle() & LVS_TYPEMASK) == LVS_REPORT) || ((GetStyle() & LVS_TYPEMASK) == LVS_LIST))); return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, dwFlags); } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L)); } CToolTipCtrl SetToolTips(HWND hWndTT) { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); } BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_WINNT >= 0x0501) int GetSelectedColumn() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETSELECTEDCOLUMN, 0, 0L); } void SetSelectedColumn(int nColumn) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_SETSELECTEDCOLUMN, nColumn, 0L); } DWORD GetView() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, LVM_GETVIEW, 0, 0L); } int SetView(DWORD dwView) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SETVIEW, dwView, 0L); } BOOL IsGroupViewEnabled() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_ISGROUPVIEWENABLED, 0, 0L); } int GetGroupInfo(int nGroupID, PLVGROUP pGroup) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETGROUPINFO, nGroupID, (LPARAM)pGroup); } int SetGroupInfo(int nGroupID, PLVGROUP pGroup) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SETGROUPINFO, nGroupID, (LPARAM)pGroup); } void GetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_GETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); } void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_SETGROUPMETRICS, 0, (LPARAM)pGroupMetrics); } void GetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_GETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); } BOOL SetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo); } void GetTileInfo(PLVTILEINFO pTileInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_GETTILEINFO, 0, (LPARAM)pTileInfo); } BOOL SetTileInfo(PLVTILEINFO pTileInfo) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETTILEINFO, 0, (LPARAM)pTileInfo); } BOOL GetInsertMark(LPLVINSERTMARK pInsertMark) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETINSERTMARK, 0, (LPARAM)pInsertMark); } BOOL SetInsertMark(LPLVINSERTMARK pInsertMark) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETINSERTMARK, 0, (LPARAM)pInsertMark); } int GetInsertMarkRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETINSERTMARKRECT, 0, (LPARAM)lpRect); } COLORREF GetInsertMarkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_GETINSERTMARKCOLOR, 0, 0L); } COLORREF SetInsertMarkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_SETINSERTMARKCOLOR, 0, clr); } COLORREF GetOutlineColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_GETOUTLINECOLOR, 0, 0L); } COLORREF SetOutlineColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, LVM_SETOUTLINECOLOR, 0, clr); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) int GetGroupCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETGROUPCOUNT, 0, 0L); } BOOL GetGroupInfoByIndex(int nIndex, PLVGROUP pGroup) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPINFOBYINDEX, nIndex, (LPARAM)pGroup); } BOOL GetGroupRect(int nGroupID, int nType, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpRect != NULL); if(lpRect != NULL) lpRect->top = nType; return (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPRECT, nGroupID, (LPARAM)lpRect); } UINT GetGroupState(int nGroupID, UINT uMask) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, LVM_GETGROUPSTATE, nGroupID, (LPARAM)uMask); } int GetFocusedGroup() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETFOCUSEDGROUP, 0, 0L); } BOOL GetEmptyText(LPWSTR lpstrText, int cchText) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETEMPTYTEXT, cchText, (LPARAM)lpstrText); } BOOL GetFooterRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERRECT, 0, (LPARAM)lpRect); } BOOL GetFooterInfo(LPLVFOOTERINFO lpFooterInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERINFO, 0, (LPARAM)lpFooterInfo); } BOOL GetFooterItemRect(int nItem, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEMRECT, nItem, (LPARAM)lpRect); } BOOL GetFooterItem(int nItem, LPLVFOOTERITEM lpFooterItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEM, nItem, (LPARAM)lpFooterItem); } BOOL GetItemIndexRect(PLVITEMINDEX pItemIndex, int nSubItem, int nType, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pItemIndex != NULL); ATLASSERT(lpRect != NULL); if(lpRect != NULL) { lpRect->top = nSubItem; lpRect->left = nType; } return (BOOL)::SendMessage(m_hWnd, LVM_GETITEMINDEXRECT, (WPARAM)pItemIndex, (LPARAM)lpRect); } BOOL SetItemIndexState(PLVITEMINDEX pItemIndex, UINT uState, UINT dwMask) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.state = uState; lvi.stateMask = dwMask; return (BOOL)::SendMessage(m_hWnd, LVM_SETITEMINDEXSTATE, (WPARAM)pItemIndex, (LPARAM)&lvi); } BOOL GetNextItemIndex(PLVITEMINDEX pItemIndex, WORD wFlags) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_GETNEXTITEMINDEX, (WPARAM)pItemIndex, MAKELPARAM(wFlags, 0)); } #endif // (_WIN32_WINNT >= 0x0600) // Operations int InsertColumn(int nCol, const LVCOLUMN* pColumn) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn); } int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1) { LVCOLUMN column = { 0 }; column.mask = LVCF_TEXT|LVCF_FMT; column.pszText = (LPTSTR)lpszColumnHeading; column.fmt = nFormat; if (nWidth != -1) { column.mask |= LVCF_WIDTH; column.cx = nWidth; } if (nSubItem != -1) { column.mask |= LVCF_SUBITEM; column.iSubItem = nSubItem; } if (iImage != -1) { column.mask |= LVCF_IMAGE; column.iImage = iImage; } if (iOrder != -1) { column.mask |= LVCF_ORDER; column.iOrder = iOrder; } return InsertColumn(nCol, &column); } BOOL DeleteColumn(int nCol) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_DELETECOLUMN, nCol, 0L); } int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM item = { 0 }; item.mask = nMask; item.iItem = nItem; item.iSubItem = 0; item.pszText = (LPTSTR)lpszItem; item.state = nState; item.stateMask = nStateMask; item.iImage = nImage; item.lParam = lParam; return InsertItem(&item); } int InsertItem(const LVITEM* pItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem); } int InsertItem(int nItem, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0); } int InsertItem(int nItem, LPCTSTR lpszItem, int nImage) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0); } int GetNextItem(int nItem, int nFlags) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0)); } BOOL DeleteItem(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_DELETEITEM, nItem, 0L); } BOOL DeleteAllItems() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_DELETEALLITEMS, 0, 0L); } int FindItem(LVFINDINFO* pFindInfo, int nStart = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo); } int FindItem(LPCTSTR lpstrFind, bool bPartial = true, bool bWrap = false, int nStart = -1) const { ATLASSERT(::IsWindow(m_hWnd)); LVFINDINFO lvfi = { 0 }; lvfi.flags = LVFI_STRING | (bWrap ? LVFI_WRAP : 0) | (bPartial ? LVFI_PARTIAL : 0); lvfi.psz = lpstrFind; return (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)&lvfi); } int HitTest(LVHITTESTINFO* pHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo); } int HitTest(POINT pt, UINT* pFlags) const { ATLASSERT(::IsWindow(m_hWnd)); LVHITTESTINFO hti = { 0 }; hti.pt = pt; int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti); if (pFlags != NULL) *pFlags = hti.flags; return nRes; } BOOL EnsureVisible(int nItem, BOOL bPartialOK) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_ENSUREVISIBLE, nItem, MAKELPARAM(bPartialOK, 0)); } BOOL Scroll(SIZE size) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SCROLL, size.cx, size.cy); } BOOL RedrawItems(int nFirst, int nLast) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_REDRAWITEMS, nFirst, nLast); } BOOL Arrange(UINT nCode) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_ARRANGE, nCode, 0L); } CEdit EditLabel(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return CEdit((HWND)::SendMessage(m_hWnd, LVM_EDITLABEL, nItem, 0L)); } BOOL Update(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_UPDATE, nItem, 0L); } BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMS, (WPARAM)lParamSort, (LPARAM)pfnCompare); } CImageList RemoveImageList(int nImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); } CImageList CreateDragImage(int nItem, LPPOINT lpPoint) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint)); } DWORD ApproximateViewRect(int cx = -1, int cy = -1, int nCount = -1) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, LVM_APPROXIMATEVIEWRECT, nCount, MAKELPARAM(cx, cy)); } int SubItemHitTest(LPLVHITTESTINFO lpInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, (LPARAM)lpInfo); } int AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1, int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM, int nFmt = LVCFMT_LEFT) { const int cxOffset = 15; ATLASSERT(::IsWindow(m_hWnd)); LVCOLUMN lvc = { 0 }; lvc.mask = nMask; lvc.fmt = nFmt; lvc.pszText = (LPTSTR)strItem; lvc.cx = GetStringWidth(lvc.pszText) + cxOffset; if(nMask & LVCF_SUBITEM) lvc.iSubItem = (nSubItem != -1) ? nSubItem : nItem; return InsertColumn(nItem, &lvc); } int AddItem(int nItem, int nSubItem, LPCTSTR strItem, int nImageIndex = -3) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvItem = { 0 }; lvItem.mask = LVIF_TEXT; lvItem.iItem = nItem; lvItem.iSubItem = nSubItem; lvItem.pszText = (LPTSTR)strItem; if(nImageIndex != -3) { lvItem.mask |= LVIF_IMAGE; lvItem.iImage = nImageIndex; } if(nSubItem == 0) return InsertItem(&lvItem); return SetItem(&lvItem) ? nItem : -1; } #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMSEX, (WPARAM)lParamSort, (LPARAM)pfnCompare); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) int InsertGroup(int nItem, PLVGROUP pGroup) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_INSERTGROUP, nItem, (LPARAM)pGroup); } int AddGroup(PLVGROUP pGroup) { return InsertGroup(-1, pGroup); } int RemoveGroup(int nGroupID) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_REMOVEGROUP, nGroupID, 0L); } void MoveGroup(int nGroupID, int nItem) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_MOVEGROUP, nGroupID, nItem); } void MoveItemToGroup(int nItem, int nGroupID) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_MOVEITEMTOGROUP, nItem, nGroupID); } int EnableGroupView(BOOL bEnable) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_ENABLEGROUPVIEW, bEnable, 0L); } int SortGroups(PFNLVGROUPCOMPARE pCompareFunc, LPVOID lpVoid = NULL) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SORTGROUPS, (WPARAM)pCompareFunc, (LPARAM)lpVoid); } void InsertGroupSorted(PLVINSERTGROUPSORTED pInsertGroupSorted) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_INSERTGROUPSORTED, (WPARAM)pInsertGroupSorted, 0L); } void RemoveAllGroups() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_REMOVEALLGROUPS, 0, 0L); } BOOL HasGroup(int nGroupID) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_HASGROUP, nGroupID, 0L); } BOOL InsertMarkHitTest(LPPOINT lpPoint, LPLVINSERTMARK pInsertMark) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)pInsertMark); } BOOL SetInfoTip(PLVSETINFOTIP pSetInfoTip) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LVM_SETINFOTIP, 0, (LPARAM)pSetInfoTip); } void CancelEditLabel() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, LVM_CANCELEDITLABEL, 0, 0L); } UINT MapIndexToID(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, LVM_MAPINDEXTOID, nIndex, 0L); } int MapIDToIndex(UINT uID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_MAPIDTOINDEX, uID, 0L); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) int HitTestEx(LPLVHITTESTINFO lpHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); } int HitTestEx(POINT pt, UINT* pFlags) const { ATLASSERT(::IsWindow(m_hWnd)); LVHITTESTINFO hti = { 0 }; hti.pt = pt; int nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)&hti); if (pFlags != NULL) *pFlags = hti.flags; return nRes; } int SubItemHitTestEx(LPLVHITTESTINFO lpHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo); } #endif // (_WIN32_WINNT >= 0x0600) // Note: selects only one item BOOL SelectItem(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); // multi-selection only: de-select all items if((GetStyle() & LVS_SINGLESEL) == 0) SetItemState(-1, 0, LVIS_SELECTED); BOOL bRet = SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); if(bRet) bRet = EnsureVisible(nIndex, FALSE); return bRet; } }; typedef CListViewCtrlT CListViewCtrl; /////////////////////////////////////////////////////////////////////////////// // CTreeViewCtrl template class CTreeViewCtrlT : public TBase { public: // Constructors CTreeViewCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CTreeViewCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_TREEVIEW; } UINT GetCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, TVM_GETCOUNT, 0, 0L); } UINT GetIndent() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, TVM_GETINDENT, 0, 0L); } void SetIndent(UINT nIndent) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TVM_SETINDENT, nIndent, 0L); } CImageList GetImageList(int nImageListType = TVSIL_NORMAL) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_GETIMAGELIST, (WPARAM)nImageListType, 0L)); } CImageList SetImageList(HIMAGELIST hImageList, int nImageListType = TVSIL_NORMAL) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageListType, (LPARAM)hImageList)); } BOOL GetItem(LPTVITEM pItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); } BOOL SetItem(LPTVITEM pItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); } BOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); TVITEM item = { 0 }; item.hItem = hItem; item.mask = nMask; item.pszText = (LPTSTR) lpszItem; item.iImage = nImage; item.iSelectedImage = nSelectedImage; item.state = nState; item.stateMask = nStateMask; item.lParam = lParam; return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item); } BOOL GetItemText(HTREEITEM hItem, LPTSTR lpstrText, int nLen) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpstrText != NULL); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_TEXT; item.pszText = lpstrText; item.cchTextMax = nLen; return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); } #ifndef _ATL_NO_COM BOOL GetItemText(HTREEITEM hItem, BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_TEXT; LPTSTR lpstrText = NULL; BOOL bRet = FALSE; for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrText = new TCHAR[nLen]); if(lpstrText == NULL) break; lpstrText[0] = NULL; item.pszText = lpstrText; item.cchTextMax = nLen; bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); if(!bRet || (lstrlen(item.pszText) < nLen - 1)) break; delete [] lpstrText; lpstrText = NULL; } if(lpstrText != NULL) { if(bRet) bstrText = ::SysAllocString(T2OLE(lpstrText)); delete [] lpstrText; } return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetItemText(HTREEITEM hItem, _CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_TEXT; strText.Empty(); BOOL bRet = FALSE; for(int nLen = 256; ; nLen *= 2) { item.pszText = strText.GetBufferSetLength(nLen); if(item.pszText == NULL) { bRet = FALSE; break; } item.cchTextMax = nLen; bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); if(!bRet || (lstrlen(item.pszText) < nLen - 1)) break; } strText.ReleaseBuffer(); return bRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL SetItemText(HTREEITEM hItem, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(hItem, TVIF_TEXT, lpszItem, 0, 0, 0, 0, NULL); } BOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const { ATLASSERT(::IsWindow(m_hWnd)); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE; BOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); if (bRes) { nImage = item.iImage; nSelectedImage = item.iSelectedImage; } return bRes; } BOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(hItem, TVIF_IMAGE|TVIF_SELECTEDIMAGE, NULL, nImage, nSelectedImage, 0, 0, NULL); } UINT GetItemState(HTREEITEM hItem, UINT nStateMask) const { ATLASSERT(::IsWindow(m_hWnd)); #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) return (((UINT)::SendMessage(m_hWnd, TVM_GETITEMSTATE, (WPARAM)hItem, (LPARAM)nStateMask)) & nStateMask); #else // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_STATE; item.state = 0; item.stateMask = nStateMask; ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); return (item.state & nStateMask); #endif // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)) } BOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(hItem, TVIF_STATE, NULL, 0, 0, nState, nStateMask, NULL); } DWORD_PTR GetItemData(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_PARAM; BOOL bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); return (DWORD_PTR)(bRet ? item.lParam : NULL); } BOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(hItem, TVIF_PARAM, NULL, 0, 0, 0, 0, (LPARAM)dwData); } CEdit GetEditControl() const { ATLASSERT(::IsWindow(m_hWnd)); return CEdit((HWND)::SendMessage(m_hWnd, TVM_GETEDITCONTROL, 0, 0L)); } UINT GetVisibleCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, TVM_GETVISIBLECOUNT, 0, 0L); } BOOL GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const { ATLASSERT(::IsWindow(m_hWnd)); *(HTREEITEM*)lpRect = hItem; return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly, (LPARAM)lpRect); } BOOL ItemHasChildren(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); TVITEM item = { 0 }; item.hItem = hItem; item.mask = TVIF_CHILDREN; ::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item); return item.cChildren; } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L)); } CToolTipCtrl SetToolTips(HWND hWndTT) { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L)); } #endif // !_WIN32_WCE int GetISearchString(LPTSTR lpstr) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TVM_GETISEARCHSTRING, 0, (LPARAM)lpstr); } // checkboxes only BOOL GetCheckState(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & TVS_CHECKBOXES) != 0); UINT uRet = GetItemState(hItem, TVIS_STATEIMAGEMASK); return (uRet >> 12) - 1; } BOOL SetCheckState(HTREEITEM hItem, BOOL bCheck) { int nCheck = bCheck ? 2 : 1; // one based index return SetItemState(hItem, INDEXTOSTATEIMAGEMASK(nCheck), TVIS_STATEIMAGEMASK); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) COLORREF GetBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_GETBKCOLOR, 0, 0L); } COLORREF SetBkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_SETBKCOLOR, 0, (LPARAM)clr); } COLORREF GetInsertMarkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_GETINSERTMARKCOLOR, 0, 0L); } COLORREF SetInsertMarkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_SETINSERTMARKCOLOR, 0, (LPARAM)clr); } int GetItemHeight() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TVM_GETITEMHEIGHT, 0, 0L); } int SetItemHeight(int cyHeight) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TVM_SETITEMHEIGHT, cyHeight, 0L); } int GetScrollTime() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TVM_GETSCROLLTIME, 0, 0L); } int SetScrollTime(int nScrollTime) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TVM_SETSCROLLTIME, nScrollTime, 0L); } COLORREF GetTextColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_GETTEXTCOLOR, 0, 0L); } COLORREF SetTextColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)clr); } BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) COLORREF GetLineColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_GETLINECOLOR, 0, 0L); } COLORREF SetLineColor(COLORREF clrNew /*= CLR_DEFAULT*/) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TVM_SETLINECOLOR, 0, (LPARAM)clrNew); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetItem(LPTVITEMEX pItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem); } BOOL SetItem(LPTVITEMEX pItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) DWORD GetExtendedStyle() const { #ifndef TVM_GETEXTENDEDSTYLE const UINT TVM_GETEXTENDEDSTYLE = (TV_FIRST + 45); #endif ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TVM_GETEXTENDEDSTYLE, 0, 0L); } DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) { #ifndef TVM_SETEXTENDEDSTYLE const UINT TVM_SETEXTENDEDSTYLE = (TV_FIRST + 44); #endif ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TVM_SETEXTENDEDSTYLE, dwMask, dwStyle); } #if (_WIN32_WINNT >= 0x0600) BOOL SetAutoScrollInfo(UINT uPixPerSec, UINT uUpdateTime) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETAUTOSCROLLINFO, (WPARAM)uPixPerSec, (LPARAM)uUpdateTime); } DWORD GetSelectedCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TVM_GETSELECTEDCOUNT, 0, 0L); } BOOL GetItemPartRect(HTREEITEM hItem, TVITEMPART partID, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); TVGETITEMPARTRECTINFO gipri = { hItem, lpRect, partID }; return (BOOL)::SendMessage(m_hWnd, TVM_GETITEMPARTRECT, 0, (LPARAM)&gipri); } #endif // (_WIN32_WINNT >= 0x0600) // Operations HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct) { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); } HTREEITEM InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); } HTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); } HTREEITEM InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); TVINSERTSTRUCT tvis = { 0 }; tvis.hParent = hParent; tvis.hInsertAfter = hInsertAfter; tvis.item.mask = nMask; tvis.item.pszText = (LPTSTR) lpszItem; tvis.item.iImage = nImage; tvis.item.iSelectedImage = nSelectedImage; tvis.item.state = nState; tvis.item.stateMask = nStateMask; tvis.item.lParam = lParam; return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); } BOOL DeleteItem(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem); } BOOL DeleteAllItems() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); } BOOL Expand(HTREEITEM hItem, UINT nCode = TVE_EXPAND) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_EXPAND, nCode, (LPARAM)hItem); } HTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); } HTREEITEM GetChildItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); } HTREEITEM GetNextSiblingItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); } HTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); } HTREEITEM GetParentItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); } HTREEITEM GetFirstVisibleItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); } HTREEITEM GetNextVisibleItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); } HTREEITEM GetPrevVisibleItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); } HTREEITEM GetSelectedItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); } HTREEITEM GetDropHilightItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); } HTREEITEM GetRootItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); } #if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) HTREEITEM GetLastVisibleItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); } #endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0600) HTREEITEM GetNextSelectedItem() const { #ifndef TVGN_NEXTSELECTED const WORD TVGN_NEXTSELECTED = 0x000B; #endif ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); } #endif // (_WIN32_IE >= 0x0600) BOOL Select(HTREEITEM hItem, UINT nCode) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, nCode, (LPARAM)hItem); } BOOL SelectItem(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem); } BOOL SelectDropTarget(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItem); } BOOL SelectSetFirstVisible(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hItem); } CEdit EditLabel(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return CEdit((HWND)::SendMessage(m_hWnd, TVM_EDITLABEL, 0, (LPARAM)hItem)); } BOOL EndEditLabelNow(BOOL bCancel) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_ENDEDITLABELNOW, bCancel, 0L); } HTREEITEM HitTest(TVHITTESTINFO* pHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); } HTREEITEM HitTest(POINT pt, UINT* pFlags) const { ATLASSERT(::IsWindow(m_hWnd)); TVHITTESTINFO hti = { 0 }; hti.pt = pt; HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); if (pFlags != NULL) *pFlags = hti.flags; return hTreeItem; } BOOL SortChildren(HTREEITEM hItem, BOOL bRecurse = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDREN, (WPARAM)bRecurse, (LPARAM)hItem); } BOOL EnsureVisible(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem); } BOOL SortChildrenCB(LPTVSORTCB pSort, BOOL bRecurse = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDRENCB, (WPARAM)bRecurse, (LPARAM)pSort); } CImageList RemoveImageList(int nImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageList, NULL)); } CImageList CreateDragImage(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem)); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL SetInsertMark(HTREEITEM hTreeItem, BOOL bAfter) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, bAfter, (LPARAM)hTreeItem); } BOOL RemoveInsertMark() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, 0, 0L); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) HTREEITEM MapAccIDToHTREEITEM(UINT uID) const { ATLASSERT(::IsWindow(m_hWnd)); return (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); } UINT MapHTREEITEMToAccID(HTREEITEM hTreeItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, TVM_MAPHTREEITEMTOACCID, (WPARAM)hTreeItem, 0L); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) void ShowInfoTip(HTREEITEM hItem) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TVM_SHOWINFOTIP, 0, (LPARAM)hItem); } #endif // (_WIN32_WINNT >= 0x0600) }; typedef CTreeViewCtrlT CTreeViewCtrl; /////////////////////////////////////////////////////////////////////////////// // CTreeViewCtrlEx // forward declaration template class CTreeViewCtrlExT; // Note: TBase here is for CTreeViewCtrlExT, and not for CTreeItemT itself template class CTreeItemT { public: HTREEITEM m_hTreeItem; CTreeViewCtrlExT* m_pTreeView; // Construction CTreeItemT(HTREEITEM hTreeItem = NULL, CTreeViewCtrlExT* pTreeView = NULL) : m_hTreeItem(hTreeItem), m_pTreeView(pTreeView) { } CTreeItemT(const CTreeItemT& posSrc) { *this = posSrc; } operator HTREEITEM() { return m_hTreeItem; } CTreeItemT& operator =(const CTreeItemT& itemSrc) { m_hTreeItem = itemSrc.m_hTreeItem; m_pTreeView = itemSrc.m_pTreeView; return *this; } // Attributes CTreeViewCtrlExT* GetTreeView() const { return m_pTreeView; } BOOL operator !() const { return m_hTreeItem == NULL; } BOOL IsNull() const { return m_hTreeItem == NULL; } BOOL GetRect(LPRECT lpRect, BOOL bTextOnly) const; BOOL GetText(LPTSTR lpstrText, int nLen) const; #ifndef _ATL_NO_COM BOOL GetText(BSTR& bstrText) const; #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetText(_CSTRING_NS::CString& strText) const; #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL SetText(LPCTSTR lpszItem); BOOL GetImage(int& nImage, int& nSelectedImage) const; BOOL SetImage(int nImage, int nSelectedImage); UINT GetState(UINT nStateMask) const; BOOL SetState(UINT nState, UINT nStateMask); DWORD_PTR GetData() const; BOOL SetData(DWORD_PTR dwData); BOOL SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam); // Operations CTreeItemT InsertAfter(LPCTSTR lpstrItem, HTREEITEM hItemAfter, int nImageIndex) { return _Insert(lpstrItem, nImageIndex, hItemAfter); } CTreeItemT AddHead(LPCTSTR lpstrItem, int nImageIndex) { return _Insert(lpstrItem, nImageIndex, TVI_FIRST); } CTreeItemT AddTail(LPCTSTR lpstrItem, int nImageIndex) { return _Insert(lpstrItem, nImageIndex, TVI_LAST); } CTreeItemT GetChild() const; CTreeItemT GetNext(UINT nCode) const; CTreeItemT GetNextSibling() const; CTreeItemT GetPrevSibling() const; CTreeItemT GetParent() const; CTreeItemT GetFirstVisible() const; CTreeItemT GetNextVisible() const; CTreeItemT GetPrevVisible() const; CTreeItemT GetSelected() const; CTreeItemT GetDropHilight() const; CTreeItemT GetRoot() const; #if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) CTreeItemT GetLastVisible() const; #endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0600) CTreeItemT GetNextSelected() const; #endif // (_WIN32_IE >= 0x0600) BOOL HasChildren() const; BOOL Delete(); BOOL Expand(UINT nCode = TVE_EXPAND); BOOL Select(UINT nCode); BOOL Select(); BOOL SelectDropTarget(); BOOL SelectSetFirstVisible(); HWND EditLabel(); HIMAGELIST CreateDragImage(); BOOL SortChildren(BOOL bRecurse = FALSE); BOOL EnsureVisible(); CTreeItemT _Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter); int GetImageIndex() const; #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL SetInsertMark(BOOL bAfter); #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) UINT MapHTREEITEMToAccID() const; #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) void ShowInfoTip(); BOOL GetPartRect(TVITEMPART partID, LPRECT lpRect) const; #endif // (_WIN32_WINNT >= 0x0600) }; typedef CTreeItemT CTreeItem; template class CTreeViewCtrlExT : public CTreeViewCtrlT< TBase > { public: // Constructors CTreeViewCtrlExT(HWND hWnd = NULL) : CTreeViewCtrlT< TBase >(hWnd) { } CTreeViewCtrlExT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Operations (overides that return CTreeItem) CTreeItemT InsertItem(LPTVINSERTSTRUCT lpInsertStruct) { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); return CTreeItemT(hTreeItem, this); } CTreeItemT InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); } CTreeItemT InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); return InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter); } CTreeItemT GetNextItem(HTREEITEM hItem, UINT nCode) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetChildItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetNextSiblingItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetPrevSiblingItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetParentItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetFirstVisibleItem() const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetNextVisibleItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetPrevVisibleItem(HTREEITEM hItem) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetSelectedItem() const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetDropHilightItem() const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT GetRootItem() const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } #if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) CTreeItemT GetLastVisibleItem() const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } #endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0600) CTreeItemT GetNextSelectedItem() const { #ifndef TVGN_NEXTSELECTED const WORD TVGN_NEXTSELECTED = 0x000B; #endif ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } #endif // (_WIN32_IE >= 0x0600) CTreeItemT HitTest(TVHITTESTINFO* pHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } CTreeItemT InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEM hInsertAfter) { ATLASSERT(::IsWindow(m_hWnd)); TVINSERTSTRUCT tvis = { 0 }; tvis.hParent = hParent; tvis.hInsertAfter = hInsertAfter; tvis.item.mask = nMask; tvis.item.pszText = (LPTSTR) lpszItem; tvis.item.iImage = nImage; tvis.item.iSelectedImage = nSelectedImage; tvis.item.state = nState; tvis.item.stateMask = nStateMask; tvis.item.lParam = lParam; HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis); return CTreeItemT(hTreeItem, this); } CTreeItemT HitTest(POINT pt, UINT* pFlags) const { ATLASSERT(::IsWindow(m_hWnd)); TVHITTESTINFO hti = { 0 }; hti.pt = pt; HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti); if (pFlags != NULL) *pFlags = hti.flags; return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } #if (_WIN32_WINNT >= 0x0501) CTreeItemT MapAccIDToHTREEITEM(UINT uID) const { ATLASSERT(::IsWindow(m_hWnd)); HTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L); return CTreeItemT(hTreeItem, (CTreeViewCtrlExT*)this); } #endif // (_WIN32_WINNT >= 0x0501) }; typedef CTreeViewCtrlExT CTreeViewCtrlEx; // CTreeItem inline methods template inline BOOL CTreeItemT::GetRect(LPRECT lpRect, BOOL bTextOnly) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemRect(m_hTreeItem,lpRect,bTextOnly); } template inline CTreeItemT CTreeItemT::GetNext(UINT nCode) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetNextItem(m_hTreeItem,nCode); } template inline CTreeItemT CTreeItemT::GetChild() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetChildItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetNextSibling() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetNextSiblingItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetPrevSibling() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetPrevSiblingItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetParent() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetParentItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetFirstVisible() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetFirstVisibleItem(); } template inline CTreeItemT CTreeItemT::GetNextVisible() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetNextVisibleItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetPrevVisible() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetPrevVisibleItem(m_hTreeItem); } template inline CTreeItemT CTreeItemT::GetSelected() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetSelectedItem(); } template inline CTreeItemT CTreeItemT::GetDropHilight() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetDropHilightItem(); } template inline CTreeItemT CTreeItemT::GetRoot() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetRootItem(); } #if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) template inline CTreeItemT CTreeItemT::GetLastVisible() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetLastVisibleItem(); } #endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0600) template inline CTreeItemT CTreeItemT::GetNextSelected() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetNextSelectedItem(); } #endif // (_WIN32_IE >= 0x0600) template inline BOOL CTreeItemT::GetText(LPTSTR lpstrText, int nLen) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemText(m_hTreeItem, lpstrText, nLen); } #ifndef _ATL_NO_COM #ifdef _OLEAUTO_H_ template inline BOOL CTreeItemT::GetText(BSTR& bstrText) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemText(m_hTreeItem, bstrText); } #endif // _OLEAUTO_H_ #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) template inline BOOL CTreeItemT::GetText(_CSTRING_NS::CString& strText) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemText(m_hTreeItem, strText); } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) template inline BOOL CTreeItemT::GetImage(int& nImage, int& nSelectedImage) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemImage(m_hTreeItem,nImage,nSelectedImage); } template inline UINT CTreeItemT::GetState(UINT nStateMask) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemState(m_hTreeItem,nStateMask); } template inline DWORD_PTR CTreeItemT::GetData() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemData(m_hTreeItem); } template inline BOOL CTreeItemT::SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetItem(m_hTreeItem, nMask, lpszItem, nImage, nSelectedImage, nState, nStateMask, lParam); } template inline BOOL CTreeItemT::SetText(LPCTSTR lpszItem) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetItemText(m_hTreeItem,lpszItem); } template inline BOOL CTreeItemT::SetImage(int nImage, int nSelectedImage) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetItemImage(m_hTreeItem,nImage,nSelectedImage); } template inline BOOL CTreeItemT::SetState(UINT nState, UINT nStateMask) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetItemState(m_hTreeItem,nState,nStateMask); } template inline BOOL CTreeItemT::SetData(DWORD_PTR dwData) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetItemData(m_hTreeItem,dwData); } template inline BOOL CTreeItemT::HasChildren() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->ItemHasChildren(m_hTreeItem); } template inline BOOL CTreeItemT::Delete() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->DeleteItem(m_hTreeItem); } template inline BOOL CTreeItemT::Expand(UINT nCode /*= TVE_EXPAND*/) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->Expand(m_hTreeItem,nCode); } template inline BOOL CTreeItemT::Select(UINT nCode) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->Select(m_hTreeItem,nCode); } template inline BOOL CTreeItemT::Select() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SelectItem(m_hTreeItem); } template inline BOOL CTreeItemT::SelectDropTarget() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SelectDropTarget(m_hTreeItem); } template inline BOOL CTreeItemT::SelectSetFirstVisible() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SelectSetFirstVisible(m_hTreeItem); } template inline HWND CTreeItemT::EditLabel() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->EditLabel(m_hTreeItem); } template inline HIMAGELIST CTreeItemT::CreateDragImage() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->CreateDragImage(m_hTreeItem); } template inline BOOL CTreeItemT::SortChildren(BOOL bRecurse /*= FALSE*/) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SortChildren(m_hTreeItem, bRecurse); } template inline BOOL CTreeItemT::EnsureVisible() { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->EnsureVisible(m_hTreeItem); } template inline CTreeItemT CTreeItemT::_Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter) { ATLASSERT(m_pTreeView != NULL); TVINSERTSTRUCT ins = { 0 }; ins.hParent = m_hTreeItem; ins.hInsertAfter = hItemAfter; ins.item.mask = TVIF_TEXT; ins.item.pszText = (LPTSTR)lpstrItem; if(nImageIndex != -1) { ins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; ins.item.iImage = nImageIndex; ins.item.iSelectedImage = nImageIndex; } return CTreeItemT(m_pTreeView->InsertItem(&ins), m_pTreeView); } template inline int CTreeItemT::GetImageIndex() const { ATLASSERT(m_pTreeView != NULL); TVITEM item = { 0 }; item.mask = TVIF_HANDLE | TVIF_IMAGE; item.hItem = m_hTreeItem; m_pTreeView->GetItem(&item); return item.iImage; } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) template inline BOOL CTreeItemT::SetInsertMark(BOOL bAfter) { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->SetInsertMark(m_hTreeItem, bAfter); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) template inline UINT CTreeItemT::MapHTREEITEMToAccID() const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->MapHTREEITEMToAccID(m_hTreeItem); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) template inline void CTreeItemT::ShowInfoTip() { ATLASSERT(m_pTreeView != NULL); m_pTreeView->ShowInfoTip(m_hTreeItem); } template inline BOOL CTreeItemT::GetPartRect(TVITEMPART partID, LPRECT lpRect) const { ATLASSERT(m_pTreeView != NULL); return m_pTreeView->GetItemPartRect(m_hTreeItem, partID, lpRect); } #endif // (_WIN32_WINNT >= 0x0600) /////////////////////////////////////////////////////////////////////////////// // CToolBarCtrl template class CToolBarCtrlT : public TBase { public: // Construction CToolBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CToolBarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return TOOLBARCLASSNAME; } BOOL IsButtonEnabled(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0L); } BOOL IsButtonChecked(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONCHECKED, nID, 0L); } BOOL IsButtonPressed(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0L); } BOOL IsButtonHidden(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return(BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0L); } BOOL IsButtonIndeterminate(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONINDETERMINATE, nID, 0L); } int GetState(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L); } BOOL SetState(int nID, UINT nState) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0)); } BOOL GetButton(int nIndex, LPTBBUTTON lpButton) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETBUTTON, nIndex, (LPARAM)lpButton); } int GetButtonCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_BUTTONCOUNT, 0, 0L); } BOOL GetItemRect(int nIndex, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETITEMRECT, nIndex, (LPARAM)lpRect); } void SetButtonStructSize(int nSize = sizeof(TBBUTTON)) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, nSize, 0L); } BOOL SetButtonSize(SIZE size) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy)); } BOOL SetButtonSize(int cx, int cy) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cy)); } BOOL SetBitmapSize(SIZE size) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy)); } BOOL SetBitmapSize(int cx, int cy) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(cx, cy)); } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TB_GETTOOLTIPS, 0, 0L)); } void SetToolTips(HWND hWndToolTip) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); } #endif // !_WIN32_WCE void SetNotifyWnd(HWND hWnd) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)hWnd, 0L); } int GetRows() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETROWS, 0, 0L); } void SetRows(int nRows, BOOL bLarger, LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETROWS, MAKELPARAM(nRows, bLarger), (LPARAM)lpRect); } BOOL SetCmdID(int nIndex, UINT nID) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETCMDID, nIndex, nID); } DWORD GetBitmapFlags() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L); } int GetBitmap(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETBITMAP, nID, 0L); } int GetButtonText(int nID, LPTSTR lpstrText) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETBUTTONTEXT, nID, (LPARAM)lpstrText); } // nIndex - IE5 or higher only CImageList GetImageList(int nIndex = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETIMAGELIST, nIndex, 0L)); } // nIndex - IE5 or higher only CImageList SetImageList(HIMAGELIST hImageList, int nIndex = 0) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETIMAGELIST, nIndex, (LPARAM)hImageList)); } // nIndex - IE5 or higher only CImageList GetDisabledImageList(int nIndex = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETDISABLEDIMAGELIST, nIndex, 0L)); } // nIndex - IE5 or higher only CImageList SetDisabledImageList(HIMAGELIST hImageList, int nIndex = 0) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETDISABLEDIMAGELIST, nIndex, (LPARAM)hImageList)); } #ifndef _WIN32_WCE // nIndex - IE5 or higher only CImageList GetHotImageList(int nIndex = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETHOTIMAGELIST, nIndex, 0L)); } // nIndex - IE5 or higher only CImageList SetHotImageList(HIMAGELIST hImageList, int nIndex = 0) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETHOTIMAGELIST, nIndex, (LPARAM)hImageList)); } #endif // !_WIN32_WCE DWORD GetStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_GETSTYLE, 0, 0L); } void SetStyle(DWORD dwStyle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETSTYLE, 0, dwStyle); } DWORD GetButtonSize() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); } void GetButtonSize(SIZE& size) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L); size.cx = LOWORD(dwRet); size.cy = HIWORD(dwRet); } BOOL GetRect(int nID, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETRECT, nID, (LPARAM)lpRect); } int GetTextRows() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0L); } BOOL SetButtonWidth(int cxMin, int cxMax) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cxMin, cxMax)); } BOOL SetIndent(int nIndent) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETINDENT, nIndent, 0L); } BOOL SetMaxTextRows(int nMaxTextRows) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, nMaxTextRows, 0L); } #if (_WIN32_IE >= 0x0400) #ifndef _WIN32_WCE BOOL GetAnchorHighlight() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETANCHORHIGHLIGHT, 0, 0L); } BOOL SetAnchorHighlight(BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETANCHORHIGHLIGHT, bEnable, 0L); } #endif // !_WIN32_WCE int GetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETBUTTONINFO, nID, (LPARAM)lptbbi); } BOOL SetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)lptbbi); } BOOL SetButtonInfo(int nID, DWORD dwMask, BYTE Style, BYTE State, LPCTSTR lpszItem, int iImage, WORD cx, int iCommand, DWORD_PTR lParam) { ATLASSERT(::IsWindow(m_hWnd)); TBBUTTONINFO tbbi = { 0 }; tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = dwMask; tbbi.idCommand = iCommand; tbbi.iImage = iImage; tbbi.fsState = State; tbbi.fsStyle = Style; tbbi.cx = cx; tbbi.pszText = (LPTSTR) lpszItem; tbbi.lParam = lParam; return (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)&tbbi); } #ifndef _WIN32_WCE int GetHotItem() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETHOTITEM, 0, 0L); } int SetHotItem(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_SETHOTITEM, nItem, 0L); } #endif // !_WIN32_WCE BOOL IsButtonHighlighted(int nButtonID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONHIGHLIGHTED, nButtonID, 0L); } DWORD SetDrawTextFlags(DWORD dwMask, DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_SETDRAWTEXTFLAGS, dwMask, dwFlags); } #ifndef _WIN32_WCE BOOL GetColorScheme(LPCOLORSCHEME lpcs) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETCOLORSCHEME, 0, (LPARAM)lpcs); } void SetColorScheme(LPCOLORSCHEME lpcs) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETCOLORSCHEME, 0, (LPARAM)lpcs); } DWORD GetExtendedStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_GETEXTENDEDSTYLE, 0, 0L); } DWORD SetExtendedStyle(DWORD dwStyle) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, dwStyle); } void GetInsertMark(LPTBINSERTMARK lptbim) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_GETINSERTMARK, 0, (LPARAM)lptbim); } void SetInsertMark(LPTBINSERTMARK lptbim) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETINSERTMARK, 0, (LPARAM)lptbim); } COLORREF GetInsertMarkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TB_GETINSERTMARKCOLOR, 0, 0L); } COLORREF SetInsertMarkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, TB_SETINSERTMARKCOLOR, 0, (LPARAM)clr); } BOOL GetMaxSize(LPSIZE lpSize) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETMAXSIZE, 0, (LPARAM)lpSize); } void GetPadding(LPSIZE lpSizePadding) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpSizePadding != NULL); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETPADDING, 0, 0L); lpSizePadding->cx = GET_X_LPARAM(dwRet); lpSizePadding->cy = GET_Y_LPARAM(dwRet); } void SetPadding(int cx, int cy, LPSIZE lpSizePadding = NULL) { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_SETPADDING, 0, MAKELPARAM(cx, cy)); if(lpSizePadding != NULL) { lpSizePadding->cx = GET_X_LPARAM(dwRet); lpSizePadding->cy = GET_Y_LPARAM(dwRet); } } BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_SETUNICODEFORMAT, bUnicode, 0L); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) int GetString(int nString, LPTSTR lpstrString, int cchMaxLen) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(cchMaxLen, nString), (LPARAM)lpstrString); } int GetStringBSTR(int nString, BSTR& bstrString) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrString == NULL); int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); if(nLength != -1) { CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(nLength + 1); if(lpstrText != NULL) { nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstrText); if(nLength != -1) bstrString = ::SysAllocString(T2OLE(lpstrText)); } else { nLength = -1; } } return nLength; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetString(int nString, _CSTRING_NS::CString& str) const { ATLASSERT(::IsWindow(m_hWnd)); int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL)); if(nLength != -1) { LPTSTR lpstr = str.GetBufferSetLength(nLength + 1); if(lpstr != NULL) nLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstr); else nLength = -1; str.ReleaseBuffer(); } return nLength; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) void GetMetrics(LPTBMETRICS lptbm) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_GETMETRICS, 0, (LPARAM)lptbm); } void SetMetrics(LPTBMETRICS lptbm) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETMETRICS, 0, (LPARAM)lptbm); } void SetWindowTheme(LPCWSTR lpstrTheme) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_WINNT >= 0x0600) CImageList GetPressedImageList(int nIndex = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETPRESSEDIMAGELIST, nIndex, 0L)); } CImageList SetPressedImageList(HIMAGELIST hImageList, int nIndex = 0) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETPRESSEDIMAGELIST, nIndex, (LPARAM)hImageList)); } void GetItemDropDownRect(int nIndex, LPRECT lpRect) const { #ifndef TB_GETITEMDROPDOWNRECT const int TB_GETITEMDROPDOWNRECT = WM_USER + 103; #endif ATLASSERT(::IsWindow(m_hWnd)); BOOL bRet = (BOOL)::SendMessage(m_hWnd, TB_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect); bRet; // avoid level 4 warning ATLASSERT(bRet != FALSE); } #endif // (_WIN32_WINNT >= 0x0600) // Operations BOOL EnableButton(int nID, BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0)); } BOOL CheckButton(int nID, BOOL bCheck = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_CHECKBUTTON, nID, MAKELPARAM(bCheck, 0)); } BOOL PressButton(int nID, BOOL bPress = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0)); } BOOL HideButton(int nID, BOOL bHide = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0)); } BOOL Indeterminate(int nID, BOOL bIndeterminate = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_INDETERMINATE, nID, MAKELPARAM(bIndeterminate, 0)); } int AddBitmap(int nNumButtons, UINT nBitmapID) { ATLASSERT(::IsWindow(m_hWnd)); TBADDBITMAP tbab = { 0 }; tbab.hInst = ModuleHelper::GetResourceInstance(); ATLASSERT(tbab.hInst != NULL); tbab.nID = nBitmapID; return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); } int AddBitmap(int nNumButtons, HBITMAP hBitmap) { ATLASSERT(::IsWindow(m_hWnd)); TBADDBITMAP tbab = { 0 }; tbab.hInst = NULL; tbab.nID = (UINT_PTR)hBitmap; return (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab); } BOOL AddButtons(int nNumButtons, LPTBBUTTON lpButtons) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_ADDBUTTONS, nNumButtons, (LPARAM)lpButtons); } BOOL InsertButton(int nIndex, LPTBBUTTON lpButton) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)lpButton); } BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam) { ATLASSERT(::IsWindow(m_hWnd)); TBBUTTON tbb = { 0 }; tbb.fsStyle = Style; tbb.fsState = State; tbb.idCommand = iCommand; tbb.iBitmap = iBitmap; tbb.iString = iString; tbb.dwData = lParam; return (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)&tbb); } BOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam) { return InsertButton(nIndex, iCommand, Style, State, iBitmap, (INT_PTR)lpszItem, lParam); } BOOL AddButton(LPTBBUTTON lpButton) { return InsertButton(-1, lpButton); } BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam) { return InsertButton(-1, iCommand, Style, State, iBitmap, iString, lParam); } BOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam) { return InsertButton(-1, iCommand, Style, State, iBitmap, lpszItem, lParam); } BOOL DeleteButton(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_DELETEBUTTON, nIndex, 0L); } BOOL InsertSeparator(int nIndex, int cxWidth = 8) { return InsertButton(nIndex, 0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0); } BOOL AddSeparator(int cxWidth = 8) { return AddButton(0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0); } int CommandToIndex(UINT nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_COMMANDTOINDEX, nID, 0L); } #ifndef _WIN32_WCE void SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) { ATLASSERT(::IsWindow(m_hWnd)); TBSAVEPARAMS tbs = { 0 }; tbs.hkr = hKeyRoot; tbs.pszSubKey = lpszSubKey; tbs.pszValueName = lpszValueName; ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs); } void RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName) { ATLASSERT(::IsWindow(m_hWnd)); TBSAVEPARAMS tbs = { 0 }; tbs.hkr = hKeyRoot; tbs.pszSubKey = lpszSubKey; tbs.pszValueName = lpszValueName; ::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs); } void Customize() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_CUSTOMIZE, 0, 0L); } #endif // !_WIN32_WCE int AddString(UINT nStringID) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)ModuleHelper::GetResourceInstance(), (LPARAM)nStringID); } int AddStrings(LPCTSTR lpszStrings) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings); } void AutoSize() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0L); } BOOL ChangeBitmap(int nID, int nBitmap) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_CHANGEBITMAP, nID, MAKELPARAM(nBitmap, 0)); } int LoadImages(int nBitmapID) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)ModuleHelper::GetResourceInstance()); } int LoadStdImages(int nBitmapID) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)HINST_COMMCTRL); } BOOL ReplaceBitmap(LPTBREPLACEBITMAP ptbrb) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_REPLACEBITMAP, 0, (LPARAM)ptbrb); } #if (_WIN32_IE >= 0x0400) int HitTest(LPPOINT lpPoint) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TB_HITTEST, 0, (LPARAM)lpPoint); } #ifndef _WIN32_WCE BOOL InsertMarkHitTest(LPPOINT lpPoint, LPTBINSERTMARK lptbim) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)lptbim); } BOOL InsertMarkHitTest(int x, int y, LPTBINSERTMARK lptbim) const { ATLASSERT(::IsWindow(m_hWnd)); POINT pt = { x, y }; return (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)&pt, (LPARAM)lptbim); } BOOL MapAccelerator(TCHAR chAccel, int& nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_MAPACCELERATOR, (WPARAM)chAccel, (LPARAM)&nID); } BOOL MarkButton(int nID, BOOL bHighlight = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_MARKBUTTON, nID, MAKELPARAM(bHighlight, 0)); } BOOL MoveButton(int nOldPos, int nNewPos) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TB_MOVEBUTTON, nOldPos, nNewPos); } HRESULT GetObject(REFIID iid, LPVOID* ppvObject) { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&iid, (LPARAM)ppvObject); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) }; typedef CToolBarCtrlT CToolBarCtrl; /////////////////////////////////////////////////////////////////////////////// // CStatusBarCtrl template class CStatusBarCtrlT : public TBase { public: // Constructors CStatusBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CStatusBarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Methods static LPCTSTR GetWndClassName() { return STATUSCLASSNAME; } int GetParts(int nParts, int* pParts) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, SB_GETPARTS, nParts, (LPARAM)pParts); } BOOL SetParts(int nParts, int* pWidths) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_SETPARTS, nParts, (LPARAM)pWidths); } int GetTextLength(int nPane, int* pType = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L); if (pType != NULL) *pType = (int)(short)HIWORD(dwRet); return (int)(short)LOWORD(dwRet); } int GetText(int nPane, LPTSTR lpszText, int* pType = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane, (LPARAM)lpszText); if(pType != NULL) *pType = (int)(short)HIWORD(dwRet); return (int)(short)LOWORD(dwRet); } #ifndef _ATL_NO_COM BOOL GetTextBSTR(int nPane, BSTR& bstrText, int* pType = NULL) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); ATLASSERT(bstrText == NULL); int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); if(nLength == 0) return FALSE; CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(nLength + 1); if(lpstrText == NULL) return FALSE; if(!GetText(nPane, lpstrText, pType)) return FALSE; bstrText = ::SysAllocString(T2OLE(lpstrText)); return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetText(int nPane, _CSTRING_NS::CString& strText, int* pType = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); int nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L)); if(nLength == 0) return 0; LPTSTR lpstr = strText.GetBufferSetLength(nLength); if(lpstr == NULL) return 0; return GetText(nPane, lpstr, pType); } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL SetText(int nPane, LPCTSTR lpszText, int nType = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); return (BOOL)::SendMessage(m_hWnd, SB_SETTEXT, (nPane | nType), (LPARAM)lpszText); } BOOL GetRect(int nPane, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); return (BOOL)::SendMessage(m_hWnd, SB_GETRECT, nPane, (LPARAM)lpRect); } BOOL GetBorders(int* pBorders) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)pBorders); } BOOL GetBorders(int& nHorz, int& nVert, int& nSpacing) const { ATLASSERT(::IsWindow(m_hWnd)); int borders[3] = { 0, 0, 0 }; BOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)&borders); if(bResult) { nHorz = borders[0]; nVert = borders[1]; nSpacing = borders[2]; } return bResult; } void SetMinHeight(int nMin) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, SB_SETMINHEIGHT, nMin, 0L); } BOOL SetSimple(BOOL bSimple = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_SIMPLE, bSimple, 0L); } BOOL IsSimple() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_ISSIMPLE, 0, 0L); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, SB_SETUNICODEFORMAT, bUnicode, 0L); } void GetTipText(int nPane, LPTSTR lpstrText, int nSize) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); ::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, nSize), (LPARAM)lpstrText); } void SetTipText(int nPane, LPCTSTR lpstrText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); ::SendMessage(m_hWnd, SB_SETTIPTEXT, nPane, (LPARAM)lpstrText); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) COLORREF SetBkColor(COLORREF clrBk) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, SB_SETBKCOLOR, 0, (LPARAM)clrBk); } HICON GetIcon(int nPane) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); return (HICON)::SendMessage(m_hWnd, SB_GETICON, nPane, 0L); } BOOL SetIcon(int nPane, HICON hIcon) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPane < 256); return (BOOL)::SendMessage(m_hWnd, SB_SETICON, nPane, (LPARAM)hIcon); } #endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) }; typedef CStatusBarCtrlT CStatusBarCtrl; /////////////////////////////////////////////////////////////////////////////// // CTabCtrl template class CTabCtrlT : public TBase { public: // Constructors CTabCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CTabCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_TABCONTROL; } CImageList GetImageList() const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_GETIMAGELIST, 0, 0L)); } CImageList SetImageList(HIMAGELIST hImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)hImageList)); } int GetItemCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_GETITEMCOUNT, 0, 0L); } BOOL GetItem(int nItem, LPTCITEM pTabCtrlItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_GETITEM, nItem, (LPARAM)pTabCtrlItem); } BOOL SetItem(int nItem, LPTCITEM pTabCtrlItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)pTabCtrlItem); } int SetItem(int nItem, UINT mask, LPCTSTR lpszItem, DWORD dwState, DWORD dwStateMask, int iImage, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); TCITEM tci = { 0 }; tci.mask = mask; tci.pszText = (LPTSTR) lpszItem; tci.dwState = dwState; tci.dwStateMask = dwStateMask; tci.iImage = iImage; tci.lParam = lParam; return (int)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)&tci); } BOOL GetItemRect(int nItem, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_GETITEMRECT, nItem, (LPARAM)lpRect); } int GetCurSel() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0L); } int SetCurSel(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_SETCURSEL, nItem, 0L); } SIZE SetItemSize(SIZE size) { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwSize = (DWORD)::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(size.cx, size.cy)); SIZE sizeRet = { GET_X_LPARAM(dwSize), GET_Y_LPARAM(dwSize) }; return sizeRet; } void SetItemSize(int cx, int cy) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(cx, cy)); } void SetPadding(SIZE size) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_SETPADDING, 0, MAKELPARAM(size.cx, size.cy)); } int GetRowCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_GETROWCOUNT, 0, 0L); } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TCM_GETTOOLTIPS, 0, 0L)); } // this method is deprecated, please use GetToolTips CToolTipCtrl GetTooltips() const { return GetToolTips(); } void SetToolTips(HWND hWndToolTip) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L); } // this method is deprecated, please use SetToolTips void SetTooltips(HWND hWndToolTip) { SetToolTips(hWndToolTip); } #endif // !_WIN32_WCE int GetCurFocus() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_GETCURFOCUS, 0, 0L); } void SetCurFocus(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_SETCURFOCUS, nItem, 0L); } BOOL SetItemExtra(int cbExtra) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetItemCount() == 0); // must be empty return (BOOL)::SendMessage(m_hWnd, TCM_SETITEMEXTRA, cbExtra, 0L); } int SetMinTabWidth(int nWidth = -1) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_SETMINTABWIDTH, 0, nWidth); } #if (_WIN32_IE >= 0x0400) DWORD GetExtendedStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TCM_GETEXTENDEDSTYLE, 0, 0L); } DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, TCM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); } #ifndef _WIN32_WCE BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) // Operations int InsertItem(int nItem, LPTCITEM pTabCtrlItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)pTabCtrlItem); } int InsertItem(int nItem, UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); TCITEM tci = { 0 }; tci.mask = mask; tci.pszText = (LPTSTR) lpszItem; tci.iImage = iImage; tci.lParam = lParam; return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); } int InsertItem(int nItem, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); TCITEM tci = { 0 }; tci.mask = TCIF_TEXT; tci.pszText = (LPTSTR) lpszItem; return (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci); } int AddItem(LPTCITEM pTabCtrlItem) { return InsertItem(GetItemCount(), pTabCtrlItem); } int AddItem(UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam) { return InsertItem(GetItemCount(), mask, lpszItem, iImage, lParam); } int AddItem(LPCTSTR lpszItem) { return InsertItem(GetItemCount(), lpszItem); } BOOL DeleteItem(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_DELETEITEM, nItem, 0L); } BOOL DeleteAllItems() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_DELETEALLITEMS, 0, 0L); } void AdjustRect(BOOL bLarger, LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect); } void RemoveImage(int nImage) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_REMOVEIMAGE, nImage, 0L); } int HitTest(TC_HITTESTINFO* pHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo); } void DeselectAll(BOOL bExcludeFocus = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TCM_DESELECTALL, bExcludeFocus, 0L); } #if (_WIN32_IE >= 0x0400) BOOL HighlightItem(int nIndex, BOOL bHighlight = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TCM_HIGHLIGHTITEM, nIndex, MAKELPARAM(bHighlight, 0)); } #endif // (_WIN32_IE >= 0x0400) }; typedef CTabCtrlT CTabCtrl; /////////////////////////////////////////////////////////////////////////////// // CTrackBarCtrl template class CTrackBarCtrlT : public TBase { public: // Constructors CTrackBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CTrackBarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return TRACKBAR_CLASS; } int GetLineSize() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETLINESIZE, 0, 0L); } int SetLineSize(int nSize) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_SETLINESIZE, 0, nSize); } int GetPageSize() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETPAGESIZE, 0, 0L); } int SetPageSize(int nSize) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_SETPAGESIZE, 0, nSize); } int GetRangeMin() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETRANGEMIN, 0, 0L); } void SetRangeMin(int nMin, BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin); } int GetRangeMax() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETRANGEMAX, 0, 0L); } void SetRangeMax(int nMax, BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETRANGEMAX, bRedraw, nMax); } void GetRange(int& nMin, int& nMax) const { nMin = GetRangeMin(); nMax = GetRangeMax(); } void SetRange(int nMin, int nMax, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETRANGE, bRedraw, MAKELPARAM(nMin, nMax)); } int GetSelStart() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L); } void SetSelStart(int nMin, BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETSELSTART, bRedraw, (LPARAM)nMin); } int GetSelEnd() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L); } void SetSelEnd(int nMax, BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETSELEND, bRedraw, (LPARAM)nMax); } void GetSelection(int& nMin, int& nMax) const { nMin = GetSelStart(); nMax = GetSelEnd(); } void SetSelection(int nMin, int nMax, BOOL bRedraw = TRUE) { SetSelStart(nMin, FALSE); SetSelEnd(nMax, bRedraw); } void GetChannelRect(LPRECT lprc) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)lprc); } void GetThumbRect(LPRECT lprc) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)lprc); } int GetPos() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETPOS, 0, 0L); } void SetPos(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETPOS, TRUE, nPos); } UINT GetNumTics() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, TBM_GETNUMTICS, 0, 0L); } DWORD* GetTicArray() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD*)::SendMessage(m_hWnd, TBM_GETPTICS, 0, 0L); } int GetTic(int nTic) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETTIC, nTic, 0L); } BOOL SetTic(int nTic) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TBM_SETTIC, 0, nTic); } int GetTicPos(int nTic) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETTICPOS, nTic, 0L); } void SetTicFreq(int nFreq) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETTICFREQ, nFreq, 0L); } int GetThumbLength() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_GETTHUMBLENGTH, 0, 0L); } void SetThumbLength(int nLength) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETTHUMBLENGTH, nLength, 0L); } void SetSel(int nStart, int nEnd, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & TBS_ENABLESELRANGE) != 0); ::SendMessage(m_hWnd, TBM_SETSEL, bRedraw, MAKELPARAM(nStart, nEnd)); } ATL::CWindow GetBuddy(BOOL bLeft = TRUE) const { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_GETBUDDY, bLeft, 0L)); } ATL::CWindow SetBuddy(HWND hWndBuddy, BOOL bLeft = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_SETBUDDY, bLeft, (LPARAM)hWndBuddy)); } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, TBM_GETTOOLTIPS, 0, 0L)); } void SetToolTips(HWND hWndTT) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETTOOLTIPS, (WPARAM)hWndTT, 0L); } int SetTipSide(int nSide) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, TBM_SETTIPSIDE, nSide, 0L); } #endif // !_WIN32_WCE #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TBM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, TBM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) // Operations void ClearSel(BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_CLEARSEL, bRedraw, 0L); } void VerifyPos() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_SETPOS, FALSE, 0L); } void ClearTics(BOOL bRedraw = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, TBM_CLEARTICS, bRedraw, 0L); } }; typedef CTrackBarCtrlT CTrackBarCtrl; /////////////////////////////////////////////////////////////////////////////// // CUpDownCtrl template class CUpDownCtrlT : public TBase { public: // Constructors CUpDownCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CUpDownCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return UPDOWN_CLASS; } UINT GetAccel(int nAccel, UDACCEL* pAccel) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETACCEL, nAccel, (LPARAM)pAccel)); } BOOL SetAccel(int nAccel, UDACCEL* pAccel) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)LOWORD(::SendMessage(m_hWnd, UDM_SETACCEL, nAccel, (LPARAM)pAccel)); } UINT GetBase() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETBASE, 0, 0L)); } int SetBase(int nBase) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, UDM_SETBASE, nBase, 0L); } ATL::CWindow GetBuddy() const { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0L)); } ATL::CWindow SetBuddy(HWND hWndBuddy) { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_SETBUDDY, (WPARAM)hWndBuddy, 0L)); } int GetPos(LPBOOL lpbError = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETPOS, 0, 0L); // Note: Seems that Windows always sets error to TRUE if // UDS_SETBUDDYINT style is not used if(lpbError != NULL) *lpbError = (HIWORD(dwRet) != 0) ? TRUE : FALSE; return (int)(short)LOWORD(dwRet); } int SetPos(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); return (int)(short)LOWORD(::SendMessage(m_hWnd, UDM_SETPOS, 0, MAKELPARAM(nPos, 0))); } DWORD GetRange() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); } void GetRange(int& nLower, int& nUpper) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L); nLower = (int)(short)HIWORD(dwRet); nUpper = (int)(short)LOWORD(dwRet); } void SetRange(int nLower, int nUpper) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower)); } #if (_WIN32_IE >= 0x0400) void SetRange32(int nLower, int nUpper) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, UDM_SETRANGE32, nLower, nUpper); } void GetRange32(int& nLower, int& nUpper) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, UDM_GETRANGE32, (WPARAM)&nLower, (LPARAM)&nUpper); } #ifndef _WIN32_WCE BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, UDM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, UDM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) int GetPos32(LPBOOL lpbError = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); // Note: Seems that Windows always sets error to TRUE if // UDS_SETBUDDYINT style is not used return (int)::SendMessage(m_hWnd, UDM_GETPOS32, 0, (LPARAM)lpbError); } int SetPos32(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, UDM_SETPOS32, 0, (LPARAM)nPos); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) }; typedef CUpDownCtrlT CUpDownCtrl; /////////////////////////////////////////////////////////////////////////////// // CProgressBarCtrl template class CProgressBarCtrlT : public TBase { public: // Constructors CProgressBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CProgressBarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return PROGRESS_CLASS; } DWORD SetRange(int nLower, int nUpper) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper)); } int SetPos(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L)); } int OffsetPos(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_DELTAPOS, nPos, 0L)); } int SetStep(int nStep) { ATLASSERT(::IsWindow(m_hWnd)); return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETSTEP, nStep, 0L)); } UINT GetPos() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, PBM_GETPOS, 0, 0L); } void GetRange(PPBRANGE pPBRange) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pPBRange != NULL); ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)pPBRange); } void GetRange(int& nLower, int& nUpper) const { ATLASSERT(::IsWindow(m_hWnd)); PBRANGE range = { 0 }; ::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)&range); nLower = range.iLow; nUpper = range.iHigh; } int GetRangeLimit(BOOL bLowLimit) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PBM_GETRANGE, bLowLimit, (LPARAM)NULL); } DWORD SetRange32(int nMin, int nMax) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE32, nMin, nMax); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) COLORREF SetBarColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PBM_SETBARCOLOR, 0, (LPARAM)clr); } COLORREF SetBkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PBM_SETBKCOLOR, 0, (LPARAM)clr); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) BOOL SetMarquee(BOOL bMarquee, UINT uUpdateTime = 0U) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PBM_SETMARQUEE, (WPARAM)bMarquee, (LPARAM)uUpdateTime); } #endif // (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE) #if (_WIN32_WINNT >= 0x0600) int GetStep() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PBM_GETSTEP, 0, 0L); } COLORREF GetBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PBM_GETBKCOLOR, 0, 0L); } COLORREF GetBarColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PBM_GETBARCOLOR, 0, 0L); } int GetState() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PBM_GETSTATE, 0, 0L); } int SetState(int nState) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PBM_SETSTATE, nState, 0L); } #endif // (_WIN32_WINNT >= 0x0600) // Operations int StepIt() { ATLASSERT(::IsWindow(m_hWnd)); return (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_STEPIT, 0, 0L)); } }; typedef CProgressBarCtrlT CProgressBarCtrl; /////////////////////////////////////////////////////////////////////////////// // CHotKeyCtrl #ifndef _WIN32_WCE template class CHotKeyCtrlT : public TBase { public: // Constructors CHotKeyCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CHotKeyCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return HOTKEY_CLASS; } DWORD GetHotKey() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); } void GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dw = (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L); wVirtualKeyCode = LOBYTE(LOWORD(dw)); wModifiers = HIBYTE(LOWORD(dw)); } void SetHotKey(WORD wVirtualKeyCode, WORD wModifiers) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, HKM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0L); } void SetRules(WORD wInvalidComb, WORD wModifiers) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, HKM_SETRULES, wInvalidComb, MAKELPARAM(wModifiers, 0)); } }; typedef CHotKeyCtrlT CHotKeyCtrl; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CAnimateCtrl #ifndef _WIN32_WCE template class CAnimateCtrlT : public TBase { public: // Constructors CAnimateCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CAnimateCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return ANIMATE_CLASS; } // Operations BOOL Open(ATL::_U_STRINGorID FileName) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, (LPARAM)FileName.m_lpstr); } BOOL Play(UINT nFrom, UINT nTo, UINT nRep) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, nRep, MAKELPARAM(nFrom, nTo)); } BOOL Stop() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_STOP, 0, 0L); } BOOL Close() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, 0L); } BOOL Seek(UINT nTo) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_PLAY, 0, MAKELPARAM(nTo, nTo)); } // Vista only BOOL IsPlaying() const { #ifndef ACM_ISPLAYING const UINT ACM_ISPLAYING = (WM_USER+104); #endif ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, ACM_ISPLAYING, 0, 0L); } }; typedef CAnimateCtrlT CAnimateCtrl; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CRichEditCtrl #ifndef _WIN32_WCE #if defined(_UNICODE) && (_RICHEDIT_VER == 0x0100) #undef RICHEDIT_CLASS #define RICHEDIT_CLASS L"RICHEDIT" #endif #if !defined(_UNICODE) && (_RICHEDIT_VER >= 0x0500) #undef MSFTEDIT_CLASS #define MSFTEDIT_CLASS "RICHEDIT50W" #endif template class CRichEditCtrlT : public TBase { public: // Constructors CRichEditCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CRichEditCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { #if (_RICHEDIT_VER >= 0x0500) return MSFTEDIT_CLASS; #else return RICHEDIT_CLASS; #endif } static LPCTSTR GetLibraryName() { #if (_RICHEDIT_VER >= 0x0500) return _T("MSFTEDIT.DLL"); #elif (_RICHEDIT_VER >= 0x0200) return _T("RICHED20.DLL"); #else return _T("RICHED32.DLL"); #endif } int GetLineCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L); } BOOL GetModify() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); } void SetModify(BOOL bModified = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L); } void GetRect(LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect); } DWORD GetOptions() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETOPTIONS, 0, 0L); } DWORD SetOptions(WORD wOperation, DWORD dwOptions) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_SETOPTIONS, wOperation, dwOptions); } // NOTE: first word in lpszBuffer must contain the size of the buffer! int GetLine(int nIndex, LPTSTR lpszBuffer) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); } int GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const { ATLASSERT(::IsWindow(m_hWnd)); *(LPWORD)lpszBuffer = (WORD)nMaxLength; return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer); } BOOL CanUndo() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); } BOOL CanPaste(UINT nFormat = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, nFormat, 0L); } void GetSel(LONG& nStartChar, LONG& nEndChar) const { ATLASSERT(::IsWindow(m_hWnd)); CHARRANGE cr = { 0, 0 }; ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); nStartChar = cr.cpMin; nEndChar = cr.cpMax; } void GetSel(CHARRANGE &cr) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); } int SetSel(LONG nStartChar, LONG nEndChar) { ATLASSERT(::IsWindow(m_hWnd)); CHARRANGE cr = { nStartChar, nEndChar }; return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); } int SetSel(CHARRANGE &cr) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr); } int SetSelAll() { return SetSel(0, -1); } int SetSelNone() { return SetSel(-1, 0); } DWORD GetDefaultCharFormat(CHARFORMAT& cf) const { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); } DWORD GetSelectionCharFormat(CHARFORMAT& cf) const { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); } DWORD GetEventMask() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETEVENTMASK, 0, 0L); } LONG GetLimitText() const { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L); } DWORD GetParaFormat(PARAFORMAT& pf) const { ATLASSERT(::IsWindow(m_hWnd)); pf.cbSize = sizeof(PARAFORMAT); return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); } #if (_RICHEDIT_VER >= 0x0200) LONG GetSelText(LPTSTR lpstrBuff) const { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); } #else // !(_RICHEDIT_VER >= 0x0200) // RichEdit 1.0 EM_GETSELTEXT is ANSI only LONG GetSelText(LPSTR lpstrBuff) const { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff); } #endif // !(_RICHEDIT_VER >= 0x0200) #ifndef _ATL_NO_COM BOOL GetSelTextBSTR(BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); CHARRANGE cr = { 0, 0 }; ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); #if (_RICHEDIT_VER >= 0x0200) CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); if(lpstrText == NULL) return FALSE; if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) return FALSE; bstrText = ::SysAllocString(T2W(lpstrText)); #else // !(_RICHEDIT_VER >= 0x0200) CTempBuffer buff; LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); if(lpstrText == NULL) return FALSE; if(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0) return FALSE; bstrText = ::SysAllocString(A2W(lpstrText)); #endif // !(_RICHEDIT_VER >= 0x0200) return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) LONG GetSelText(_CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); CHARRANGE cr = { 0, 0 }; ::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr); #if (_RICHEDIT_VER >= 0x0200) LONG lLen = 0; LPTSTR lpstrText = strText.GetBufferSetLength(cr.cpMax - cr.cpMin); if(lpstrText != NULL) { lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); strText.ReleaseBuffer(); } #else // !(_RICHEDIT_VER >= 0x0200) CTempBuffer buff; LPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1); if(lpstrText == NULL) return 0; LONG lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText); if(lLen == 0) return 0; USES_CONVERSION; strText = A2T(lpstrText); #endif // !(_RICHEDIT_VER >= 0x0200) return lLen; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) WORD GetSelectionType() const { ATLASSERT(::IsWindow(m_hWnd)); return (WORD)::SendMessage(m_hWnd, EM_SELECTIONTYPE, 0, 0L); } COLORREF SetBackgroundColor(COLORREF cr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 0, cr); } COLORREF SetBackgroundColor() // sets to system background { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 1, 0); } BOOL SetCharFormat(CHARFORMAT& cf, WORD wFlags) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); } BOOL SetDefaultCharFormat(CHARFORMAT& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); } BOOL SetSelectionCharFormat(CHARFORMAT& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); } BOOL SetWordCharFormat(CHARFORMAT& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); } DWORD SetEventMask(DWORD dwEventMask) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_SETEVENTMASK, 0, dwEventMask); } BOOL SetParaFormat(PARAFORMAT& pf) { ATLASSERT(::IsWindow(m_hWnd)); pf.cbSize = sizeof(PARAFORMAT); return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); } BOOL SetTargetDevice(HDC hDC, int cxLineWidth) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTARGETDEVICE, (WPARAM)hDC, cxLineWidth); } int GetTextLength() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); } BOOL SetReadOnly(BOOL bReadOnly = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L); } int GetFirstVisibleLine() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); } int GetTextRange(TEXTRANGE* pTextRange) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)pTextRange); } #if (_RICHEDIT_VER < 0x0200) EDITWORDBREAKPROCEX GetWordBreakProcEx() const { ATLASSERT(::IsWindow(m_hWnd)); return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_GETWORDBREAKPROCEX, 0, 0L); } EDITWORDBREAKPROCEX SetWordBreakProcEx(EDITWORDBREAKPROCEX pfnEditWordBreakProcEx) { ATLASSERT(::IsWindow(m_hWnd)); return (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_SETWORDBREAKPROCEX, 0, (LPARAM)pfnEditWordBreakProcEx); } #endif // (_RICHEDIT_VER < 0x0200) #if (_RICHEDIT_VER >= 0x0200) int GetTextRange(LONG nStartChar, LONG nEndChar, LPTSTR lpstrText) const { ATLASSERT(::IsWindow(m_hWnd)); TEXTRANGE tr = { 0 }; tr.chrg.cpMin = nStartChar; tr.chrg.cpMax = nEndChar; tr.lpstrText = lpstrText; return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); } #else // !(_RICHEDIT_VER >= 0x0200) int GetTextRange(LONG nStartChar, LONG nEndChar, LPSTR lpstrText) const { ATLASSERT(::IsWindow(m_hWnd)); TEXTRANGE tr = { 0 }; tr.chrg.cpMin = nStartChar; tr.chrg.cpMax = nEndChar; tr.lpstrText = lpstrText; return (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr); } #endif // !(_RICHEDIT_VER >= 0x0200) #if (_RICHEDIT_VER >= 0x0200) DWORD GetDefaultCharFormat(CHARFORMAT2& cf) const { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf); } BOOL SetCharFormat(CHARFORMAT2& cf, WORD wFlags) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf); } BOOL SetDefaultCharFormat(CHARFORMAT2& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf); } DWORD GetSelectionCharFormat(CHARFORMAT2& cf) const { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf); } BOOL SetSelectionCharFormat(CHARFORMAT2& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); } BOOL SetWordCharFormat(CHARFORMAT2& cf) { ATLASSERT(::IsWindow(m_hWnd)); cf.cbSize = sizeof(CHARFORMAT2); return (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf); } DWORD GetParaFormat(PARAFORMAT2& pf) const { ATLASSERT(::IsWindow(m_hWnd)); pf.cbSize = sizeof(PARAFORMAT2); return (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf); } BOOL SetParaFormat(PARAFORMAT2& pf) { ATLASSERT(::IsWindow(m_hWnd)); pf.cbSize = sizeof(PARAFORMAT2); return (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf); } TEXTMODE GetTextMode() const { ATLASSERT(::IsWindow(m_hWnd)); return (TEXTMODE)::SendMessage(m_hWnd, EM_GETTEXTMODE, 0, 0L); } BOOL SetTextMode(TEXTMODE enumTextMode) { ATLASSERT(::IsWindow(m_hWnd)); return !(BOOL)::SendMessage(m_hWnd, EM_SETTEXTMODE, enumTextMode, 0L); } UNDONAMEID GetUndoName() const { ATLASSERT(::IsWindow(m_hWnd)); return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETUNDONAME, 0, 0L); } UNDONAMEID GetRedoName() const { ATLASSERT(::IsWindow(m_hWnd)); return (UNDONAMEID)::SendMessage(m_hWnd, EM_GETREDONAME, 0, 0L); } BOOL CanRedo() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); } BOOL GetAutoURLDetect() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETAUTOURLDETECT, 0, 0L); } BOOL SetAutoURLDetect(BOOL bAutoDetect = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return !(BOOL)::SendMessage(m_hWnd, EM_AUTOURLDETECT, bAutoDetect, 0L); } // this method is deprecated, please use SetAutoURLDetect BOOL EnableAutoURLDetect(BOOL bEnable = TRUE) { return SetAutoURLDetect(bEnable); } UINT SetUndoLimit(UINT uUndoLimit) { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_SETUNDOLIMIT, uUndoLimit, 0L); } void SetPalette(HPALETTE hPalette) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETPALETTE, (WPARAM)hPalette, 0L); } int GetTextEx(GETTEXTEX* pGetTextEx, LPTSTR lpstrText) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)pGetTextEx, (LPARAM)lpstrText); } int GetTextEx(LPTSTR lpstrText, int nTextLen, DWORD dwFlags = GT_DEFAULT, UINT uCodePage = CP_ACP, LPCSTR lpDefaultChar = NULL, LPBOOL lpUsedDefChar = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); GETTEXTEX gte = { 0 }; gte.cb = nTextLen * sizeof(TCHAR); gte.codepage = uCodePage; gte.flags = dwFlags; gte.lpDefaultChar = lpDefaultChar; gte.lpUsedDefChar = lpUsedDefChar; return (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)>e, (LPARAM)lpstrText); } int GetTextLengthEx(GETTEXTLENGTHEX* pGetTextLengthEx) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)pGetTextLengthEx, 0L); } int GetTextLengthEx(DWORD dwFlags = GTL_DEFAULT, UINT uCodePage = CP_ACP) const { ATLASSERT(::IsWindow(m_hWnd)); GETTEXTLENGTHEX gtle = { 0 }; gtle.codepage = uCodePage; gtle.flags = dwFlags; return (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)>le, 0L); } EDITWORDBREAKPROC GetWordBreakProc() const { ATLASSERT(::IsWindow(m_hWnd)); return (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L); } void SetWordBreakProc(EDITWORDBREAKPROC ewbprc) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc); } #endif // (_RICHEDIT_VER >= 0x0200) #if (_RICHEDIT_VER >= 0x0300) int SetTextEx(SETTEXTEX* pSetTextEx, LPCTSTR lpstrText) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)pSetTextEx, (LPARAM)lpstrText); } int SetTextEx(LPCTSTR lpstrText, DWORD dwFlags = ST_DEFAULT, UINT uCodePage = CP_ACP) { ATLASSERT(::IsWindow(m_hWnd)); SETTEXTEX ste = { 0 }; ste.flags = dwFlags; ste.codepage = uCodePage; return (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpstrText); } int GetEditStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_GETEDITSTYLE, 0, 0L); } int SetEditStyle(int nStyle, int nMask = -1) { ATLASSERT(::IsWindow(m_hWnd)); if(nMask == -1) nMask = nStyle; // set everything specified return (int)::SendMessage(m_hWnd, EM_SETEDITSTYLE, nStyle, nMask); } BOOL SetFontSize(int nFontSizeDelta) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nFontSizeDelta >= -1637 && nFontSizeDelta <= 1638); return (BOOL)::SendMessage(m_hWnd, EM_SETFONTSIZE, nFontSizeDelta, 0L); } void GetScrollPos(LPPOINT lpPoint) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpPoint != NULL); ::SendMessage(m_hWnd, EM_GETSCROLLPOS, 0, (LPARAM)lpPoint); } void SetScrollPos(LPPOINT lpPoint) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpPoint != NULL); ::SendMessage(m_hWnd, EM_SETSCROLLPOS, 0, (LPARAM)lpPoint); } BOOL GetZoom(int& nNum, int& nDen) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETZOOM, (WPARAM)&nNum, (LPARAM)&nDen); } BOOL SetZoom(int nNum, int nDen) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nNum >= 0 && nNum <= 64); ATLASSERT(nDen >= 0 && nDen <= 64); return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, nNum, nDen); } BOOL SetZoomOff() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, 0, 0L); } void SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight)); } #endif // (_RICHEDIT_VER >= 0x0300) // Operations void LimitText(LONG nChars = 0) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_EXLIMITTEXT, 0, nChars); } int LineFromChar(LONG nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nIndex); } POINT PosFromChar(LONG nChar) const { ATLASSERT(::IsWindow(m_hWnd)); POINT point = { 0, 0 }; ::SendMessage(m_hWnd, EM_POSFROMCHAR, (WPARAM)&point, nChar); return point; } int CharFromPos(POINT pt) const { ATLASSERT(::IsWindow(m_hWnd)); POINTL ptl = { pt.x, pt.y }; return (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&ptl); } void EmptyUndoBuffer() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L); } int LineIndex(int nLine = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L); } int LineLength(int nLine = -1) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L); } BOOL LineScroll(int nLines) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_LINESCROLL, 0, nLines); } void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText); } void SetRect(LPCRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect); } BOOL DisplayBand(LPRECT pDisplayRect) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_DISPLAYBAND, 0, (LPARAM)pDisplayRect); } LONG FindText(DWORD dwFlags, FINDTEXT& ft) const { ATLASSERT(::IsWindow(m_hWnd)); #if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTW, dwFlags, (LPARAM)&ft); #else return (LONG)::SendMessage(m_hWnd, EM_FINDTEXT, dwFlags, (LPARAM)&ft); #endif } LONG FindText(DWORD dwFlags, FINDTEXTEX& ft) const { ATLASSERT(::IsWindow(m_hWnd)); #if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE) return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEXW, dwFlags, (LPARAM)&ft); #else return (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&ft); #endif } LONG FormatRange(FORMATRANGE& fr, BOOL bDisplay = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)&fr); } LONG FormatRange(FORMATRANGE* pFormatRange, BOOL bDisplay = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)pFormatRange); } void HideSelection(BOOL bHide = TRUE, BOOL bChangeStyle = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_HIDESELECTION, bHide, bChangeStyle); } void PasteSpecial(UINT uClipFormat, DWORD dwAspect = 0, HMETAFILE hMF = 0) { ATLASSERT(::IsWindow(m_hWnd)); REPASTESPECIAL reps = { dwAspect, (DWORD_PTR)hMF }; ::SendMessage(m_hWnd, EM_PASTESPECIAL, uClipFormat, (LPARAM)&reps); } void RequestResize() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_REQUESTRESIZE, 0, 0L); } LONG StreamIn(UINT uFormat, EDITSTREAM& es) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, uFormat, (LPARAM)&es); } LONG StreamOut(UINT uFormat, EDITSTREAM& es) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, uFormat, (LPARAM)&es); } DWORD FindWordBreak(int nCode, LONG nStartChar) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_FINDWORDBREAK, nCode, nStartChar); } // Additional operations void ScrollCaret() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L); } int InsertText(long nInsertAfterChar, LPCTSTR lpstrText, BOOL bCanUndo = FALSE) { int nRet = SetSel(nInsertAfterChar, nInsertAfterChar); ReplaceSel(lpstrText, bCanUndo); return nRet; } int AppendText(LPCTSTR lpstrText, BOOL bCanUndo = FALSE) { return InsertText(GetWindowTextLength(), lpstrText, bCanUndo); } // Clipboard operations BOOL Undo() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L); } void Clear() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); } void Copy() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_COPY, 0, 0L); } void Cut() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CUT, 0, 0L); } void Paste() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); } // OLE support IRichEditOle* GetOleInterface() const { ATLASSERT(::IsWindow(m_hWnd)); IRichEditOle *pRichEditOle = NULL; ::SendMessage(m_hWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle); return pRichEditOle; } BOOL SetOleCallback(IRichEditOleCallback* pCallback) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETOLECALLBACK, 0, (LPARAM)pCallback); } #if (_RICHEDIT_VER >= 0x0200) BOOL Redo() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_REDO, 0, 0L); } void StopGroupTyping() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_STOPGROUPTYPING, 0, 0L); } void ShowScrollBar(int nBarType, BOOL bVisible = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SHOWSCROLLBAR, nBarType, bVisible); } #endif // (_RICHEDIT_VER >= 0x0200) #if (_RICHEDIT_VER >= 0x0300) BOOL SetTabStops(int nTabStops, LPINT rgTabStops) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops); } BOOL SetTabStops() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L); } BOOL SetTabStops(const int& cxEachStop) // takes an 'int' { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop); } #endif // (_RICHEDIT_VER >= 0x0300) #if (_RICHEDIT_VER >= 0x0800) AutoCorrectProc GetAutoCorrectProc() const { ATLASSERT(::IsWindow(m_hWnd)); return (AutoCorrectProc)::SendMessage(m_hWnd, EM_GETAUTOCORRECTPROC, 0, 0L); } BOOL SetAutoCorrectProc(AutoCorrectProc pfn) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETAUTOCORRECTPROC, (WPARAM)pfn, 0L); } BOOL CallAutoCorrectProc(WCHAR ch) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CALLAUTOCORRECTPROC, (WPARAM)ch, 0L); } DWORD GetEditStyleEx() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETEDITSTYLEEX, 0, 0L); } DWORD SetEditStyleEx(DWORD dwStyleEx, DWORD dwMask) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_SETEDITSTYLEEX, dwStyleEx, dwMask); } DWORD GetStoryType(int nStoryIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_GETSTORYTYPE, nStoryIndex, 0L); } DWORD SetStoryType(int nStoryIndex, DWORD dwStoryType) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, EM_SETSTORYTYPE, nStoryIndex, dwStoryType); } DWORD GetEllipsisMode() const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwMode = 0; BOOL bRet = (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISMODE, 0, (LPARAM)&dwMode); bRet; // avoid level 4 warning ATLASSERT(bRet != FALSE); return dwMode; } BOOL SetEllipsisMode(DWORD dwEllipsisMode) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETELLIPSISMODE, 0, dwEllipsisMode); } BOOL GetEllipsisState() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISSTATE, 0, 0L); } BOOL GetTouchOptions(int nTouchOptions) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETTOUCHOPTIONS, nTouchOptions, 0L); } void SetTouchOptions(int nTouchOptions, BOOL bEnable) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETTOUCHOPTIONS, nTouchOptions, bEnable); } HRESULT InsertTable(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, EM_INSERTTABLE, (WPARAM)pRowParams, (LPARAM)pCellParams); } HRESULT GetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) const { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, EM_GETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams); } HRESULT SetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, EM_SETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams); } HRESULT InsertImage(RICHEDIT_IMAGE_PARAMETERS* pParams) { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, EM_INSERTIMAGE, 0, (LPARAM)pParams); } BOOL SetUiaName(LPCTSTR lpstrName) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_SETUIANAME, 0, (LPARAM)lpstrName); } #endif // (_RICHEDIT_VER >= 0x0800) }; typedef CRichEditCtrlT CRichEditCtrl; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CRichEditCommands - message handlers for standard EDIT commands #ifndef _WIN32_WCE // Chain to CRichEditCommands message map. Your class must also derive from CRichEditCtrl. // Example: // class CMyRichEdit : public CWindowImpl, // public CRichEditCommands // { // public: // BEGIN_MSG_MAP(CMyRichEdit) // // your handlers... // CHAIN_MSG_MAP_ALT(CRichEditCommands, 1) // END_MSG_MAP() // // other stuff... // }; template class CRichEditCommands : public CEditCommands< T > { public: BEGIN_MSG_MAP(CRichEditCommands< T >) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_EDIT_CLEAR, CEditCommands< T >::OnEditClear) COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, CEditCommands< T >::OnEditClearAll) COMMAND_ID_HANDLER(ID_EDIT_COPY, CEditCommands< T >::OnEditCopy) COMMAND_ID_HANDLER(ID_EDIT_CUT, CEditCommands< T >::OnEditCut) COMMAND_ID_HANDLER(ID_EDIT_PASTE, CEditCommands< T >::OnEditPaste) COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, CEditCommands< T >::OnEditSelectAll) COMMAND_ID_HANDLER(ID_EDIT_UNDO, CEditCommands< T >::OnEditUndo) #if (_RICHEDIT_VER >= 0x0200) COMMAND_ID_HANDLER(ID_EDIT_REDO, OnEditRedo) #endif // (_RICHEDIT_VER >= 0x0200) END_MSG_MAP() #if (_RICHEDIT_VER >= 0x0200) LRESULT OnEditRedo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Redo(); return 0; } #endif // (_RICHEDIT_VER >= 0x0200) // State (update UI) helpers BOOL CanCut() const { return HasSelection(); } BOOL CanCopy() const { return HasSelection(); } BOOL CanClear() const { return HasSelection(); } // Implementation BOOL HasSelection() const { const T* pT = static_cast(this); return (pT->GetSelectionType() != SEL_EMPTY); } }; #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CDragListBox #ifndef _WIN32_WCE template class CDragListBoxT : public CListBoxT< TBase > { public: // Constructors CDragListBoxT(HWND hWnd = NULL) : CListBoxT< TBase >(hWnd) { } CDragListBoxT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); if(hWnd != NULL) MakeDragList(); return hWnd; } // Operations BOOL MakeDragList() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0); return ::MakeDragList(m_hWnd); } int LBItemFromPt(POINT pt, BOOL bAutoScroll = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ::LBItemFromPt(m_hWnd, pt, bAutoScroll); } void DrawInsert(int nItem) { ATLASSERT(::IsWindow(m_hWnd)); ::DrawInsert(GetParent(), m_hWnd, nItem); } static UINT GetDragListMessage() { static UINT uDragListMessage = 0; if(uDragListMessage == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDragListBox::GetDragListMessage.\n")); ATLASSERT(FALSE); return 0; } if(uDragListMessage == 0) uDragListMessage = ::RegisterWindowMessage(DRAGLISTMSGSTRING); lock.Unlock(); } ATLASSERT(uDragListMessage != 0); return uDragListMessage; } }; typedef CDragListBoxT CDragListBox; template class CDragListNotifyImpl { public: BEGIN_MSG_MAP(CDragListNotifyImpl< T >) MESSAGE_HANDLER(CDragListBox::GetDragListMessage(), OnDragListNotify) END_MSG_MAP() LRESULT OnDragListNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { uMsg; // avoid level 4 warning ATLASSERT(uMsg == CDragListBox::GetDragListMessage()); T* pT = static_cast(this); LPDRAGLISTINFO lpDragListInfo = (LPDRAGLISTINFO)lParam; LRESULT lRet = 0; switch(lpDragListInfo->uNotification) { case DL_BEGINDRAG: lRet = (LPARAM)pT->OnBeginDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); break; case DL_CANCELDRAG: pT->OnCancelDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); break; case DL_DRAGGING: lRet = (LPARAM)pT->OnDragging((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); break; case DL_DROPPED: pT->OnDropped((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor); break; default: ATLTRACE2(atlTraceUI, 0, _T("Unknown DragListBox notification\n")); bHandled = FALSE; // don't handle it break; } return lRet; } // Overrideables BOOL OnBeginDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) { return TRUE; // allow dragging } void OnCancelDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) { // nothing to do } int OnDragging(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) { return 0; // don't change cursor } void OnDropped(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/) { // nothing to do } }; #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CReBarCtrl template class CReBarCtrlT : public TBase { public: // Constructors CReBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CReBarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return REBARCLASSNAME; } UINT GetBandCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, RB_GETBANDCOUNT, 0, 0L); } BOOL GetBandInfo(int nBand, LPREBARBANDINFO lprbbi) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_GETBANDINFO, nBand, (LPARAM)lprbbi); } BOOL SetBandInfo(int nBand, LPREBARBANDINFO lprbbi) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SETBANDINFO, nBand, (LPARAM)lprbbi); } BOOL GetBarInfo(LPREBARINFO lprbi) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)lprbi); } BOOL SetBarInfo(LPREBARINFO lprbi) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)lprbi); } CImageList GetImageList() const { ATLASSERT(::IsWindow(m_hWnd)); REBARINFO rbi = { 0 }; rbi.cbSize = sizeof(REBARINFO); rbi.fMask = RBIM_IMAGELIST; BOOL bRet = (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)&rbi); return CImageList((bRet != FALSE) ? rbi.himl : NULL); } BOOL SetImageList(HIMAGELIST hImageList) { ATLASSERT(::IsWindow(m_hWnd)); REBARINFO rbi = { 0 }; rbi.cbSize = sizeof(REBARINFO); rbi.fMask = RBIM_IMAGELIST; rbi.himl = hImageList; return (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)&rbi); } UINT GetRowCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, RB_GETROWCOUNT, 0, 0L); } UINT GetRowHeight(int nBand) const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, RB_GETROWHEIGHT, nBand, 0L); } #if (_WIN32_IE >= 0x0400) COLORREF GetTextColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, RB_GETTEXTCOLOR, 0, 0L); } COLORREF SetTextColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, RB_SETTEXTCOLOR, 0, (LPARAM)clr); } COLORREF GetBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, RB_GETBKCOLOR, 0, 0L); } COLORREF SetBkColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, RB_SETBKCOLOR, 0, (LPARAM)clr); } UINT GetBarHeight() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, RB_GETBARHEIGHT, 0, 0L); } BOOL GetRect(int nBand, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_GETRECT, nBand, (LPARAM)lpRect); } #ifndef _WIN32_WCE CToolTipCtrl GetToolTips() const { ATLASSERT(::IsWindow(m_hWnd)); return CToolTipCtrl((HWND)::SendMessage(m_hWnd, RB_GETTOOLTIPS, 0, 0L)); } void SetToolTips(HWND hwndToolTip) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_SETTOOLTIPS, (WPARAM)hwndToolTip, 0L); } #endif // !_WIN32_WCE void GetBandBorders(int nBand, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpRect != NULL); ::SendMessage(m_hWnd, RB_GETBANDBORDERS, nBand, (LPARAM)lpRect); } #ifndef _WIN32_WCE BOOL GetColorScheme(LPCOLORSCHEME lpColorScheme) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpColorScheme != NULL); return (BOOL)::SendMessage(m_hWnd, RB_GETCOLORSCHEME, 0, (LPARAM)lpColorScheme); } void SetColorScheme(LPCOLORSCHEME lpColorScheme) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpColorScheme != NULL); ::SendMessage(m_hWnd, RB_SETCOLORSCHEME, 0, (LPARAM)lpColorScheme); } HPALETTE GetPalette() const { ATLASSERT(::IsWindow(m_hWnd)); return (HPALETTE)::SendMessage(m_hWnd, RB_GETPALETTE, 0, 0L); } HPALETTE SetPalette(HPALETTE hPalette) { ATLASSERT(::IsWindow(m_hWnd)); return (HPALETTE)::SendMessage(m_hWnd, RB_SETPALETTE, 0, (LPARAM)hPalette); } BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SETUNICODEFORMAT, bUnicode, 0L); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_WINNT >= 0x0501) // requires uxtheme.h to be included to use MARGINS struct #ifndef _UXTHEME_H_ typedef struct _MARGINS* PMARGINS; #endif // !_UXTHEME_H_ void GetBandMargins(PMARGINS pMargins) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_GETBANDMARGINS, 0, (LPARAM)pMargins); } void SetWindowTheme(LPCWSTR lpstrTheme) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); } #endif // (_WIN32_WINNT >= 0x0501) #if (_WIN32_IE >= 0x0600) DWORD GetExtendedStyle() const { #ifndef RB_GETEXTENDEDSTYLE const UINT RB_GETEXTENDEDSTYLE = WM_USER + 42; #endif ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, RB_GETEXTENDEDSTYLE, 0, 0L); } DWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask) { #ifndef RB_SETEXTENDEDSTYLE const UINT RB_SETEXTENDEDSTYLE = WM_USER + 41; #endif ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, RB_SETEXTENDEDSTYLE, dwMask, dwStyle); } #endif // (_WIN32_IE >= 0x0600) // Operations BOOL InsertBand(int nBand, LPREBARBANDINFO lprbbi) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_INSERTBAND, nBand, (LPARAM)lprbbi); } BOOL AddBand(LPREBARBANDINFO lprbbi) { return InsertBand(-1, lprbbi); } BOOL DeleteBand(int nBand) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_DELETEBAND, nBand, 0L); } ATL::CWindow SetNotifyWnd(HWND hWnd) { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow((HWND)::SendMessage(m_hWnd, RB_SETPARENT, (WPARAM)hWnd, 0L)); } #if (_WIN32_IE >= 0x0400) void BeginDrag(int nBand, DWORD dwPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, dwPos); } void BeginDrag(int nBand, int xPos, int yPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, MAKELPARAM(xPos, yPos)); } void EndDrag() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_ENDDRAG, 0, 0L); } void DragMove(DWORD dwPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, dwPos); } void DragMove(int xPos, int yPos) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_DRAGMOVE, 0, MAKELPARAM(xPos, yPos)); } #ifndef _WIN32_WCE void GetDropTarget(IDropTarget** ppDropTarget) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_GETDROPTARGET, 0, (LPARAM)ppDropTarget); } #endif // !_WIN32_WCE void MaximizeBand(int nBand, BOOL bIdeal = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_MAXIMIZEBAND, nBand, bIdeal); } void MinimizeBand(int nBand) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_MINIMIZEBAND, nBand, 0L); } BOOL SizeToRect(LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SIZETORECT, 0, (LPARAM)lpRect); } int IdToIndex(UINT uBandID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, RB_IDTOINDEX, uBandID, 0L); } int HitTest(LPRBHITTESTINFO lprbht) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, RB_HITTEST, 0, (LPARAM)lprbht); } BOOL ShowBand(int nBand, BOOL bShow) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SHOWBAND, nBand, bShow); } #ifndef _WIN32_WCE BOOL MoveBand(int nBand, int nNewPos) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nNewPos >= 0 && nNewPos <= ((int)GetBandCount() - 1)); return (BOOL)::SendMessage(m_hWnd, RB_MOVEBAND, nBand, nNewPos); } #endif // !_WIN32_WCE #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) void PushChevron(int nBand, LPARAM lAppValue) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, RB_PUSHCHEVRON, nBand, lAppValue); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) // Extra operations #if (_WIN32_IE >= 0x0400) void LockBands(bool bLock) { int nBandCount = GetBandCount(); for(int i =0; i < nBandCount; i++) { REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; rbbi.fMask = RBBIM_STYLE; BOOL bRet = GetBandInfo(i, &rbbi); ATLASSERT(bRet); if((rbbi.fStyle & RBBS_GRIPPERALWAYS) == 0) { rbbi.fStyle |= RBBS_GRIPPERALWAYS; bRet = SetBandInfo(i, &rbbi); ATLASSERT(bRet); rbbi.fStyle &= ~RBBS_GRIPPERALWAYS; } if(bLock) rbbi.fStyle |= RBBS_NOGRIPPER; else rbbi.fStyle &= ~RBBS_NOGRIPPER; bRet = SetBandInfo(i, &rbbi); ATLASSERT(bRet); } } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_WINNT >= 0x0600) BOOL SetBandWidth(int nBand, int cxWidth) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, RB_SETBANDWIDTH, nBand, cxWidth); } #endif // (_WIN32_WINNT >= 0x0600) }; typedef CReBarCtrlT CReBarCtrl; /////////////////////////////////////////////////////////////////////////////// // CComboBoxEx #ifndef _WIN32_WCE template class CComboBoxExT : public CComboBoxT< TBase > { public: // Constructors CComboBoxExT(HWND hWnd = NULL) : CComboBoxT< TBase >(hWnd) { } CComboBoxExT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_COMBOBOXEX; } CImageList GetImageList() const { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_GETIMAGELIST, 0, 0L)); } CImageList SetImageList(HIMAGELIST hImageList) { ATLASSERT(::IsWindow(m_hWnd)); return CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_SETIMAGELIST, 0, (LPARAM)hImageList)); } #if (_WIN32_IE >= 0x0400) DWORD GetExtendedStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, 0, 0L); } DWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, dwExMask, dwExStyle); } BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CBEM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CBEM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_WINNT >= 0x0501) void SetWindowTheme(LPCWSTR lpstrTheme) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, CBEM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme); } #endif // (_WIN32_WINNT >= 0x0501) // Operations int InsertItem(const COMBOBOXEXITEM* lpcCBItem) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)lpcCBItem); } int InsertItem(UINT nMask, int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = nMask; cbex.iItem = nIndex; cbex.pszText = (LPTSTR) lpszItem; cbex.iImage = nImage; cbex.iSelectedImage = nSelImage; cbex.iIndent = iIndent; cbex.iOverlay = iOverlay; cbex.lParam = lParam; return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); } int InsertItem(int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) { ATLASSERT(::IsWindow(m_hWnd)); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT | CBEIF_LPARAM; cbex.iItem = nIndex; cbex.pszText = (LPTSTR) lpszItem; cbex.iImage = nImage; cbex.iSelectedImage = nSelImage; cbex.iIndent = iIndent; cbex.lParam = lParam; return (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex); } int AddItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam) { return InsertItem(nMask, -1, lpszItem, nImage, nSelImage, iIndent, iOverlay, lParam); } int AddItem(LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0) { return InsertItem(-1, lpszItem, nImage, nSelImage, iIndent, lParam); } int DeleteItem(int nIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CBEM_DELETEITEM, nIndex, 0L); } BOOL GetItem(PCOMBOBOXEXITEM pCBItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)pCBItem); } BOOL SetItem(const COMBOBOXEXITEM* lpcCBItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)lpcCBItem); } int SetItem(int nIndex, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = nMask; cbex.iItem = nIndex; cbex.pszText = (LPTSTR) lpszItem; cbex.iImage = nImage; cbex.iSelectedImage = nSelImage; cbex.iIndent = iIndent; cbex.iOverlay = iOverlay; cbex.lParam = lParam; return (int)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)&cbex); } BOOL GetItemText(int nIndex, LPTSTR lpszItem, int nLen) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpszItem != NULL); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = CBEIF_TEXT; cbex.iItem = nIndex; cbex.pszText = lpszItem; cbex.cchTextMax = nLen; return (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); } #ifndef _ATL_NO_COM BOOL GetItemText(int nIndex, BSTR& bstrText) const { USES_CONVERSION; ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(bstrText == NULL); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = CBEIF_TEXT; cbex.iItem = nIndex; LPTSTR lpstrText = NULL; BOOL bRet = FALSE; for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrText = new TCHAR[nLen]); if(lpstrText == NULL) break; lpstrText[0] = NULL; cbex.pszText = lpstrText; cbex.cchTextMax = nLen; bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) break; delete [] lpstrText; lpstrText = NULL; } if(lpstrText != NULL) { if(bRet) bstrText = ::SysAllocString(T2OLE(lpstrText)); delete [] lpstrText; } return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetItemText(int nIndex, _CSTRING_NS::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); COMBOBOXEXITEM cbex = { 0 }; cbex.mask = CBEIF_TEXT; cbex.iItem = nIndex; strText.Empty(); BOOL bRet = FALSE; for(int nLen = 256; ; nLen *= 2) { cbex.pszText = strText.GetBufferSetLength(nLen); if(cbex.pszText == NULL) { bRet = FALSE; break; } cbex.cchTextMax = nLen; bRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex); if(!bRet || (lstrlen(cbex.pszText) < nLen - 1)) break; } strText.ReleaseBuffer(); return bRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL SetItemText(int nIndex, LPCTSTR lpszItem) { ATLASSERT(::IsWindow(m_hWnd)); return SetItem(nIndex, CBEIF_TEXT, lpszItem, 0, 0, 0, 0, 0); } CComboBox GetComboCtrl() const { ATLASSERT(::IsWindow(m_hWnd)); return CComboBox((HWND)::SendMessage(m_hWnd, CBEM_GETCOMBOCONTROL, 0, 0L)); } CEdit GetEditCtrl() const { ATLASSERT(::IsWindow(m_hWnd)); return CEdit((HWND)::SendMessage(m_hWnd, CBEM_GETEDITCONTROL, 0, 0L)); } BOOL HasEditChanged() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CBEM_HASEDITCHANGED, 0, 0L); } // Non-functional int AddString(LPCTSTR /*lpszItem*/) { ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem return 0; } int InsertString(int /*nIndex*/, LPCTSTR /*lpszString*/) { ATLASSERT(FALSE); // Not available in CComboBoxEx; use InsertItem return 0; } int Dir(UINT /*attr*/, LPCTSTR /*lpszWildCard*/) { ATLASSERT(FALSE); // Not available in CComboBoxEx return 0; } int FindString(int /*nStartAfter*/, LPCTSTR /*lpszString*/) const { ATLASSERT(FALSE); // Not available in CComboBoxEx; try FindStringExact return 0; } }; typedef CComboBoxExT CComboBoxEx; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CMonthCalendarCtrl template class CMonthCalendarCtrlT : public TBase { public: // Constructors CMonthCalendarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CMonthCalendarCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return MONTHCAL_CLASS; } COLORREF GetColor(int nColorType) const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, MCM_GETCOLOR, nColorType, 0L); } COLORREF SetColor(int nColorType, COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, MCM_SETCOLOR, nColorType, clr); } BOOL GetCurSel(LPSYSTEMTIME lpSysTime) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETCURSEL, 0, (LPARAM)lpSysTime); } BOOL SetCurSel(LPSYSTEMTIME lpSysTime) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETCURSEL, 0, (LPARAM)lpSysTime); } int GetFirstDayOfWeek(BOOL* pbLocaleVal = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_GETFIRSTDAYOFWEEK, 0, 0L); if(pbLocaleVal != NULL) *pbLocaleVal = (BOOL)HIWORD(dwRet); return (int)(short)LOWORD(dwRet); } int SetFirstDayOfWeek(int nDay, BOOL* pbLocaleVal = NULL) { ATLASSERT(::IsWindow(m_hWnd)); DWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_SETFIRSTDAYOFWEEK, 0, nDay); if(pbLocaleVal != NULL) *pbLocaleVal = (BOOL)HIWORD(dwRet); return (int)(short)LOWORD(dwRet); } int GetMaxSelCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_GETMAXSELCOUNT, 0, 0L); } BOOL SetMaxSelCount(int nMax) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETMAXSELCOUNT, nMax, 0L); } int GetMonthDelta() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_GETMONTHDELTA, 0, 0L); } int SetMonthDelta(int nDelta) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_SETMONTHDELTA, nDelta, 0L); } DWORD GetRange(LPSYSTEMTIME lprgSysTimeArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, MCM_GETRANGE, 0, (LPARAM)lprgSysTimeArray); } BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETRANGE, dwFlags, (LPARAM)lprgSysTimeArray); } BOOL GetSelRange(LPSYSTEMTIME lprgSysTimeArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETSELRANGE, 0, (LPARAM)lprgSysTimeArray); } BOOL SetSelRange(LPSYSTEMTIME lprgSysTimeArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETSELRANGE, 0, (LPARAM)lprgSysTimeArray); } BOOL GetToday(LPSYSTEMTIME lpSysTime) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETTODAY, 0, (LPARAM)lpSysTime); } void SetToday(LPSYSTEMTIME lpSysTime) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, MCM_SETTODAY, 0, (LPARAM)lpSysTime); } BOOL GetMinReqRect(LPRECT lpRectInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETMINREQRECT, 0, (LPARAM)lpRectInfo); } int GetMaxTodayWidth() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_GETMAXTODAYWIDTH, 0, 0L); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetUnicodeFormat() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETUNICODEFORMAT, 0, 0L); } BOOL SetUnicodeFormat(BOOL bUnicode = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETUNICODEFORMAT, bUnicode, 0L); } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) DWORD GetCurrentView() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, MCM_GETCURRENTVIEW, 0, 0L); } BOOL SetCurrentView(DWORD dwView) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETCURRENTVIEW, 0, dwView); } DWORD GetCalendarCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, MCM_GETCALENDARCOUNT, 0, 0L); } BOOL GetCalendarGridInfo(PMCGRIDINFO pGridInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_GETCALENDARGRIDINFO, 0, (LPARAM)pGridInfo); } CALID GetCALID() const { ATLASSERT(::IsWindow(m_hWnd)); return (CALID)::SendMessage(m_hWnd, MCM_GETCALID, 0, 0L); } void SetCALID(CALID calid) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, MCM_SETCALID, (LPARAM)calid, 0L); } int GetCalendarBorder() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_GETCALENDARBORDER, 0, 0L); } void SetCalendarBorder(int cxyBorder, BOOL bSet = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, MCM_SETCALENDARBORDER, (WPARAM)bSet, (LPARAM)cxyBorder); } #endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) // Operations int GetMonthRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, MCM_GETMONTHRANGE, dwFlags, (LPARAM)lprgSysTimeArray); } BOOL SetDayState(int nMonths, LPMONTHDAYSTATE lpDayStateArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, MCM_SETDAYSTATE, nMonths, (LPARAM)lpDayStateArray); } DWORD HitTest(PMCHITTESTINFO pMCHitTest) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, MCM_HITTEST, 0, (LPARAM)pMCHitTest); } #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) void SizeRectToMin(LPRECT lpRect) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, MCM_SIZERECTTOMIN, 0, (LPARAM)lpRect); } #endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) }; typedef CMonthCalendarCtrlT CMonthCalendarCtrl; /////////////////////////////////////////////////////////////////////////////// // CDateTimePickerCtrl template class CDateTimePickerCtrlT : public TBase { public: // Constructors CDateTimePickerCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CDateTimePickerCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Operations static LPCTSTR GetWndClassName() { return DATETIMEPICK_CLASS; } BOOL SetFormat(LPCTSTR lpszFormat) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DTM_SETFORMAT, 0, (LPARAM)lpszFormat); } COLORREF GetMonthCalColor(int nColorType) const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, DTM_GETMCCOLOR, nColorType, 0L); } COLORREF SetMonthCalColor(int nColorType, COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, DTM_SETMCCOLOR, nColorType, clr); } DWORD GetRange(LPSYSTEMTIME lpSysTimeArray) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, DTM_GETRANGE, 0, (LPARAM)lpSysTimeArray); } BOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lpSysTimeArray) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DTM_SETRANGE, dwFlags, (LPARAM)lpSysTimeArray); } DWORD GetSystemTime(LPSYSTEMTIME lpSysTime) const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)lpSysTime); } BOOL SetSystemTime(DWORD dwFlags, LPSYSTEMTIME lpSysTime) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DTM_SETSYSTEMTIME, dwFlags, (LPARAM)lpSysTime); } CMonthCalendarCtrl GetMonthCal() const { ATLASSERT(::IsWindow(m_hWnd)); return CMonthCalendarCtrl((HWND)::SendMessage(m_hWnd, DTM_GETMONTHCAL, 0, 0L)); } #if (_WIN32_IE >= 0x0400) CFontHandle GetMonthCalFont() const { ATLASSERT(::IsWindow(m_hWnd)); return CFontHandle((HFONT)::SendMessage(m_hWnd, DTM_GETMCFONT, 0, 0L)); } void SetMonthCalFont(HFONT hFont, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_SETMCFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0)); } #endif // (_WIN32_IE >= 0x0400) #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) DWORD GetMonthCalStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, DTM_GETMCSTYLE, 0, 0L); } DWORD SetMonthCalStyle(DWORD dwStyle) { ATLASSERT(::IsWindow(m_hWnd)); return (DWORD)::SendMessage(m_hWnd, DTM_SETMCSTYLE, 0, (LPARAM)dwStyle); } void GetDateTimePickerInfo(LPDATETIMEPICKERINFO lpPickerInfo) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_GETDATETIMEPICKERINFO, 0, (LPARAM)lpPickerInfo); } BOOL GetIdealSize(LPSIZE lpSize) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)lpSize); } void CloseMonthCal() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_CLOSEMONTHCAL, 0, 0L); } #endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) }; typedef CDateTimePickerCtrlT CDateTimePickerCtrl; /////////////////////////////////////////////////////////////////////////////// // CFlatScrollBarImpl - support for flat scroll bars #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) template class CFlatScrollBarImpl { public: // Initialization BOOL FlatSB_Initialize() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::InitializeFlatSB(pT->m_hWnd); } HRESULT FlatSB_Uninitialize() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::UninitializeFlatSB(pT->m_hWnd); } // Flat scroll bar properties BOOL FlatSB_GetScrollProp(UINT uIndex, LPINT lpnValue) const { const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_GetScrollProp(pT->m_hWnd, uIndex, lpnValue); } BOOL FlatSB_SetScrollProp(UINT uIndex, int nValue, BOOL bRedraw = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_SetScrollProp(pT->m_hWnd, uIndex, nValue, bRedraw); } // Attributes int FlatSB_GetScrollPos(int nBar) const { const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_GetScrollPos(pT->m_hWnd, nBar); } int FlatSB_SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_SetScrollPos(pT->m_hWnd, nBar, nPos, bRedraw); } BOOL FlatSB_GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const { const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_GetScrollRange(pT->m_hWnd, nBar, lpMinPos, lpMaxPos); } BOOL FlatSB_SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_SetScrollRange(pT->m_hWnd, nBar, nMinPos, nMaxPos, bRedraw); } BOOL FlatSB_GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) const { const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_GetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo); } int FlatSB_SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_SetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo, bRedraw); } // Operations BOOL FlatSB_ShowScrollBar(UINT nBar, BOOL bShow = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_ShowScrollBar(pT->m_hWnd, nBar, bShow); } BOOL FlatSB_EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::FlatSB_EnableScrollBar(pT->m_hWnd, uSBFlags, uArrowFlags); } }; template class CFlatScrollBarT : public TBase, public CFlatScrollBarImpl > { public: CFlatScrollBarT(HWND hWnd = NULL) : TBase(hWnd) { } CFlatScrollBarT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } }; typedef CFlatScrollBarT CFlatScrollBar; #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CIPAddressCtrl #if (_WIN32_IE >= 0x0400) template class CIPAddressCtrlT : public TBase { public: // Constructors CIPAddressCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CIPAddressCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Atteributes static LPCTSTR GetWndClassName() { return WC_IPADDRESS; } BOOL IsBlank() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, IPM_ISBLANK, 0, 0L); } int GetAddress(LPDWORD lpdwAddress) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM)lpdwAddress); } void SetAddress(DWORD dwAddress) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IPM_SETADDRESS, 0, dwAddress); } void ClearAddress() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IPM_CLEARADDRESS, 0, 0L); } void SetRange(int nField, WORD wRange) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IPM_SETRANGE, nField, wRange); } void SetRange(int nField, BYTE nMin, BYTE nMax) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IPM_SETRANGE, nField, MAKEIPRANGE(nMin, nMax)); } void SetFocus(int nField) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IPM_SETFOCUS, nField, 0L); } }; typedef CIPAddressCtrlT CIPAddressCtrl; #endif // (_WIN32_IE >= 0x0400) /////////////////////////////////////////////////////////////////////////////// // CPagerCtrl #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) template class CPagerCtrlT : public TBase { public: // Constructors CPagerCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CPagerCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { return WC_PAGESCROLLER; } int GetButtonSize() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_GETBUTTONSIZE, 0, 0L); } int SetButtonSize(int nButtonSize) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_SETBUTTONSIZE, 0, nButtonSize); } DWORD GetButtonState(int nButton) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nButton == PGB_TOPORLEFT || nButton == PGB_BOTTOMORRIGHT); return (DWORD)::SendMessage(m_hWnd, PGM_GETBUTTONSTATE, 0, nButton); } COLORREF GetBkColor() const { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PGM_GETBKCOLOR, 0, 0L); } COLORREF SetBkColor(COLORREF clrBk) { ATLASSERT(::IsWindow(m_hWnd)); return (COLORREF)::SendMessage(m_hWnd, PGM_SETBKCOLOR, 0, (LPARAM)clrBk); } int GetBorder() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_GETBORDER, 0, 0L); } int SetBorder(int nBorderSize) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_SETBORDER, 0, nBorderSize); } int GetPos() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_GETPOS, 0, 0L); } int SetPos(int nPos) { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PGM_SETPOS, 0, nPos); } // Operations void SetChild(HWND hWndChild) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PGM_SETCHILD, 0, (LPARAM)hWndChild); } void ForwardMouse(BOOL bForward = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PGM_FORWARDMOUSE, bForward, 0L); } void RecalcSize() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PGM_RECALCSIZE, 0, 0L); } void GetDropTarget(IDropTarget** ppDropTarget) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(ppDropTarget != NULL); ::SendMessage(m_hWnd, PGM_GETDROPTARGET, 0, (LPARAM)ppDropTarget); } }; typedef CPagerCtrlT CPagerCtrl; #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CLinkCtrl - Windows SYSLINK control #if (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) template class CLinkCtrlT : public TBase { public: // Constructors CLinkCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CLinkCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { return TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); } // Attributes static LPCTSTR GetWndClassName() { #ifdef _UNICODE return WC_LINK; #else // !_UNICODE return "SysLink"; #endif // !_UNICODE } int GetIdealHeight(int cxMaxWidth = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LM_GETIDEALHEIGHT, cxMaxWidth, 0L); } BOOL GetItem(PLITEM pLItem) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LM_GETITEM, 0, (LPARAM)pLItem); } BOOL SetItem(PLITEM pLItem) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LM_SETITEM, 0, (LPARAM)pLItem); } // Vista only int GetIdealSize(SIZE& size, int cxMaxWidth = 0) const { #ifndef LM_GETIDEALSIZE const UINT LM_GETIDEALSIZE = LM_GETIDEALHEIGHT; #endif ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, LM_GETIDEALSIZE, cxMaxWidth, (LPARAM)&size); } // Operations BOOL HitTest(PLHITTESTINFO pLHitTestInfo) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, LM_HITTEST, 0, (LPARAM)pLHitTestInfo); } }; typedef CLinkCtrlT CLinkCtrl; #endif // (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CCustomDraw - MI class for custom-draw support template class CCustomDraw { public: #if (_ATL_VER < 0x0700) BOOL m_bHandledCD; BOOL IsMsgHandled() const { return m_bHandledCD; } void SetMsgHandled(BOOL bHandled) { m_bHandledCD = bHandled; } #endif // !(_ATL_VER < 0x0700) // Message map and handlers BEGIN_MSG_MAP(CCustomDraw< T >) NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) ALT_MSG_MAP(1) REFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw) END_MSG_MAP() // message handler LRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) { T* pT = static_cast(this); pT->SetMsgHandled(TRUE); LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh; DWORD dwRet = 0; switch(lpNMCustomDraw->dwDrawStage) { case CDDS_PREPAINT: dwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw); break; case CDDS_POSTPAINT: dwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw); break; case CDDS_PREERASE: dwRet = pT->OnPreErase(idCtrl, lpNMCustomDraw); break; case CDDS_POSTERASE: dwRet = pT->OnPostErase(idCtrl, lpNMCustomDraw); break; case CDDS_ITEMPREPAINT: dwRet = pT->OnItemPrePaint(idCtrl, lpNMCustomDraw); break; case CDDS_ITEMPOSTPAINT: dwRet = pT->OnItemPostPaint(idCtrl, lpNMCustomDraw); break; case CDDS_ITEMPREERASE: dwRet = pT->OnItemPreErase(idCtrl, lpNMCustomDraw); break; case CDDS_ITEMPOSTERASE: dwRet = pT->OnItemPostErase(idCtrl, lpNMCustomDraw); break; #if (_WIN32_IE >= 0x0400) case (CDDS_ITEMPREPAINT | CDDS_SUBITEM): dwRet = pT->OnSubItemPrePaint(idCtrl, lpNMCustomDraw); break; #endif // (_WIN32_IE >= 0x0400) default: pT->SetMsgHandled(FALSE); break; } bHandled = pT->IsMsgHandled(); return dwRet; } // Overrideables DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } DWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } #if (_WIN32_IE >= 0x0400) DWORD OnSubItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_DODEFAULT; } #endif // (_WIN32_IE >= 0x0400) }; // --- Windows CE common controls --- #ifdef _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CCECommandBarCtrl template class CCECommandBarCtrlT : public TBase { public: // Constructors CCECommandBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CCECommandBarCtrlT< TBase >& operator=(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes BOOL IsVisible() const { return IsWindowVisible(); } int GetHeight() const { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_Height(m_hWnd); } HMENU GetMenu(WORD wButton) const { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_GetMenu(m_hWnd, wButton); } // Operations HWND Create(HWND hWndParent, int nCmdBarID) { m_hWnd = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), hWndParent, nCmdBarID); ATLASSERT(::IsWindow(m_hWnd)); return m_hWnd; } void Destroy() { DestroyWindow(); } BOOL Show(BOOL bShow = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_Show(m_hWnd, bShow); } BOOL DrawMenuBar(WORD wButton) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_DrawMenuBar(m_hWnd, wButton); } BOOL AddAdornments(DWORD dwFlags = 0) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_AddAdornments(m_hWnd, dwFlags, 0); } int AddBitmap(int nBitmapID, int nNumImages) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_AddBitmap(m_hWnd, ModuleHelper::GetResourceInstance(), nBitmapID, nNumImages, 16, 16); } BOOL AddButtons(UINT uNumButtons, LPTBBUTTON lpButtons) { ATLASSERT(::IsWindow(m_hWnd)); return CommandBar_AddButtons(m_hWnd, uNumButtons, lpButtons); } BOOL AddToolTips(UINT uNumToolTips, LPTSTR lpToolTips) { ATLASSERT(::IsWindow(m_hWnd)); return CommandBar_AddToolTips(m_hWnd, uNumToolTips, lpToolTips); } BOOL InsertButton(int nButton, LPTBBUTTON lpButton) { ATLASSERT(::IsWindow(m_hWnd)); return CommandBar_InsertButton(m_hWnd, nButton, lpButton); } HWND InsertComboBox(int nWidth, UINT dwStyle, WORD wComboBoxID, WORD wButton) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_InsertComboBox(m_hWnd, ModuleHelper::GetModuleInstance(), nWidth, dwStyle, wComboBoxID, wButton); } BOOL InsertMenubar(WORD wMenuID, WORD wButton) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_InsertMenubar(m_hWnd, ModuleHelper::GetResourceInstance(), wMenuID, wButton); } BOOL InsertMenubarEx(ATL::_U_STRINGorID menu, WORD wButton) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBar_InsertMenubarEx(m_hWnd, ModuleHelper::GetResourceInstance(), (LPTSTR)menu.m_lpstr, wButton); } BOOL IsCommandBarMessage(LPMSG lpMsg) { ATLASSERT(::IsWindow(m_hWnd)); return ::IsCommandBarMessage(m_hWnd, lpMsg); } }; #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC MenuBar typedef CCECommandBarCtrlT CMenuBarCtrl; #else typedef CCECommandBarCtrlT CCECommandBarCtrl; #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) /////////////////////////////////////////////////////////////////////////////// // CCECommandBandsCtrl template class CCECommandBandsCtrlT : public TBase { public: // Constructors CCECommandBandsCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CCECommandBandsCtrlT< TBase >& operator=(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes BOOL IsVisible() const { return IsWindowVisible(); } #if (_WIN32_IE >= 0x0400) UINT GetHeight() const { ATLASSERT(::IsWindow(m_hWnd)); return CommandBands_Height(m_hWnd); } #endif // (_WIN32_IE >= 0x0400) HWND GetCommandBar(UINT uBand) const { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBands_GetCommandBar(m_hWnd, uBand); } BOOL GetRestoreInformation(UINT uBand, LPCOMMANDBANDSRESTOREINFO pcbr) const { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBands_GetRestoreInformation(m_hWnd, uBand, pcbr); } // Operations HWND Create(HWND hWndParent, UINT wID, DWORD dwStyles, HIMAGELIST hImageList = NULL) { m_hWnd = ::CommandBands_Create(ModuleHelper::GetModuleInstance(), hWndParent, wID, dwStyles, hImageList); ATLASSERT(::IsWindow(m_hWnd)); return m_hWnd; } BOOL AddAdornments(DWORD dwFlags = 0, LPREBARBANDINFO prbbi = NULL) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBands_AddAdornments(m_hWnd, ModuleHelper::GetModuleInstance(), dwFlags, prbbi); } BOOL AddBands(UINT uBandCount, LPREBARBANDINFO prbbi) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBands_AddBands(m_hWnd, ModuleHelper::GetModuleInstance(), uBandCount, prbbi); } BOOL Show(BOOL bShow = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return ::CommandBands_Show(m_hWnd, bShow); } }; typedef CCECommandBandsCtrlT CCECommandBandsCtrl; #endif // _WIN32_WCE }; // namespace WTL #endif // __ATLCTRLS_H__ ================================================ FILE: WTL/atlctrlw.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLCTRLW_H__ #define __ATLCTRLW_H__ #pragma once #ifdef _WIN32_WCE #error atlctrlw.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atlctrlw.h requires atlapp.h to be included first #endif #ifndef __ATLCTRLS_H__ #error atlctrlw.h requires atlctrls.h to be included first #endif #if (_WIN32_IE < 0x0400) #error atlctrlw.h requires _WIN32_IE >= 0x0400 #endif // Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support #if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) #define _WTL_CMDBAR_VISTA_MENUS 1 #endif #if _WTL_CMDBAR_VISTA_MENUS #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)) #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) #endif #endif // Note: Define _WTL_CMDBAR_VISTA_STD_MENUBAR to use Vista standard menubar look with Vista menus /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CCommandBarCtrlImpl // CCommandBarCtrl // CMDICommandBarCtrlImpl // CMDICommandBarCtrl namespace WTL { /////////////////////////////////////////////////////////////////////////////// // Command Bars // Window Styles: #define CBRWS_TOP CCS_TOP #define CBRWS_BOTTOM CCS_BOTTOM #define CBRWS_NORESIZE CCS_NORESIZE #define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN #define CBRWS_NODIVIDER CCS_NODIVIDER // Extended styles #define CBR_EX_TRANSPARENT 0x00000001L #define CBR_EX_SHAREMENU 0x00000002L #define CBR_EX_ALTFOCUSMODE 0x00000004L #define CBR_EX_TRACKALWAYS 0x00000008L #define CBR_EX_NOVISTAMENUS 0x00000010L // standard command bar styles #define ATL_SIMPLE_CMDBAR_PANE_STYLE \ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN) // Messages - support chevrons for frame windows #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu typedef struct tagCBRPOPUPMENU { int cbSize; HMENU hMenu; // popup menu do display UINT uFlags; // TPM_* flags for ::TrackPopupMenuEx int x; int y; LPTPMPARAMS lptpm; // ptr to TPMPARAMS for ::TrackPopupMenuEx } CBRPOPUPMENU, *LPCBRPOPUPMENU; // helper class template class CSimpleStack : public ATL::CSimpleArray< T > { public: BOOL Push(T t) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize()); #endif return Add(t); } T Pop() { int nLast = GetSize() - 1; if(nLast < 0) return NULL; // must be able to convert to NULL T t = m_aT[nLast]; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize()); #endif if(!RemoveAt(nLast)) return NULL; return t; } T GetCurrent() { int nLast = GetSize() - 1; if(nLast < 0) return NULL; // must be able to convert to NULL return m_aT[nLast]; } }; /////////////////////////////////////////////////////////////////////////////// // CCommandBarCtrlBase - base class for the Command Bar implementation class CCommandBarCtrlBase : public CToolBarCtrl { public: struct _MsgHookData { HHOOK hMsgHook; DWORD dwUsage; _MsgHookData() : hMsgHook(NULL), dwUsage(0) { } }; typedef ATL::CSimpleMap CMsgHookMap; static CMsgHookMap* s_pmapMsgHook; static HHOOK s_hCreateHook; static bool s_bW2K; // For animation flag static CCommandBarCtrlBase* s_pCurrentBar; static bool s_bStaticInit; CSimpleStack m_stackMenuWnd; CSimpleStack m_stackMenuHandle; HWND m_hWndHook; DWORD m_dwMagic; CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314) { // init static variables if(!s_bStaticInit) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n")); ATLASSERT(FALSE); return; } if(!s_bStaticInit) { // Just in case... AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // Animation on Win2000 only s_bW2K = !AtlIsOldWindows(); // done s_bStaticInit = true; } lock.Unlock(); } } bool IsCommandBarBase() const { return m_dwMagic == 1314; } }; __declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL; __declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL; __declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL; __declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false; __declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false; /////////////////////////////////////////////////////////////////////////////// // CCommandBarCtrl - ATL implementation of Command Bars template class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > { public: DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) // Declarations struct _MenuItemData // menu item data { DWORD dwMagic; LPTSTR lpstrText; UINT fType; UINT fState; int iButton; _MenuItemData() { dwMagic = 0x1313; } bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); } }; struct _ToolBarData // toolbar resource data { WORD wVersion; WORD wWidth; WORD wHeight; WORD wItemCount; //WORD aItems[wItemCount] WORD* items() { return (WORD*)(this+1); } }; // Constants enum _CmdBarDrawConstants { s_kcxGap = 1, s_kcxTextMargin = 2, s_kcxButtonMargin = 3, s_kcyButtonMargin = 3 }; enum { _nMaxMenuItemTextLength = 100, _chChevronShortcut = _T('/') }; #ifndef DT_HIDEPREFIX enum { DT_HIDEPREFIX = 0x00100000 }; #endif // !DT_HIDEPREFIX // Data members HMENU m_hMenu; HIMAGELIST m_hImageList; ATL::CSimpleValArray m_arrCommand; DWORD m_dwExtendedStyle; // Command Bar specific extended styles ATL::CContainedWindow m_wndParent; bool m_bMenuActive:1; bool m_bAttachedMenu:1; bool m_bImagesVisible:1; bool m_bPopupItem:1; bool m_bContextMenu:1; bool m_bEscapePressed:1; bool m_bSkipMsg:1; bool m_bParentActive:1; bool m_bFlatMenus:1; bool m_bUseKeyboardCues:1; bool m_bShowKeyboardCues:1; bool m_bAllowKeyboardCues:1; bool m_bKeyboardInput:1; bool m_bAlphaImages:1; bool m_bLayoutRTL:1; bool m_bSkipPostDown:1; bool m_bVistaMenus:1; int m_nPopBtn; int m_nNextPopBtn; SIZE m_szBitmap; SIZE m_szButton; COLORREF m_clrMask; CFont m_fontMenu; // used internally, only to measure text UINT m_uSysKey; HWND m_hWndFocus; // Alternate focus mode int m_cxExtraSpacing; #if _WTL_CMDBAR_VISTA_MENUS ATL::CSimpleValArray m_arrVistaBitmap; // Bitmaps for Vista menus #endif // _WTL_CMDBAR_VISTA_MENUS // Constructor/destructor CCommandBarCtrlImpl() : m_hMenu(NULL), m_hImageList(NULL), m_wndParent(this, 1), m_bMenuActive(false), m_bAttachedMenu(false), m_nPopBtn(-1), m_nNextPopBtn(-1), m_bPopupItem(false), m_bImagesVisible(true), m_bSkipMsg(false), m_uSysKey(0), m_hWndFocus(NULL), m_bContextMenu(false), m_bEscapePressed(false), m_clrMask(RGB(192, 192, 192)), m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS), m_bParentActive(true), m_bFlatMenus(false), m_bUseKeyboardCues(false), m_bShowKeyboardCues(false), m_bAllowKeyboardCues(true), m_bKeyboardInput(false), m_cxExtraSpacing(0), m_bAlphaImages(false), m_bLayoutRTL(false), m_bSkipPostDown(false), m_bVistaMenus(false) { SetImageSize(16, 15); // default } ~CCommandBarCtrlImpl() { if(m_wndParent.IsWindow()) /*scary!*/ m_wndParent.UnsubclassWindow(); if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) ::DestroyMenu(m_hMenu); if(m_hImageList != NULL) ::ImageList_Destroy(m_hImageList); } // Attributes DWORD GetCommandBarExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); return dwPrevStyle; } CMenuHandle GetMenu() const { ATLASSERT(::IsWindow(m_hWnd)); return m_hMenu; } COLORREF GetImageMaskColor() const { return m_clrMask; } COLORREF SetImageMaskColor(COLORREF clrMask) { COLORREF clrOld = m_clrMask; m_clrMask = clrMask; return clrOld; } bool GetImagesVisible() const { return m_bImagesVisible; } bool SetImagesVisible(bool bVisible) { bool bOld = m_bImagesVisible; m_bImagesVisible = bVisible; return bOld; } void GetImageSize(SIZE& size) const { size = m_szBitmap; } bool SetImageSize(SIZE& size) { return SetImageSize(size.cx, size.cy); } bool SetImageSize(int cx, int cy) { if(m_hImageList != NULL) { if(::ImageList_GetImageCount(m_hImageList) == 0) // empty { ::ImageList_Destroy(m_hImageList); m_hImageList = NULL; } else { return false; // can't set, image list exists } } if(cx == 0 || cy == 0) return false; m_szBitmap.cx = cx; m_szBitmap.cy = cy; m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin; m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin; return true; } bool GetAlphaImages() const { return m_bAlphaImages; } bool SetAlphaImages(bool bAlphaImages) { if(m_hImageList != NULL) { if(::ImageList_GetImageCount(m_hImageList) == 0) // empty { ::ImageList_Destroy(m_hImageList); m_hImageList = NULL; } else { return false; // can't set, image list exists } } m_bAlphaImages = bAlphaImages; return true; } HWND GetCmdBar() const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); } // Methods HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) { // These styles are required for command bars dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT; #if (_MSC_VER >= 1300) return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam); #endif // !(_MSC_VER >= 1300) } BOOL AttachToWindow(HWND hWnd) { ATLASSERT(m_hWnd == NULL); ATLASSERT(::IsWindow(hWnd)); BOOL bRet = SubclassWindow(hWnd); if(bRet) { m_bAttachedMenu = true; T* pT = static_cast(this); pT->GetSystemSettings(); } return bRet; } BOOL LoadMenu(ATL::_U_STRINGorID menu) { ATLASSERT(::IsWindow(m_hWnd)); if(m_bAttachedMenu) // doesn't work in this mode return FALSE; if(menu.m_lpstr == NULL) return FALSE; HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); if(hMenu == NULL) return FALSE; return AttachMenu(hMenu); } BOOL AttachMenu(HMENU hMenu) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); if(hMenu != NULL && !::IsMenu(hMenu)) return FALSE; #if _WTL_CMDBAR_VISTA_MENUS // remove Vista bitmaps if used if(m_bVistaMenus && (m_hMenu != NULL)) { T* pT = static_cast(this); pT->_RemoveVistaBitmapsFromMenu(); } #endif // _WTL_CMDBAR_VISTA_MENUS // destroy old menu, if needed, and set new one if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0) ::DestroyMenu(m_hMenu); m_hMenu = hMenu; if(m_bAttachedMenu) // Nothing else in this mode return TRUE; // Build buttons according to menu SetRedraw(FALSE); // Clear all buttons int nCount = GetButtonCount(); for(int i = 0; i < nCount; i++) ATLVERIFY(DeleteButton(0) != FALSE); // Add buttons for each menu item if(m_hMenu != NULL) { int nItems = ::GetMenuItemCount(m_hMenu); T* pT = static_cast(this); pT; // avoid level 4 warning TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; for(int i = 0; i < nItems; i++) { CMenuItemInfo mii; mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU; mii.fType = MFT_STRING; mii.dwTypeData = szString; mii.cch = pT->_nMaxMenuItemTextLength; BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii); ATLASSERT(bRet); // If we have more than the buffer, we assume we have bitmaps bits if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1) { mii.fType = MFT_BITMAP; ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii); szString[0] = 0; } // NOTE: Command Bar currently supports only drop-down menu items ATLASSERT(mii.hSubMenu != NULL); TBBUTTON btn = { 0 }; btn.iBitmap = 0; btn.idCommand = i; btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0); btn.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_DROPDOWN; btn.dwData = 0; btn.iString = 0; bRet = InsertButton(-1, &btn); ATLASSERT(bRet); TBBUTTONINFO bi = { 0 }; bi.cbSize = sizeof(TBBUTTONINFO); bi.dwMask = TBIF_TEXT; bi.pszText = szString; bRet = SetButtonInfo(i, &bi); ATLASSERT(bRet); } } SetRedraw(TRUE); Invalidate(); UpdateWindow(); return TRUE; } BOOL LoadImages(ATL::_U_STRINGorID image) { return _LoadImagesHelper(image, false); } BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) { return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize); } BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) { ATLASSERT(::IsWindow(m_hWnd)); HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR); if(hRsrc == NULL) return FALSE; HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc); if(hGlobal == NULL) return FALSE; _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal); if(pData == NULL) return FALSE; ATLASSERT(pData->wVersion == 1); WORD* pItems = pData->items(); int nItems = pData->wItemCount; // Set internal data SetImageSize(pData->wWidth, pData->wHeight); // Create image list if needed if(m_hImageList == NULL) { // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only) T* pT = static_cast(this); m_bAlphaImages = AtlIsAlphaBitmapResource(image); if(!pT->CreateInternalImageList(pData->wItemCount)) return FALSE; } #if _WTL_CMDBAR_VISTA_MENUS int nOldImageCount = ::ImageList_GetImageCount(m_hImageList); #endif // _WTL_CMDBAR_VISTA_MENUS // Add bitmap to our image list CBitmap bmp; if(bMapped) { ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0); // if mapped, must be a numeric ID int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr)); bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize); } else { if(m_bAlphaImages) bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); else bmp.LoadBitmap(image.m_lpstr); } ATLASSERT(bmp.m_hBitmap != NULL); if(bmp.m_hBitmap == NULL) return FALSE; if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1) return FALSE; // Fill the array with command IDs for(int i = 0; i < nItems; i++) { if(pItems[i] != 0) m_arrCommand.Add(pItems[i]); } int nImageCount = ::ImageList_GetImageCount(m_hImageList); ATLASSERT(nImageCount == m_arrCommand.GetSize()); if(nImageCount != m_arrCommand.GetSize()) return FALSE; #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista()) { T* pT = static_cast(this); pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount); ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize()); } #endif // _WTL_CMDBAR_VISTA_MENUS return TRUE; } BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); CBitmap bmp; bmp.LoadBitmap(bitmap.m_lpstr); if(bmp.m_hBitmap == NULL) return FALSE; return AddBitmap(bmp, nCommandID); } BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); // Create image list if it doesn't exist if(m_hImageList == NULL) { if(!pT->CreateInternalImageList(1)) return FALSE; } // check bitmap size CBitmapHandle bmp = hBitmap; SIZE size = { 0, 0 }; bmp.GetSize(size); if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy) { ATLASSERT(FALSE); // must match size! return FALSE; } // add bitmap int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask); if(nRet == -1) return FALSE; BOOL bRet = m_arrCommand.Add((WORD)nCommandID); ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista()) { pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); } #endif // _WTL_CMDBAR_VISTA_MENUS return bRet; } BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); if(hIcon == NULL) return FALSE; return AddIcon(hIcon, nCommandID); } BOOL AddIcon(HICON hIcon, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); // create image list if it doesn't exist if(m_hImageList == NULL) { if(!pT->CreateInternalImageList(1)) return FALSE; } int nRet = ::ImageList_AddIcon(m_hImageList, hIcon); if(nRet == -1) return FALSE; BOOL bRet = m_arrCommand.Add((WORD)nCommandID); ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize()); #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista()) { pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1); ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize()); } #endif // _WTL_CMDBAR_VISTA_MENUS return bRet; } BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); CBitmap bmp; bmp.LoadBitmap(bitmap.m_lpstr); if(bmp.m_hBitmap == NULL) return FALSE; return ReplaceBitmap(bmp, nCommandID); } BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); BOOL bRet = FALSE; for(int i = 0; i < m_arrCommand.GetSize(); i++) { if(m_arrCommand[i] == nCommandID) { bRet = ::ImageList_Remove(m_hImageList, i); if(bRet) { m_arrCommand.RemoveAt(i); #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista()) { if(m_arrVistaBitmap[i] != NULL) ::DeleteObject(m_arrVistaBitmap[i]); m_arrVistaBitmap.RemoveAt(i); } #endif // _WTL_CMDBAR_VISTA_MENUS } break; } } if(bRet) bRet = AddBitmap(hBitmap, nCommandID); return bRet; } BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); if(hIcon == NULL) return FALSE; return ReplaceIcon(hIcon, nCommandID); } BOOL ReplaceIcon(HICON hIcon, UINT nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); BOOL bRet = FALSE; for(int i = 0; i < m_arrCommand.GetSize(); i++) { if(m_arrCommand[i] == nCommandID) { bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1); #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista() && bRet != FALSE) { T* pT = static_cast(this); pT->_ReplaceVistaBitmapFromImageList(i); } #endif // _WTL_CMDBAR_VISTA_MENUS break; } } return bRet; } BOOL RemoveImage(int nCommandID) { ATLASSERT(::IsWindow(m_hWnd)); BOOL bRet = FALSE; for(int i = 0; i < m_arrCommand.GetSize(); i++) { if(m_arrCommand[i] == nCommandID) { bRet = ::ImageList_Remove(m_hImageList, i); if(bRet) { m_arrCommand.RemoveAt(i); #if _WTL_CMDBAR_VISTA_MENUS if(RunTimeHelper::IsVista()) { if(m_arrVistaBitmap[i] != NULL) ::DeleteObject(m_arrVistaBitmap[i]); m_arrVistaBitmap.RemoveAt(i); } #endif // _WTL_CMDBAR_VISTA_MENUS } break; } } return bRet; } BOOL RemoveAllImages() { ATLASSERT(::IsWindow(m_hWnd)); ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n")); BOOL bRet = ::ImageList_RemoveAll(m_hImageList); if(bRet) { m_arrCommand.RemoveAll(); #if _WTL_CMDBAR_VISTA_MENUS for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) { if(m_arrVistaBitmap[i] != NULL) ::DeleteObject(m_arrVistaBitmap[i]); } m_arrVistaBitmap.RemoveAll(); #endif // _WTL_CMDBAR_VISTA_MENUS } return bRet; } BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(::IsMenu(hMenu)); if(!::IsMenu(hMenu)) return FALSE; m_bContextMenu = true; if(m_bUseKeyboardCues) m_bShowKeyboardCues = m_bKeyboardInput; T* pT = static_cast(this); return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams); } BOOL SetMDIClient(HWND /*hWndMDIClient*/) { // Use CMDICommandBarCtrl for MDI support ATLASSERT(FALSE); return FALSE; } // Message map and handlers BEGIN_MSG_MAP(CCommandBarCtrlImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_INITMENU, OnInitMenu) MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup) MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar) MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) MESSAGE_HANDLER(WM_CHAR, OnChar) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown) MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp) MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) // public API handlers - these stay to support chevrons in atlframe.h MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu) MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu) MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar) MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg) ALT_MSG_MAP(1) // Parent window messages NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange) NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown) MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup) MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar) MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand) MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu) MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar) MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu) MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange) MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem) MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem) MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw) ALT_MSG_MAP(2) // MDI client window messages // Use CMDICommandBarCtrl for MDI support ALT_MSG_MAP(3) // Message hook messages MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown) MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp) MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar) MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown) MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu) MESSAGE_HANDLER(WM_CHAR, OnHookChar) END_MSG_MAP() LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { LPMSG pMsg = (LPMSG)lParam; if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST) m_bKeyboardInput = false; else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) m_bKeyboardInput = true; LRESULT lRet = 0; ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3); return lRet; } LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { // Let the toolbar initialize itself LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); // get and use system settings T* pT = static_cast(this); pT->GetSystemSettings(); // Parent init ATL::CWindow wndParent = GetParent(); ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent(); m_wndParent.SubclassWindow(wndTopLevelParent); // Toolbar Init SetButtonStructSize(); SetImageList(NULL); // Create message hook if needed CWindowCreateCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n")); ATLASSERT(FALSE); return -1; } if(s_pmapMsgHook == NULL) { ATLTRY(s_pmapMsgHook = new CMsgHookMap); ATLASSERT(s_pmapMsgHook != NULL); } if(s_pmapMsgHook != NULL) { DWORD dwThreadID = ::GetCurrentThreadId(); _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); if(pData == NULL) { ATLTRY(pData = new _MsgHookData); ATLASSERT(pData != NULL); HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID); ATLASSERT(hMsgHook != NULL); if(pData != NULL && hMsgHook != NULL) { pData->hMsgHook = hMsgHook; pData->dwUsage = 1; BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData); bRet; ATLASSERT(bRet); } } else { (pData->dwUsage)++; } } lock.Unlock(); // Get layout #if (WINVER >= 0x0500) m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0); #endif // (WINVER >= 0x0500) return lRet; } LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); #if _WTL_CMDBAR_VISTA_MENUS if(m_bVistaMenus && (m_hMenu != NULL)) { T* pT = static_cast(this); pT->_RemoveVistaBitmapsFromMenu(); } for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++) { if(m_arrVistaBitmap[i] != NULL) ::DeleteObject(m_arrVistaBitmap[i]); } #endif // _WTL_CMDBAR_VISTA_MENUS if(m_bAttachedMenu) // nothing to do in this mode return lRet; CWindowCreateCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n")); ATLASSERT(FALSE); return lRet; } if(s_pmapMsgHook != NULL) { DWORD dwThreadID = ::GetCurrentThreadId(); _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); if(pData != NULL) { (pData->dwUsage)--; if(pData->dwUsage == 0) { BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook); ATLASSERT(bRet); bRet = s_pmapMsgHook->Remove(dwThreadID); ATLASSERT(bRet); if(bRet) delete pData; } if(s_pmapMsgHook->GetSize() == 0) { delete s_pmapMsgHook; s_pmapMsgHook = NULL; } } } lock.Unlock(); return lRet; } LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n")); #endif if(m_bAttachedMenu) // nothing to do in this mode { bHandled = FALSE; return 1; } bHandled = FALSE; // Simulate Alt+Space for the parent if(wParam == VK_SPACE) { m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29)); bHandled = TRUE; } #if (_WIN32_IE >= 0x0500) else if(wParam == VK_LEFT || wParam == VK_RIGHT) { WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; if(!m_bMenuActive) { T* pT = static_cast(this); int nBtn = GetHotItem(); int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn); if(nNextBtn == -2) { SetHotItem(-1); if(pT->DisplayChevronMenu()) bHandled = TRUE; } } } #endif // (_WIN32_IE >= 0x0500) return 0; } LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n")); #endif if(m_bAttachedMenu) // nothing to do in this mode { bHandled = FALSE; return 1; } if(wParam != VK_SPACE) bHandled = FALSE; return 0; } LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n")); #endif if(m_bAttachedMenu) // nothing to do in this mode { bHandled = FALSE; return 1; } if(wParam != VK_SPACE) bHandled = FALSE; else return 0; // Security if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd) return 0; // Handle mnemonic press when we have focus int nBtn = 0; if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) { #if (_WIN32_IE >= 0x0500) if((TCHAR)LOWORD(wParam) != _chChevronShortcut) #endif // (_WIN32_IE >= 0x0500) ::MessageBeep(0); } else { #if (_WIN32_IE >= 0x0500) RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcBtn = { 0 }; GetItemRect(nBtn, &rcBtn); TBBUTTON tbb = { 0 }; GetButton(nBtn, &tbb); if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) { #endif // (_WIN32_IE >= 0x0500) PostMessage(WM_KEYDOWN, VK_DOWN, 0L); if(wParam != VK_RETURN) SetHotItem(nBtn); #if (_WIN32_IE >= 0x0500) } else { ::MessageBeep(0); bHandled = TRUE; } #endif // (_WIN32_IE >= 0x0500) } return 0; } LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n")); #endif bHandled = FALSE; return 0; } LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n")); #endif bHandled = FALSE; return 0; } LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n")); #endif bHandled = FALSE; return 0; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT)) { bHandled = FALSE; return 0; } CDCHandle dc = (HDC)wParam; RECT rect = { 0 }; GetClientRect(&rect); dc.FillRect(&rect, COLOR_MENU); return 1; // don't do the default erase } LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { int nIndex = GetHotItem(); SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu); bHandled = FALSE; return 1; } LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if((BOOL)HIWORD(lParam)) // System menu, do nothing { bHandled = FALSE; return 1; } if(!(m_bAttachedMenu || m_bMenuActive)) // Not attached or ours, do nothing { bHandled = FALSE; return 1; } #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n")); #endif // forward to the parent or subclassed window, so it can handle update UI LRESULT lRet = 0; if(m_bAttachedMenu) lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); else lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem()); #if _WTL_CMDBAR_VISTA_MENUS // If Vista menus are active, just set bitmaps and return if(m_bVistaMenus) { CMenuHandle menu = (HMENU)wParam; ATLASSERT(menu.m_hMenu != NULL); for(int i = 0; i < menu.GetMenuItemCount(); i++) { WORD nID = (WORD)menu.GetMenuItemID(i); int nIndex = m_arrCommand.Find(nID); CMenuItemInfo mii; mii.fMask = MIIM_BITMAP; mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL; menu.SetMenuItemInfo(i, TRUE, &mii); } return lRet; } #endif // _WTL_CMDBAR_VISTA_MENUS // Convert menu items to ownerdraw, add our data if(m_bImagesVisible) { CMenuHandle menuPopup = (HMENU)wParam; ATLASSERT(menuPopup.m_hMenu != NULL); T* pT = static_cast(this); pT; // avoid level 4 warning TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; BOOL bRet = FALSE; for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) { CMenuItemInfo mii; mii.cch = pT->_nMaxMenuItemTextLength; mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; mii.dwTypeData = szString; bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); if(!(mii.fType & MFT_OWNERDRAW)) // Not already an ownerdraw item { mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; _MenuItemData* pMI = NULL; ATLTRY(pMI = new _MenuItemData); ATLASSERT(pMI != NULL); if(pMI != NULL) { pMI->fType = mii.fType; pMI->fState = mii.fState; mii.fType |= MFT_OWNERDRAW; pMI->iButton = -1; for(int j = 0; j < m_arrCommand.GetSize(); j++) { if(m_arrCommand[j] == mii.wID) { pMI->iButton = j; break; } } int cchLen = lstrlen(szString) + 1; pMI->lpstrText = NULL; ATLTRY(pMI->lpstrText = new TCHAR[cchLen]); ATLASSERT(pMI->lpstrText != NULL); if(pMI->lpstrText != NULL) SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString); mii.dwItemData = (ULONG_PTR)pMI; bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); } } } // Add it to the list m_stackMenuHandle.Push(menuPopup.m_hMenu); } return lRet; } LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if(!m_bAttachedMenu) // Not attached, do nothing, forward to parent { m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP); if(m_wndParent.IsWindow()) m_wndParent.SendMessage(uMsg, wParam, lParam); bHandled = FALSE; return 1; } // Check if a menu is closing, do a cleanup if(HIWORD(wParam) == 0xFFFF && lParam == NULL) // Menu closing { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n")); #endif ATLASSERT(m_stackMenuWnd.GetSize() == 0); // Restore the menu items to the previous state for all menus that were converted if(m_bImagesVisible) { HMENU hMenu = NULL; while((hMenu = m_stackMenuHandle.Pop()) != NULL) { CMenuHandle menuPopup = hMenu; ATLASSERT(menuPopup.m_hMenu != NULL); // Restore state and delete menu item data BOOL bRet = FALSE; for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) { CMenuItemInfo mii; mii.fMask = MIIM_DATA | MIIM_TYPE; bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; if(pMI != NULL && pMI->IsCmdBarMenuItem()) { mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; mii.fType = pMI->fType; mii.dwTypeData = pMI->lpstrText; mii.cch = lstrlen(pMI->lpstrText); mii.dwItemData = NULL; bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); delete [] pMI->lpstrText; pMI->dwMagic = 0x6666; delete pMI; } } } } } bHandled = FALSE; return 1; } LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { int nIndex = (int)wParam; T* pT = static_cast(this); pT->DoPopupMenu(nIndex, false); return 0; } LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // Let's make sure we're not embedded in another process if((LPVOID)wParam != NULL) *((DWORD*)wParam) = GetCurrentProcessId(); if(IsWindowVisible()) return (LRESULT)static_cast(this); else return NULL; } LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { #ifndef SPI_SETKEYBOARDCUES const UINT SPI_SETKEYBOARDCUES = 0x100B; #endif // !SPI_SETKEYBOARDCUES #ifndef SPI_GETFLATMENU const UINT SPI_SETFLATMENU = 0x1023; #endif // !SPI_GETFLATMENU if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU) { T* pT = static_cast(this); pT->GetSystemSettings(); } return 0; } LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam; int cyMin = ::GetSystemMetrics(SM_CYMENU); if(lpWP->cy < cyMin) lpWP->cy = cyMin; return lRet; } LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n")); #endif bHandled = TRUE; T* pT = static_cast(this); LRESULT lRet; if(m_bMenuActive && LOWORD(wParam) != 0x0D) lRet = 0; else lRet = MAKELRESULT(1, 1); if(m_bMenuActive && HIWORD(wParam) == MF_POPUP) { // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout TCHAR ch = (TCHAR)LOWORD(wParam); CMenuHandle menu = (HMENU)lParam; int nCount = ::GetMenuItemCount(menu); int nRetCode = MNC_EXECUTE; BOOL bRet = FALSE; TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 }; WORD wMnem = 0; bool bFound = false; for(int i = 0; i < nCount; i++) { CMenuItemInfo mii; mii.cch = pT->_nMaxMenuItemTextLength; mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; mii.dwTypeData = szString; bRet = menu.GetMenuItemInfo(i, TRUE, &mii); if(!bRet || (mii.fType & MFT_SEPARATOR)) continue; _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData; if(pmd != NULL && pmd->IsCmdBarMenuItem()) { LPTSTR p = pmd->lpstrText; if(p != NULL) { while(*p && *p != _T('&')) p = ::CharNext(p); if(p != NULL && *p) { DWORD dwP = MAKELONG(*(++p), 0); DWORD dwC = MAKELONG(ch, 0); if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC))) { if(!bFound) { wMnem = (WORD)i; bFound = true; } else { nRetCode = MNC_SELECT; break; } } } } } } if(bFound) { if(nRetCode == MNC_EXECUTE) { PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); pT->GiveFocusBack(); } bHandled = TRUE; lRet = MAKELRESULT(wMnem, nRetCode); } } else if(!m_bMenuActive) { int nBtn = 0; if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn)) { bHandled = FALSE; PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); pT->GiveFocusBack(); #if (_WIN32_IE >= 0x0500) // check if we should display chevron menu if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut) { if(pT->DisplayChevronMenu()) bHandled = TRUE; } #endif // (_WIN32_IE >= 0x0500) } else if(m_wndParent.IsWindowEnabled()) { #if (_WIN32_IE >= 0x0500) RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcBtn = { 0 }; GetItemRect(nBtn, &rcBtn); TBBUTTON tbb = { 0 }; GetButton(nBtn, &tbb); if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right) { #endif // (_WIN32_IE >= 0x0500) if(m_bUseKeyboardCues && !m_bShowKeyboardCues) { m_bAllowKeyboardCues = true; ShowKeyboardCues(true); } pT->TakeFocus(); PostMessage(WM_KEYDOWN, VK_DOWN, 0L); SetHotItem(nBtn); #if (_WIN32_IE >= 0x0500) } else { ::MessageBeep(0); } #endif // (_WIN32_IE >= 0x0500) } } return lRet; } LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bUseKeyboardCues && m_bShowKeyboardCues) ShowKeyboardCues(false); bHandled = FALSE; return 1; } LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam; _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) { T* pT = static_cast(this); pT->DrawItem(lpDrawItemStruct); } else { bHandled = FALSE; } return (LRESULT)TRUE; } LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam; _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem()) { T* pT = static_cast(this); pT->MeasureItem(lpMeasureItemStruct); } else { bHandled = FALSE; } return (LRESULT)TRUE; } // API message handlers LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)m_hMenu; } LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { if(lParam == NULL) return FALSE; LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam; if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU)) return FALSE; T* pT = static_cast(this); return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm); } LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)m_hWnd; } // Parent window message handlers LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh; // Check if this comes from us if(pnmh->hwndFrom != m_hWnd) { bHandled = FALSE; return 0; } bool bBlockTracking = false; if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0) { DWORD dwProcessID; ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID); bBlockTracking = (::GetCurrentProcessId() != dwProcessID); } if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE)) { return 1; } else { #ifndef HICF_LMOUSE const DWORD HICF_LMOUSE = 0x00000080; // left mouse button selected #endif bHandled = FALSE; // Send WM_MENUSELECT to the app if it needs to display a status text if(!(lpNMHT->dwFlags & HICF_MOUSE) && !(lpNMHT->dwFlags & HICF_ACCELERATOR) && !(lpNMHT->dwFlags & HICF_LMOUSE)) { if(lpNMHT->dwFlags & HICF_ENTERING) m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu); if(lpNMHT->dwFlags & HICF_LEAVING) m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL); } return 0; } } LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { // Check if this comes from us if(pnmh->hwndFrom != m_hWnd) { bHandled = FALSE; return 1; } T* pT = static_cast(this); if(::GetFocus() != m_hWnd) pT->TakeFocus(); LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh; int nIndex = CommandToIndex(pNMToolBar->iItem); m_bContextMenu = false; m_bEscapePressed = false; pT->DoPopupMenu(nIndex, true); return TBDDRET_DEFAULT; } LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnInitMenuPopup(uMsg, wParam, lParam, bHandled); } LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnInternalGetBar(uMsg, wParam, lParam, bHandled); } LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; if((m_uSysKey == VK_MENU || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80)) || m_uSysKey == VK_SPACE) && wParam == SC_KEYMENU) { T* pT = static_cast(this); if(::GetFocus() == m_hWnd) { pT->GiveFocusBack(); // exit menu "loop" PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); } else if(m_uSysKey != VK_SPACE && !m_bSkipMsg) { if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) ShowKeyboardCues(true); pT->TakeFocus(); // enter menu "loop" bHandled = TRUE; } else if(m_uSysKey != VK_SPACE) { bHandled = TRUE; } } m_bSkipMsg = false; return 0; } LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnAPIGetMenu(uMsg, wParam, lParam, bHandled); } LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnMenuChar(uMsg, wParam, lParam, bHandled); } LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled); } LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled); } LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { OnSettingChange(uMsg, wParam, lParam, bHandled); bHandled = FALSE; return 1; } LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnDrawItem(uMsg, wParam, lParam, bHandled); } LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnMeasureItem(uMsg, wParam, lParam, bHandled); } LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues) { ShowKeyboardCues(false); // this will repaint our window } else { Invalidate(); UpdateWindow(); } bHandled = FALSE; return 1; } LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LRESULT lRet = CDRF_DODEFAULT; bHandled = FALSE; if(pnmh->hwndFrom == m_hWnd) { LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh; if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT) { lRet = CDRF_NOTIFYITEMDRAW; bHandled = TRUE; } else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) { #if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) if(m_bVistaMenus) { ::SetRectEmpty(&lpTBCustomDraw->rcText); lRet = CDRF_NOTIFYPOSTPAINT; bHandled = TRUE; } else #endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) { if(m_bFlatMenus) { #ifndef COLOR_MENUHILIGHT const int COLOR_MENUHILIGHT = 29; #endif // !COLOR_MENUHILIGHT bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT || (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED)) { ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT)); ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT)); lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT); } else if(bDisabled || !m_bParentActive) { lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); } _ParentCustomDrawHelper(lpTBCustomDraw); lRet = CDRF_SKIPDEFAULT; bHandled = TRUE; } else if(!m_bParentActive) { lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); bHandled = TRUE; } } } #if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) else if (lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT) { bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED); if(bDisabled || !m_bParentActive) lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT); _ParentCustomDrawHelper(lpTBCustomDraw); lRet = CDRF_SKIPDEFAULT; bHandled = TRUE; } #endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR) } return lRet; } void _ParentCustomDrawHelper(LPNMTBCUSTOMDRAW lpTBCustomDraw) { CDCHandle dc = lpTBCustomDraw->nmcd.hdc; dc.SetTextColor(lpTBCustomDraw->clrText); dc.SetBkMode(lpTBCustomDraw->nStringBkMode); HFONT hFont = GetFont(); HFONT hFontOld = NULL; if(hFont != NULL) hFontOld = dc.SelectFont(hFont); const int cchText = 200; TCHAR szText[cchText] = { 0 }; TBBUTTONINFO tbbi = { 0 }; tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = szText; tbbi.cchText = cchText; GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi); dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); if(hFont != NULL) dc.SelectFont(hFontOld); } // Message hook handlers LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { static POINT s_point = { -1, -1 }; DWORD dwPoint = ::GetMessagePos(); POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) }; bHandled = FALSE; if(m_bMenuActive) { if(::WindowFromPoint(point) == m_hWnd) { ScreenToClient(&point); int nHit = HitTest(&point); if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1) { TBBUTTON tbb = { 0 }; GetButton(nHit, &tbb); if((tbb.fsState & TBSTATE_ENABLED) != 0) { m_nNextPopBtn = nHit | 0xFFFF0000; HWND hWndMenu = m_stackMenuWnd.GetCurrent(); ATLASSERT(hWndMenu != NULL); // this one is needed to close a menu if mouse button was down ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y)); // this one closes a popup menu ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); bHandled = TRUE; } } } } else { ScreenToClient(&point); } s_point = point; return 0; } LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam); #endif if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues) ShowKeyboardCues(true); if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd) { m_bAllowKeyboardCues = false; PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); T* pT = static_cast(this); pT->GiveFocusBack(); m_bSkipMsg = true; } else { if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues) { m_bAllowKeyboardCues = true; ShowKeyboardCues(false); } m_uSysKey = (UINT)wParam; } return 0; } LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(!m_bAllowKeyboardCues) m_bAllowKeyboardCues = true; bHandled = FALSE; wParam; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam); #endif return 0; } LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam); #endif if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE) bHandled = TRUE; return 0; } LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam); #endif bHandled = FALSE; T* pT = static_cast(this); if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1) { if(m_bMenuActive && !m_bContextMenu) { int nHot = GetHotItem(); if(nHot == -1) nHot = m_nPopBtn; if(nHot == -1) nHot = 0; SetHotItem(nHot); bHandled = TRUE; pT->TakeFocus(); m_bEscapePressed = true; // To keep focus m_bSkipPostDown = false; } else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow()) { SetHotItem(-1); pT->GiveFocusBack(); bHandled = TRUE; } } else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN) { if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow()) { int nHot = GetHotItem(); if(nHot != -1) { if(wParam != VK_RETURN) { if(!m_bSkipPostDown) { // IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click #if (_WIN32_IE < 0x0500) DWORD dwMajor = 0, dwMinor = 0; ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80)) { RECT rect = { 0 }; GetItemRect(nHot, &rect); PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top)); } #endif // (_WIN32_IE < 0x0500) PostMessage(WM_KEYDOWN, VK_DOWN, 0L); m_bSkipPostDown = true; } else { ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n")); m_bSkipPostDown = false; } } } else { ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n")); } } if(wParam == VK_RETURN && m_bMenuActive) { PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L); m_nNextPopBtn = -1; pT->GiveFocusBack(); } } else if(wParam == VK_LEFT || wParam == VK_RIGHT) { WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT; WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT; if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem)) { bool bAction = false; if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1) { m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn); if(m_nNextPopBtn != -1) bAction = true; } else if(wParam == wpNext) { m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn); if(m_nNextPopBtn != -1) bAction = true; } HWND hWndMenu = m_stackMenuWnd.GetCurrent(); ATLASSERT(hWndMenu != NULL); // Close the popup menu if(bAction) { ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); if(wParam == wpNext) { int cItem = m_stackMenuWnd.GetSize() - 1; while(cItem >= 0) { hWndMenu = m_stackMenuWnd[cItem]; if(hWndMenu != NULL) ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L); cItem--; } } #if (_WIN32_IE >= 0x0500) if(m_nNextPopBtn == -2) { m_nNextPopBtn = -1; pT->DisplayChevronMenu(); } #endif // (_WIN32_IE >= 0x0500) bHandled = TRUE; } } } return 0; } LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n")); #endif bHandled = FALSE; return 1; } LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam); #endif bHandled = (wParam == VK_ESCAPE); return 0; } // Implementation - ownerdraw overrideables and helpers void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { T* pT = static_cast(this); if(m_bFlatMenus) pT->DrawItemFlat(lpDrawItemStruct); else pT->DrawItem3D(lpDrawItemStruct); } void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct) { _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; CDCHandle dc = lpDrawItemStruct->hDC; const RECT& rcItem = lpDrawItemStruct->rcItem; T* pT = static_cast(this); if(pmd->fType & MFT_SEPARATOR) { // draw separator RECT rc = rcItem; rc.top += (rc.bottom - rc.top) / 2; // vertical center dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line } else // not a separator { BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; BOOL bHasImage = FALSE; if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) bSelected = FALSE; RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically int iButton = pmd->iButton; if(iButton >= 0) { bHasImage = TRUE; // calc drawing point SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; sz.cx /= 2; sz.cy /= 2; POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; // fill background depending on state if(!bChecked || (bSelected && !bDisabled)) { if(!bDisabled) dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU); else dc.FillRect(&rcButn, COLOR_MENU); } else { COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); CBrush hbr(CDCHandle::GetHalftoneBrush()); dc.SetBrushOrg(rcButn.left, rcButn.top); dc.FillRect(&rcButn, hbr); dc.SetTextColor(crTxt); dc.SetBkColor(crBk); } // draw disabled or normal if(!bDisabled) { // draw pushed-in or popped-out edge if(bSelected || bChecked) { RECT rc2 = rcButn; dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT); } // draw the image ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); } else { HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU); pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground); } } else { // no image - look for custom checked/unchecked bitmaps CMenuItemInfo info; info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); if(bChecked || info.hbmpUnchecked != NULL) { BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); } } // draw item text int cxButn = m_szButton.cx; COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) { RECT rcBG = rcItem; if(bHasImage) rcBG.left += cxButn + s_kcxGap; dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU); } // calc text rectangle and colors RECT rcText = rcItem; rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; rcText.right -= cxButn; dc.SetBkMode(TRANSPARENT); COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); // font already selected by Windows if(bDisabled && (!bSelected || colorText == colorBG)) { // disabled - draw shadow text shifted down and right 1 pixel (unles selected) RECT rcDisabled = rcText; ::OffsetRect(&rcDisabled, 1, 1); pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT)); } pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! } } void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct) { _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData; CDCHandle dc = lpDrawItemStruct->hDC; const RECT& rcItem = lpDrawItemStruct->rcItem; T* pT = static_cast(this); #ifndef COLOR_MENUHILIGHT const int COLOR_MENUHILIGHT = 29; #endif // !COLOR_MENUHILIGHT BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED; BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED; BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED; // paint background if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT) { if(bSelected) { dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT)); dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT)); } else { dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU)); } } if(pmd->fType & MFT_SEPARATOR) { // draw separator RECT rc = rcItem; rc.top += (rc.bottom - rc.top) / 2; // vertical center dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line } else // not a separator { if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1) bSelected = FALSE; RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically // draw background and border for checked items if(bChecked) { RECT rcCheck = rcButn; ::InflateRect(&rcCheck, -1, -1); if(bSelected) dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU)); dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT)); } int iButton = pmd->iButton; if(iButton >= 0) { // calc drawing point SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy }; sz.cx /= 2; sz.cy /= 2; POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy }; // draw disabled or normal if(!bDisabled) { ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT); } else { HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU); HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW); pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage); } } else { // no image - look for custom checked/unchecked bitmaps CMenuItemInfo info; info.fMask = MIIM_CHECKMARKS | MIIM_TYPE; ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info); if(bChecked || info.hbmpUnchecked != NULL) { BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0); pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked); } } // draw item text int cxButn = m_szButton.cx; // calc text rectangle and colors RECT rcText = rcItem; rcText.left += cxButn + s_kcxGap + s_kcxTextMargin; rcText.right -= cxButn; dc.SetBkMode(TRANSPARENT); COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally! } } void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color) { int nTab = -1; const int nLen = lstrlen(lpstrText); for(int i = 0; i < nLen; i++) { if(lpstrText[i] == _T('\t')) { nTab = i; break; } } dc.SetTextColor(color); dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); if(nTab != -1) dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX)); } void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point, HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) { #if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) if(m_bAlphaImages) { IMAGELISTDRAWPARAMS ildp = { 0 }; ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); ildp.himl = m_hImageList; ildp.i = nImage; ildp.hdcDst = dc; ildp.x = point.x; ildp.y = point.y; ildp.cx = 0; ildp.cy = 0; ildp.xBitmap = 0; ildp.yBitmap = 0; ildp.fStyle = ILD_TRANSPARENT; ildp.fState = ILS_SATURATE; ildp.Frame = 0; ::ImageList_DrawIndirect(&ildp); } else #endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501) { // create memory DC CDC dcMem; dcMem.CreateCompatibleDC(dc); // create mono or color bitmap CBitmap bmp; bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy); ATLASSERT(bmp.m_hBitmap != NULL); // draw image into memory DC--fill BG white first HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS); // If white is the text color, we can't use the normal painting since // it would blend with the WHITENESS, but the mask is OK UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL; ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle); dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage); dcMem.SelectBitmap(hBmpOld); // restore } } // old name BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) { return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck); } BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck) { // get checkmark bitmap, if none, use Windows standard SIZE size = { 0, 0 }; CBitmapHandle bmp = hBmpCheck; if(hBmpCheck != NULL) { bmp.GetSize(size); } else { size.cx = ::GetSystemMetrics(SM_CXMENUCHECK); size.cy = ::GetSystemMetrics(SM_CYMENUCHECK); bmp.CreateCompatibleBitmap(dc, size.cx, size.cy); ATLASSERT(bmp.m_hBitmap != NULL); } // center bitmap in caller's rectangle RECT rcDest = rc; if((rc.right - rc.left) > size.cx) { rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2; rcDest.right = rcDest.left + size.cx; } if((rc.bottom - rc.top) > size.cy) { rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2; rcDest.bottom = rcDest.top + size.cy; } // paint background if(!m_bFlatMenus) { if(bSelected && !bDisabled) { dc.FillRect(&rcDest, COLOR_MENU); } else { COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE)); COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT)); CBrush hbr(CDCHandle::GetHalftoneBrush()); dc.SetBrushOrg(rcDest.left, rcDest.top); dc.FillRect(&rcDest, hbr); dc.SetTextColor(clrTextOld); dc.SetBkColor(clrBkOld); } } // create source image CDC dcSource; dcSource.CreateCompatibleDC(dc); HBITMAP hBmpOld = dcSource.SelectBitmap(bmp); // set colors const COLORREF clrBlack = RGB(0, 0, 0); const COLORREF clrWhite = RGB(255, 255, 255); COLORREF clrTextOld = dc.SetTextColor(clrBlack); COLORREF clrBkOld = dc.SetBkColor(clrWhite); // create mask CDC dcMask; dcMask.CreateCompatibleDC(dc); CBitmap bmpMask; bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL); HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask); // draw the checkmark transparently int cx = rcDest.right - rcDest.left; int cy = rcDest.bottom - rcDest.top; if(hBmpCheck != NULL) { // build mask based on transparent color dcSource.SetBkColor(m_clrMask); dcMask.SetBkColor(clrBlack); dcMask.SetTextColor(clrWhite); dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY); // draw bitmap using the mask dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND); dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT); } else { const DWORD ROP_DSno = 0x00BB0226L; const DWORD ROP_DSa = 0x008800C6L; const DWORD ROP_DSo = 0x00EE0086L; const DWORD ROP_DSna = 0x00220326L; // draw mask RECT rcSource = { 0, 0, __min(size.cx, rc.right - rc.left), __min(size.cy, rc.bottom - rc.top) }; dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK); // draw shadow if disabled if(!m_bFlatMenus && bDisabled) { // offset by one pixel int x = rcDest.left + 1; int y = rcDest.top + 1; // paint source bitmap const int nColor = COLOR_3DHILIGHT; dcSource.FillRect(&rcSource, nColor); // draw checkmark - special case black and white colors COLORREF clrCheck = ::GetSysColor(nColor); if(clrCheck == clrWhite) { dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSno); dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa); } else { if(clrCheck != clrBlack) { ATLASSERT(dcSource.GetTextColor() == clrBlack); ATLASSERT(dcSource.GetBkColor() == clrWhite); dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); } dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSa); dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo); } } // paint source bitmap const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT; dcSource.FillRect(&rcSource, nColor); // draw checkmark - special case black and white colors COLORREF clrCheck = ::GetSysColor(nColor); if(clrCheck == clrWhite) { dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSno); dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa); } else { if(clrCheck != clrBlack) { ATLASSERT(dcSource.GetTextColor() == clrBlack); ATLASSERT(dcSource.GetBkColor() == clrWhite); dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna); } dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSa); dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo); } } // restore all dc.SetTextColor(clrTextOld); dc.SetBkColor(clrBkOld); dcSource.SelectBitmap(hBmpOld); dcMask.SelectBitmap(hBmpOld1); if(hBmpCheck == NULL) bmp.DeleteObject(); // draw pushed-in hilight if(!m_bFlatMenus && !bDisabled) { if(rc.right - rc.left > size.cx) ::InflateRect(&rcDest, 1,1); // inflate checkmark by one pixel all around dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT); } return TRUE; } void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData; if(pmd->fType & MFT_SEPARATOR) // separator - use half system height and zero width { lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2; lpMeasureItemStruct->itemWidth = 0; } else { // compute size of text - use DrawText with DT_CALCRECT CWindowDC dc(NULL); CFont fontBold; HFONT hOldFont = NULL; if(pmd->fState & MFS_DEFAULT) { // need bold version of font LOGFONT lf = { 0 }; m_fontMenu.GetLogFont(lf); lf.lfWeight += 200; fontBold.CreateFontIndirect(&lf); ATLASSERT(fontBold.m_hFont != NULL); hOldFont = dc.SelectFont(fontBold); } else { hOldFont = dc.SelectFont(m_fontMenu); } RECT rcText = { 0 }; dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); int cx = rcText.right - rcText.left; dc.SelectFont(hOldFont); LOGFONT lf = { 0 }; m_fontMenu.GetLogFont(lf); int cy = lf.lfHeight; if(cy < 0) cy = -cy; const int cyMargin = 8; cy += cyMargin; // height of item is the bigger of these two lpMeasureItemStruct->itemHeight = __max(cy, (int)m_szButton.cy); // width is width of text plus a bunch of stuff cx += 2 * s_kcxTextMargin; // L/R margin for readability cx += s_kcxGap; // space between button and menu text cx += 2 * m_szButton.cx; // button width (L=button; R=empty margin) cx += m_cxExtraSpacing; // extra between item text and accelerator keys // Windows adds 1 to returned value cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1; lpMeasureItemStruct->itemWidth = cx; // done deal } } // Implementation - Hook procs static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam) { const int cchClassName = 7; TCHAR szClassName[cchClassName] = { 0 }; if(nCode == HCBT_CREATEWND) { HWND hWndMenu = (HWND)wParam; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu); #endif ::GetClassName(hWndMenu, szClassName, cchClassName); if(!lstrcmp(_T("#32768"), szClassName)) s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu); } else if(nCode == HCBT_DESTROYWND) { HWND hWndMenu = (HWND)wParam; #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu); #endif ::GetClassName(hWndMenu, szClassName, cchClassName); if(!lstrcmp(_T("#32768"), szClassName)) { ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent()); s_pCurrentBar->m_stackMenuWnd.Pop(); } } return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam); } static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam) { LPMSG pMsg = (LPMSG)lParam; if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG) { CCommandBarCtrlBase* pCmdBar = NULL; HWND hWnd = pMsg->hwnd; DWORD dwPID = 0; while(pCmdBar == NULL && hWnd != NULL) { pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L); hWnd = ::GetParent(hWnd); } if(pCmdBar != NULL && dwPID == GetCurrentProcessId()) { pCmdBar->m_hWndHook = pMsg->hwnd; ATLASSERT(pCmdBar->IsCommandBarBase()); if(::IsWindow(pCmdBar->m_hWnd)) pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg); else ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n")); } } LRESULT lRet = 0; ATLASSERT(s_pmapMsgHook != NULL); if(s_pmapMsgHook != NULL) { DWORD dwThreadID = ::GetCurrentThreadId(); _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID); if(pData != NULL) { lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam); } } return lRet; } // Implementation void DoPopupMenu(int nIndex, bool bAnimate) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false"); #endif // Menu animation flags #ifndef TPM_VERPOSANIMATION const UINT TPM_VERPOSANIMATION = 0x1000L; #endif #ifndef TPM_NOANIMATION const UINT TPM_NOANIMATION = 0x4000L; #endif T* pT = static_cast(this); // get popup menu and it's position RECT rect = { 0 }; GetItemRect(nIndex, &rect); POINT pt = { rect.left, rect.bottom }; MapWindowPoints(NULL, &pt, 1); MapWindowPoints(NULL, &rect); TPMPARAMS TPMParams = { 0 }; TPMParams.cbSize = sizeof(TPMPARAMS); TPMParams.rcExclude = rect; HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex); ATLASSERT(hMenuPopup != NULL); // get button ID TBBUTTON tbb = { 0 }; GetButton(nIndex, &tbb); int nCmdID = tbb.idCommand; m_nPopBtn = nIndex; // remember current button's index // press button and display popup menu PressButton(nCmdID, TRUE); SetHotItem(nCmdID); pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams); PressButton(nCmdID, FALSE); if(::GetFocus() != m_hWnd) SetHotItem(-1); m_nPopBtn = -1; // restore // eat next message if click is on the same button MSG msg = { 0 }; if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt)) ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); // check if another popup menu should be displayed if(m_nNextPopBtn != -1) { PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF); if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem) PostMessage(WM_KEYDOWN, VK_DOWN, 0); m_nNextPopBtn = -1; } else { m_bContextMenu = false; // If user didn't hit escape, give focus back if(!m_bEscapePressed) { if(m_bUseKeyboardCues && m_bShowKeyboardCues) m_bAllowKeyboardCues = false; pT->GiveFocusBack(); } else { SetHotItem(nCmdID); SetAnchorHighlight(TRUE); } } } BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL) { CMenuHandle menuPopup = hMenu; CWindowCreateCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n")); ATLASSERT(FALSE); return FALSE; } ATLASSERT(s_hCreateHook == NULL); s_pCurrentBar = static_cast(this); s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId()); ATLASSERT(s_hCreateHook != NULL); m_bPopupItem = false; m_bMenuActive = true; BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams); m_bMenuActive = false; ::UnhookWindowsHookEx(s_hCreateHook); s_hCreateHook = NULL; s_pCurrentBar = NULL; lock.Unlock(); // cleanup - convert menus back to original state #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n")); #endif ATLASSERT(m_stackMenuWnd.GetSize() == 0); UpdateWindow(); ATL::CWindow wndTL = GetTopLevelParent(); wndTL.UpdateWindow(); // restore the menu items to the previous state for all menus that were converted if(m_bImagesVisible) { HMENU hMenuSav = NULL; while((hMenuSav = m_stackMenuHandle.Pop()) != NULL) { menuPopup = hMenuSav; BOOL bRet = FALSE; // restore state and delete menu item data for(int i = 0; i < menuPopup.GetMenuItemCount(); i++) { CMenuItemInfo mii; mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID; bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData; if(pMI != NULL && pMI->IsCmdBarMenuItem()) { mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; mii.fType = pMI->fType; mii.fState = pMI->fState; mii.dwTypeData = pMI->lpstrText; mii.cch = lstrlen(pMI->lpstrText); mii.dwItemData = NULL; bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); // this one triggers WM_MEASUREITEM menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText); ATLASSERT(bRet); delete [] pMI->lpstrText; delete pMI; } } } } return bTrackRet; } int GetPreviousMenuItem(int nBtn) const { if(nBtn == -1) return -1; #if (_WIN32_IE >= 0x0500) RECT rcClient = { 0 }; GetClientRect(&rcClient); #endif // (_WIN32_IE >= 0x0500) int nNextBtn; for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--) { if(nNextBtn < 0) nNextBtn = ::GetMenuItemCount(m_hMenu) - 1; TBBUTTON tbb = { 0 }; GetButton(nNextBtn, &tbb); #if (_WIN32_IE >= 0x0500) RECT rcBtn = { 0 }; GetItemRect(nNextBtn, &rcBtn); if(rcBtn.right > rcClient.right) { nNextBtn = -2; // chevron break; } #endif // (_WIN32_IE >= 0x0500) if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) break; } return (nNextBtn != nBtn) ? nNextBtn : -1; } int GetNextMenuItem(int nBtn) const { if(nBtn == -1) return -1; #if (_WIN32_IE >= 0x0500) RECT rcClient = { 0 }; GetClientRect(&rcClient); #endif // (_WIN32_IE >= 0x0500) int nNextBtn = 0; int nCount = ::GetMenuItemCount(m_hMenu); for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++) { if(nNextBtn >= nCount) nNextBtn = 0; TBBUTTON tbb = { 0 }; GetButton(nNextBtn, &tbb); #if (_WIN32_IE >= 0x0500) RECT rcBtn = { 0 }; GetItemRect(nNextBtn, &rcBtn); if(rcBtn.right > rcClient.right) { nNextBtn = -2; // chevron break; } #endif // (_WIN32_IE >= 0x0500) if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0) break; } return (nNextBtn != nBtn) ? nNextBtn : -1; } #if (_WIN32_IE >= 0x0500) bool DisplayChevronMenu() { // assume we are in a rebar HWND hWndReBar = GetParent(); int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); bool bRet = false; for(int i = 0; i < nCount; i++) { REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE }; BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi); if(bRetBandInfo && rbbi.hwndChild == m_hWnd) { if((rbbi.fStyle & RBBS_USECHEVRON) != 0) { ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L); PostMessage(WM_KEYDOWN, VK_DOWN, 0L); bRet = true; } break; } } return bRet; } #endif // (_WIN32_IE >= 0x0500) void GetSystemSettings() { // refresh our font NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); ATLASSERT(bRet); if(bRet) { LOGFONT logfont = { 0 }; if(m_fontMenu.m_hFont != NULL) m_fontMenu.GetLogFont(logfont); if(logfont.lfHeight != info.lfMenuFont.lfHeight || logfont.lfWidth != info.lfMenuFont.lfWidth || logfont.lfEscapement != info.lfMenuFont.lfEscapement || logfont.lfOrientation != info.lfMenuFont.lfOrientation || logfont.lfWeight != info.lfMenuFont.lfWeight || logfont.lfItalic != info.lfMenuFont.lfItalic || logfont.lfUnderline != info.lfMenuFont.lfUnderline || logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut || logfont.lfCharSet != info.lfMenuFont.lfCharSet || logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision || logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision || logfont.lfQuality != info.lfMenuFont.lfQuality || logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily || lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0) { HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont); ATLASSERT(hFontMenu != NULL); if(hFontMenu != NULL) { if(m_fontMenu.m_hFont != NULL) m_fontMenu.DeleteObject(); m_fontMenu.Attach(hFontMenu); SetFont(m_fontMenu); AddStrings(_T("NS\0")); // for proper item height AutoSize(); } } } // check if we need extra spacing for menu item text CWindowDC dc(m_hWnd); HFONT hFontOld = dc.SelectFont(m_fontMenu); RECT rcText = { 0 }; dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); if((rcText.right - rcText.left) < 4) { ::SetRectEmpty(&rcText); dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT); m_cxExtraSpacing = rcText.right - rcText.left; } else { m_cxExtraSpacing = 0; } dc.SelectFont(hFontOld); // get Windows version #ifndef _versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; ::GetVersionEx(&ovi); #endif // !_versionhelpers_H_INCLUDED_ // query keyboard cues mode (Windows 2000 or later) #ifdef _versionhelpers_H_INCLUDED_ if(::IsWindowsVersionOrGreater(5, 0, 0)) #else // !_versionhelpers_H_INCLUDED_ if (ovi.dwMajorVersion >= 5) #endif // _versionhelpers_H_INCLUDED_ { #ifndef SPI_GETKEYBOARDCUES const UINT SPI_GETKEYBOARDCUES = 0x100A; #endif // !SPI_GETKEYBOARDCUES BOOL bRetVal = TRUE; bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0); m_bUseKeyboardCues = (bRet && !bRetVal); m_bAllowKeyboardCues = true; ShowKeyboardCues(!m_bUseKeyboardCues); } // query flat menu mode (Windows XP or later) #ifdef _versionhelpers_H_INCLUDED_ if(::IsWindowsXPOrGreater()) #else // !_versionhelpers_H_INCLUDED_ if ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) #endif // _versionhelpers_H_INCLUDED_ { #ifndef SPI_GETFLATMENU const UINT SPI_GETFLATMENU = 0x1022; #endif // !SPI_GETFLATMENU BOOL bRetVal = FALSE; bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0); m_bFlatMenus = (bRet && bRetVal); } #if _WTL_CMDBAR_VISTA_MENUS // check if we should use Vista menus bool bVistaMenus = (((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0) && RunTimeHelper::IsVista() && RunTimeHelper::IsThemeAvailable()); if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0)) { T* pT = static_cast(this); pT->_RemoveVistaBitmapsFromMenu(); } m_bVistaMenus = bVistaMenus; #endif // _WTL_CMDBAR_VISTA_MENUS #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"), m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false"); #endif } // Implementation - alternate focus mode support void TakeFocus() { if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL) m_hWndFocus = ::GetFocus(); SetFocus(); } void GiveFocusBack() { if(m_bParentActive) { if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus)) ::SetFocus(m_hWndFocus); else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow()) m_wndParent.SetFocus(); } m_hWndFocus = NULL; SetAnchorHighlight(FALSE); if(m_bUseKeyboardCues && m_bShowKeyboardCues) ShowKeyboardCues(false); m_bSkipPostDown = false; } void ShowKeyboardCues(bool bShow) { m_bShowKeyboardCues = bShow; SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX); Invalidate(); UpdateWindow(); } // Implementation - internal message helpers static UINT GetAutoPopupMessage() { static UINT uAutoPopupMessage = 0; if(uAutoPopupMessage == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n")); ATLASSERT(FALSE); return 0; } if(uAutoPopupMessage == 0) uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg")); lock.Unlock(); } ATLASSERT(uAutoPopupMessage != 0); return uAutoPopupMessage; } static UINT GetGetBarMessage() { static UINT uGetBarMessage = 0; if(uGetBarMessage == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n")); ATLASSERT(FALSE); return 0; } if(uGetBarMessage == 0) uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg")); lock.Unlock(); } ATLASSERT(uGetBarMessage != 0); return uGetBarMessage; } // Implementation bool CreateInternalImageList(int cImages) { UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK; m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1); ATLASSERT(m_hImageList != NULL); return (m_hImageList != NULL); } // Implementation - support for Vista menus #if _WTL_CMDBAR_VISTA_MENUS void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount) { // Create display compatible memory DC CClientDC dc(NULL); CDC dcMem; dcMem.CreateCompatibleDC(dc); HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); T* pT = static_cast(this); // Create bitmaps for all menu items for(int i = 0; i < nCount; i++) { HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, dc, dcMem); dcMem.SelectBitmap(hBitmapSave); m_arrVistaBitmap.Add(hBitmap); } } void _AddVistaBitmapFromImageList(int nIndex) { // Create display compatible memory DC CClientDC dc(NULL); CDC dcMem; dcMem.CreateCompatibleDC(dc); HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); // Create bitmap for menu item T* pT = static_cast(this); HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem); // Select saved bitmap back and add bitmap to the array dcMem.SelectBitmap(hBitmapSave); m_arrVistaBitmap.Add(hBitmap); } void _ReplaceVistaBitmapFromImageList(int nIndex) { // Delete existing bitmap if(m_arrVistaBitmap[nIndex] != NULL) ::DeleteObject(m_arrVistaBitmap[nIndex]); // Create display compatible memory DC CClientDC dc(NULL); CDC dcMem; dcMem.CreateCompatibleDC(dc); HBITMAP hBitmapSave = dcMem.GetCurrentBitmap(); // Create bitmap for menu item T* pT = static_cast(this); HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem); // Select saved bitmap back and replace bitmap in the array dcMem.SelectBitmap(hBitmapSave); m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap); } HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget) { // Create 32-bit bitmap BITMAPINFO bi = { 0 }; bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = m_szBitmap.cx; bi.bmiHeader.biHeight = m_szBitmap.cy; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = 0; bi.bmiHeader.biXPelsPerMeter = 0; bi.bmiHeader.biYPelsPerMeter = 0; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0); ATLASSERT(hBitmap != NULL); // Select bitmap into target DC and draw from image list to it if(hBitmap != NULL) { ::SelectObject(hDCTarget, hBitmap); IMAGELISTDRAWPARAMS ildp = { 0 }; ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS); ildp.himl = m_hImageList; ildp.i = nIndex; ildp.hdcDst = hDCTarget; ildp.x = 0; ildp.y = 0; ildp.cx = 0; ildp.cy = 0; ildp.xBitmap = 0; ildp.yBitmap = 0; ildp.fStyle = ILD_TRANSPARENT; ildp.fState = ILS_ALPHA; ildp.Frame = 255; ::ImageList_DrawIndirect(&ildp); } return hBitmap; } void _RemoveVistaBitmapsFromMenu() { CMenuHandle menu = m_hMenu; for(int i = 0; i < m_arrCommand.GetSize(); i++) { CMenuItemInfo mii; mii.fMask = MIIM_BITMAP; mii.hbmpItem = NULL; menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii); } } #endif // _WTL_CMDBAR_VISTA_MENUS }; class CCommandBarCtrl : public CCommandBarCtrlImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName()) }; /////////////////////////////////////////////////////////////////////////////// // CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps template class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits> { public: // Data members ATL::CContainedWindow m_wndMDIClient; bool m_bChildMaximized; HWND m_hWndChildMaximized; HICON m_hIconChildMaximized; int m_nBtnPressed; int m_nBtnWasPressed; int m_cxyOffset; // offset between nonclient elements int m_cxIconWidth; // small icon width int m_cyIconHeight; // small icon height int m_cxBtnWidth; // nonclient button width int m_cyBtnHeight; // nonclient button height int m_cxLeft; // left nonclient area width int m_cxRight; // right nonclient area width // Theme declarations and data members #ifndef _WTL_NO_AUTO_THEME #ifndef _UXTHEME_H_ typedef HANDLE HTHEME; #endif // !_UXTHEME_H_ typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList); typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme); typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc); HMODULE m_hThemeDLL; HTHEME m_hTheme; PFN_DrawThemeBackground m_pfnDrawThemeBackground; PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground; #endif // !_WTL_NO_AUTO_THEME // Constructor/destructor CMDICommandBarCtrlImpl() : m_wndMDIClient(this, 2), m_bChildMaximized(false), m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL), m_nBtnPressed(-1), m_nBtnWasPressed(-1), #ifndef _WTL_NO_AUTO_THEME m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL), #endif // !_WTL_NO_AUTO_THEME m_cxyOffset(2), m_cxIconWidth(16), m_cyIconHeight(16), m_cxBtnWidth(16), m_cyBtnHeight(14), m_cxLeft(20), m_cxRight(55) { } ~CMDICommandBarCtrlImpl() { if(m_wndMDIClient.IsWindow()) /*scary!*/ m_wndMDIClient.UnsubclassWindow(); } // Operations BOOL SetMDIClient(HWND hWndMDIClient) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(::IsWindow(hWndMDIClient)); if(!::IsWindow(hWndMDIClient)) return FALSE; #ifdef _DEBUG // BLOCK: Test if the passed window is MDICLIENT { LPCTSTR lpszMDIClientClass = _T("MDICLIENT"); const int nNameLen = 9 + 1; // "MDICLIENT" + NULL TCHAR szClassName[nNameLen] = { 0 }; ::GetClassName(hWndMDIClient, szClassName, nNameLen); ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0); } #endif // _DEBUG if(m_wndMDIClient.IsWindow()) /*scary!*/ m_wndMDIClient.UnsubclassWindow(); return m_wndMDIClient.SubclassWindow(hWndMDIClient); } // Message maps typedef CCommandBarCtrlImpl< T, TBase, TWinTraits > _baseClass; BEGIN_MSG_MAP(CMDICommandBarCtrlImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) #ifndef _WTL_NO_AUTO_THEME MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged) #endif // !_WTL_NO_AUTO_THEME MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) CHAIN_MSG_MAP(_baseClass) ALT_MSG_MAP(1) // Parent window messages MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate) CHAIN_MSG_MAP_ALT(_baseClass, 1) ALT_MSG_MAP(2) // MDI client window messages MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) // no chaining needed since this was moved from the base class here ALT_MSG_MAP(3) // Message hook messages MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages) CHAIN_MSG_MAP_ALT(_baseClass, 3) END_MSG_MAP() // Additional MDI message handlers LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled); if(lRet == (LRESULT)-1) return lRet; #ifndef _WTL_NO_AUTO_THEME // this will fail if theming is not supported m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); if(m_hThemeDLL != NULL) { m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground"); ATLASSERT(m_pfnDrawThemeBackground != NULL); if(m_pfnDrawThemeBackground != NULL) { T* pT = static_cast(this); pT->_OpenThemeData(); } else { ::FreeLibrary(m_hThemeDLL); m_hThemeDLL = NULL; } m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground"); ATLASSERT(m_pfnDrawThemeParentBackground != NULL); } #endif // !_WTL_NO_AUTO_THEME return lRet; } LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled); #ifndef _WTL_NO_AUTO_THEME if(m_hThemeDLL != NULL) { T* pT = static_cast(this); pT->_CloseThemeData(); ::FreeLibrary(m_hThemeDLL); m_hThemeDLL = NULL; } #endif // !_WTL_NO_AUTO_THEME return lRet; } #ifndef _WTL_NO_AUTO_THEME LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_hThemeDLL != NULL) { T* pT = static_cast(this); pT->_CloseThemeData(); pT->_OpenThemeData(); } return 0; } #endif // !_WTL_NO_AUTO_THEME LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); T* pT = static_cast(this); pT->_AdjustBtnSize(GET_Y_LPARAM(lParam)); return lRet; } LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(m_bChildMaximized && (BOOL)wParam) { LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam; if(m_bLayoutRTL) { lpParams->rgrc[0].left += m_cxRight; lpParams->rgrc[0].right -= m_cxLeft; } else { lpParams->rgrc[0].left += m_cxLeft; lpParams->rgrc[0].right -= m_cxRight; } } return lRet; } LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(!m_bChildMaximized) return lRet; ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL); // get DC and window rectangle CWindowDC dc(m_hWnd); RECT rect = { 0 }; GetWindowRect(&rect); int cxWidth = rect.right - rect.left; int cyHeight = rect.bottom - rect.top; // paint left side nonclient background and draw icon ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight); #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) { if(m_pfnDrawThemeParentBackground != NULL) m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); else dc.FillRect(&rect, COLOR_WINDOW); } else #endif // !_WTL_NO_AUTO_THEME { if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) dc.FillRect(&rect, COLOR_3DFACE); else dc.FillRect(&rect, COLOR_MENU); } RECT rcIcon = { 0 }; T* pT = static_cast(this); pT->_CalcIconRect(cxWidth, cyHeight, rcIcon); dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight); // paint right side nonclient background ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight); #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) { if(m_pfnDrawThemeParentBackground != NULL) { // this is to account for the left non-client area POINT ptOrg = { 0, 0 }; dc.GetViewportOrg(&ptOrg); dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y); ::OffsetRect(&rect, -m_cxLeft, 0); m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect); // restore dc.SetViewportOrg(ptOrg); ::OffsetRect(&rect, m_cxLeft, 0); } else { dc.FillRect(&rect, COLOR_3DFACE); } } else #endif // !_WTL_NO_AUTO_THEME { if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0) dc.FillRect(&rect, COLOR_3DFACE); else dc.FillRect(&rect, COLOR_MENU); } // draw buttons RECT arrRect[3] = { 0 }; pT->_CalcBtnRects(cxWidth, cyHeight, arrRect); pT->_DrawMDIButton(dc, arrRect, -1); // draw all buttons return lRet; } LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(m_bChildMaximized) { RECT rect = { 0 }; GetWindowRect(&rect); POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top }; if(m_bLayoutRTL) { if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft))) lRet = HTBORDER; } else { if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight))) lRet = HTBORDER; } } return lRet; } LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(!m_bChildMaximized) { bHandled = FALSE; return 1; } ATLASSERT(_DebugCheckChild()); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; RECT rect = { 0 }; GetWindowRect(&rect); pt.x -= rect.left; pt.y -= rect.top; RECT rcIcon = { 0 }; T* pT = static_cast(this); pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); RECT arrRect[3] = { 0 }; pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); if(::PtInRect(&rcIcon, pt)) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n")); #endif #ifndef TPM_VERPOSANIMATION const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag #endif CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized); // eat next message if click is on the same button ::OffsetRect(&rcIcon, rect.left, rect.top); MSG msg = { 0 }; if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt)) ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE); if(uRet != 0) ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L); } else if(::PtInRect(&arrRect[0], pt)) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n")); #endif m_nBtnWasPressed = m_nBtnPressed = 0; } else if(::PtInRect(&arrRect[1], pt)) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n")); #endif m_nBtnWasPressed = m_nBtnPressed = 1; } else if(::PtInRect(&arrRect[2], pt)) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n")); #endif m_nBtnWasPressed = m_nBtnPressed = 2; } else { bHandled = FALSE; } // draw the button state if it was pressed if(m_nBtnPressed != -1) { SetCapture(); CWindowDC dc(m_hWnd); pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed); } return 0; } LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) { bHandled = FALSE; return 1; } POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ClientToScreen(&pt); RECT rect = { 0 }; GetWindowRect(&rect); pt.x -= rect.left; pt.y -= rect.top; RECT arrRect[3] = { 0 }; T* pT = static_cast(this); pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); int nOldBtnPressed = m_nBtnPressed; m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1; if(nOldBtnPressed != m_nBtnPressed) { CWindowDC dc(m_hWnd); pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed); } return 0; } LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1) { bHandled = FALSE; return 1; } ATLASSERT(_DebugCheckChild()); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ClientToScreen(&pt); RECT rect = { 0 }; GetWindowRect(&rect); pt.x -= rect.left; pt.y -= rect.top; int nBtn = m_nBtnWasPressed; ReleaseCapture(); RECT arrRect[3] = { 0 }; T* pT = static_cast(this); pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); if(::PtInRect(&arrRect[nBtn], pt)) { switch(nBtn) { case 0: // close #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n")); #endif ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L); break; case 1: // restore #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n")); #endif ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L); break; case 2: // minimize #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n")); #endif ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L); break; default: break; } } return 0; } LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(!m_bChildMaximized || m_nBtnWasPressed != -1) { bHandled = FALSE; return 1; } ATLASSERT(_DebugCheckChild()); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; RECT rect = { 0 }; GetWindowRect(&rect); pt.x -= rect.left; pt.y -= rect.top; RECT rcIcon = { 0 }; T* pT = static_cast(this); pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL); RECT arrRect[3] = { 0 }; pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL); if(::PtInRect(&rcIcon, pt)) { CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE); UINT uDefID = menu.GetMenuDefaultItem(); if(uDefID == (UINT)-1) uDefID = SC_CLOSE; ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L); } return 0; } LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bChildMaximized) { if(m_nBtnPressed != -1) { ATLASSERT(m_nBtnPressed == m_nBtnWasPressed); // must be m_nBtnPressed = -1; RECT rect = { 0 }; GetWindowRect(&rect); RECT arrRect[3] = { 0 }; T* pT = static_cast(this); pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect); CWindowDC dc(m_hWnd); pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed); } m_nBtnWasPressed = -1; } else { bHandled = FALSE; } return 0; } // Parent window message handlers LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { m_bParentActive = (LOWORD(wParam) != WA_INACTIVE); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW); bHandled = FALSE; return 1; } // MDI client window message handlers LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam); HMENU hOldMenu = GetMenu(); BOOL bRet = AttachMenu((HMENU)wParam); bRet; // avoid level 4 warning ATLASSERT(bRet); #if (_WIN32_IE >= 0x0400) T* pT = static_cast(this); pT->UpdateRebarBandIdealSize(); #endif // (_WIN32_IE >= 0x0400) return (LRESULT)hOldMenu; } // All messages from the message hook LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->_ProcessAllHookMessages(uMsg, wParam, lParam); bHandled = FALSE; return 1; } // Overrideables // override this to provide different ideal size void UpdateRebarBandIdealSize() { // assuming we are in a rebar, change ideal size to our size // we hope that if we are not in a rebar, nCount will be 0 int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); for(int i = 0; i < nCount; i++) { REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); if(rbi.hwndChild == m_hWnd) { rbi.fMask = RBBIM_IDEALSIZE; rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0; int nBtnCount = GetButtonCount(); if(nBtnCount > 0) { RECT rect = { 0 }; GetItemRect(nBtnCount - 1, &rect); rbi.cxIdeal += rect.right; } ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); break; } } } // all hook messages - check for the maximized MDI child window change void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/) { if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU) return; BOOL bMaximized = FALSE; HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); bool bMaxOld = m_bChildMaximized; m_bChildMaximized = (hWndChild != NULL && bMaximized); HICON hIconOld = m_hIconChildMaximized; if(m_bChildMaximized) { if(m_hWndChildMaximized != hWndChild) { ATL::CWindow wnd = m_hWndChildMaximized = hWndChild; m_hIconChildMaximized = wnd.GetIcon(FALSE); if(m_hIconChildMaximized == NULL) { m_hIconChildMaximized = wnd.GetIcon(TRUE); if(m_hIconChildMaximized == NULL) { // no icon set with WM_SETICON, get the class one // need conditional code because types don't match in winuser.h #ifdef _WIN64 m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM); #else m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM)); #endif } } } } else { m_hWndChildMaximized = NULL; m_hIconChildMaximized = NULL; } if(bMaxOld != m_bChildMaximized) { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false"); #endif // assuming we are in a rebar, change our size to accomodate new state // we hope that if we are not in a rebar, nCount will be 0 int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L); int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight); for(int i = 0; i < nCount; i++) { #if (_WIN32_IE >= 0x0500) REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE }; ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); if(rbi.hwndChild == m_hWnd) { if((rbi.fStyle & RBBS_USECHEVRON) != 0) { rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; rbi.cxMinChild += cxDiff; rbi.cxIdeal += cxDiff; ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); } break; } #elif (_WIN32_IE >= 0x0400) REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE }; ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); if(rbi.hwndChild == m_hWnd) { rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE; rbi.cxMinChild += cxDiff; rbi.cxIdeal += cxDiff; ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); break; } #else // (_WIN32_IE < 0x0400) REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE }; ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi); if(rbi.hwndChild == m_hWnd) { rbi.fMask = RBBIM_CHILDSIZE; rbi.cxMinChild += cxDiff; ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi); break; } #endif // (_WIN32_IE < 0x0400) } } if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized) { // force size change and redraw everything RECT rect = { 0 }; GetWindowRect(&rect); ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2); SetRedraw(FALSE); SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE); SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW); } } // Implementation void GetSystemSettings() { #ifdef _CMDBAR_EXTRA_TRACE ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n")); #endif _baseClass::GetSystemSettings(); NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0); ATLASSERT(bRet); if(bRet) { m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON); m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON); m_cxLeft = m_cxIconWidth; #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) { m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset; m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; m_cxRight = 3 * m_cxBtnWidth; } else #endif // !_WTL_NO_AUTO_THEME { m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset; m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset; m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; } } RECT rect = { 0 }; GetClientRect(&rect); T* pT = static_cast(this); pT->_AdjustBtnSize(rect.bottom); } void _AdjustBtnSize(int cyHeight) { if(cyHeight > 1 && m_cyBtnHeight > cyHeight) { #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) { m_cyBtnHeight = cyHeight; m_cxBtnWidth = cyHeight; m_cxRight = 3 * m_cxBtnWidth; } else #endif // !_WTL_NO_AUTO_THEME { m_cyBtnHeight = cyHeight; m_cxBtnWidth = cyHeight + m_cxyOffset; m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset; } } } void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const { int xStart = (m_cxLeft - m_cxIconWidth) / 2; if(xStart < 0) xStart = 0; int yStart = (cyHeight - m_cyIconHeight) / 2; if(yStart < 0) yStart = 0; if(bInvertX) ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight); else ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight); } void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const { int yStart = (cyHeight - m_cyBtnHeight) / 2; if(yStart < 0) yStart = 0; RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight }; int nDirection = -1; if(bInvertX) { ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight); nDirection = 1; } arrRect[0] = rcBtn; #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); else #endif // !_WTL_NO_AUTO_THEME ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0); arrRect[1] = rcBtn; ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0); arrRect[2] = rcBtn; } void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn) { #ifndef _WTL_NO_AUTO_THEME if(m_hTheme != NULL) { #if !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__) const int WP_MDICLOSEBUTTON = 20; const int CBS_NORMAL = 1; const int CBS_PUSHED = 3; const int CBS_DISABLED = 4; const int WP_MDIRESTOREBUTTON = 22; const int RBS_NORMAL = 1; const int RBS_PUSHED = 3; const int RBS_DISABLED = 4; const int WP_MDIMINBUTTON = 16; const int MINBS_NORMAL = 1; const int MINBS_PUSHED = 3; const int MINBS_DISABLED = 4; #endif // !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__) if(nBtn == -1 || nBtn == 0) m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL); if(nBtn == -1 || nBtn == 1) m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL); if(nBtn == -1 || nBtn == 2) m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL); } else #endif // !_WTL_NO_AUTO_THEME { if(nBtn == -1 || nBtn == 0) dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0)); if(nBtn == -1 || nBtn == 1) dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0)); if(nBtn == -1 || nBtn == 2) dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0)); } } #ifndef _WTL_NO_AUTO_THEME static UINT _GetThemeChangedMsg() { #ifndef WM_THEMECHANGED static const UINT WM_THEMECHANGED = 0x031A; #endif // !WM_THEMECHANGED return WM_THEMECHANGED; } void _OpenThemeData() { ATLASSERT(m_hThemeDLL != NULL); PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData"); ATLASSERT(pfnOpenThemeData != NULL); if(pfnOpenThemeData != NULL) m_hTheme = pfnOpenThemeData(m_hWnd, L"Window"); } void _CloseThemeData() { ATLASSERT(m_hThemeDLL != NULL); if(m_hTheme == NULL) return; // nothing to do PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData"); ATLASSERT(pfnCloseThemeData != NULL); if(pfnCloseThemeData != NULL) { pfnCloseThemeData(m_hTheme); m_hTheme = NULL; } } #endif // !_WTL_NO_AUTO_THEME bool _DebugCheckChild() { #ifdef _DEBUG BOOL bMaximized = FALSE; HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); return (bMaximized && hWndChild == m_hWndChildMaximized); #else // !_DEBUG return true; #endif // !_DEBUG } }; class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName()) }; }; // namespace WTL #endif // __ATLCTRLW_H__ ================================================ FILE: WTL/atlctrlx.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLCTRLX_H__ #define __ATLCTRLX_H__ #pragma once #ifndef __ATLAPP_H__ #error atlctrlx.h requires atlapp.h to be included first #endif #ifndef __ATLCTRLS_H__ #error atlctrlx.h requires atlctrls.h to be included first #endif #ifndef WM_UPDATEUISTATE #define WM_UPDATEUISTATE 0x0128 #endif // !WM_UPDATEUISTATE /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CBitmapButtonImpl // CBitmapButton // CCheckListViewCtrlImpl // CCheckListViewCtrl // CHyperLinkImpl // CHyperLink // CWaitCursor // CCustomWaitCursor // CMultiPaneStatusBarCtrlImpl // CMultiPaneStatusBarCtrl // CPaneContainerImpl // CPaneContainer // CSortListViewImpl // CSortListViewCtrlImpl // CSortListViewCtrl // CTabViewImpl // CTabView namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CBitmapButton - bitmap button implementation #ifndef _WIN32_WCE // bitmap button extended styles #define BMPBTN_HOVER 0x00000001 #define BMPBTN_AUTO3D_SINGLE 0x00000002 #define BMPBTN_AUTO3D_DOUBLE 0x00000004 #define BMPBTN_AUTOSIZE 0x00000008 #define BMPBTN_SHAREIMAGELISTS 0x00000010 #define BMPBTN_AUTOFIRE 0x00000020 #define BMPBTN_CHECK 0x00000040 #define BMPBTN_AUTOCHECK 0x00000080 // Note: BMPBTN_CHECK/BMPBTN_AUTOCHECK disables BN_DOUBLECLICKED, // BMPBTN_AUTOFIRE doesn't work with BMPBTN_CHECK/BMPBTN_AUTOCHECK template class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > { public: DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) enum { _nImageNormal = 0, _nImagePushed, _nImageFocusOrHover, _nImageDisabled, _nImageCount = 4, }; enum { ID_TIMER_FIRST = 1000, ID_TIMER_REPEAT = 1001 }; // Bitmap button specific extended styles DWORD m_dwExtendedStyle; CImageList m_ImageList; int m_nImage[_nImageCount]; CToolTipCtrl m_tip; LPTSTR m_lpstrToolTipText; // Internal states unsigned m_fMouseOver:1; unsigned m_fFocus:1; unsigned m_fPressed:1; unsigned m_fChecked:1; // Constructor/Destructor CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : m_dwExtendedStyle(dwExtendedStyle), m_ImageList(hImageList), m_lpstrToolTipText(NULL), m_fMouseOver(0), m_fFocus(0), m_fPressed(0), m_fChecked(0) { m_nImage[_nImageNormal] = -1; m_nImage[_nImagePushed] = -1; m_nImage[_nImageFocusOrHover] = -1; m_nImage[_nImageDisabled] = -1; #ifdef _DEBUG if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode()) ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n")); #endif // _DEBUG } ~CBitmapButtonImpl() { if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0) m_ImageList.Destroy(); delete [] m_lpstrToolTipText; } // overridden to provide proper initialization BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->Init(); } return bRet; } // Attributes DWORD GetBitmapButtonExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); #ifdef _DEBUG if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode()) ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n")); #endif // _DEBUG return dwPrevStyle; } HIMAGELIST GetImageList() const { return m_ImageList; } HIMAGELIST SetImageList(HIMAGELIST hImageList) { HIMAGELIST hImageListPrev = m_ImageList; m_ImageList = hImageList; if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd)) SizeToImage(); return hImageListPrev; } int GetToolTipTextLength() const { return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText); } bool GetToolTipText(LPTSTR lpstrText, int nLength) const { ATLASSERT(lpstrText != NULL); if(m_lpstrToolTipText == NULL) return false; errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE); return (nRet == 0 || nRet == STRUNCATE); } bool SetToolTipText(LPCTSTR lpstrText) { if(m_lpstrToolTipText != NULL) { delete [] m_lpstrToolTipText; m_lpstrToolTipText = NULL; } if(lpstrText == NULL) { if(m_tip.IsWindow()) m_tip.Activate(FALSE); return true; } int cchLen = lstrlen(lpstrText) + 1; ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]); if(m_lpstrToolTipText == NULL) return false; SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText); if(m_tip.IsWindow()) { m_tip.Activate(TRUE); m_tip.AddTool(m_hWnd, m_lpstrToolTipText); } return true; } bool GetCheck() const { return (m_fChecked == 1); } void SetCheck(bool bCheck, bool bUpdate = true) { m_fChecked = bCheck ? 1 : 0; if(bUpdate) { Invalidate(); UpdateWindow(); } } // Operations void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1) { if(nNormal != -1) m_nImage[_nImageNormal] = nNormal; if(nPushed != -1) m_nImage[_nImagePushed] = nPushed; if(nFocusOrHover != -1) m_nImage[_nImageFocusOrHover] = nFocusOrHover; if(nDisabled != -1) m_nImage[_nImageDisabled] = nDisabled; } BOOL SizeToImage() { ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL); int cx = 0; int cy = 0; if(!m_ImageList.GetIconSize(cx, cy)) return FALSE; return ResizeClient(cx, cy); } // Overrideables void DoPaint(CDCHandle dc) { ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set ATLASSERT(m_nImage[0] != -1); // main bitmap must be set // set bitmap according to the current button state bool bHover = IsHoverMode(); bool bPressed = (m_fPressed == 1) || (IsCheckMode() && (m_fChecked == 1)); int nImage = -1; if(!IsWindowEnabled()) nImage = m_nImage[_nImageDisabled]; else if(bPressed) nImage = m_nImage[_nImagePushed]; else if((!bHover && (m_fFocus == 1)) || (bHover && (m_fMouseOver == 1))) nImage = m_nImage[_nImageFocusOrHover]; // if none is set, use default one if(nImage == -1) nImage = m_nImage[_nImageNormal]; // draw the button image bool bAuto3D = (m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0; int xyPos = (bPressed && bAuto3D && (m_nImage[_nImagePushed] == -1)) ? 1 : 0; m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL); // draw 3D border if required if(bAuto3D) { RECT rect = { 0 }; GetClientRect(&rect); if(bPressed) dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT); else if(!bHover || (m_fMouseOver == 1)) dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT); if(!bHover && (m_fFocus == 1)) { ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE)); dc.DrawFocusRect(&rect); } } } // Message map and handlers BEGIN_MSG_MAP(CBitmapButtonImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) MESSAGE_HANDLER(WM_ENABLE, OnEnable) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) MESSAGE_HANDLER(WM_TIMER, OnTimer) MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->Init(); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_tip.IsWindow()) { m_tip.DestroyWindow(); m_tip.m_hWnd = NULL; } bHandled = FALSE; return 1; } LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { MSG msg = { m_hWnd, uMsg, wParam, lParam }; if(m_tip.IsWindow()) m_tip.RelayEvent(&msg); bHandled = FALSE; return 1; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background needed } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if(wParam != NULL) { pT->DoPaint((HDC)wParam); } else { CPaintDC dc(m_hWnd); pT->DoPaint(dc.m_hDC); } return 0; } LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0; Invalidate(); UpdateWindow(); bHandled = FALSE; return 1; } LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = 0; if(IsHoverMode()) SetCapture(); else lRet = DefWindowProc(uMsg, wParam, lParam); if(::GetCapture() == m_hWnd) { m_fPressed = 1; Invalidate(); UpdateWindow(); } if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && !IsCheckMode()) { int nElapse = 250; int nDelay = 0; if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0)) nElapse += nDelay * 250; // all milli-seconds SetTimer(ID_TIMER_FIRST, nElapse); } return lRet; } LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = 0; if(!IsHoverMode() && !IsCheckMode()) lRet = DefWindowProc(uMsg, wParam, lParam); if(::GetCapture() != m_hWnd) SetCapture(); if(m_fPressed == 0) { m_fPressed = 1; Invalidate(); UpdateWindow(); } return lRet; } LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if(((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) && (m_fPressed == 1)) SetCheck(!GetCheck(), false); LRESULT lRet = 0; if(!IsHoverMode() && !IsCheckMode()) lRet = DefWindowProc(uMsg, wParam, lParam); if(::GetCapture() == m_hWnd) { if((IsHoverMode() || IsCheckMode()) && (m_fPressed == 1)) ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); ::ReleaseCapture(); } return lRet; } LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_fPressed == 1) { m_fPressed = 0; Invalidate(); UpdateWindow(); } bHandled = FALSE; return 1; } LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { Invalidate(); UpdateWindow(); bHandled = FALSE; return 1; } LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(::GetCapture() == m_hWnd) { POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ClientToScreen(&ptCursor); RECT rect = { 0 }; GetWindowRect(&rect); unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0; if(m_fPressed != uPressed) { m_fPressed = uPressed; Invalidate(); UpdateWindow(); } } else if(IsHoverMode() && m_fMouseOver == 0) { m_fMouseOver = 1; Invalidate(); UpdateWindow(); StartTrackMouseLeave(); } bHandled = FALSE; return 1; } LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_fMouseOver == 1) { m_fMouseOver = 0; Invalidate(); UpdateWindow(); } return 0; } LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam == VK_SPACE && IsHoverMode()) return 0; // ignore if in hover mode if(wParam == VK_SPACE && m_fPressed == 0) { m_fPressed = 1; Invalidate(); UpdateWindow(); } bHandled = FALSE; return 1; } LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam == VK_SPACE && IsHoverMode()) return 0; // ignore if in hover mode if(wParam == VK_SPACE && m_fPressed == 1) { m_fPressed = 0; if((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) SetCheck(!GetCheck(), false); Invalidate(); UpdateWindow(); } bHandled = FALSE; return 1; } LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0); switch(wParam) // timer ID { case ID_TIMER_FIRST: KillTimer(ID_TIMER_FIRST); if(m_fPressed == 1) { ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); int nElapse = 250; int nRepeat = 40; if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0)) nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated SetTimer(ID_TIMER_REPEAT, nElapse); } break; case ID_TIMER_REPEAT: if(m_fPressed == 1) ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); else if(::GetCapture() != m_hWnd) KillTimer(ID_TIMER_REPEAT); break; default: // not our timer break; } return 0; } LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // If the control is subclassed or superclassed, this message can cause // repainting without WM_PAINT. We don't use this state, so just do nothing. return 0; } // Implementation void Init() { // We need this style to prevent Windows from painting the button ModifyStyle(0, BS_OWNERDRAW); // create a tool tip m_tip.Create(m_hWnd); ATLASSERT(m_tip.IsWindow()); if(m_tip.IsWindow() && m_lpstrToolTipText != NULL) { m_tip.Activate(TRUE); m_tip.AddTool(m_hWnd, m_lpstrToolTipText); } if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0) SizeToImage(); } BOOL StartTrackMouseLeave() { TRACKMOUSEEVENT tme = { 0 }; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = m_hWnd; return _TrackMouseEvent(&tme); } bool IsHoverMode() const { return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0); } bool IsCheckMode() const { return ((m_dwExtendedStyle & (BMPBTN_CHECK | BMPBTN_AUTOCHECK)) != 0); } }; class CBitmapButton : public CBitmapButtonImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName()) CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : CBitmapButtonImpl(dwExtendedStyle, hImageList) { } }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CCheckListCtrlView - list view control with check boxes template class CCheckListViewCtrlImplTraits { public: static DWORD GetWndStyle(DWORD dwStyle) { return (dwStyle == 0) ? t_dwStyle : dwStyle; } static DWORD GetWndExStyle(DWORD dwExStyle) { return (dwExStyle == 0) ? t_dwExStyle : dwExStyle; } static DWORD GetExtendedLVStyle() { return t_dwExListViewStyle; } }; typedef CCheckListViewCtrlImplTraits CCheckListViewCtrlTraits; template class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl { public: DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) // Attributes static DWORD GetExtendedLVStyle() { return TWinTraits::GetExtendedLVStyle(); } // Operations BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->Init(); } return bRet; } void CheckSelectedItems(int nCurrItem) { // first check if this item is selected LVITEM lvi = { 0 }; lvi.iItem = nCurrItem; lvi.iSubItem = 0; lvi.mask = LVIF_STATE; lvi.stateMask = LVIS_SELECTED; GetItem(&lvi); // if item is not selected, don't do anything if(!(lvi.state & LVIS_SELECTED)) return; // new check state will be reverse of the current state, BOOL bCheck = !GetCheckState(nCurrItem); int nItem = -1; int nOldItem = -1; while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1) { if(nItem != nCurrItem) SetCheckState(nItem, bCheck); nOldItem = nItem; } } // Implementation void Init() { T* pT = static_cast(this); pT; // avoid level 4 warning ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); SetExtendedListViewStyle(pT->GetExtendedLVStyle()); } // Message map and handlers BEGIN_MSG_MAP(CCheckListViewCtrlImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { // first let list view control initialize everything LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(lRet == 0) { T* pT = static_cast(this); pT->Init(); } return lRet; } LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; LVHITTESTINFO lvh = { 0 }; lvh.pt = ptMsg; if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0) { T* pT = static_cast(this); pT->CheckSelectedItems(lvh.iItem); } bHandled = FALSE; return 1; } LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam == VK_SPACE) { int nCurrItem = GetNextItem(-1, LVNI_FOCUSED); if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0) { T* pT = static_cast(this); pT->CheckSelectedItems(nCurrItem); } } bHandled = FALSE; return 1; } }; class CCheckListViewCtrl : public CCheckListViewCtrlImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName()) }; /////////////////////////////////////////////////////////////////////////////// // CHyperLink - hyper link control implementation #if (WINVER < 0x0500) && !defined(_WIN32_WCE) __declspec(selectany) struct { enum { cxWidth = 32, cyHeight = 32 }; int xHotSpot; int yHotSpot; unsigned char arrANDPlane[cxWidth * cyHeight / 8]; unsigned char arrXORPlane[cxWidth * cyHeight / 8]; } _AtlHyperLink_CursorData = { 5, 0, { 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) #define HLINK_UNDERLINED 0x00000000 #define HLINK_NOTUNDERLINED 0x00000001 #define HLINK_UNDERLINEHOVER 0x00000002 #define HLINK_COMMANDBUTTON 0x00000004 #define HLINK_NOTIFYBUTTON 0x0000000C #define HLINK_USETAGS 0x00000010 #define HLINK_USETAGSBOLD 0x00000030 #define HLINK_NOTOOLTIP 0x00000040 #define HLINK_AUTOCREATELINKFONT 0x00000080 #define HLINK_SINGLELINE 0x00000100 // Notes: // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored template class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > { public: LPTSTR m_lpstrLabel; LPTSTR m_lpstrHyperLink; HCURSOR m_hCursor; HFONT m_hFontLink; HFONT m_hFontNormal; RECT m_rcLink; #ifndef _WIN32_WCE CToolTipCtrl m_tip; #endif // !_WIN32_WCE COLORREF m_clrLink; COLORREF m_clrVisited; DWORD m_dwExtendedStyle; // Hyper Link specific extended styles bool m_bPaintLabel:1; bool m_bVisited:1; bool m_bHover:1; bool m_bInternalLinkFont:1; bool m_bInternalNormalFont:1; // Constructor/Destructor CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : m_lpstrLabel(NULL), m_lpstrHyperLink(NULL), m_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL), m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)), m_dwExtendedStyle(dwExtendedStyle), m_bPaintLabel(true), m_bVisited(false), m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false) { ::SetRectEmpty(&m_rcLink); } ~CHyperLinkImpl() { delete [] m_lpstrLabel; delete [] m_lpstrHyperLink; #if (WINVER < 0x0500) && !defined(_WIN32_WCE) // It was created, not loaded, so we have to destroy it if(m_hCursor != NULL) ::DestroyCursor(m_hCursor); #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) } // Attributes DWORD GetHyperLinkExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); return dwPrevStyle; } bool GetLabel(LPTSTR lpstrBuffer, int nLength) const { if(m_lpstrLabel == NULL) return false; ATLASSERT(lpstrBuffer != NULL); if(nLength <= lstrlen(m_lpstrLabel)) return false; SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel); return true; } bool SetLabel(LPCTSTR lpstrLabel) { delete [] m_lpstrLabel; m_lpstrLabel = NULL; int cchLen = lstrlen(lpstrLabel) + 1; ATLTRY(m_lpstrLabel = new TCHAR[cchLen]); if(m_lpstrLabel == NULL) return false; SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel); T* pT = static_cast(this); pT->CalcLabelRect(); if(m_hWnd != NULL) SetWindowText(lpstrLabel); // Set this for accessibility return true; } bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const { if(m_lpstrHyperLink == NULL) return false; ATLASSERT(lpstrBuffer != NULL); if(nLength <= lstrlen(m_lpstrHyperLink)) return false; SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink); return true; } bool SetHyperLink(LPCTSTR lpstrLink) { delete [] m_lpstrHyperLink; m_lpstrHyperLink = NULL; int cchLen = lstrlen(lpstrLink) + 1; ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]); if(m_lpstrHyperLink == NULL) return false; SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink); if(m_lpstrLabel == NULL) { T* pT = static_cast(this); pT->CalcLabelRect(); } #ifndef _WIN32_WCE if(m_tip.IsWindow()) { m_tip.Activate(TRUE); m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); } #endif // !_WIN32_WCE return true; } HFONT GetLinkFont() const { return m_hFontLink; } void SetLinkFont(HFONT hFont) { if(m_bInternalLinkFont) { ::DeleteObject(m_hFontLink); m_bInternalLinkFont = false; } m_hFontLink = hFont; T* pT = static_cast(this); pT->CalcLabelRect(); } int GetIdealHeight() const { ATLASSERT(::IsWindow(m_hWnd)); if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) return -1; if(!m_bPaintLabel) return -1; UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; CClientDC dc(m_hWnd); RECT rect = { 0 }; GetClientRect(&rect); HFONT hFontOld = dc.SelectFont(m_hFontNormal); RECT rcText = rect; dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(m_hFontLink); RECT rcLink = rect; dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(hFontOld); return __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top); } bool GetIdealSize(SIZE& size) const { int cx = 0, cy = 0; bool bRet = GetIdealSize(cx, cy); if(bRet) { size.cx = cx; size.cy = cy; } return bRet; } bool GetIdealSize(int& cx, int& cy) const { ATLASSERT(::IsWindow(m_hWnd)); if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) return false; if(!m_bPaintLabel) return false; CClientDC dc(m_hWnd); RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcAll = rcClient; if(IsUsingTags()) { // find tags and label parts LPTSTR lpstrLeft = NULL; int cchLeft = 0; LPTSTR lpstrLink = NULL; int cchLink = 0; LPTSTR lpstrRight = NULL; int cchRight = 0; const T* pT = static_cast(this); pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); // get label part rects UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; HFONT hFontOld = dc.SelectFont(m_hFontNormal); RECT rcLeft = rcClient; dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(m_hFontLink); RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom }; dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(m_hFontNormal); RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom }; dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(hFontOld); int cyMax = __max(rcLeft.bottom, __max(rcLink.bottom, rcRight.bottom)); ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax); } else { HFONT hOldFont = NULL; if(m_hFontLink != NULL) hOldFont = dc.SelectFont(m_hFontLink); LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; DWORD dwStyle = GetStyle(); UINT uFormat = DT_LEFT; if (dwStyle & SS_CENTER) uFormat = DT_CENTER; else if (dwStyle & SS_RIGHT) uFormat = DT_RIGHT; uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT); if(m_hFontLink != NULL) dc.SelectFont(hOldFont); if (dwStyle & SS_CENTER) { int dx = (rcClient.right - rcAll.right) / 2; ::OffsetRect(&rcAll, dx, 0); } else if (dwStyle & SS_RIGHT) { int dx = rcClient.right - rcAll.right; ::OffsetRect(&rcAll, dx, 0); } } cx = rcAll.right - rcAll.left; cy = rcAll.bottom - rcAll.top; return true; } // for command buttons only bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const { ATLASSERT(IsCommandButton()); return GetHyperLink(lpstrBuffer, nLength); } bool SetToolTipText(LPCTSTR lpstrToolTipText) { ATLASSERT(IsCommandButton()); return SetHyperLink(lpstrToolTipText); } // Operations BOOL SubclassWindow(HWND hWnd) { ATLASSERT(m_hWnd == NULL); ATLASSERT(::IsWindow(hWnd)); if(m_hFontNormal == NULL) m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->Init(); } return bRet; } bool Navigate() { ATLASSERT(::IsWindow(m_hWnd)); bool bRet = true; if(IsNotifyButton()) { NMHDR nmhdr = { m_hWnd, (UINT_PTR)GetDlgCtrlID(), NM_CLICK }; ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); } else if(IsCommandButton()) { ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); } else { ATLASSERT(m_lpstrHyperLink != NULL); #ifndef _WIN32_WCE DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL); bRet = (dwRet > 32); #else // CE specific SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 }; ::ShellExecuteEx(&shExeInfo); DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp; bRet = (dwRet == 0) || (dwRet > 32); #endif // _WIN32_WCE ATLASSERT(bRet); if(bRet) { m_bVisited = true; Invalidate(); } } return bRet; } void CreateLinkFontFromNormal() { if(m_bInternalLinkFont) { ::DeleteObject(m_hFontLink); m_bInternalLinkFont = false; } CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT); LOGFONT lf = { 0 }; font.GetLogFont(&lf); if(IsUsingTagsBold()) lf.lfWeight = FW_BOLD; else if(!IsNotUnderlined()) lf.lfUnderline = TRUE; m_hFontLink = ::CreateFontIndirect(&lf); m_bInternalLinkFont = true; ATLASSERT(m_hFontLink != NULL); } // Message map and handlers BEGIN_MSG_MAP(CHyperLinkImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_CHAR, OnChar) MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) MESSAGE_HANDLER(WM_ENABLE, OnEnable) MESSAGE_HANDLER(WM_GETFONT, OnGetFont) MESSAGE_HANDLER(WM_SETFONT, OnSetFont) MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) MESSAGE_HANDLER(WM_SIZE, OnSize) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Init(); return 0; } #ifndef _WIN32_WCE LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_tip.IsWindow()) { m_tip.DestroyWindow(); m_tip.m_hWnd = NULL; } if(m_bInternalLinkFont) { ::DeleteObject(m_hFontLink); m_hFontLink = NULL; m_bInternalLinkFont = false; } if(m_bInternalNormalFont) { ::DeleteObject(m_hFontNormal); m_hFontNormal = NULL; m_bInternalNormalFont = false; } bHandled = FALSE; return 1; } LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { MSG msg = { m_hWnd, uMsg, wParam, lParam }; if(m_tip.IsWindow() && IsUsingToolTip()) m_tip.RelayEvent(&msg); bHandled = FALSE; return 1; } #endif // !_WIN32_WCE LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background painting needed (we do it all during WM_PAINT) } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(!m_bPaintLabel) { bHandled = FALSE; return 1; } T* pT = static_cast(this); if(wParam != NULL) { pT->DoEraseBackground((HDC)wParam); pT->DoPaint((HDC)wParam); } else { CPaintDC dc(m_hWnd); pT->DoEraseBackground(dc.m_hDC); pT->DoPaint(dc.m_hDC); } return 0; } LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bPaintLabel) Invalidate(); else bHandled = FALSE; return 0; } LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) { ::SetCursor(m_hCursor); if(IsUnderlineHover()) { if(!m_bHover) { m_bHover = true; InvalidateRect(&m_rcLink); UpdateWindow(); #ifndef _WIN32_WCE StartTrackMouseLeave(); #endif // !_WIN32_WCE } } } else { if(IsUnderlineHover()) { if(m_bHover) { m_bHover = false; InvalidateRect(&m_rcLink); UpdateWindow(); } } bHandled = FALSE; } return 0; } #ifndef _WIN32_WCE LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(IsUnderlineHover() && m_bHover) { m_bHover = false; InvalidateRect(&m_rcLink); UpdateWindow(); } return 0; } #endif // !_WIN32_WCE LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if(::PtInRect(&m_rcLink, pt)) { SetFocus(); SetCapture(); } return 0; } LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { if(GetCapture() == m_hWnd) { ReleaseCapture(); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if(::PtInRect(&m_rcLink, pt)) { T* pT = static_cast(this); pT->Navigate(); } } return 0; } LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(wParam == VK_RETURN || wParam == VK_SPACE) { T* pT = static_cast(this); pT->Navigate(); } return 0; } LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return DLGC_WANTCHARS; } LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { POINT pt = { 0, 0 }; GetCursorPos(&pt); ScreenToClient(&pt); if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) { return TRUE; } bHandled = FALSE; return FALSE; } LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { Invalidate(); UpdateWindow(); return 0; } LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)m_hFontNormal; } LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if(m_bInternalNormalFont) { ::DeleteObject(m_hFontNormal); m_bInternalNormalFont = false; } bool bCreateLinkFont = m_bInternalLinkFont; m_hFontNormal = (HFONT)wParam; if(bCreateLinkFont || IsAutoCreateLinkFont()) CreateLinkFontFromNormal(); T* pT = static_cast(this); pT->CalcLabelRect(); if((BOOL)lParam) { Invalidate(); UpdateWindow(); } return 0; } LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // If the control is subclassed or superclassed, this message can cause // repainting without WM_PAINT. We don't use this state, so just do nothing. return 0; } LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->CalcLabelRect(); pT->Invalidate(); return 0; } // Implementation void Init() { ATLASSERT(::IsWindow(m_hWnd)); // Check if we should paint a label const int cchBuff = 8; TCHAR szBuffer[cchBuff] = { 0 }; if(::GetClassName(m_hWnd, szBuffer, cchBuff)) { if(lstrcmpi(szBuffer, _T("static")) == 0) { ModifyStyle(0, SS_NOTIFY); // we need this DWORD dwStyle = GetStyle() & 0x000000FF; #ifndef _WIN32_WCE if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT || dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME || dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW || dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE) #else // CE specific if(dwStyle == SS_ICON || dwStyle == SS_BITMAP) #endif // _WIN32_WCE m_bPaintLabel = false; } } // create or load a cursor #if (WINVER >= 0x0500) || defined(_WIN32_WCE) m_hCursor = ::LoadCursor(NULL, IDC_HAND); #else m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane); #endif ATLASSERT(m_hCursor != NULL); // set fonts if(m_bPaintLabel) { if(m_hFontNormal == NULL) { m_hFontNormal = AtlCreateControlFont(); m_bInternalNormalFont = true; } if(m_hFontLink == NULL) CreateLinkFontFromNormal(); } #ifndef _WIN32_WCE // create a tool tip m_tip.Create(m_hWnd); ATLASSERT(m_tip.IsWindow()); #endif // !_WIN32_WCE // set label (defaults to window text) if(m_lpstrLabel == NULL) { int nLen = GetWindowTextLength(); if(nLen > 0) { ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]); if(m_lpstrLabel != NULL) ATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0); } } T* pT = static_cast(this); pT->CalcLabelRect(); // set hyperlink (defaults to label), or just activate tool tip if already set if(m_lpstrHyperLink == NULL && !IsCommandButton()) { if(m_lpstrLabel != NULL) SetHyperLink(m_lpstrLabel); } #ifndef _WIN32_WCE else { m_tip.Activate(TRUE); m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); } #endif // !_WIN32_WCE // set link colors if(m_bPaintLabel) { CRegKeyEx rk; LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings")); if(lRet == ERROR_SUCCESS) { const int cchValue = 12; TCHAR szValue[cchValue] = { 0 }; ULONG ulCount = cchValue; lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount); if(lRet == ERROR_SUCCESS) { COLORREF clr = pT->_ParseColorString(szValue); ATLASSERT(clr != CLR_INVALID); if(clr != CLR_INVALID) m_clrLink = clr; } ulCount = cchValue; lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount); if(lRet == ERROR_SUCCESS) { COLORREF clr = pT->_ParseColorString(szValue); ATLASSERT(clr != CLR_INVALID); if(clr != CLR_INVALID) m_clrVisited = clr; } } } } static COLORREF _ParseColorString(LPTSTR lpstr) { int c[3] = { -1, -1, -1 }; LPTSTR p = NULL; for(int i = 0; i < 2; i++) { for(p = lpstr; *p != _T('\0'); p = ::CharNext(p)) { if(*p == _T(',')) { *p = _T('\0'); c[i] = MinCrtHelper::_atoi(lpstr); lpstr = &p[1]; break; } } if(c[i] == -1) return CLR_INVALID; } if(*lpstr == _T('\0')) return CLR_INVALID; c[2] = MinCrtHelper::_atoi(lpstr); return RGB(c[0], c[1], c[2]); } bool CalcLabelRect() { if(!::IsWindow(m_hWnd)) return false; if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) return false; CClientDC dc(m_hWnd); RECT rcClient = { 0 }; GetClientRect(&rcClient); m_rcLink = rcClient; if(!m_bPaintLabel) return true; if(IsUsingTags()) { // find tags and label parts LPTSTR lpstrLeft = NULL; int cchLeft = 0; LPTSTR lpstrLink = NULL; int cchLink = 0; LPTSTR lpstrRight = NULL; int cchRight = 0; T* pT = static_cast(this); pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); ATLASSERT(lpstrLink != NULL); ATLASSERT(cchLink > 0); // get label part rects HFONT hFontOld = dc.SelectFont(m_hFontNormal); UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; RECT rcLeft = rcClient; if(lpstrLeft != NULL) dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(m_hFontLink); RECT rcLink = rcClient; if(lpstrLeft != NULL) rcLink.left = rcLeft.right; dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT); dc.SelectFont(hFontOld); m_rcLink = rcLink; } else { HFONT hOldFont = NULL; if(m_hFontLink != NULL) hOldFont = dc.SelectFont(m_hFontLink); LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; DWORD dwStyle = GetStyle(); UINT uFormat = DT_LEFT; if (dwStyle & SS_CENTER) uFormat = DT_CENTER; else if (dwStyle & SS_RIGHT) uFormat = DT_RIGHT; uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT); if(m_hFontLink != NULL) dc.SelectFont(hOldFont); if (dwStyle & SS_CENTER) { int dx = (rcClient.right - m_rcLink.right) / 2; ::OffsetRect(&m_rcLink, dx, 0); } else if (dwStyle & SS_RIGHT) { int dx = rcClient.right - m_rcLink.right; ::OffsetRect(&m_rcLink, dx, 0); } } return true; } void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const { lpstrLeft = NULL; cchLeft = 0; lpstrLink = NULL; cchLink = 0; lpstrRight = NULL; cchRight = 0; LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; int cchText = lstrlen(lpstrText); bool bOutsideLink = true; for(int i = 0; i < cchText; i++) { if(lpstrText[i] != _T('<')) continue; if(bOutsideLink) { if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T(""), 3) == CSTR_EQUAL) { if(i > 0) { lpstrLeft = lpstrText; cchLeft = i; } lpstrLink = &lpstrText[i + 3]; bOutsideLink = false; } } else { if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T(""), 4) == CSTR_EQUAL) { cchLink = i - 3 - cchLeft; if(lpstrText[i + 4] != 0) { lpstrRight = &lpstrText[i + 4]; cchRight = cchText - (i + 4); break; } } } } } void DoEraseBackground(CDCHandle dc) { HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd); if(hBrush != NULL) { RECT rect = { 0 }; GetClientRect(&rect); dc.FillRect(&rect, hBrush); } } void DoPaint(CDCHandle dc) { if(IsUsingTags()) { // find tags and label parts LPTSTR lpstrLeft = NULL; int cchLeft = 0; LPTSTR lpstrLink = NULL; int cchLink = 0; LPTSTR lpstrRight = NULL; int cchRight = 0; T* pT = static_cast(this); pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); // get label part rects RECT rcClient = { 0 }; GetClientRect(&rcClient); dc.SetBkMode(TRANSPARENT); HFONT hFontOld = dc.SelectFont(m_hFontNormal); UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; if(lpstrLeft != NULL) dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat); COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) dc.SelectFont(m_hFontLink); else dc.SelectFont(m_hFontNormal); dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat); dc.SetTextColor(clrOld); dc.SelectFont(m_hFontNormal); if(lpstrRight != NULL) { RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom }; dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat); } if(GetFocus() == m_hWnd) dc.DrawFocusRect(&m_rcLink); dc.SelectFont(hFontOld); } else { dc.SetBkMode(TRANSPARENT); COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); HFONT hFontOld = NULL; if(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) hFontOld = dc.SelectFont(m_hFontLink); else hFontOld = dc.SelectFont(m_hFontNormal); LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; DWORD dwStyle = GetStyle(); UINT uFormat = DT_LEFT; if (dwStyle & SS_CENTER) uFormat = DT_CENTER; else if (dwStyle & SS_RIGHT) uFormat = DT_RIGHT; uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK; dc.DrawText(lpstrText, -1, &m_rcLink, uFormat); if(GetFocus() == m_hWnd) dc.DrawFocusRect(&m_rcLink); dc.SetTextColor(clrOld); dc.SelectFont(hFontOld); } } #ifndef _WIN32_WCE BOOL StartTrackMouseLeave() { TRACKMOUSEEVENT tme = { 0 }; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = m_hWnd; return _TrackMouseEvent(&tme); } #endif // !_WIN32_WCE // Implementation helpers bool IsUnderlined() const { return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0); } bool IsNotUnderlined() const { return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0); } bool IsUnderlineHover() const { return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0); } bool IsCommandButton() const { return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0); } bool IsNotifyButton() const { return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON); } bool IsUsingTags() const { return ((m_dwExtendedStyle & HLINK_USETAGS) != 0); } bool IsUsingTagsBold() const { return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD); } bool IsUsingToolTip() const { return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0); } bool IsAutoCreateLinkFont() const { return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT); } bool IsSingleLine() const { return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE); } }; class CHyperLink : public CHyperLinkImpl { public: DECLARE_WND_CLASS(_T("WTL_HyperLink")) }; /////////////////////////////////////////////////////////////////////////////// // CWaitCursor - displays a wait cursor class CWaitCursor { public: // Data HCURSOR m_hWaitCursor; HCURSOR m_hOldCursor; bool m_bInUse; // Constructor/destructor CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false) { HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance(); m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor); ATLASSERT(m_hWaitCursor != NULL); if(bSet) Set(); } ~CWaitCursor() { Restore(); } // Methods bool Set() { if(m_bInUse) return false; m_hOldCursor = ::SetCursor(m_hWaitCursor); m_bInUse = true; return true; } bool Restore() { if(!m_bInUse) return false; ::SetCursor(m_hOldCursor); m_bInUse = false; return true; } }; /////////////////////////////////////////////////////////////////////////////// // CCustomWaitCursor - for custom and animated cursors class CCustomWaitCursor : public CWaitCursor { public: // Constructor/destructor CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) : CWaitCursor(false, IDC_WAIT, true) { if(hInstance == NULL) hInstance = ModuleHelper::GetResourceInstance(); m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); if(bSet) Set(); } ~CCustomWaitCursor() { Restore(); #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) ::DestroyCursor(m_hWaitCursor); #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) } }; /////////////////////////////////////////////////////////////////////////////// // CMultiPaneStatusBarCtrl - Status Bar with multiple panes template class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase > { public: DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) // Data enum { m_cxPaneMargin = 3 }; int m_nPanes; int* m_pPane; // Constructor/destructor CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL) { } ~CMultiPaneStatusBarCtrlImpl() { delete [] m_pPane; } // Methods HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) { #if (_MSC_VER >= 1300) return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase > _baseClass; return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); #endif // !(_MSC_VER >= 1300) } HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) { const int cchMax = 128; // max text length is 127 for status bars (+1 for null) TCHAR szText[cchMax] = { 0 }; ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); return Create(hWndParent, szText, dwStyle, nID); } BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPanes > 0); m_nPanes = nPanes; delete [] m_pPane; m_pPane = NULL; ATLTRY(m_pPane = new int[nPanes]); ATLASSERT(m_pPane != NULL); if(m_pPane == NULL) return FALSE; CTempBuffer buff; int* pPanesPos = buff.Allocate(nPanes); ATLASSERT(pPanesPos != NULL); if(pPanesPos == NULL) return FALSE; SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int)); // get status bar DC and set font CClientDC dc(m_hWnd); HFONT hOldFont = dc.SelectFont(GetFont()); // get status bar borders int arrBorders[3] = { 0 }; GetBorders(arrBorders); const int cchBuff = 128; TCHAR szBuff[cchBuff] = { 0 }; SIZE size = { 0, 0 }; int cxLeft = arrBorders[0]; // calculate right edge of each part for(int i = 0; i < nPanes; i++) { if(pPanes[i] == ID_DEFAULT_PANE) { // make very large, will be resized later pPanesPos[i] = INT_MAX / 2; } else { ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); dc.GetTextExtent(szBuff, lstrlen(szBuff), &size); T* pT = static_cast(this); pT; pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin; } cxLeft = pPanesPos[i]; } BOOL bRet = SetParts(nPanes, pPanesPos); if(bRet && bSetText) { for(int i = 0; i < nPanes; i++) { if(pPanes[i] != ID_DEFAULT_PANE) { ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); SetPaneText(m_pPane[i], szBuff); } } } dc.SelectFont(hOldFont); return bRet; } bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return false; int nLength = GetTextLength(nIndex, pnType); if(pcchLength != NULL) *pcchLength = nLength; return true; } BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; int nLength = GetText(nIndex, lpstrText, pnType); if(pcchLength != NULL) *pcchLength = nLength; return TRUE; } BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0) { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; return SetText(nIndex, lpstrText, nType); } BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; return GetRect(nIndex, lpRect); } BOOL SetPaneWidth(int nPaneID, int cxWidth) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; // get pane positions CTempBuffer buff; int* pPanesPos = buff.Allocate(m_nPanes); if(pPanesPos == NULL) return FALSE; GetParts(m_nPanes, pPanesPos); // calculate offset int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]); int cxOff = cxWidth - cxPaneWidth; // find variable width pane int nDef = m_nPanes; for(int i = 0; i < m_nPanes; i++) { if(m_pPane[i] == ID_DEFAULT_PANE) { nDef = i; break; } } // resize if(nIndex < nDef) // before default pane { for(int i = nIndex; i < nDef; i++) pPanesPos[i] += cxOff; } else // after default one { for(int i = nDef; i < nIndex; i++) pPanesPos[i] -= cxOff; } // set pane postions return SetParts(m_nPanes, pPanesPos); } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; GetTipText(nIndex, lpstrText, nSize); return TRUE; } BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText) { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; SetTipText(nIndex, lpstrText); return TRUE; } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) #if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; hIcon = GetIcon(nIndex); return TRUE; } BOOL SetPaneIcon(int nPaneID, HICON hIcon) { ATLASSERT(::IsWindow(m_hWnd)); int nIndex = GetPaneIndexFromID(nPaneID); if(nIndex == -1) return FALSE; return SetIcon(nIndex, hIcon); } #endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) // Message map and handlers BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >) MESSAGE_HANDLER(WM_SIZE, OnSize) END_MSG_MAP() LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(wParam != SIZE_MINIMIZED && m_nPanes > 0) { T* pT = static_cast(this); pT->UpdatePanesLayout(); } return lRet; } // Implementation BOOL UpdatePanesLayout() { // get pane positions CTempBuffer buff; int* pPanesPos = buff.Allocate(m_nPanes); ATLASSERT(pPanesPos != NULL); if(pPanesPos == NULL) return FALSE; int nRet = GetParts(m_nPanes, pPanesPos); ATLASSERT(nRet == m_nPanes); if(nRet != m_nPanes) return FALSE; // calculate offset RECT rcClient = { 0 }; GetClientRect(&rcClient); int cxOff = rcClient.right - pPanesPos[m_nPanes - 1]; #ifndef _WIN32_WCE // Move panes left if size grip box is present if((GetStyle() & SBARS_SIZEGRIP) != 0) cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE); #endif // !_WIN32_WCE // find variable width pane int i; for(i = 0; i < m_nPanes; i++) { if(m_pPane[i] == ID_DEFAULT_PANE) break; } // resize all panes from the variable one to the right if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1])) { for(; i < m_nPanes; i++) pPanesPos[i] += cxOff; } // set pane postions return SetParts(m_nPanes, pPanesPos); } int GetPaneIndexFromID(int nPaneID) const { for(int i = 0; i < m_nPanes; i++) { if(m_pPane[i] == nPaneID) return i; } return -1; // not found } }; class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName()) }; /////////////////////////////////////////////////////////////////////////////// // CPaneContainer - provides header with title and close button for panes // pane container extended styles #define PANECNT_NOCLOSEBUTTON 0x00000001 #define PANECNT_VERTICAL 0x00000002 #define PANECNT_FLATBORDER 0x00000004 #define PANECNT_NOBORDER 0x00000008 #define PANECNT_DIVIDER 0x00000010 #define PANECNT_GRADIENT 0x00000020 // Note: PANECNT_GRADIENT doesn't work with _ATL_NO_MSIMG template class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T > { public: DECLARE_WND_CLASS_EX(NULL, 0, -1) // Constants enum { m_cxyBorder = 2, m_cxyTextOffset = 4, m_cxyBtnOffset = 1, m_cchTitle = 80, m_cxImageTB = 13, m_cyImageTB = 11, m_cxyBtnAddTB = 7, m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset, m_xBtnImageLeft = 6, m_yBtnImageTop = 5, m_xBtnImageRight = 12, m_yBtnImageBottom = 11, m_nCloseBtnID = ID_PANE_CLOSE }; // Data members CToolBarCtrl m_tb; ATL::CWindow m_wndClient; int m_cxyHeader; TCHAR m_szTitle[m_cchTitle]; DWORD m_dwExtendedStyle; // Pane container specific extended styles HFONT m_hFont; bool m_bInternalFont; // Constructor CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false) { m_szTitle[0] = 0; } // Attributes DWORD GetPaneContainerExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); if(m_hWnd != NULL) { T* pT = static_cast(this); bool bUpdate = false; if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button { pT->CreateCloseButton(); bUpdate = true; } else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button { pT->DestroyCloseButton(); bUpdate = true; } if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation { pT->CalcSize(); bUpdate = true; } if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) != (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border { bUpdate = true; } #if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) if((dwPrevStyle & PANECNT_GRADIENT) != (m_dwExtendedStyle & PANECNT_GRADIENT)) // change background { bUpdate = true; } #endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) if(bUpdate) pT->UpdateLayout(); } return dwPrevStyle; } HWND GetClient() const { return m_wndClient; } HWND SetClient(HWND hWndClient) { HWND hWndOldClient = m_wndClient; m_wndClient = hWndClient; if(m_hWnd != NULL) { T* pT = static_cast(this); pT->UpdateLayout(); } return hWndOldClient; } BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const { ATLASSERT(lpstrTitle != NULL); errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE); return (nRet == 0 || nRet == STRUNCATE); } BOOL SetTitle(LPCTSTR lpstrTitle) { ATLASSERT(lpstrTitle != NULL); errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); bool bRet = (nRet == 0 || nRet == STRUNCATE); if(bRet && m_hWnd != NULL) { T* pT = static_cast(this); pT->UpdateLayout(); } return bRet; } int GetTitleLength() const { return lstrlen(m_szTitle); } // Methods HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) { if(lpstrTitle != NULL) SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); #if (_MSC_VER >= 1300) return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); #endif // !(_MSC_VER >= 1300) } HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) { if(uTitleID != 0U) ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle); #if (_MSC_VER >= 1300) return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); #endif // !(_MSC_VER >= 1300) } BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->Init(); RECT rect = { 0 }; GetClientRect(&rect); pT->UpdateLayout(rect.right, rect.bottom); } return bRet; } BOOL EnableCloseButton(BOOL bEnable) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT; // avoid level 4 warning return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE; } void UpdateLayout() { RECT rcClient = { 0 }; GetClientRect(&rcClient); T* pT = static_cast(this); pT->UpdateLayout(rcClient.right, rcClient.bottom); } // Message map and handlers BEGIN_MSG_MAP(CPaneContainerImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_GETFONT, OnGetFont) MESSAGE_HANDLER(WM_SETFONT, OnSetFont) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_NOTIFY, OnNotify) MESSAGE_HANDLER(WM_COMMAND, OnCommand) FORWARD_NOTIFICATIONS() END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->Init(); return 0; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_bInternalFont) { ::DeleteObject(m_hFont); m_hFont = NULL; m_bInternalFont = false; } return 0; } LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_wndClient.m_hWnd != NULL) m_wndClient.SetFocus(); return 0; } LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)m_hFont; } LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if(m_bInternalFont) { ::DeleteObject(m_hFont); m_bInternalFont = false; } m_hFont = (HFONT)wParam; T* pT = static_cast(this); pT->CalcSize(); if((BOOL)lParam != FALSE) pT->UpdateLayout(); return 0; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->DrawPaneTitleBackground((HDC)wParam); return 1; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if(wParam != NULL) { pT->DrawPaneTitle((HDC)wParam); if(m_wndClient.m_hWnd == NULL) // no client window pT->DrawPane((HDC)wParam); } else { CPaintDC dc(m_hWnd); pT->DrawPaneTitle(dc.m_hDC); if(m_wndClient.m_hWnd == NULL) // no client window pT->DrawPane(dc.m_hDC); } return 0; } LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(m_tb.m_hWnd == NULL) { bHandled = FALSE; return 1; } T* pT = static_cast(this); pT; LPNMHDR lpnmh = (LPNMHDR)lParam; LRESULT lRet = 0; // pass toolbar custom draw notifications to the base class if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd) lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled); #ifndef _WIN32_WCE // tooltip notifications come with the tooltip window handle and button ID, // pass them to the parent if we don't handle them else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID) bHandled = pT->GetToolTipText(lpnmh); #endif // !_WIN32_WCE // only let notifications not from the toolbar go to the parent else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID) bHandled = FALSE; return lRet; } LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // if command comes from the close button, substitute HWND of the pane container instead if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd) return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd); bHandled = FALSE; return 1; } // Custom draw overrides DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_NOTIFYITEMDRAW; // we need per-item notifications } DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) { return CDRF_NOTIFYPOSTPAINT; } DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) { CDCHandle dc = lpNMCustomDraw->hdc; #if (_WIN32_IE >= 0x0400) RECT& rc = lpNMCustomDraw->rc; #else // !(_WIN32_IE >= 0x0400) RECT rc = { 0 }; m_tb.GetItemRect(0, &rc); #endif // !(_WIN32_IE >= 0x0400) RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 }; ::OffsetRect(&rcImage, rc.left, rc.top); T* pT = static_cast(this); if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0) { RECT rcShadow = rcImage; ::OffsetRect(&rcShadow, 1, 1); CPen pen1; pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT)); pT->DrawButtonImage(dc, rcShadow, pen1); CPen pen2; pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW)); pT->DrawButtonImage(dc, rcImage, pen2); } else { if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0) ::OffsetRect(&rcImage, 1, 1); CPen pen; pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT)); pT->DrawButtonImage(dc, rcImage, pen); } return CDRF_DODEFAULT; // continue with the default item painting } // Implementation - overrideable methods void Init() { if(m_hFont == NULL) { // The same as AtlCreateControlFont() for horizontal pane #ifndef _WIN32_WCE LOGFONT lf = { 0 }; ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE); if(IsVertical()) lf.lfEscapement = 900; // 90 degrees m_hFont = ::CreateFontIndirect(&lf); #else // CE specific m_hFont = (HFONT)::GetStockObject(SYSTEM_FONT); if(IsVertical()) { CLogFont lf(m_hFont); lf.lfEscapement = 900; // 90 degrees m_hFont = ::CreateFontIndirect(&lf); } #endif // _WIN32_WCE m_bInternalFont = true; } T* pT = static_cast(this); pT->CalcSize(); if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0) pT->CreateCloseButton(); } void UpdateLayout(int cxWidth, int cyHeight) { ATLASSERT(::IsWindow(m_hWnd)); RECT rect = { 0 }; if(IsVertical()) { ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight); if(m_tb.m_hWnd != NULL) m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(m_wndClient.m_hWnd != NULL) m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER); else rect.right = cxWidth; } else { ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader); if(m_tb.m_hWnd != NULL) m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); if(m_wndClient.m_hWnd != NULL) m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER); else rect.bottom = cyHeight; } InvalidateRect(&rect); } void CreateCloseButton() { ATLASSERT(m_tb.m_hWnd == NULL); // create toolbar for the "x" button m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0); ATLASSERT(m_tb.IsWindow()); if(m_tb.m_hWnd != NULL) { T* pT = static_cast(this); pT; // avoid level 4 warning m_tb.SetButtonStructSize(); TBBUTTON tbbtn = { 0 }; tbbtn.idCommand = pT->m_nCloseBtnID; tbbtn.fsState = TBSTATE_ENABLED; tbbtn.fsStyle = BTNS_BUTTON; m_tb.AddButtons(1, &tbbtn); m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB); m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB); if(IsVertical()) m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOACTIVATE); else m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); } } void DestroyCloseButton() { if(m_tb.m_hWnd != NULL) m_tb.DestroyWindow(); } void CalcSize() { T* pT = static_cast(this); CFontHandle font = pT->GetTitleFont(); if(font.IsNull()) font = (HFONT)::GetStockObject(SYSTEM_FONT); LOGFONT lf = { 0 }; font.GetLogFont(lf); if(IsVertical()) { m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + 1; } else { int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset; int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset + 1; m_cxyHeader = __max(cyFont, cyBtn); } } HFONT GetTitleFont() const { return m_hFont; } #ifndef _WIN32_WCE BOOL GetToolTipText(LPNMHDR /*lpnmh*/) { return FALSE; } #endif // !_WIN32_WCE void DrawPaneTitle(CDCHandle dc) { RECT rect = { 0 }; GetClientRect(&rect); UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST; if(IsVertical()) { rect.right = rect.left + m_cxyHeader; uBorder |= BF_BOTTOM; } else { rect.bottom = rect.top + m_cxyHeader; uBorder |= BF_RIGHT; } if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0) { if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0) uBorder |= BF_FLAT; dc.DrawEdge(&rect, EDGE_ETCHED, uBorder); } if((m_dwExtendedStyle & PANECNT_DIVIDER) != 0) { uBorder = BF_FLAT | BF_ADJUST | (IsVertical() ? BF_RIGHT : BF_BOTTOM); dc.DrawEdge(&rect, BDR_SUNKENOUTER, uBorder); } // draw title text dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); dc.SetBkMode(TRANSPARENT); T* pT = static_cast(this); HFONT hFontOld = dc.SelectFont(pT->GetTitleFont()); #if defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS) const UINT DT_END_ELLIPSIS = 0; #endif // defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS) if(IsVertical()) { rect.top += m_cxyTextOffset; rect.bottom -= m_cxyTextOffset; if(m_tb.m_hWnd != NULL) rect.top += m_cxToolBar;; RECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top }; int cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT); RECT rcText = { 0 }; rcText.left = (rect.right - rect.left - cxFont) / 2; rcText.right = rcText.left + (rect.bottom - rect.top); rcText.top = rect.bottom; rcText.bottom = rect.top; dc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS); } else { rect.left += m_cxyTextOffset; rect.right -= m_cxyTextOffset; if(m_tb.m_hWnd != NULL) rect.right -= m_cxToolBar;; dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); } dc.SelectFont(hFontOld); } void DrawPaneTitleBackground(CDCHandle dc) { RECT rect = { 0 }; GetClientRect(&rect); if(IsVertical()) rect.right = m_cxyHeader; else rect.bottom = m_cxyHeader; #if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) if((m_dwExtendedStyle & PANECNT_GRADIENT) != 0) dc.GradientFillRect(rect, ::GetSysColor(COLOR_WINDOW), ::GetSysColor(COLOR_3DFACE), IsVertical()); else #endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) dc.FillRect(&rect, COLOR_3DFACE); } // called only if pane is empty void DrawPane(CDCHandle dc) { RECT rect = { 0 }; GetClientRect(&rect); if(IsVertical()) rect.left += m_cxyHeader; else rect.top += m_cxyHeader; if((GetExStyle() & WS_EX_CLIENTEDGE) == 0) dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); dc.FillRect(&rect, COLOR_APPWORKSPACE); } // drawing helper - draws "x" button image void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen) { #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) HPEN hPenOld = dc.SelectPen(hPen); dc.MoveTo(rcImage.left, rcImage.top); dc.LineTo(rcImage.right, rcImage.bottom); dc.MoveTo(rcImage.left + 1, rcImage.top); dc.LineTo(rcImage.right + 1, rcImage.bottom); dc.MoveTo(rcImage.left, rcImage.bottom - 1); dc.LineTo(rcImage.right, rcImage.top - 1); dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1); dc.LineTo(rcImage.right + 1, rcImage.top - 1); dc.SelectPen(hPenOld); #else // (_WIN32_WCE < 400) rcImage; hPen; // no support for the "x" button image #endif // (_WIN32_WCE < 400) } bool IsVertical() const { return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0); } }; class CPaneContainer : public CPaneContainerImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1) }; /////////////////////////////////////////////////////////////////////////////// // CSortListViewCtrl - implements sorting for a listview control // sort listview extended styles #define SORTLV_USESHELLBITMAPS 0x00000001 // Notification sent to parent when sort column is changed by user clicking header. #define SLVN_SORTCHANGED LVN_LAST // A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification typedef struct tagNMSORTLISTVIEW { NMHDR hdr; int iNewSortColumn; int iOldSortColumn; } NMSORTLISTVIEW, *LPNMSORTLISTVIEW; // Column sort types. Can be set on a per-column basis with the SetColumnSortType method. enum { LVCOLSORT_NONE, LVCOLSORT_TEXT, // default LVCOLSORT_TEXTNOCASE, LVCOLSORT_LONG, LVCOLSORT_DOUBLE, LVCOLSORT_DECIMAL, LVCOLSORT_DATETIME, LVCOLSORT_DATE, LVCOLSORT_TIME, LVCOLSORT_CUSTOM, LVCOLSORT_LAST = LVCOLSORT_CUSTOM }; template class CSortListViewImpl { public: enum { m_cchCmpTextMax = 32, // overrideable m_cxSortImage = 16, m_cySortImage = 15, m_cxSortArrow = 11, m_cySortArrow = 6, m_iSortUp = 0, // index of sort bitmaps m_iSortDown = 1, m_nShellSortUpID = 133 }; // passed to LVCompare functions as lParam1 and lParam2 struct LVCompareParam { int iItem; DWORD_PTR dwItemData; union { long lValue; double dblValue; DECIMAL decValue; LPCTSTR pszValue; }; }; // passed to LVCompare functions as the lParamSort parameter struct LVSortInfo { T* pT; int iSortCol; bool bDescending; }; bool m_bSortDescending; bool m_bCommCtrl6; int m_iSortColumn; CBitmap m_bmSort[2]; int m_fmtOldSortCol; HBITMAP m_hbmOldSortCol; DWORD m_dwSortLVExtendedStyle; ATL::CSimpleArray m_arrColSortType; bool m_bUseWaitCursor; CSortListViewImpl() : m_bSortDescending(false), m_bCommCtrl6(false), m_iSortColumn(-1), m_fmtOldSortCol(0), m_hbmOldSortCol(NULL), m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS), m_bUseWaitCursor(true) { #ifndef _WIN32_WCE DWORD dwMajor = 0; DWORD dwMinor = 0; HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6; #endif // !_WIN32_WCE } // Attributes void SetSortColumn(int iCol) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); CHeaderCtrl header = pT->GetHeader(); ATLASSERT(header.m_hWnd != NULL); ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize()); int iOldSortCol = m_iSortColumn; m_iSortColumn = iCol; if(m_bCommCtrl6) { #ifndef HDF_SORTUP const int HDF_SORTUP = 0x0400; #endif // HDF_SORTUP #ifndef HDF_SORTDOWN const int HDF_SORTDOWN = 0x0200; #endif // HDF_SORTDOWN const int nMask = HDF_SORTUP | HDF_SORTDOWN; HDITEM hditem = { HDI_FORMAT }; if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem)) { hditem.fmt &= ~nMask; header.SetItem(iOldSortCol, &hditem); } if(iCol >= 0 && header.GetItem(iCol, &hditem)) { hditem.fmt &= ~nMask; hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP; header.SetItem(iCol, &hditem); } return; } if(m_bmSort[m_iSortUp].IsNull()) pT->CreateSortBitmaps(); // restore previous sort column's bitmap, if any, and format HDITEM hditem = { HDI_BITMAP | HDI_FORMAT }; if(iOldSortCol != iCol && iOldSortCol >= 0) { hditem.hbm = m_hbmOldSortCol; hditem.fmt = m_fmtOldSortCol; header.SetItem(iOldSortCol, &hditem); } // save new sort column's bitmap and format, and add our sort bitmap if(iCol >= 0 && header.GetItem(iCol, &hditem)) { if(iOldSortCol != iCol) { m_fmtOldSortCol = hditem.fmt; m_hbmOldSortCol = hditem.hbm; } hditem.fmt &= ~HDF_IMAGE; hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT; int i = m_bSortDescending ? m_iSortDown : m_iSortUp; hditem.hbm = m_bmSort[i]; header.SetItem(iCol, &hditem); } } int GetSortColumn() const { return m_iSortColumn; } void SetColumnSortType(int iCol, WORD wType) { ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST); m_arrColSortType[iCol] = wType; } WORD GetColumnSortType(int iCol) const { ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize()); return m_arrColSortType[iCol]; } int GetColumnCount() const { const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); CHeaderCtrl header = pT->GetHeader(); return header.m_hWnd != NULL ? header.GetItemCount() : 0; } bool IsSortDescending() const { return m_bSortDescending; } DWORD GetSortListViewExtendedStyle() const { return m_dwSortLVExtendedStyle; } DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwSortLVExtendedStyle; if(dwMask == 0) m_dwSortLVExtendedStyle = dwExtendedStyle; else m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); return dwPrevStyle; } // Operations bool DoSortItems(int iCol, bool bDescending = false) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); WORD wType = m_arrColSortType[iCol]; if(wType == LVCOLSORT_NONE) return false; int nCount = pT->GetItemCount(); if(nCount < 2) { m_bSortDescending = bDescending; SetSortColumn(iCol); return true; } CWaitCursor waitCursor(false); if(m_bUseWaitCursor) waitCursor.Set(); LVCompareParam* pParam = NULL; ATLTRY(pParam = new LVCompareParam[nCount]); PFNLVCOMPARE pFunc = NULL; TCHAR pszTemp[pT->m_cchCmpTextMax] = { 0 }; bool bStrValue = false; switch(wType) { case LVCOLSORT_TEXT: pFunc = (PFNLVCOMPARE)pT->LVCompareText; case LVCOLSORT_TEXTNOCASE: if(pFunc == NULL) pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase; case LVCOLSORT_CUSTOM: { if(pFunc == NULL) pFunc = (PFNLVCOMPARE)pT->LVCompareCustom; for(int i = 0; i < nCount; i++) { pParam[i].iItem = i; pParam[i].dwItemData = pT->GetItemData(i); pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax]; pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax); pT->SetItemData(i, (DWORD_PTR)&pParam[i]); } bStrValue = true; } break; case LVCOLSORT_LONG: { pFunc = (PFNLVCOMPARE)pT->LVCompareLong; for(int i = 0; i < nCount; i++) { pParam[i].iItem = i; pParam[i].dwItemData = pT->GetItemData(i); pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); pParam[i].lValue = pT->StrToLong(pszTemp); pT->SetItemData(i, (DWORD_PTR)&pParam[i]); } } break; case LVCOLSORT_DOUBLE: { pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; for(int i = 0; i < nCount; i++) { pParam[i].iItem = i; pParam[i].dwItemData = pT->GetItemData(i); pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); pParam[i].dblValue = pT->StrToDouble(pszTemp); pT->SetItemData(i, (DWORD_PTR)&pParam[i]); } } break; case LVCOLSORT_DECIMAL: { pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal; for(int i = 0; i < nCount; i++) { pParam[i].iItem = i; pParam[i].dwItemData = pT->GetItemData(i); pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); pT->StrToDecimal(pszTemp, &pParam[i].decValue); pT->SetItemData(i, (DWORD_PTR)&pParam[i]); } } break; case LVCOLSORT_DATETIME: case LVCOLSORT_DATE: case LVCOLSORT_TIME: { pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; DWORD dwFlags = LOCALE_NOUSEROVERRIDE; if(wType == LVCOLSORT_DATE) dwFlags |= VAR_DATEVALUEONLY; else if(wType == LVCOLSORT_TIME) dwFlags |= VAR_TIMEVALUEONLY; for(int i = 0; i < nCount; i++) { pParam[i].iItem = i; pParam[i].dwItemData = pT->GetItemData(i); pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags); pT->SetItemData(i, (DWORD_PTR)&pParam[i]); } } break; default: ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n")); break; } // switch(wType) ATLASSERT(pFunc != NULL); LVSortInfo lvsi = { pT, iCol, bDescending }; bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE); for(int i = 0; i < nCount; i++) { DWORD_PTR dwItemData = pT->GetItemData(i); LVCompareParam* p = (LVCompareParam*)dwItemData; ATLASSERT(p != NULL); if(bStrValue) delete [] (TCHAR*)p->pszValue; pT->SetItemData(i, p->dwItemData); } delete [] pParam; if(bRet) { m_bSortDescending = bDescending; SetSortColumn(iCol); } if(m_bUseWaitCursor) waitCursor.Restore(); return bRet; } void CreateSortBitmaps() { if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0) { bool bFree = false; LPCTSTR pszModule = _T("shell32.dll"); HINSTANCE hShell = ::GetModuleHandle(pszModule); if (hShell == NULL) { hShell = ::LoadLibrary(pszModule); bFree = true; } if (hShell != NULL) { bool bSuccess = true; for(int i = m_iSortUp; i <= m_iSortDown; i++) { if(!m_bmSort[i].IsNull()) m_bmSort[i].DeleteObject(); m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i), #ifndef _WIN32_WCE IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); #else // CE specific IMAGE_BITMAP, 0, 0, 0); #endif // _WIN32_WCE if(m_bmSort[i].IsNull()) { bSuccess = false; break; } } if(bFree) ::FreeLibrary(hShell); if(bSuccess) return; } } T* pT = static_cast(this); for(int i = m_iSortUp; i <= m_iSortDown; i++) { if(!m_bmSort[i].IsNull()) m_bmSort[i].DeleteObject(); CDC dcMem; CClientDC dc(::GetDesktopWindow()); dcMem.CreateCompatibleDC(dc.m_hDC); m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage); HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]); RECT rc = { 0, 0, m_cxSortImage, m_cySortImage }; pT->DrawSortBitmap(dcMem.m_hDC, i, &rc); dcMem.SelectBitmap(hbmOld); dcMem.DeleteDC(); } } void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol) { T* pT = static_cast(this); int nID = pT->GetDlgCtrlID(); NMSORTLISTVIEW nm = { { pT->m_hWnd, (UINT_PTR)nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol }; ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm); } // Overrideables int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/) { // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members. // If item1 > item2 return 1, if item1 < item2 return -1, else return 0. return 0; } void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc) { dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE)); HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); CPen pen; pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW)); HPEN hpenOld = dc.SelectPen(pen); POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 }; if(iBitmap == m_iSortUp) { POINT pts[3] = { { ptOrg.x + m_cxSortArrow / 2, ptOrg.y }, { ptOrg.x, ptOrg.y + m_cySortArrow - 1 }, { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 } }; dc.Polygon(pts, 3); } else { POINT pts[3] = { { ptOrg.x, ptOrg.y }, { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 }, { ptOrg.x + m_cxSortArrow - 1, ptOrg.y } }; dc.Polygon(pts, 3); } dc.SelectBrush(hbrOld); dc.SelectPen(hpenOld); } double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags) { ATLASSERT(lpstr != NULL); if(lpstr == NULL || lpstr[0] == _T('\0')) return 0; USES_CONVERSION; HRESULT hRet = E_FAIL; DATE dRet = 0; if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet))) { ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet); dRet = 0; } return dRet; } long StrToLong(LPCTSTR lpstr) { ATLASSERT(lpstr != NULL); if(lpstr == NULL || lpstr[0] == _T('\0')) return 0; USES_CONVERSION; HRESULT hRet = E_FAIL; long lRet = 0; if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet))) { ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet); lRet = 0; } return lRet; } double StrToDouble(LPCTSTR lpstr) { ATLASSERT(lpstr != NULL); if(lpstr == NULL || lpstr[0] == _T('\0')) return 0; USES_CONVERSION; HRESULT hRet = E_FAIL; double dblRet = 0; if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet))) { ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet); dblRet = 0; } return dblRet; } bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal) { ATLASSERT(lpstr != NULL); ATLASSERT(pDecimal != NULL); if(lpstr == NULL || pDecimal == NULL) return false; USES_CONVERSION; HRESULT hRet = E_FAIL; if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal))) { ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet); pDecimal->Lo64 = 0; pDecimal->Hi32 = 0; pDecimal->signscale = 0; return false; } return true; } // Overrideable PFNLVCOMPARE functions static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue); return pInfo->bDescending ? -nRet : nRet; } static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue); return pInfo->bDescending ? -nRet : nRet; } static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = 0; if(pParam1->lValue > pParam2->lValue) nRet = 1; else if(pParam1->lValue < pParam2->lValue) nRet = -1; return pInfo->bDescending ? -nRet : nRet; } static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = 0; if(pParam1->dblValue > pParam2->dblValue) nRet = 1; else if(pParam1->dblValue < pParam2->dblValue) nRet = -1; return pInfo->bDescending ? -nRet : nRet; } static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol); return pInfo->bDescending ? -nRet : nRet; } #ifndef _WIN32_WCE static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue); nRet--; return pInfo->bDescending ? -nRet : nRet; } #else // Compare mantissas, ignore sign and scale static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight) { if (decLeft.Hi32 < decRight.Hi32) { return -1; } if (decLeft.Hi32 > decRight.Hi32) { return 1; } // Here, decLeft.Hi32 == decRight.Hi32 if (decLeft.Lo64 < decRight.Lo64) { return -1; } if (decLeft.Lo64 > decRight.Lo64) { return 1; } return 0; } // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight) { static const ULONG powersOfTen[] = { 10ul, 100ul, 1000ul, 10000ul, 100000ul, 1000000ul, 10000000ul, 100000000ul, 1000000000ul }; static const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]); if (!pdecLeft || !pdecRight) { return VARCMP_NULL; } // Degenerate case - at least one comparand is of the form // [+-]0*10^N (denormalized zero) bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32); bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32); if (bLeftZero && bRightZero) { return VARCMP_EQ; } bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0); bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0); if (bLeftZero) { return (bRightNeg ? VARCMP_GT : VARCMP_LT); } // This also covers the case where the comparands have different signs if (bRightZero || bLeftNeg != bRightNeg) { return (bLeftNeg ? VARCMP_LT : VARCMP_GT); } // Here both comparands have the same sign and need to be compared // on mantissa and scale. The result is obvious when // 1. Scales are equal (then compare mantissas) // 2. A number with smaller scale is also the one with larger mantissa // (then this number is obviously larger) // In the remaining case, we would multiply the number with smaller // scale by 10 and simultaneously increment its scale (which amounts to // adding trailing zeros after decimal point), until the numbers fall under // one of the two cases above DECIMAL temp; bool bInvert = bLeftNeg; // the final result needs to be inverted if (pdecLeft->scale < pdecRight->scale) { temp = *pdecLeft; } else { temp = *pdecRight; pdecRight = pdecLeft; bInvert = !bInvert; } // Now temp is the number with smaller (or equal) scale, and // we can modify it freely without touching original parameters int comp; while ((comp = CompareMantissas(temp, *pdecRight)) < 0 && temp.scale < pdecRight->scale) { // Multiply by an appropriate power of 10 int scaleDiff = pdecRight->scale - temp.scale; if (scaleDiff > largestPower) { // Keep the multiplier representable in 32bit scaleDiff = largestPower; } DWORDLONG power = powersOfTen[scaleDiff - 1]; // Multiply temp's mantissa by power DWORDLONG product = temp.Lo32 * power; ULONG carry = static_cast(product >> 32); temp.Lo32 = static_cast(product); product = temp.Mid32 * power + carry; carry = static_cast(product >> 32); temp.Mid32 = static_cast(product); product = temp.Hi32 * power + carry; if (static_cast(product >> 32)) { // Multiplication overflowed - pdecLeft is clearly larger break; } temp.Hi32 = static_cast(product); temp.scale = (BYTE)(temp.scale + scaleDiff); } if (temp.scale < pdecRight->scale) { comp = 1; } if (bInvert) { comp = -comp; } return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ); } static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); LVCompareParam* pParam1 = (LVCompareParam*)lParam1; LVCompareParam* pParam2 = (LVCompareParam*)lParam2; LVSortInfo* pInfo = (LVSortInfo*)lParamSort; int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue); nRet--; return pInfo->bDescending ? -nRet : nRet; } #endif // !_WIN32_WCE BEGIN_MSG_MAP(CSortListViewImpl) MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn) MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn) NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick) NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) END_MSG_MAP() LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); if(lRet == -1) return -1; WORD wType = 0; m_arrColSortType.Add(wType); int nCount = m_arrColSortType.GetSize(); ATLASSERT(nCount == GetColumnCount()); for(int i = nCount - 1; i > lRet; i--) m_arrColSortType[i] = m_arrColSortType[i - 1]; m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT; if(lRet <= m_iSortColumn) m_iSortColumn++; return lRet; } LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); if(lRet == 0) return 0; int iCol = (int)wParam; if(m_iSortColumn == iCol) m_iSortColumn = -1; else if(m_iSortColumn > iCol) m_iSortColumn--; m_arrColSortType.RemoveAt(iCol); return lRet; } LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LPNMHEADER p = (LPNMHEADER)pnmh; if(p->iButton == 0) { int iOld = m_iSortColumn; bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false; if(DoSortItems(p->iItem, bDescending)) NotifyParentSortChanged(p->iItem, iOld); } bHandled = FALSE; return 0; } LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifndef _WIN32_WCE if(wParam == SPI_SETNONCLIENTMETRICS) GetSystemSettings(); #else // CE specific wParam; // avoid level 4 warning GetSystemSettings(); #endif // _WIN32_WCE bHandled = FALSE; return 0; } void GetSystemSettings() { if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull()) { T* pT = static_cast(this); pT->CreateSortBitmaps(); if(m_iSortColumn != -1) SetSortColumn(m_iSortColumn); } } }; typedef ATL::CWinTraits CSortListViewCtrlTraits; template class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl, public CSortListViewImpl { public: DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) bool SortItems(int iCol, bool bDescending = false) { return DoSortItems(iCol, bDescending); } BEGIN_MSG_MAP(CSortListViewCtrlImpl) MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl::OnInsertColumn) MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl::OnDeleteColumn) NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl::OnHeaderItemClick) NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl::OnHeaderItemClick) MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl::OnSettingChange) END_MSG_MAP() }; class CSortListViewCtrl : public CSortListViewCtrlImpl { public: DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName()) }; /////////////////////////////////////////////////////////////////////////////// // CTabView - implements tab view window // TabView Notifications #define TBVN_PAGEACTIVATED (0U-741) #define TBVN_CONTEXTMENU (0U-742) // Notification data for TBVN_CONTEXTMENU struct TBVCONTEXTMENUINFO { NMHDR hdr; POINT pt; }; typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO; template class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > { public: DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) // Declarations and enums struct TABVIEWPAGE { HWND hWnd; LPTSTR lpstrTitle; LPVOID pData; }; struct TCITEMEXTRA { TCITEMHEADER tciheader; TABVIEWPAGE tvpage; operator LPTCITEM() { return (LPTCITEM)this; } }; enum { m_nTabID = 1313, m_cxMoveMark = 6, m_cyMoveMark = 3, m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1) }; // Data members ATL::CContainedWindowT m_tab; int m_cyTabHeight; int m_nActivePage; int m_nInsertItem; POINT m_ptStartDrag; CMenuHandle m_menu; int m_cchTabTextLength; int m_nMenuItemsCount; ATL::CWindow m_wndTitleBar; LPTSTR m_lpstrTitleBarBase; int m_cchTitleBarLength; CImageList m_ilDrag; bool m_bDestroyPageOnRemove:1; bool m_bDestroyImageList:1; bool m_bActivePageMenuItem:1; bool m_bActiveAsDefaultMenuItem:1; bool m_bEmptyMenuItem:1; bool m_bWindowsMenuItem:1; bool m_bNoTabDrag:1; // internal bool m_bTabCapture:1; bool m_bTabDrag:1; bool m_bInternalFont:1; // Constructor/destructor CTabViewImpl() : m_nActivePage(-1), m_cyTabHeight(0), m_tab(this, 1), m_nInsertItem(-1), m_cchTabTextLength(30), m_nMenuItemsCount(10), m_lpstrTitleBarBase(NULL), m_cchTitleBarLength(100), m_bDestroyPageOnRemove(true), m_bDestroyImageList(true), m_bActivePageMenuItem(true), m_bActiveAsDefaultMenuItem(false), m_bEmptyMenuItem(false), m_bWindowsMenuItem(false), m_bNoTabDrag(false), m_bTabCapture(false), m_bTabDrag(false), m_bInternalFont(false) { m_ptStartDrag.x = 0; m_ptStartDrag.y = 0; } ~CTabViewImpl() { delete [] m_lpstrTitleBarBase; } // Message filter function - to be called from PreTranslateMessage of the main window BOOL PreTranslateMessage(MSG* pMsg) { if(IsWindow() == FALSE) return FALSE; BOOL bRet = FALSE; // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page) int nCount = GetPageCount(); if(nCount > 0) { bool bControl = (::GetKeyState(VK_CONTROL) < 0); if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl) { if(nCount > 1) { int nPage = m_nActivePage; bool bShift = (::GetKeyState(VK_SHIFT) < 0); if(bShift) nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1); else nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0; SetActivePage(nPage); T* pT = static_cast(this); pT->OnPageActivated(m_nActivePage); } bRet = TRUE; } } // If we are doing drag-drop, check for Escape key that cancels it if(bRet == FALSE) { if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) { ::ReleaseCapture(); bRet = TRUE; } } // Pass the message to the active page if(bRet == FALSE) { if(m_nActivePage != -1) bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg); } return bRet; } // Attributes int GetPageCount() const { ATLASSERT(::IsWindow(m_hWnd)); return m_tab.GetItemCount(); } int GetActivePage() const { return m_nActivePage; } void SetActivePage(int nPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); T* pT = static_cast(this); SetRedraw(FALSE); if(m_nActivePage != -1) ::ShowWindow(GetPageHWND(m_nActivePage), FALSE); m_nActivePage = nPage; m_tab.SetCurSel(m_nActivePage); ::ShowWindow(GetPageHWND(m_nActivePage), TRUE); pT->UpdateLayout(); SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); if(::GetFocus() != m_tab.m_hWnd) ::SetFocus(GetPageHWND(m_nActivePage)); pT->UpdateTitleBar(); pT->UpdateMenu(); } HIMAGELIST GetImageList() const { ATLASSERT(::IsWindow(m_hWnd)); return m_tab.GetImageList(); } HIMAGELIST SetImageList(HIMAGELIST hImageList) { ATLASSERT(::IsWindow(m_hWnd)); return m_tab.SetImageList(hImageList); } void SetWindowMenu(HMENU hMenu) { ATLASSERT(::IsWindow(m_hWnd)); m_menu = hMenu; T* pT = static_cast(this); pT->UpdateMenu(); } void SetTitleBarWindow(HWND hWnd) { ATLASSERT(::IsWindow(m_hWnd)); delete [] m_lpstrTitleBarBase; m_lpstrTitleBarBase = NULL; m_wndTitleBar = hWnd; if(hWnd == NULL) return; int cchLen = m_wndTitleBar.GetWindowTextLength() + 1; ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]); if(m_lpstrTitleBarBase != NULL) { m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen); T* pT = static_cast(this); pT->UpdateTitleBar(); } } // Page attributes HWND GetPageHWND(int nPage) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_PARAM; m_tab.GetItem(nPage, tcix); return tcix.tvpage.hWnd; } LPCTSTR GetPageTitle(int nPage) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_PARAM; if(m_tab.GetItem(nPage, tcix) == FALSE) return NULL; return tcix.tvpage.lpstrTitle; } bool SetPageTitle(int nPage, LPCTSTR lpstrTitle) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); T* pT = static_cast(this); int cchBuff = lstrlen(lpstrTitle) + 1; LPTSTR lpstrBuff = NULL; ATLTRY(lpstrBuff = new TCHAR[cchBuff]); if(lpstrBuff == NULL) return false; SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_PARAM; if(m_tab.GetItem(nPage, tcix) == FALSE) return false; CTempBuffer buff; LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); if(lpstrTabText == NULL) return false; delete [] tcix.tvpage.lpstrTitle; pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM; tcix.tciheader.pszText = lpstrTabText; tcix.tvpage.lpstrTitle = lpstrBuff; if(m_tab.SetItem(nPage, tcix) == FALSE) return false; pT->UpdateTitleBar(); pT->UpdateMenu(); return true; } LPVOID GetPageData(int nPage) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_PARAM; m_tab.GetItem(nPage, tcix); return tcix.tvpage.pData; } LPVOID SetPageData(int nPage, LPVOID pData) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_PARAM; m_tab.GetItem(nPage, tcix); LPVOID pDataOld = tcix.tvpage.pData; tcix.tvpage.pData = pData; m_tab.SetItem(nPage, tcix); return pDataOld; } int GetPageImage(int nPage) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_IMAGE; m_tab.GetItem(nPage, tcix); return tcix.tciheader.iImage; } int SetPageImage(int nPage, int nImage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_IMAGE; m_tab.GetItem(nPage, tcix); int nImageOld = tcix.tciheader.iImage; tcix.tciheader.iImage = nImage; m_tab.SetItem(nPage, tcix); return nImageOld; } // Operations bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) { return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData); } bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage)); T* pT = static_cast(this); int cchBuff = lstrlen(lpstrTitle) + 1; LPTSTR lpstrBuff = NULL; ATLTRY(lpstrBuff = new TCHAR[cchBuff]); if(lpstrBuff == NULL) return false; SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); CTempBuffer buff; LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); if(lpstrTabText == NULL) return false; pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); SetRedraw(FALSE); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; tcix.tciheader.pszText = lpstrTabText; tcix.tciheader.iImage = nImage; tcix.tvpage.hWnd = hWndView; tcix.tvpage.lpstrTitle = lpstrBuff; tcix.tvpage.pData = pData; int nItem = m_tab.InsertItem(nPage, tcix); if(nItem == -1) { delete [] lpstrBuff; SetRedraw(TRUE); return false; } // adjust active page index, if inserted before it if(nPage <= m_nActivePage) m_nActivePage++; SetActivePage(nItem); pT->OnPageActivated(m_nActivePage); if(GetPageCount() == 1) pT->ShowTabControl(true); pT->UpdateLayout(); SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); return true; } void RemovePage(int nPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(IsValidPageIndex(nPage)); T* pT = static_cast(this); SetRedraw(FALSE); if(GetPageCount() == 1) pT->ShowTabControl(false); if(m_bDestroyPageOnRemove) ::DestroyWindow(GetPageHWND(nPage)); else ::ShowWindow(GetPageHWND(nPage), FALSE); LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage); delete [] lpstrTitle; ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE); if(m_nActivePage == nPage) { m_nActivePage = -1; if(nPage > 0) { SetActivePage(nPage - 1); } else if(GetPageCount() > 0) { SetActivePage(nPage); } else { SetRedraw(TRUE); Invalidate(); UpdateWindow(); pT->UpdateTitleBar(); pT->UpdateMenu(); } } else { nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage; m_nActivePage = -1; SetActivePage(nPage); } pT->OnPageActivated(m_nActivePage); } void RemoveAllPages() { ATLASSERT(::IsWindow(m_hWnd)); if(GetPageCount() == 0) return; T* pT = static_cast(this); SetRedraw(FALSE); pT->ShowTabControl(false); for(int i = 0; i < GetPageCount(); i++) { if(m_bDestroyPageOnRemove) ::DestroyWindow(GetPageHWND(i)); else ::ShowWindow(GetPageHWND(i), FALSE); LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i); delete [] lpstrTitle; } m_tab.DeleteAllItems(); m_nActivePage = -1; pT->OnPageActivated(m_nActivePage); SetRedraw(TRUE); Invalidate(); UpdateWindow(); pT->UpdateTitleBar(); pT->UpdateMenu(); } int PageIndexFromHwnd(HWND hWnd) const { int nIndex = -1; for(int i = 0; i < GetPageCount(); i++) { if(GetPageHWND(i) == hWnd) { nIndex = i; break; } } return nIndex; } void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false) { ATLASSERT(::IsWindow(m_hWnd)); CMenuHandle menu = hMenu; T* pT = static_cast(this); pT; // avoid level 4 warning int nFirstPos = 0; // Find first menu item in our range #ifndef _WIN32_WCE for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++) { UINT nID = menu.GetMenuItemID(nFirstPos); if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST) break; } #else // CE specific for(nFirstPos = 0; ; nFirstPos++) { CMenuItemInfo mii; mii.fMask = MIIM_ID; BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii); if(bRet == FALSE) break; if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST) break; } #endif // _WIN32_WCE // Remove all menu items for tab pages BOOL bRet = TRUE; while(bRet != FALSE) bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION); // Add separator if it's not already there int nPageCount = GetPageCount(); if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0)) { CMenuItemInfo mii; mii.fMask = MIIM_TYPE; menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0)) { menu.AppendMenu(MF_SEPARATOR); nFirstPos++; } } // Add menu items for all pages if(nPageCount > 0) { // Append menu items for all pages const int cchPrefix = 3; // 2 digits + space nMenuItemsCount = __min(__min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax); ATLASSERT(nMenuItemsCount < 100); // 2 digits only if(nMenuItemsCount >= 100) nMenuItemsCount = 99; for(int i = 0; i < nMenuItemsCount; i++) { LPCTSTR lpstrTitle = GetPageTitle(i); int nLen = lstrlen(lpstrTitle); CTempBuffer buff; LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1); ATLASSERT(lpstrText != NULL); if(lpstrText != NULL) { LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s"); SecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle); menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText); } } // Mark active page if(bActivePageMenuItem && (m_nActivePage != -1)) { #ifndef _WIN32_WCE if(bActiveAsDefaultMenuItem) { menu.SetMenuDefaultItem((UINT)-1, TRUE); menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE); } else #else // CE specific bActiveAsDefaultMenuItem; // avoid level 4 warning #endif // _WIN32_WCE { menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION); } } } else { if(bEmptyMenuItem) { menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText()); menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED); } // Remove separator if nothing else is there if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0)) { CMenuItemInfo mii; mii.fMask = MIIM_TYPE; menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); if((mii.fType & MFT_SEPARATOR) != 0) menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION); } } // Add "Windows..." menu item if(bWindowsMenuItem) menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText()); } BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->CreateTabControl(); pT->UpdateLayout(); } return bRet; } // Message map and handlers BEGIN_MSG_MAP(CTabViewImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_GETFONT, OnGetFont) MESSAGE_HANDLER(WM_SETFONT, OnSetFont) NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged) NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification) #ifndef _WIN32_WCE NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo) #endif // !_WIN32_WCE FORWARD_NOTIFICATIONS() ALT_MSG_MAP(1) // tab control MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown) MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged) MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove) MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->CreateTabControl(); return 0; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { RemoveAllPages(); if(m_bDestroyImageList) { CImageList il = m_tab.SetImageList(NULL); if(il.m_hImageList != NULL) il.Destroy(); } if(m_bInternalFont) { HFONT hFont = m_tab.GetFont(); m_tab.SetFont(NULL, FALSE); ::DeleteObject(hFont); m_bInternalFont = false; } return 0; } LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->UpdateLayout(); return 0; } LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_nActivePage != -1) ::SetFocus(GetPageHWND(m_nActivePage)); return 0; } LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return m_tab.SendMessage(WM_GETFONT); } LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if(m_bInternalFont) { HFONT hFont = m_tab.GetFont(); m_tab.SetFont(NULL, FALSE); ::DeleteObject(hFont); m_bInternalFont = false; } m_tab.SendMessage(WM_SETFONT, wParam, lParam); T* pT = static_cast(this); m_cyTabHeight = pT->CalcTabHeight(); if((BOOL)lParam != FALSE) pT->UpdateLayout(); return 0; } LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { SetActivePage(m_tab.GetCurSel()); T* pT = static_cast(this); pT->OnPageActivated(m_nActivePage); return 0; } LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { // nothing to do - this just blocks all tab control // notifications from being propagated further return 0; } #ifndef _WIN32_WCE LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh; if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips()) { T* pT = static_cast(this); pT->UpdateTooltipText(pTTDI); } else { bHandled = FALSE; } return 0; } #endif // !_WIN32_WCE // Tab control message handlers LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(!m_bNoTabDrag && (m_tab.GetItemCount() > 1)) { m_bTabCapture = true; m_tab.SetCapture(); m_ptStartDrag.x = GET_X_LPARAM(lParam); m_ptStartDrag.y = GET_Y_LPARAM(lParam); } bHandled = FALSE; return 0; } LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(m_bTabCapture) { if(m_bTabDrag) { TCHITTESTINFO hti = { 0 }; hti.pt.x = GET_X_LPARAM(lParam); hti.pt.y = GET_Y_LPARAM(lParam); int nItem = m_tab.HitTest(&hti); if(nItem != -1) MovePage(m_nActivePage, nItem); } ::ReleaseCapture(); } bHandled = FALSE; return 0; } LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bTabCapture) { m_bTabCapture = false; if(m_bTabDrag) { m_bTabDrag = false; T* pT = static_cast(this); pT->DrawMoveMark(-1); #ifndef _WIN32_WCE m_ilDrag.DragLeave(GetDesktopWindow()); #endif // !_WIN32_WCE m_ilDrag.EndDrag(); m_ilDrag.Destroy(); m_ilDrag.m_hImageList = NULL; } } bHandled = FALSE; return 0; } LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; if(m_bTabCapture) { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if(!m_bTabDrag) { #ifndef _WIN32_WCE if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) || abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG)) #else // CE specific if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 || abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4) #endif // _WIN32_WCE { T* pT = static_cast(this); pT->GenerateDragImage(m_nActivePage); int cxCursor = ::GetSystemMetrics(SM_CXCURSOR); int cyCursor = ::GetSystemMetrics(SM_CYCURSOR); m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2)); #ifndef _WIN32_WCE POINT ptEnter = m_ptStartDrag; m_tab.ClientToScreen(&ptEnter); m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter); #endif // !_WIN32_WCE m_bTabDrag = true; } } if(m_bTabDrag) { TCHITTESTINFO hti = { 0 }; hti.pt = pt; int nItem = m_tab.HitTest(&hti); T* pT = static_cast(this); pT->SetMoveCursor(nItem != -1); if(m_nInsertItem != nItem) pT->DrawMoveMark(nItem); m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE); m_tab.ClientToScreen(&pt); m_ilDrag.DragMove(pt); bHandled = TRUE; } } return 0; } LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { TCHITTESTINFO hti = { 0 }; hti.pt.x = GET_X_LPARAM(lParam); hti.pt.y = GET_Y_LPARAM(lParam); int nItem = m_tab.HitTest(&hti); if(nItem != -1) { T* pT = static_cast(this); pT->OnContextMenu(nItem, hti.pt); } return 0; } LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bool bShift = (::GetKeyState(VK_SHIFT) < 0); if(wParam == VK_F10 && bShift) { if(m_nActivePage != -1) { RECT rect = { 0 }; m_tab.GetItemRect(m_nActivePage, &rect); POINT pt = { rect.left, rect.bottom }; T* pT = static_cast(this); pT->OnContextMenu(m_nActivePage, pt); } } else { bHandled = FALSE; } return 0; } // Implementation helpers bool IsValidPageIndex(int nPage) const { return (nPage >= 0 && nPage < GetPageCount()); } bool MovePage(int nMovePage, int nInsertBeforePage) { ATLASSERT(IsValidPageIndex(nMovePage)); ATLASSERT(IsValidPageIndex(nInsertBeforePage)); if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage)) return false; if(nMovePage == nInsertBeforePage) return true; // nothing to do CTempBuffer buff; LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); if(lpstrTabText == NULL) return false; TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; tcix.tciheader.pszText = lpstrTabText; tcix.tciheader.cchTextMax = m_cchTabTextLength + 1; BOOL bRet = m_tab.GetItem(nMovePage, tcix); ATLASSERT(bRet != FALSE); if(bRet == FALSE) return false; int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage; int nNewItem = m_tab.InsertItem(nInsertItem, tcix); ATLASSERT(nNewItem == nInsertItem); if(nNewItem != nInsertItem) { ATLVERIFY(m_tab.DeleteItem(nNewItem)); return false; } if(nMovePage > nInsertBeforePage) ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE); else if(nMovePage < nInsertBeforePage) ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE); SetActivePage(nInsertBeforePage); T* pT = static_cast(this); pT->OnPageActivated(m_nActivePage); return true; } // Implementation overrideables bool CreateTabControl() { #ifndef _WIN32_WCE m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); #else // CE specific m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID); #endif // _WIN32_WCE ATLASSERT(m_tab.m_hWnd != NULL); if(m_tab.m_hWnd == NULL) return false; m_tab.SetFont(AtlCreateControlFont()); m_bInternalFont = true; m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); T* pT = static_cast(this); m_cyTabHeight = pT->CalcTabHeight(); return true; } int CalcTabHeight() { int nCount = m_tab.GetItemCount(); TCHAR szText[] = _T("NS"); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_TEXT; tcix.tciheader.pszText = szText; int nIndex = m_tab.InsertItem(nCount, tcix); RECT rect = { 0, 0, 1000, 1000 }; m_tab.AdjustRect(FALSE, &rect); RECT rcWnd = { 0, 0, 1000, rect.top }; ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); int nHeight = rcWnd.bottom - rcWnd.top; m_tab.DeleteItem(nIndex); return nHeight; } void ShowTabControl(bool bShow) { m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE); T* pT = static_cast(this); pT->UpdateLayout(); } void UpdateLayout() { RECT rect = { 0 }; GetClientRect(&rect); int cyOffset = 0; if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) { m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER); cyOffset = m_cyTabHeight; } if(m_nActivePage != -1) ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, cyOffset, rect.right - rect.left, rect.bottom - rect.top - cyOffset, SWP_NOZORDER); } void UpdateMenu() { if(m_menu.m_hMenu != NULL) BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem); } void UpdateTitleBar() { if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL) return; // nothing to do if(m_nActivePage != -1) { T* pT = static_cast(this); LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage); LPCTSTR lpstrDivider = pT->GetTitleDividerText(); int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1; CTempBuffer buff; LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer); ATLASSERT(lpstrPageTitle != NULL); if(lpstrPageTitle != NULL) { pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1); SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider); SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase); } else { lpstrPageTitle = m_lpstrTitleBarBase; } m_wndTitleBar.SetWindowText(lpstrPageTitle); } else { m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase); } } void DrawMoveMark(int nItem) { T* pT = static_cast(this); if(m_nInsertItem != -1) { RECT rect = { 0 }; pT->GetMoveMarkRect(rect); m_tab.InvalidateRect(&rect); } m_nInsertItem = nItem; if(m_nInsertItem != -1) { CClientDC dc(m_tab.m_hWnd); RECT rect = { 0 }; pT->GetMoveMarkRect(rect); CPen pen; pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT)); CBrush brush; brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT)); HPEN hPenOld = dc.SelectPen(pen); HBRUSH hBrushOld = dc.SelectBrush(brush); int x = rect.left; int y = rect.top; POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } }; dc.Polygon(ptsTop, 3); y = rect.bottom - 1; POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } }; dc.Polygon(ptsBottom, 3); dc.SelectPen(hPenOld); dc.SelectBrush(hBrushOld); } } void GetMoveMarkRect(RECT& rect) const { m_tab.GetClientRect(&rect); RECT rcItem = { 0 }; m_tab.GetItemRect(m_nInsertItem, &rcItem); if(m_nInsertItem <= m_nActivePage) { rect.left = rcItem.left - m_cxMoveMark / 2 - 1; rect.right = rcItem.left + m_cxMoveMark / 2; } else { rect.left = rcItem.right - m_cxMoveMark / 2 - 1; rect.right = rcItem.right + m_cxMoveMark / 2; } } void SetMoveCursor(bool bCanMove) { ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO)); } void GenerateDragImage(int nItem) { ATLASSERT(IsValidPageIndex(nItem)); #ifndef _WIN32_WCE RECT rcItem = { 0 }; m_tab.GetItemRect(nItem, &rcItem); ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item #else // CE specific nItem; // avoid level 4 warning RECT rcItem = { 0, 0, 40, 20 }; #endif // _WIN32_WCE ATLASSERT(m_ilDrag.m_hImageList == NULL); m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1); CClientDC dc(m_hWnd); CDC dcMem; dcMem.CreateCompatibleDC(dc); ATLASSERT(dcMem.m_hDC != NULL); dcMem.SetViewportOrg(-rcItem.left, -rcItem.top); CBitmap bmp; bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top); ATLASSERT(bmp.m_hBitmap != NULL); HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); #ifndef _WIN32_WCE m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC); #else // CE specific dcMem.Rectangle(&rcItem); #endif // _WIN32_WCE dcMem.SelectBitmap(hBmpOld); ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1); } void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle) { if(lstrlen(lpstrTitle) >= cchShortTitle) { LPCTSTR lpstrEllipsis = _T("..."); int cchEllipsis = lstrlen(lpstrEllipsis); SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1); SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis); } else { SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle); } } #ifndef _WIN32_WCE void UpdateTooltipText(LPNMTTDISPINFO pTTDI) { ATLASSERT(pTTDI != NULL); pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom); } #endif // !_WIN32_WCE // Text for menu items and title bar - override to provide different strings static LPCTSTR GetEmptyListText() { return _T("(Empty)"); } static LPCTSTR GetWindowsMenuItemText() { return _T("&Windows..."); } static LPCTSTR GetTitleDividerText() { return _T(" - "); } // Notifications - override to provide different behavior void OnPageActivated(int nPage) { NMHDR nmhdr = { 0 }; nmhdr.hwndFrom = m_hWnd; nmhdr.idFrom = nPage; nmhdr.code = TBVN_PAGEACTIVATED; ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); } void OnContextMenu(int nPage, POINT pt) { m_tab.ClientToScreen(&pt); TBVCONTEXTMENUINFO cmi = { 0 }; cmi.hdr.hwndFrom = m_hWnd; cmi.hdr.idFrom = nPage; cmi.hdr.code = TBVN_CONTEXTMENU; cmi.pt = pt; ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi); } }; class CTabView : public CTabViewImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE) }; }; // namespace WTL #endif // __ATLCTRLX_H__ ================================================ FILE: WTL/atlddx.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLDDX_H__ #define __ATLDDX_H__ #pragma once #ifndef __ATLAPP_H__ #error atlddx.h requires atlapp.h to be included first #endif #if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) #error Cannot use floating point DDX with _ATL_MIN_CRT defined #endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT) #ifdef _ATL_USE_DDX_FLOAT #include #endif // _ATL_USE_DDX_FLOAT /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CWinDataExchange namespace WTL { // Constants #define DDX_LOAD FALSE #define DDX_SAVE TRUE // DDX map macros #define BEGIN_DDX_MAP(thisClass) \ BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \ { \ (bSaveAndValidate); \ (nCtlID); #define DDX_TEXT(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \ return FALSE; \ } #define DDX_TEXT_LEN(nID, var, len) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \ return FALSE; \ } #define DDX_INT(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \ return FALSE; \ } #define DDX_INT_RANGE(nID, var, min, max) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \ return FALSE; \ } #define DDX_UINT(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \ return FALSE; \ } #define DDX_UINT_RANGE(nID, var, min, max) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \ return FALSE; \ } #ifdef _ATL_USE_DDX_FLOAT #define DDX_FLOAT(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Float(nID, var, bSaveAndValidate)) \ return FALSE; \ } #define DDX_FLOAT_RANGE(nID, var, min, max) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \ return FALSE; \ } #define DDX_FLOAT_P(nID, var, precision) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \ return FALSE; \ } #define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ { \ if(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \ return FALSE; \ } #endif // _ATL_USE_DDX_FLOAT #define DDX_CONTROL(nID, obj) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ DDX_Control(nID, obj, bSaveAndValidate); #define DDX_CONTROL_HANDLE(nID, obj) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ DDX_Control_Handle(nID, obj, bSaveAndValidate); #define DDX_CHECK(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ DDX_Check(nID, var, bSaveAndValidate); #define DDX_RADIO(nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ DDX_Radio(nID, var, bSaveAndValidate); #define END_DDX_MAP() \ return TRUE; \ } // DDX support for Tab, Combo, ListBox and ListView selection index // Note: Specialized versions require atlctrls.h to be included first #if (_MSC_VER >= 1300) #define DDX_INDEX(CtrlClass, nID, var) \ if(nCtlID == (UINT)-1 || nCtlID == nID) \ DDX_Index(nID, var, bSaveAndValidate); #ifdef __ATLCTRLS_H__ #define DDX_TAB_INDEX(nID, var) DDX_INDEX(WTL::CTabCtrl, nID, var) #ifndef WIN32_PLATFORM_WFSP // No COMBOBOX on SmartPhones #define DDX_COMBO_INDEX(nID, var) DDX_INDEX(WTL::CComboBox, nID, var) #endif #define DDX_LISTBOX_INDEX(nID, var) DDX_INDEX(WTL::CListBox, nID, var) #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var) #endif // __ATLCTRLS_H__ #endif // (_MSC_VER >= 1300) /////////////////////////////////////////////////////////////////////////////// // CWinDataExchange - provides support for DDX template class CWinDataExchange { public: // Data exchange method - override in your derived class BOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1) { // this one should never be called, override it in // your derived class by implementing DDX map ATLASSERT(FALSE); return FALSE; } // Helpers for validation error reporting enum _XDataType { ddxDataNull = 0, ddxDataText = 1, ddxDataInt = 2, ddxDataFloat = 3, ddxDataDouble = 4 }; struct _XTextData { int nLength; int nMaxLength; }; struct _XIntData { long nVal; long nMin; long nMax; }; struct _XFloatData { double nVal; double nMin; double nMax; }; struct _XData { _XDataType nDataType; union { _XTextData textData; _XIntData intData; _XFloatData floatData; }; }; // Text exchange BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) { T* pT = static_cast(this); BOOL bSuccess = TRUE; if(bSave) { HWND hWndCtrl = pT->GetDlgItem(nID); int nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR)); if(nRetLen < ::GetWindowTextLength(hWndCtrl)) bSuccess = FALSE; } else { ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); bSuccess = pT->SetDlgItemText(nID, lpstrText); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nLength > 0); if(lstrlen(lpstrText) > nLength) { _XData data = { ddxDataText }; data.textData.nLength = lstrlen(lpstrText); data.textData.nMaxLength = nLength; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) { T* pT = static_cast(this); BOOL bSuccess = TRUE; if(bSave) { bSuccess = pT->GetDlgItemText(nID, bstrText); } else { USES_CONVERSION; LPTSTR lpstrText = OLE2T(bstrText); ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); bSuccess = pT->SetDlgItemText(nID, lpstrText); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nLength > 0); if((int)::SysStringLen(bstrText) > nLength) { _XData data = { ddxDataText }; data.textData.nLength = (int)::SysStringLen(bstrText); data.textData.nMaxLength = nLength; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } BOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) { T* pT = static_cast(this); BOOL bSuccess = TRUE; if(bSave) { bSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText); } else { USES_CONVERSION; LPTSTR lpstrText = OLE2T(bstrText); ATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength)); bSuccess = pT->SetDlgItemText(nID, lpstrText); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nLength > 0); if((int)bstrText.Length() > nLength) { _XData data = { ddxDataText }; data.textData.nLength = (int)bstrText.Length(); data.textData.nMaxLength = nLength; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) { T* pT = static_cast(this); BOOL bSuccess = TRUE; if(bSave) { HWND hWndCtrl = pT->GetDlgItem(nID); int nLen = ::GetWindowTextLength(hWndCtrl); int nRetLen = -1; LPTSTR lpstr = strText.GetBufferSetLength(nLen); if(lpstr != NULL) { nRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1); strText.ReleaseBuffer(); } if(nRetLen < nLen) bSuccess = FALSE; } else { bSuccess = pT->SetDlgItemText(nID, strText); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nLength > 0); if(strText.GetLength() > nLength) { _XData data = { ddxDataText }; data.textData.nLength = strText.GetLength(); data.textData.nMaxLength = nLength; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Numeric exchange template BOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0) { T* pT = static_cast(this); BOOL bSuccess = TRUE; if(bSave) { nVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned); } else { ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); bSuccess = pT->SetDlgItemInt(nID, nVal, bSigned); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nMin != nMax); if(nVal < nMin || nVal > nMax) { _XData data = { ddxDataInt }; data.intData.nVal = (long)nVal; data.intData.nMin = (long)nMin; data.intData.nMax = (long)nMax; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } // Float exchange #ifdef _ATL_USE_DDX_FLOAT static BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d) { ATLASSERT(lpszText != NULL); while (*lpszText == _T(' ') || *lpszText == _T('\t')) lpszText++; TCHAR chFirst = lpszText[0]; d = _tcstod(lpszText, (LPTSTR*)&lpszText); if (d == 0.0 && chFirst != _T('0')) return FALSE; // could not convert while (*lpszText == _T(' ') || *lpszText == _T('\t')) lpszText++; if (*lpszText != _T('\0')) return FALSE; // not terminated properly return TRUE; } BOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG) { T* pT = static_cast(this); BOOL bSuccess = TRUE; const int cchBuff = 32; TCHAR szBuff[cchBuff] = { 0 }; if(bSave) { pT->GetDlgItemText(nID, szBuff, cchBuff); double d = 0; if(_AtlSimpleFloatParse(szBuff, d)) nVal = (float)d; else bSuccess = FALSE; } else { ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); bSuccess = pT->SetDlgItemText(nID, szBuff); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nMin != nMax); if(nVal < nMin || nVal > nMax) { _XData data = { ddxDataFloat }; data.floatData.nVal = (double)nVal; data.floatData.nMin = (double)nMin; data.floatData.nMax = (double)nMax; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } BOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG) { T* pT = static_cast(this); BOOL bSuccess = TRUE; const int cchBuff = 32; TCHAR szBuff[cchBuff] = { 0 }; if(bSave) { pT->GetDlgItemText(nID, szBuff, cchBuff); double d = 0; if(_AtlSimpleFloatParse(szBuff, d)) nVal = d; else bSuccess = FALSE; } else { ATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax)); SecureHelper::sprintf_x(szBuff, cchBuff, _T("%.*g"), nPrecision, nVal); bSuccess = pT->SetDlgItemText(nID, szBuff); } if(!bSuccess) { pT->OnDataExchangeError(nID, bSave); } else if(bSave && bValidate) // validation { ATLASSERT(nMin != nMax); if(nVal < nMin || nVal > nMax) { _XData data = { ddxDataFloat }; data.floatData.nVal = nVal; data.floatData.nMin = nMin; data.floatData.nMax = nMax; pT->OnDataValidateError(nID, bSave, data); bSuccess = FALSE; } } return bSuccess; } #endif // _ATL_USE_DDX_FLOAT // Full control subclassing (for CWindowImpl derived controls) template void DDX_Control(UINT nID, TControl& ctrl, BOOL bSave) { if(!bSave && ctrl.m_hWnd == NULL) { T* pT = static_cast(this); ctrl.SubclassWindow(pT->GetDlgItem(nID)); } } // Simple control attaching (for HWND wrapper controls) template void DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave) { if(!bSave && ctrl.m_hWnd == NULL) { T* pT = static_cast(this); ctrl = pT->GetDlgItem(nID); } } // Control state void DDX_Check(UINT nID, int& nValue, BOOL bSave) { T* pT = static_cast(this); HWND hWndCtrl = pT->GetDlgItem(nID); if(bSave) { nValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L); ATLASSERT(nValue >= 0 && nValue <= 2); } else { if(nValue < 0 || nValue > 2) { ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - dialog data checkbox value (%d) out of range.\n"), nValue); nValue = 0; // default to off } ::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L); } } // variant that supports bool (checked/not-checked, no intermediate state) void DDX_Check(UINT nID, bool& bCheck, BOOL bSave) { int nValue = bCheck ? 1 : 0; DDX_Check(nID, nValue, bSave); if(bSave) { if(nValue == 2) ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - checkbox state (%d) out of supported range.\n"), nValue); bCheck = (nValue == 1); } } void DDX_Radio(UINT nID, int& nValue, BOOL bSave) { T* pT = static_cast(this); HWND hWndCtrl = pT->GetDlgItem(nID); ATLASSERT(hWndCtrl != NULL); // must be first in a group of auto radio buttons ATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP); ATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); if(bSave) nValue = -1; // value if none found // walk all children in group int nButton = 0; do { if(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON) { // control in group is a radio button if(bSave) { if(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0) { ATLASSERT(nValue == -1); // only set once nValue = nButton; } } else { // select button ::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L); } nButton++; } else { ATLTRACE2(atlTraceUI, 0, _T("ATL: Warning - skipping non-radio button in group.\n")); } hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); } while (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP)); } // DDX support for Tab, Combo, ListBox and ListView selection index #if (_MSC_VER >= 1300) template INT _getSel(TCtrl& tCtrl) { return tCtrl.GetCurSel(); } template void _setSel(TCtrl& tCtrl, INT iSel) { if(iSel < 0) tCtrl.SetCurSel(-1); else tCtrl.SetCurSel(iSel); } #ifdef __ATLCTRLS_H__ // ListViewCtrl specialization template <> INT _getSel(WTL::CListViewCtrl& tCtrl) { return tCtrl.GetSelectedIndex(); } template <> void _setSel(WTL::CListViewCtrl& tCtrl, INT iSel) { if(iSel < 0) tCtrl.SelectItem(-1); else tCtrl.SelectItem(iSel); } #endif // __ATLCTRLS_H__ template void DDX_Index(UINT nID, INT& nVal, BOOL bSave) { T* pT = static_cast(this); TCtrl ctrl(pT->GetDlgItem(nID)); if(bSave) nVal = _getSel(ctrl); else _setSel(ctrl, nVal); } #endif // (_MSC_VER >= 1300) // Overrideables void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) { // Override to display an error message ::MessageBeep((UINT)-1); T* pT = static_cast(this); ::SetFocus(pT->GetDlgItem(nCtrlID)); } void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) { // Override to display an error message ::MessageBeep((UINT)-1); T* pT = static_cast(this); ::SetFocus(pT->GetDlgItem(nCtrlID)); } }; }; // namespace WTL #endif // __ATLDDX_H__ ================================================ FILE: WTL/atldlgs.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLDLGS_H__ #define __ATLDLGS_H__ #pragma once #ifndef __ATLAPP_H__ #error atldlgs.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atldlgs.h requires atlwin.h to be included first #endif #include #include #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) #include #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CFileDialogImpl // CFileDialog // CFileDialogEx // CMultiFileDialogImpl // CMultiFileDialog // CShellFileDialogImpl // CShellFileOpenDialogImpl // CShellFileOpenDialog // CShellFileSaveDialogImpl // CShellFileSaveDialog // CFolderDialogImpl // CFolderDialog // CFontDialogImpl // CFontDialog // CRichEditFontDialogImpl // CRichEditFontDialog // CColorDialogImpl // CColorDialog // CPrintDialogImpl // CPrintDialog // CPrintDialogExImpl // CPrintDialogEx // CPageSetupDialogImpl // CPageSetupDialog // CFindReplaceDialogImpl // CFindReplaceDialog // // CDialogBaseUnits // CMemDlgTemplate // CIndirectDialogImpl // // CPropertySheetWindow // CPropertySheetImpl // CPropertySheet // CPropertyPageWindow // CPropertyPageImpl // CPropertyPage // CAxPropertyPageImpl // CAxPropertyPage // // CWizard97SheetWindow // CWizard97SheetImpl // CWizard97Sheet // CWizard97PageWindow // CWizard97PageImpl // CWizard97ExteriorPageImpl // CWizard97InteriorPageImpl // // CAeroWizardFrameWindow // CAeroWizardFrameImpl // CAeroWizardFrame // CAeroWizardPageWindow // CAeroWizardPageImpl // CAeroWizardPage // CAeroWizardAxPageImpl // CAeroWizardAxPage // // CTaskDialogConfig // CTaskDialogImpl // CTaskDialog // // Global functions: // AtlTaskDialog() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CFileDialogImpl - used for File Open or File Save As // compatibility with the old (vc6.0) headers #if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) #ifndef CDSIZEOF_STRUCT #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) #endif #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) #ifdef UNICODE #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400W #else #define OPENFILENAME_SIZE_VERSION_400 OPENFILENAME_SIZE_VERSION_400A #endif // !UNICODE #endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400) #if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM) #define CDN_INCLUDEITEM (CDN_FIRST - 0x0007) #endif template class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase { public: #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) OPENFILENAMEEX m_ofn; #else OPENFILENAME m_ofn; #endif BOOL m_bOpenFileDialog; // TRUE for file open, FALSE for file save TCHAR m_szFileTitle[_MAX_FNAME]; // contains file title after return TCHAR m_szFileName[_MAX_PATH]; // contains full path name after return CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, HWND hWndParent = NULL) { memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL m_szFileName[0] = _T('\0'); m_szFileTitle[0] = _T('\0'); m_bOpenFileDialog = bOpenFileDialog; #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME); #else m_ofn.lStructSize = sizeof(m_ofn); #endif #if (_WIN32_WINNT >= 0x0500) // adjust struct size if running on older version of Windows if(AtlIsOldWindows()) { ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400); // must be m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; } #endif // (_WIN32_WINNT >= 0x0500) m_ofn.lpstrFile = m_szFileName; m_ofn.nMaxFile = _MAX_PATH; m_ofn.lpstrDefExt = lpszDefExt; m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle; m_ofn.nMaxFileTitle = _MAX_FNAME; #ifndef _WIN32_WCE m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING; #else // CE specific m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK; #endif // !_WIN32_WCE m_ofn.lpstrFilter = lpszFilter; m_ofn.hInstance = ModuleHelper::GetResourceInstance(); m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc; m_ofn.hwndOwner = hWndParent; // setup initial file name if(lpszFileName != NULL) SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE); } INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0); ATLASSERT(m_ofn.lpfnHook != NULL); // can still be a user hook ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); if(m_ofn.hwndOwner == NULL) // set only if not specified before m_ofn.hwndOwner = hWndParent; ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRetTh = m_thunk.Init(NULL, NULL); if(bRetTh == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this); BOOL bRet; if(m_bOpenFileDialog) #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) bRet = ::GetOpenFileNameEx(&m_ofn); else bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn); #else bRet = ::GetOpenFileName(&m_ofn); else bRet = ::GetSaveFileName(&m_ofn); #endif m_hWnd = NULL; return bRet ? IDOK : IDCANCEL; } // Attributes ATL::CWindow GetFileDialogWindow() const { ATLASSERT(::IsWindow(m_hWnd)); return ATL::CWindow(GetParent()); } int GetFilePath(LPTSTR lpstrFilePath, int nLength) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath); } int GetFolderIDList(LPVOID lpBuff, int nLength) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff); } int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath); } int GetSpec(LPTSTR lpstrSpec, int nLength) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec); } void SetControlText(int nCtrlID, LPCTSTR lpstrText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText); } void SetDefExt(LPCTSTR lpstrExt) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt); } BOOL GetReadOnlyPref() const // return TRUE if readonly checked { return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE; } // Operations void HideControl(int nCtrlID) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0); GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID); } // Special override for common dialogs BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) { ATLASSERT(::IsWindow(m_hWnd)); GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0)); return TRUE; } // Message map and handlers BEGIN_MSG_MAP(CFileDialogImpl) NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK) NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange) NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp) NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone) NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange) NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation) NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange) #ifndef _WIN32_WCE NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem) #endif // !_WIN32_WCE END_MSG_MAP() LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); return !pT->OnFileOK((LPOFNOTIFY)pnmh); } LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT->OnFolderChange((LPOFNOTIFY)pnmh); return 0; } LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT->OnHelp((LPOFNOTIFY)pnmh); return 0; } LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT->OnInitDone((LPOFNOTIFY)pnmh); return 0; } LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT->OnSelChange((LPOFNOTIFY)pnmh); return 0; } LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); return pT->OnShareViolation((LPOFNOTIFY)pnmh); } LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); pT->OnTypeChange((LPOFNOTIFY)pnmh); return 0; } #ifndef _WIN32_WCE LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) { ATLASSERT(::IsWindow(m_hWnd)); T* pT = static_cast(this); return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh); } #endif // !_WIN32_WCE // Overrideables BOOL OnFileOK(LPOFNOTIFY /*lpon*/) { return TRUE; } void OnFolderChange(LPOFNOTIFY /*lpon*/) { } void OnHelp(LPOFNOTIFY /*lpon*/) { } void OnInitDone(LPOFNOTIFY /*lpon*/) { } void OnSelChange(LPOFNOTIFY /*lpon*/) { } int OnShareViolation(LPOFNOTIFY /*lpon*/) { return 0; } void OnTypeChange(LPOFNOTIFY /*lpon*/) { } #ifndef _WIN32_WCE BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/) { return TRUE; // include item } #endif // !_WIN32_WCE }; class CFileDialog : public CFileDialogImpl { public: CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, HWND hWndParent = NULL) : CFileDialogImpl(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) { } // override base class map and references to handlers DECLARE_EMPTY_MSG_MAP() }; #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) class CFileDialogEx : public CFileDialogImpl { public: CFileDialogEx( // Supports only FileOpen LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW, OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO, LPCTSTR lpszFilter = NULL, HWND hWndParent = NULL) : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) { m_ofn.ExFlags = ExFlags; m_ofn.dwSortOrder = dwSortOrder; } // override base class map and references to handlers DECLARE_EMPTY_MSG_MAP() }; #endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501) /////////////////////////////////////////////////////////////////////////////// // Multi File Dialog - Multi-select File Open dialog #ifndef _WIN32_WCE // The class dynamically resizes the buffer as the file selection changes // (as described in Knowledge Base article 131462). It also expands selected // shortcut files to take into account the full path of the target file. // Note that this doesn't work on Win9x for the old style dialogs, as well as // on NT for non-Unicode builds. #ifndef _WTL_FIXED_OFN_BUFFER_LENGTH #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000 #endif template class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T > { public: mutable LPCTSTR m_pNextFile; #ifndef _UNICODE bool m_bIsNT; #endif CMultiFileDialogImpl( LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY, LPCTSTR lpszFilter = NULL, HWND hWndParent = NULL) : CFileDialogImpl(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent), m_pNextFile(NULL) { m_ofn.Flags |= OFN_ALLOWMULTISELECT; // Force multiple selection mode #ifndef _UNICODE #ifdef _versionhelpers_H_INCLUDED_ OSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) }; ovi.dwPlatformId = VER_PLATFORM_WIN32_NT; DWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); m_bIsNT = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE); #else // !_versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; ::GetVersionEx(&ovi); m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT); #endif // _versionhelpers_H_INCLUDED_ if (m_bIsNT) { // On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there // is absolutely nothing we can do except to start off with a large buffer. ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH)); } #endif } ~CMultiFileDialogImpl() { if (m_ofn.lpstrFile != m_szFileName) // Free the buffer if we allocated it delete[] m_ofn.lpstrFile; } // Operations // Get the directory that the files were chosen from. // The function returns the number of characters copied, not including the terminating zero. // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. // If the function fails, the return value is zero. int GetDirectory(LPTSTR pBuffer, int nBufLen) const { if (m_ofn.lpstrFile == NULL) return 0; LPCTSTR pStr = m_ofn.lpstrFile; int nLength = lstrlen(pStr); if (pStr[nLength + 1] == 0) { // The OFN buffer contains a single item so extract its path. LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\')); if (pSep != NULL) nLength = (int)(DWORD_PTR)(pSep - pStr); } int nRet = 0; if (pBuffer == NULL) // If the buffer is NULL, return the required length { nRet = nLength + 1; } else if (nBufLen > nLength) { SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength); nRet = nLength; } return nRet; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) bool GetDirectory(_CSTRING_NS::CString& strDir) const { bool bRet = false; int nLength = GetDirectory(NULL, 0); if (nLength > 0) { bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0); strDir.ReleaseBuffer(nLength - 1); } return bRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Get the first filename as a pointer into the buffer. LPCTSTR GetFirstFileName() const { if (m_ofn.lpstrFile == NULL) return NULL; m_pNextFile = NULL; // Reset internal buffer pointer LPCTSTR pStr = m_ofn.lpstrFile; int nLength = lstrlen(pStr); if (pStr[nLength + 1] != 0) { // Multiple items were selected. The first string is the directory, // so skip forwards to the second string. pStr += nLength + 1; // Set up m_pNext so it points to the second item (or null). m_pNextFile = pStr; GetNextFileName(); } else { // A single item was selected. Skip forward past the path. LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\')); if (pSep != NULL) pStr = pSep + 1; } return pStr; } // Get the next filename as a pointer into the buffer. LPCTSTR GetNextFileName() const { if (m_pNextFile == NULL) return NULL; LPCTSTR pStr = m_pNextFile; // Set "m_pNextFile" to point to the next file name, or null if we // have reached the last file in the list. int nLength = lstrlen(pStr); m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL; return pStr; } // Get the first filename as a full path. // The function returns the number of characters copied, not including the terminating zero. // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. // If the function fails, the return value is zero. int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const { LPCTSTR pStr = GetFirstFileName(); int nLengthDir = GetDirectory(NULL, 0); if((pStr == NULL) || (nLengthDir == 0)) return 0; // Figure out the required length. int nLengthTotal = nLengthDir + lstrlen(pStr); int nRet = 0; if(pBuffer == NULL) // If the buffer is NULL, return the required length { nRet = nLengthTotal + 1; } else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path { GetDirectory(pBuffer, nBufLen); SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); SecureHelper::strcat_x(pBuffer, nBufLen, pStr); nRet = nLengthTotal; } return nRet; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) bool GetFirstPathName(_CSTRING_NS::CString& strPath) const { bool bRet = false; int nLength = GetFirstPathName(NULL, 0); if (nLength > 0) { bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0); strPath.ReleaseBuffer(nLength - 1); } return bRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Get the next filename as a full path. // The function returns the number of characters copied, not including the terminating zero. // If the buffer is NULL, the function returns the required size, in characters, including the terminating zero. // If the function fails, the return value is zero. // The internal position marker is moved forward only if the function succeeds and the buffer was large enough. int GetNextPathName(LPTSTR pBuffer, int nBufLen) const { if (m_pNextFile == NULL) return 0; int nRet = 0; LPCTSTR pStr = m_pNextFile; // Does the filename contain a backslash? if (MinCrtHelper::_strrchr(pStr, _T('\\')) != NULL) { // Yes, so we'll assume it's a full path. int nLength = lstrlen(pStr); if (pBuffer == NULL) // If the buffer is NULL, return the required length { nRet = nLength + 1; } else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename { SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName()); nRet = nBufLen; } } else { // The filename is relative, so construct the full path. int nLengthDir = GetDirectory(NULL, 0); if (nLengthDir > 0) { // Calculate the required space. int nLengthTotal = nLengthDir + lstrlen(pStr); if(pBuffer == NULL) // If the buffer is NULL, return the required length { nRet = nLengthTotal + 1; } else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path { GetDirectory(pBuffer, nBufLen); SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\")); SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName()); nRet = nLengthTotal; } } } return nRet; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) bool GetNextPathName(_CSTRING_NS::CString& strPath) const { bool bRet = false; int nLength = GetNextPathName(NULL, 0); if (nLength > 0) { bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0); strPath.ReleaseBuffer(nLength - 1); } return bRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Implementation bool ResizeFilenameBuffer(DWORD dwLength) { if (dwLength > m_ofn.nMaxFile) { // Free the old buffer. if (m_ofn.lpstrFile != m_szFileName) { delete[] m_ofn.lpstrFile; m_ofn.lpstrFile = NULL; m_ofn.nMaxFile = 0; } // Allocate the new buffer. LPTSTR lpstrBuff = NULL; ATLTRY(lpstrBuff = new TCHAR[dwLength]); if (lpstrBuff != NULL) { m_ofn.lpstrFile = lpstrBuff; m_ofn.lpstrFile[0] = 0; m_ofn.nMaxFile = dwLength; } } return (m_ofn.lpstrFile != NULL); } void OnSelChange(LPOFNOTIFY /*lpon*/) { #ifndef _UNICODE // There is no point resizing the buffer in ANSI builds running on NT. if (m_bIsNT) return; #endif // Get the buffer length required to hold the spec. int nLength = GetSpec(NULL, 0); if (nLength <= 1) return; // no files are selected, presumably // Add room for the directory, and an extra terminating zero. nLength += GetFolderPath(NULL, 0) + 1; if (!ResizeFilenameBuffer(nLength)) { ATLASSERT(FALSE); return; } // If we are not following links then our work is done. if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0) return; // Get the file spec, which is the text in the edit control. if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0) return; // Get the ID-list of the current folder. int nBytes = GetFolderIDList(NULL, 0); #ifdef STRICT_TYPED_ITEMIDS CTempBuffer idlist; #else CTempBuffer idlist; #endif idlist.AllocateBytes(nBytes); if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0)) return; // First bind to the desktop folder, then to the current folder. ATL::CComPtr pDesktop, pFolder; if (FAILED(::SHGetDesktopFolder(&pDesktop))) return; if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder))) return; // Work through the file spec, looking for quoted filenames. If we find a shortcut file, then // we need to add enough extra buffer space to hold its target path. DWORD nExtraChars = 0; bool bInsideQuotes = false; LPCTSTR pAnchor = m_ofn.lpstrFile; LPCTSTR pChar = m_ofn.lpstrFile; for ( ; *pChar; ++pChar) { // Look for quotation marks. if (*pChar == _T('\"')) { // We are either entering or leaving a passage of quoted text. bInsideQuotes = !bInsideQuotes; // Is it an opening or closing quote? if (bInsideQuotes) { // We found an opening quote, so set "pAnchor" to the following character. pAnchor = pChar + 1; } else // closing quote { // Each quoted entity should be shorter than MAX_PATH. if (pChar - pAnchor >= MAX_PATH) return; // Get the ID-list and attributes of the file. USES_CONVERSION; int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor); TCHAR szFileName[MAX_PATH] = { 0 }; SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength); #ifdef STRICT_TYPED_ITEMIDS PIDLIST_RELATIVE pidl = NULL; #else LPITEMIDLIST pidl = NULL; #endif DWORD dwAttrib = SFGAO_LINK; if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib))) { // Is it a shortcut file? if (dwAttrib & SFGAO_LINK) { // Bind to its IShellLink interface. ATL::CComPtr pLink; if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink))) { // Get the shortcut's target path. TCHAR szPath[MAX_PATH] = { 0 }; if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0))) { // If the target path is longer than the shortcut name, then add on the number // of extra characters that are required. int nNewLength = lstrlen(szPath); if (nNewLength > nFileNameLength) nExtraChars += nNewLength - nFileNameLength; } } } // Free the ID-list returned by ParseDisplayName. ::CoTaskMemFree(pidl); } } } } // If we need more space for shortcut targets, then reallocate. if (nExtraChars > 0) ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars)); } }; class CMultiFileDialog : public CMultiFileDialogImpl { public: CMultiFileDialog( LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY, LPCTSTR lpszFilter = NULL, HWND hWndParent = NULL) : CMultiFileDialogImpl(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent) { } BEGIN_MSG_MAP(CMultiFileDialog) CHAIN_MSG_MAP(CMultiFileDialogImpl) END_MSG_MAP() }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // Shell File Dialog - new Shell File Open and Save dialogs in Vista // Note: Use GetPtr() to access dialog interface methods. // Example: // CShellFileOpenDialog dlg; // dlg.GetPtr()->SetTitle(L"MyFileOpenDialog"); #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl template class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents { public: // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { INT_PTR nRet = -1; T* pT = static_cast(this); if(pT->m_spFileDlg == NULL) { ATLASSERT(FALSE); return nRet; } DWORD dwCookie = 0; pT->_Advise(dwCookie); HRESULT hRet = pT->m_spFileDlg->Show(hWndParent); if(SUCCEEDED(hRet)) nRet = IDOK; else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED)) nRet = IDCANCEL; else ATLASSERT(FALSE); // error pT->_Unadvise(dwCookie); return nRet; } bool IsNull() const { const T* pT = static_cast(this); return (pT->m_spFileDlg == NULL); } // Operations - get file path after dialog returns HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); ATL::CComPtr spItem; HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); if(SUCCEEDED(hRet)) hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength); return hRet; } HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); ATL::CComPtr spItem; HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); if(SUCCEEDED(hRet)) hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength); return hRet; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); ATL::CComPtr spItem; HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); if(SUCCEEDED(hRet)) hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath); return hRet; } HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); ATL::CComPtr spItem; HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem); if(SUCCEEDED(hRet)) hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle); return hRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Helpers for IShellItem static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength) { ATLASSERT(pShellItem != NULL); LPWSTR lpstrName = NULL; HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); if(SUCCEEDED(hRet)) { if(lstrlenW(lpstrName) < cchLength) { SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName); } else { ATLASSERT(FALSE); hRet = DISP_E_BUFFERTOOSMALL; } ::CoTaskMemFree(lpstrName); } return hRet; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str) { ATLASSERT(pShellItem != NULL); LPWSTR lpstrName = NULL; HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName); if(SUCCEEDED(hRet)) { str = lpstrName; ::CoTaskMemFree(lpstrName); } return hRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) // Implementation void _Advise(DWORD& dwCookie) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie); ATLVERIFY(SUCCEEDED(hRet)); } void _Unadvise(DWORD dwCookie) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie); ATLVERIFY(SUCCEEDED(hRet)); } void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg != NULL); HRESULT hRet = E_FAIL; if(lpszFileName != NULL) { hRet = pT->m_spFileDlg->SetFileName(lpszFileName); ATLASSERT(SUCCEEDED(hRet)); } hRet = pT->m_spFileDlg->SetOptions(dwOptions); ATLASSERT(SUCCEEDED(hRet)); if(lpszDefExt != NULL) { hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt); ATLASSERT(SUCCEEDED(hRet)); } if(arrFilterSpec != NULL && uFilterSpecCount != 0U) { hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec); ATLASSERT(SUCCEEDED(hRet)); } } // Implementation - IUnknown interface STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) { if(ppvObject == NULL) return E_POINTER; T* pT = static_cast(this); if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents)) { *ppvObject = (IFileDialogEvents*)pT; // AddRef() not needed return S_OK; } return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } virtual ULONG STDMETHODCALLTYPE Release() { return 1; } // Implementation - IFileDialogEvents interface virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnFileOk(); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnFolderChanging(psiFolder); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnFolderChange(); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnSelectionChange(); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnShareViolation(psi, pResponse); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnTypeChange(); } virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse) { T* pT = static_cast(this); ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd)); pfd; // avoid level 4 warning return pT->OnOverwrite(psi, pResponse); } // Overrideables - Event handlers HRESULT OnFileOk() { return E_NOTIMPL; } HRESULT OnFolderChanging(IShellItem* /*psiFolder*/) { return E_NOTIMPL; } HRESULT OnFolderChange() { return E_NOTIMPL; } HRESULT OnSelectionChange() { return E_NOTIMPL; } HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/) { return E_NOTIMPL; } HRESULT OnTypeChange() { return E_NOTIMPL; } HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/) { return E_NOTIMPL; } }; /////////////////////////////////////////////////////////////////////////////// // CShellFileOpenDialogImpl - implements new Shell File Open dialog template class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T > { public: ATL::CComPtr m_spFileDlg; CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL, DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, LPCWSTR lpszDefExt = NULL, const COMDLG_FILTERSPEC* arrFilterSpec = NULL, UINT uFilterSpecCount = 0U) { HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog); if(SUCCEEDED(hRet)) _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); } IFileOpenDialog* GetPtr() { return m_spFileDlg; } }; /////////////////////////////////////////////////////////////////////////////// // CShellFileOpenDialog - new Shell File Open dialog without events class CShellFileOpenDialog : public CShellFileOpenDialogImpl { public: CShellFileOpenDialog(LPCWSTR lpszFileName = NULL, DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, LPCWSTR lpszDefExt = NULL, const COMDLG_FILTERSPEC* arrFilterSpec = NULL, UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) { } // Implementation (remove _Advise/_Unadvise code using template magic) void _Advise(DWORD& /*dwCookie*/) { } void _Unadvise(DWORD /*dwCookie*/) { } }; /////////////////////////////////////////////////////////////////////////////// // CShellFileSaveDialogImpl - implements new Shell File Save dialog template class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T > { public: ATL::CComPtr m_spFileDlg; CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL, DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, LPCWSTR lpszDefExt = NULL, const COMDLG_FILTERSPEC* arrFilterSpec = NULL, UINT uFilterSpecCount = 0U) { HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog); if(SUCCEEDED(hRet)) _Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount); } IFileSaveDialog* GetPtr() { return m_spFileDlg; } }; /////////////////////////////////////////////////////////////////////////////// // CShellFileSaveDialog - new Shell File Save dialog without events class CShellFileSaveDialog : public CShellFileSaveDialogImpl { public: CShellFileSaveDialog(LPCWSTR lpszFileName = NULL, DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, LPCWSTR lpszDefExt = NULL, const COMDLG_FILTERSPEC* arrFilterSpec = NULL, UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount) { } // Implementation (remove _Advise/_Unadvise code using template magic) void _Advise(DWORD& /*dwCookie*/) { } void _Unadvise(DWORD /*dwCookie*/) { } }; #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CFolderDialogImpl - used for browsing for a folder #ifndef _WIN32_WCE template class ATL_NO_VTABLE CFolderDialogImpl { public: BROWSEINFO m_bi; LPCTSTR m_lpstrInitialFolder; LPCITEMIDLIST m_pidlInitialSelection; bool m_bExpandInitialSelection; TCHAR m_szFolderDisplayName[MAX_PATH]; TCHAR m_szFolderPath[MAX_PATH]; #ifdef STRICT_TYPED_ITEMIDS PIDLIST_ABSOLUTE m_pidlSelected; #else LPITEMIDLIST m_pidlSelected; #endif HWND m_hWnd; // used only in the callback function // Constructor CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL) { memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL m_bi.hwndOwner = hWndParent; m_bi.pidlRoot = NULL; m_bi.pszDisplayName = m_szFolderDisplayName; m_bi.lpszTitle = lpstrTitle; m_bi.ulFlags = uFlags; m_bi.lpfn = BrowseCallbackProc; m_bi.lParam = (LPARAM)static_cast(this); m_szFolderPath[0] = 0; m_szFolderDisplayName[0] = 0; } ~CFolderDialogImpl() { ::CoTaskMemFree(m_pidlSelected); } // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { if(m_bi.hwndOwner == NULL) // set only if not specified before m_bi.hwndOwner = hWndParent; // Clear out any previous results m_szFolderPath[0] = 0; m_szFolderDisplayName[0] = 0; ::CoTaskMemFree(m_pidlSelected); INT_PTR nRet = IDCANCEL; m_pidlSelected = ::SHBrowseForFolder(&m_bi); if(m_pidlSelected != NULL) { nRet = IDOK; // If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path. // Otherwise, the caller must handle the ID-list directly. if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0) { if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE) nRet = IDCANCEL; } } return nRet; } // Methods to call before DoModal void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true) { // lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified m_lpstrInitialFolder = lpstrInitialFolder; m_bExpandInitialSelection = bExpand; } void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true) { m_pidlInitialSelection = pidl; m_bExpandInitialSelection = bExpand; } #ifdef STRICT_TYPED_ITEMIDS void SetRootFolder(PCIDLIST_ABSOLUTE pidl) #else void SetRootFolder(LPCITEMIDLIST pidl) #endif { m_bi.pidlRoot = pidl; } // Methods to call after DoModal LPITEMIDLIST GetSelectedItem(bool bDetach = false) { LPITEMIDLIST pidl = m_pidlSelected; if(bDetach) m_pidlSelected = NULL; return pidl; } LPCTSTR GetFolderPath() const { return m_szFolderPath; } LPCTSTR GetFolderDisplayName() const { return m_szFolderDisplayName; } int GetFolderImageIndex() const { return m_bi.iImage; } // Callback function and overrideables static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { #ifndef BFFM_VALIDATEFAILED #ifdef UNICODE const int BFFM_VALIDATEFAILED = 4; #else const int BFFM_VALIDATEFAILED = 3; #endif #endif // !BFFM_VALIDATEFAILED #ifndef BFFM_IUNKNOWN const int BFFM_IUNKNOWN = 5; #endif // !BFFM_IUNKNOWN #ifndef BIF_NEWDIALOGSTYLE const UINT BIF_NEWDIALOGSTYLE = 0x0040; #endif // !BIF_NEWDIALOGSTYLE int nRet = 0; T* pT = (T*)lpData; bool bClear = false; if(pT->m_hWnd == NULL) { pT->m_hWnd = hWnd; bClear = true; } else { ATLASSERT(pT->m_hWnd == hWnd); } switch(uMsg) { case BFFM_INITIALIZED: // Set initial selection // Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder if(pT->m_pidlInitialSelection != NULL) pT->SetSelection(pT->m_pidlInitialSelection); else if(pT->m_lpstrInitialFolder != NULL) pT->SetSelection(pT->m_lpstrInitialFolder); // Expand initial selection if appropriate if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0)) { if(pT->m_pidlInitialSelection != NULL) pT->SetExpanded(pT->m_pidlInitialSelection); else if(pT->m_lpstrInitialFolder != NULL) pT->SetExpanded(pT->m_lpstrInitialFolder); } pT->OnInitialized(); break; case BFFM_SELCHANGED: pT->OnSelChanged((LPITEMIDLIST)lParam); break; case BFFM_VALIDATEFAILED: nRet = pT->OnValidateFailed((LPCTSTR)lParam); break; case BFFM_IUNKNOWN: pT->OnIUnknown((IUnknown*)lParam); break; default: ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n")); break; } if(bClear) pT->m_hWnd = NULL; return nRet; } void OnInitialized() { } void OnSelChanged(LPITEMIDLIST /*pItemIDList*/) { } int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/) { return 1; // 1=continue, 0=EndDialog } void OnIUnknown(IUnknown* /*pUnknown*/) { } // Commands - valid to call only from handlers void EnableOK(BOOL bEnable) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable); } void SetSelection(LPCITEMIDLIST pItemIDList) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList); } void SetSelection(LPCTSTR lpstrFolderPath) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath); } void SetStatusText(LPCTSTR lpstrText) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText); } void SetOKText(LPCTSTR lpstrOKText) { #ifndef BFFM_SETOKTEXT const UINT BFFM_SETOKTEXT = WM_USER + 105; #endif ATLASSERT(m_hWnd != NULL); USES_CONVERSION; LPCWSTR lpstr = T2CW(lpstrOKText); ::SendMessage(m_hWnd, BFFM_SETOKTEXT, 0, (LPARAM)lpstr); } void SetExpanded(LPCITEMIDLIST pItemIDList) { #ifndef BFFM_SETEXPANDED const UINT BFFM_SETEXPANDED = WM_USER + 106; #endif ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList); } void SetExpanded(LPCTSTR lpstrFolderPath) { #ifndef BFFM_SETEXPANDED const UINT BFFM_SETEXPANDED = WM_USER + 106; #endif ATLASSERT(m_hWnd != NULL); USES_CONVERSION; LPCWSTR lpstr = T2CW(lpstrFolderPath); ::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr); } }; class CFolderDialog : public CFolderDialogImpl { public: CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : CFolderDialogImpl(hWndParent, lpstrTitle, uFlags) { } }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CCommonDialogImplBase - base class for common dialog classes class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase { public: static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg != WM_INITDIALOG) return 0; CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); ATLASSERT(pT != NULL); ATLASSERT(pT->m_hWnd == NULL); ATLASSERT(::IsWindow(hWnd)); // subclass dialog's window if(!pT->SubclassWindow(hWnd)) { ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n")); return 0; } // check message map for WM_INITDIALOG handler LRESULT lRes = 0; if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) return 0; return lRes; } // Special override for common dialogs BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) { ATLASSERT(::IsWindow(m_hWnd)); SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); return TRUE; } // Implementation - try to override these, to prevent errors HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID) { ATLASSERT(FALSE); // should not be called return NULL; } static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { ATLASSERT(FALSE); // should not be called return 0; } }; /////////////////////////////////////////////////////////////////////////////// // CFontDialogImpl - font selection dialog #ifndef _WIN32_WCE template class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase { public: enum { _cchStyleName = 64 }; CHOOSEFONT m_cf; TCHAR m_szStyleName[_cchStyleName]; // contains style name after return LOGFONT m_lf; // default LOGFONT to store the info // Constructors CFontDialogImpl(LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, HDC hDCPrinter = NULL, HWND hWndParent = NULL) { memset(&m_cf, 0, sizeof(m_cf)); memset(&m_lf, 0, sizeof(m_lf)); memset(&m_szStyleName, 0, sizeof(m_szStyleName)); m_cf.lStructSize = sizeof(m_cf); m_cf.hwndOwner = hWndParent; m_cf.rgbColors = RGB(0, 0, 0); m_cf.lpszStyle = (LPTSTR)&m_szStyleName; m_cf.Flags = dwFlags | CF_ENABLEHOOK; m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc; if(lplfInitial != NULL) { m_cf.lpLogFont = lplfInitial; m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; m_lf = *lplfInitial; } else { m_cf.lpLogFont = &m_lf; } if(hDCPrinter != NULL) { m_cf.hDC = hDCPrinter; m_cf.Flags |= CF_PRINTERFONTS; } } // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0); ATLASSERT(m_cf.lpfnHook != NULL); // can still be a user hook if(m_cf.hwndOwner == NULL) // set only if not specified before m_cf.hwndOwner = hWndParent; ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRetTh = m_thunk.Init(NULL, NULL); if(bRetTh == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); BOOL bRet = ::ChooseFont(&m_cf); m_hWnd = NULL; if(bRet) // copy logical font from user's initialization buffer (if needed) SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf)); return bRet ? IDOK : IDCANCEL; } // works only when the dialog is dislayed or after void GetCurrentFont(LPLOGFONT lplf) const { ATLASSERT(lplf != NULL); if(m_hWnd != NULL) ::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf); else *lplf = m_lf; } // works only when the dialog is dislayed or before #ifndef _WIN32_WCE void SetLogFont(LPLOGFONT lplf) { ATLASSERT(lplf != NULL); #ifndef WM_CHOOSEFONT_SETLOGFONT const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101); #endif if(m_hWnd != NULL) { ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf); } else { m_lf = *lplf; m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; } } void SetFlags(DWORD dwFlags) { #ifndef WM_CHOOSEFONT_SETFLAGS const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102); #endif if(m_hWnd != NULL) { CHOOSEFONT cf = { sizeof(CHOOSEFONT) }; cf.Flags = dwFlags; ::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf); } else { m_cf.Flags = dwFlags; } } #endif // !_WIN32_WCE // Helpers for parsing information after successful return LPCTSTR GetFaceName() const // return the face name of the font { return (LPCTSTR)m_cf.lpLogFont->lfFaceName; } LPCTSTR GetStyleName() const // return the style name of the font { return m_cf.lpszStyle; } int GetSize() const // return the pt size of the font { return m_cf.iPointSize; } COLORREF GetColor() const // return the color of the font { return m_cf.rgbColors; } int GetWeight() const // return the chosen font weight { return (int)m_cf.lpLogFont->lfWeight; } BOOL IsStrikeOut() const // return TRUE if strikeout { return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE; } BOOL IsUnderline() const // return TRUE if underline { return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE; } BOOL IsBold() const // return TRUE if bold font { return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE; } BOOL IsItalic() const // return TRUE if italic font { return m_cf.lpLogFont->lfItalic ? TRUE : FALSE; } }; class CFontDialog : public CFontDialogImpl { public: CFontDialog(LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, HDC hDCPrinter = NULL, HWND hWndParent = NULL) : CFontDialogImpl(lplfInitial, dwFlags, hDCPrinter, hWndParent) { } DECLARE_EMPTY_MSG_MAP() }; #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CRichEditFontDialogImpl - font selection for the Rich Edit ctrl #if defined(_RICHEDIT_) && !defined(_WIN32_WCE) template class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T > { public: CRichEditFontDialogImpl(const CHARFORMAT& charformat, DWORD dwFlags = CF_SCREENFONTS, HDC hDCPrinter = NULL, HWND hWndParent = NULL) : CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent) { m_cf.Flags |= CF_INITTOLOGFONTSTRUCT; m_cf.Flags |= FillInLogFont(charformat); m_cf.lpLogFont = &m_lf; if((charformat.dwMask & CFM_COLOR) != 0) m_cf.rgbColors = charformat.crTextColor; } void GetCharFormat(CHARFORMAT& cf) const { USES_CONVERSION; cf.dwEffects = 0; cf.dwMask = 0; if((m_cf.Flags & CF_NOSTYLESEL) == 0) { cf.dwMask |= CFM_BOLD | CFM_ITALIC; cf.dwEffects |= IsBold() ? CFE_BOLD : 0; cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0; } if((m_cf.Flags & CF_NOSIZESEL) == 0) { cf.dwMask |= CFM_SIZE; // GetSize() returns in tenths of points so mulitply by 2 to get twips cf.yHeight = GetSize() * 2; } if((m_cf.Flags & CF_NOFACESEL) == 0) { cf.dwMask |= CFM_FACE; cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily; #if (_RICHEDIT_VER >= 0x0200) SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName()); #else // !(_RICHEDIT_VER >= 0x0200) SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName())); #endif // !(_RICHEDIT_VER >= 0x0200) } if((m_cf.Flags & CF_EFFECTS) != 0) { cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR; cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0; cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0; cf.crTextColor = GetColor(); } if((m_cf.Flags & CF_NOSCRIPTSEL) == 0) { cf.bCharSet = m_cf.lpLogFont->lfCharSet; cf.dwMask |= CFM_CHARSET; } cf.yOffset = 0; } DWORD FillInLogFont(const CHARFORMAT& cf) { USES_CONVERSION; DWORD dwFlags = 0; if((cf.dwMask & CFM_SIZE) != 0) { HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL); LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY); m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440); } else m_lf.lfHeight = 0; m_lf.lfWidth = 0; m_lf.lfEscapement = 0; m_lf.lfOrientation = 0; if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD)) { m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL; m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE); } else { dwFlags |= CF_NOSTYLESEL; m_lf.lfWeight = FW_DONTCARE; m_lf.lfItalic = FALSE; } if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR)) { dwFlags |= CF_EFFECTS; m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE); m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE); } else { m_lf.lfUnderline = (BYTE)FALSE; m_lf.lfStrikeOut = (BYTE)FALSE; } if((cf.dwMask & CFM_CHARSET) != 0) m_lf.lfCharSet = cf.bCharSet; else dwFlags |= CF_NOSCRIPTSEL; m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS; m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; m_lf.lfQuality = DEFAULT_QUALITY; if((cf.dwMask & CFM_FACE) != 0) { m_lf.lfPitchAndFamily = cf.bPitchAndFamily; #if (_RICHEDIT_VER >= 0x0200) SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName); #else // !(_RICHEDIT_VER >= 0x0200) SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName)); #endif // !(_RICHEDIT_VER >= 0x0200) } else { m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE; m_lf.lfFaceName[0] = (TCHAR)0; } return dwFlags; } }; class CRichEditFontDialog : public CRichEditFontDialogImpl { public: CRichEditFontDialog(const CHARFORMAT& charformat, DWORD dwFlags = CF_SCREENFONTS, HDC hDCPrinter = NULL, HWND hWndParent = NULL) : CRichEditFontDialogImpl(charformat, dwFlags, hDCPrinter, hWndParent) { } DECLARE_EMPTY_MSG_MAP() }; #endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CColorDialogImpl - color selection #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) #ifdef _WIN32_WCE #pragma comment(lib, "commdlg.lib") #ifndef SETRGBSTRING #define SETRGBSTRING _T("commdlg_SetRGBColor") #endif #ifndef COLOROKSTRING #define COLOROKSTRING _T("commdlg_ColorOK") #endif #endif template class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase { public: CHOOSECOLOR m_cc; // Constructor CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) { memset(&m_cc, 0, sizeof(m_cc)); m_cc.lStructSize = sizeof(m_cc); m_cc.lpCustColors = GetCustomColors(); m_cc.hwndOwner = hWndParent; m_cc.Flags = dwFlags | CC_ENABLEHOOK; m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc; if(clrInit != 0) { m_cc.rgbResult = clrInit; m_cc.Flags |= CC_RGBINIT; } } // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0); ATLASSERT(m_cc.lpfnHook != NULL); // can still be a user hook if(m_cc.hwndOwner == NULL) // set only if not specified before m_cc.hwndOwner = hWndParent; ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRetTh = m_thunk.Init(NULL, NULL); if(bRetTh == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); BOOL bRet = ::ChooseColor(&m_cc); m_hWnd = NULL; return bRet ? IDOK : IDCANCEL; } // Set the current color while dialog is displayed void SetCurrentColor(COLORREF clr) { ATLASSERT(::IsWindow(m_hWnd)); SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr); } // Get the selected color after DoModal returns, or in OnColorOK COLORREF GetColor() const { return m_cc.rgbResult; } // Special override for the color dialog static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage()) return 0; LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam; CCommonDialogImplBase* pT = NULL; if(uMsg == WM_INITDIALOG) { pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData(); lpCC->lCustData = (LPARAM)pT; ATLASSERT(pT != NULL); ATLASSERT(pT->m_hWnd == NULL); ATLASSERT(::IsWindow(hWnd)); // subclass dialog's window if(!pT->SubclassWindow(hWnd)) { ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n")); return 0; } } else if(uMsg == _GetColorOKMessage()) { pT = (CCommonDialogImplBase*)lpCC->lCustData; ATLASSERT(pT != NULL); ATLASSERT(::IsWindow(pT->m_hWnd)); } else { ATLASSERT(FALSE); return 0; } // pass to the message map LRESULT lRes = 0; if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE) return 0; return lRes; } // Helpers static COLORREF* GetCustomColors() { static COLORREF rgbCustomColors[16] = { RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), }; return rgbCustomColors; } static UINT _GetSetRGBMessage() { static UINT uSetRGBMessage = 0; if(uSetRGBMessage == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n")); ATLASSERT(FALSE); return 0; } if(uSetRGBMessage == 0) uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING); lock.Unlock(); } ATLASSERT(uSetRGBMessage != 0); return uSetRGBMessage; } static UINT _GetColorOKMessage() { static UINT uColorOKMessage = 0; if(uColorOKMessage == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n")); ATLASSERT(FALSE); return 0; } if(uColorOKMessage == 0) uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING); lock.Unlock(); } ATLASSERT(uColorOKMessage != 0); return uColorOKMessage; } // Message map and handlers BEGIN_MSG_MAP(CColorDialogImpl) MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK) END_MSG_MAP() LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&) { T* pT = static_cast(this); return pT->OnColorOK(); } // Overrideable BOOL OnColorOK() // validate color { return FALSE; } }; class CColorDialog : public CColorDialogImpl { public: CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL) : CColorDialogImpl(clrInit, dwFlags, hWndParent) { } // override base class map and references to handlers DECLARE_EMPTY_MSG_MAP() }; #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500))) /////////////////////////////////////////////////////////////////////////////// // CPrintDialogImpl - used for Print... and PrintSetup... #ifndef _WIN32_WCE // global helper static inline HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode) { if(hDevNames == NULL) return NULL; LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames); LPDEVMODE lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL; if(lpDevNames == NULL) return NULL; HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset, (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset, (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset, lpDevMode); ::GlobalUnlock(hDevNames); if(hDevMode != NULL) ::GlobalUnlock(hDevMode); return hDC; } #pragma warning(push) #pragma warning(disable: 4512) // assignment operator could not be generated template class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase { public: // print dialog parameter block (note this is a reference) PRINTDLG& m_pd; // Constructors CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE, // TRUE for Print Setup, FALSE for Print Dialog DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, HWND hWndParent = NULL) : m_pd(m_pdActual) { memset(&m_pdActual, 0, sizeof(m_pdActual)); m_pd.lStructSize = sizeof(m_pdActual); m_pd.hwndOwner = hWndParent; m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK); m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc; m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc; if(bPrintSetupOnly) m_pd.Flags |= PD_PRINTSETUP; else m_pd.Flags |= PD_RETURNDC; m_pd.Flags &= ~PD_RETURNIC; // do not support information context } // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0); ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0); ATLASSERT(m_pd.lpfnPrintHook != NULL); // can still be a user hook ATLASSERT(m_pd.lpfnSetupHook != NULL); // can still be a user hook ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this if(m_pd.hwndOwner == NULL) // set only if not specified before m_pd.hwndOwner = hWndParent; ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRetTh = m_thunk.Init(NULL, NULL); if(bRetTh == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); BOOL bRet = ::PrintDlg(&m_pd); m_hWnd = NULL; return bRet ? IDOK : IDCANCEL; } // GetDefaults will not display a dialog but will get device defaults BOOL GetDefaults() { m_pd.Flags |= PD_RETURNDEFAULT; ATLASSERT(m_pd.hDevMode == NULL); // must be NULL ATLASSERT(m_pd.hDevNames == NULL); // must be NULL return ::PrintDlg(&m_pd); } // Helpers for parsing information after successful return num. copies requested int GetCopies() const { if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0) { LPDEVMODE lpDevMode = GetDevMode(); return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; } return m_pd.nCopies; } BOOL PrintCollate() const // TRUE if collate checked { return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; } BOOL PrintSelection() const // TRUE if printing selection { return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; } BOOL PrintAll() const // TRUE if printing all pages { return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; } BOOL PrintRange() const // TRUE if printing page range { return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; } BOOL PrintToFile() const // TRUE if printing to a file { return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; } int GetFromPage() const // starting page if valid { return PrintRange() ? m_pd.nFromPage : -1; } int GetToPage() const // ending page if valid { return PrintRange() ? m_pd.nToPage : -1; } LPDEVMODE GetDevMode() const // return DEVMODE { if(m_pd.hDevMode == NULL) return NULL; return (LPDEVMODE)::GlobalLock(m_pd.hDevMode); } LPCTSTR GetDriverName() const // return driver name { if(m_pd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wDriverOffset; } LPCTSTR GetDeviceName() const // return device name { if(m_pd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wDeviceOffset; } LPCTSTR GetPortName() const // return output port name { if(m_pd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wOutputOffset; } HDC GetPrinterDC() const // return HDC (caller must delete) { ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0); return m_pd.hDC; } // This helper creates a DC based on the DEVNAMES and DEVMODE structures. // This DC is returned, but also stored in m_pd.hDC as though it had been // returned by CommDlg. It is assumed that any previously obtained DC // has been/will be deleted by the user. This may be // used without ever invoking the print/print setup dialogs. HDC CreatePrinterDC() { m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode); return m_pd.hDC; } // Implementation PRINTDLG m_pdActual; // the Print/Print Setup need to share this // The following handle the case of print setup... from the print dialog CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit) { } BEGIN_MSG_MAP(CPrintDialogImpl) #ifdef psh1 COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed #else // !psh1 COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h #endif // !psh1 END_MSG_MAP() LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/) { T dlgSetup(m_pd); ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup); return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl); } }; class CPrintDialog : public CPrintDialogImpl { public: CPrintDialog(BOOL bPrintSetupOnly = FALSE, DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION, HWND hWndParent = NULL) : CPrintDialogImpl(bPrintSetupOnly, dwFlags, hWndParent) { } CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl(pdInit) { } }; #pragma warning(pop) #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CPrintDialogExImpl - new print dialog for Windows 2000 #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) }; // namespace WTL #include extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}}; namespace WTL { template class ATL_NO_VTABLE CPrintDialogExImpl : public ATL::CWindow, public ATL::CMessageMap, public IPrintDialogCallback, public ATL::IObjectWithSiteImpl< T > { public: PRINTDLGEX m_pdex; // Constructor CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, HWND hWndParent = NULL) { memset(&m_pdex, 0, sizeof(m_pdex)); m_pdex.lStructSize = sizeof(PRINTDLGEX); m_pdex.hwndOwner = hWndParent; m_pdex.Flags = dwFlags; m_pdex.nStartPage = START_PAGE_GENERAL; // callback object will be set in DoModal m_pdex.Flags &= ~PD_RETURNIC; // do not support information context } // Operations HRESULT DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT(m_hWnd == NULL); ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0); // use GetDefaults for this if(m_pdex.hwndOwner == NULL) // set only if not specified before m_pdex.hwndOwner = hWndParent; T* pT = static_cast(this); m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT; HRESULT hResult = ::PrintDlgEx(&m_pdex); m_hWnd = NULL; return hResult; } BOOL EndDialog(INT_PTR /*nRetCode*/ = 0) { ATLASSERT(::IsWindow(m_hWnd)); SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0)); return TRUE; } // GetDefaults will not display a dialog but will get device defaults HRESULT GetDefaults() { ATLASSERT(m_pdex.hDevMode == NULL); // must be NULL ATLASSERT(m_pdex.hDevNames == NULL); // must be NULL if(m_pdex.hwndOwner == NULL) // set only if not specified before m_pdex.hwndOwner = ::GetActiveWindow(); m_pdex.Flags |= PD_RETURNDEFAULT; HRESULT hRet = ::PrintDlgEx(&m_pdex); m_pdex.Flags &= ~PD_RETURNDEFAULT; return hRet; } // Helpers for parsing information after successful return num. copies requested int GetCopies() const { if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0) { LPDEVMODE lpDevMode = GetDevMode(); return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1; } return m_pdex.nCopies; } BOOL PrintCollate() const // TRUE if collate checked { return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE; } BOOL PrintSelection() const // TRUE if printing selection { return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE; } BOOL PrintAll() const // TRUE if printing all pages { return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE; } BOOL PrintRange() const // TRUE if printing page range { return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE; } BOOL PrintToFile() const // TRUE if printing to a file { return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE; } LPDEVMODE GetDevMode() const // return DEVMODE { if(m_pdex.hDevMode == NULL) return NULL; return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode); } LPCTSTR GetDriverName() const // return driver name { if(m_pdex.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wDriverOffset; } LPCTSTR GetDeviceName() const // return device name { if(m_pdex.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wDeviceOffset; } LPCTSTR GetPortName() const // return output port name { if(m_pdex.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames); if(lpDev == NULL) return NULL; return (LPCTSTR)lpDev + lpDev->wOutputOffset; } HDC GetPrinterDC() const // return HDC (caller must delete) { ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0); return m_pdex.hDC; } // This helper creates a DC based on the DEVNAMES and DEVMODE structures. // This DC is returned, but also stored in m_pdex.hDC as though it had been // returned by CommDlg. It is assumed that any previously obtained DC // has been/will be deleted by the user. This may be // used without ever invoking the print/print setup dialogs. HDC CreatePrinterDC() { m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode); return m_pdex.hDC; } // Implementation - interfaces // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) { if(ppvObject == NULL) return E_POINTER; T* pT = static_cast(this); if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback)) { *ppvObject = (IPrintDialogCallback*)pT; // AddRef() not needed return S_OK; } else if(IsEqualGUID(riid, IID_IObjectWithSite)) { *ppvObject = (IObjectWithSite*)pT; // AddRef() not needed return S_OK; } return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef() { return 1; } virtual ULONG STDMETHODCALLTYPE Release() { return 1; } // IPrintDialogCallback STDMETHOD(InitDone)() { return S_FALSE; } STDMETHOD(SelectionChange)() { return S_FALSE; } STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult) { // set up m_hWnd the first time if(m_hWnd == NULL) Attach(hWnd); // call message map HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE; if(hRet == S_OK && uMsg == WM_NOTIFY) // return in DWLP_MSGRESULT ::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult); if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE) hRet = S_FALSE; return hRet; } }; class CPrintDialogEx : public CPrintDialogExImpl { public: CPrintDialogEx( DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE, HWND hWndParent = NULL) : CPrintDialogExImpl(dwFlags, hWndParent) { } DECLARE_EMPTY_MSG_MAP() }; #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CPageSetupDialogImpl - Page Setup dialog #ifndef _WIN32_WCE template class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase { public: PAGESETUPDLG m_psd; ATL::CWndProcThunk m_thunkPaint; // Constructors CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) { memset(&m_psd, 0, sizeof(m_psd)); m_psd.lStructSize = sizeof(m_psd); m_psd.hwndOwner = hWndParent; m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK); m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc; m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this); #if (_ATL_VER >= 0x0700) m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC(); #else m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk); #endif } DECLARE_EMPTY_MSG_MAP() // Attributes LPDEVMODE GetDevMode() const // return DEVMODE { if(m_psd.hDevMode == NULL) return NULL; return (LPDEVMODE)::GlobalLock(m_psd.hDevMode); } LPCTSTR GetDriverName() const // return driver name { if(m_psd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); return (LPCTSTR)lpDev + lpDev->wDriverOffset; } LPCTSTR GetDeviceName() const // return device name { if(m_psd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); return (LPCTSTR)lpDev + lpDev->wDeviceOffset; } LPCTSTR GetPortName() const // return output port name { if(m_psd.hDevNames == NULL) return NULL; LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames); return (LPCTSTR)lpDev + lpDev->wOutputOffset; } HDC CreatePrinterDC() { return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode); } SIZE GetPaperSize() const { SIZE size = { m_psd.ptPaperSize.x, m_psd.ptPaperSize.y }; return size; } void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const { if(lpRectMargins != NULL) *lpRectMargins = m_psd.rtMargin; if(lpRectMinMargins != NULL) *lpRectMinMargins = m_psd.rtMinMargin; } // Operations INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0); ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0); ATLASSERT(m_psd.lpfnPageSetupHook != NULL); // can still be a user hook ATLASSERT(m_psd.lpfnPagePaintHook != NULL); // can still be a user hook if(m_psd.hwndOwner == NULL) // set only if not specified before m_psd.hwndOwner = hWndParent; ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRetTh = m_thunk.Init(NULL, NULL); if(bRetTh == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); BOOL bRet = ::PageSetupDlg(&m_psd); m_hWnd = NULL; return bRet ? IDOK : IDCANCEL; } // Implementation static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { T* pT = (T*)hWnd; UINT_PTR uRet = 0; switch(uMsg) { case WM_PSD_PAGESETUPDLG: uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam); break; case WM_PSD_FULLPAGERECT: case WM_PSD_MINMARGINRECT: case WM_PSD_MARGINRECT: case WM_PSD_GREEKTEXTRECT: case WM_PSD_ENVSTAMPRECT: case WM_PSD_YAFULLPAGERECT: uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam); break; default: ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n")); break; } return uRet; } // Overridables UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/) { // return 1 to prevent any more drawing return 0; } UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/) { return 0; // do the default } }; class CPageSetupDialog : public CPageSetupDialogImpl { public: CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL) : CPageSetupDialogImpl(dwFlags, hWndParent) { } // override PaintHookProc and references to handlers static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM) { return 0; } }; #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CFindReplaceDialogImpl - Find/FindReplace modeless dialogs #ifndef _WIN32_WCE template class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase { public: enum { _cchFindReplaceBuffer = 128 }; FINDREPLACE m_fr; TCHAR m_szFindWhat[_cchFindReplaceBuffer]; TCHAR m_szReplaceWith[_cchFindReplaceBuffer]; // Constructors CFindReplaceDialogImpl() { memset(&m_fr, 0, sizeof(m_fr)); m_szFindWhat[0] = _T('\0'); m_szReplaceWith[0] = _T('\0'); m_fr.lStructSize = sizeof(m_fr); m_fr.Flags = FR_ENABLEHOOK; m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc; m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat; m_fr.wFindWhatLen = _cchFindReplaceBuffer; m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith; m_fr.wReplaceWithLen = _cchFindReplaceBuffer; } // Note: You must allocate the object on the heap. // If you do not, you must override OnFinalMessage() virtual void OnFinalMessage(HWND /*hWnd*/) { delete this; } HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace LPCTSTR lpszFindWhat, LPCTSTR lpszReplaceWith = NULL, DWORD dwFlags = FR_DOWN, HWND hWndParent = NULL) { ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0); ATLASSERT(m_fr.lpfnHook != NULL); m_fr.Flags |= dwFlags; if(hWndParent == NULL) m_fr.hwndOwner = ::GetActiveWindow(); else m_fr.hwndOwner = hWndParent; ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog if(lpszFindWhat != NULL) SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE); if(lpszReplaceWith != NULL) SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE); ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this); HWND hWnd = NULL; if(bFindDialogOnly) hWnd = ::FindText(&m_fr); else hWnd = ::ReplaceText(&m_fr); ATLASSERT(m_hWnd == hWnd); return hWnd; } static const UINT GetFindReplaceMsg() { static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING); return nMsgFindReplace; } // call while handling FINDMSGSTRING registered message // to retreive the object static T* PASCAL GetNotifier(LPARAM lParam) { ATLASSERT(lParam != NULL); T* pDlg = (T*)(lParam - offsetof(T, m_fr)); return pDlg; } // Operations // Helpers for parsing information after successful return LPCTSTR GetFindString() const // get find string { return (LPCTSTR)m_fr.lpstrFindWhat; } LPCTSTR GetReplaceString() const // get replacement string { return (LPCTSTR)m_fr.lpstrReplaceWith; } BOOL SearchDown() const // TRUE if search down, FALSE is up { return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE; } BOOL FindNext() const // TRUE if command is find next { return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE; } BOOL MatchCase() const // TRUE if matching case { return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE; } BOOL MatchWholeWord() const // TRUE if matching whole words only { return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE; } BOOL ReplaceCurrent() const // TRUE if replacing current string { return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE; } BOOL ReplaceAll() const // TRUE if replacing all occurrences { return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE; } BOOL IsTerminating() const // TRUE if terminating dialog { return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ; } }; class CFindReplaceDialog : public CFindReplaceDialogImpl { public: DECLARE_EMPTY_MSG_MAP() }; #endif // !_WIN32_WCE ///////////////////////////////////////////////////////////////////////// // CDialogBaseUnits - Dialog Units helper // class CDialogBaseUnits { public: SIZE m_sizeUnits; // Constructors CDialogBaseUnits() { // The base units of the out-dated System Font LONG nDlgBaseUnits = ::GetDialogBaseUnits(); m_sizeUnits.cx = LOWORD(nDlgBaseUnits); m_sizeUnits.cy = HIWORD(nDlgBaseUnits); } CDialogBaseUnits(HWND hWnd) { if(!InitDialogBaseUnits(hWnd)) { LONG nDlgBaseUnits = ::GetDialogBaseUnits(); m_sizeUnits.cx = LOWORD(nDlgBaseUnits); m_sizeUnits.cy = HIWORD(nDlgBaseUnits); } } CDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) { if(!InitDialogBaseUnits(hFont, hWnd)) { LONG nDlgBaseUnits = ::GetDialogBaseUnits(); m_sizeUnits.cx = LOWORD(nDlgBaseUnits); m_sizeUnits.cy = HIWORD(nDlgBaseUnits); } } CDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) { if(!InitDialogBaseUnits(lf, hWnd)) { LONG nDlgBaseUnits = ::GetDialogBaseUnits(); m_sizeUnits.cx = LOWORD(nDlgBaseUnits); m_sizeUnits.cy = HIWORD(nDlgBaseUnits); } } // Operations BOOL InitDialogBaseUnits(HWND hWnd) { ATLASSERT(::IsWindow(hWnd)); RECT rc = { 0, 0, 4, 8 }; if(!::MapDialogRect(hWnd, &rc)) return FALSE; m_sizeUnits.cx = rc.right; m_sizeUnits.cy = rc.bottom; return TRUE; } BOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL) { CFont font; font.CreateFontIndirect(&lf); if(font.IsNull()) return FALSE; return InitDialogBaseUnits(font, hWnd); } BOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL) { ATLASSERT(hFont != NULL); CWindowDC dc = hWnd; TEXTMETRIC tmText = { 0 }; SIZE sizeText = { 0 }; HFONT hFontOld = dc.SelectFont(hFont); dc.GetTextMetrics(&tmText); m_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading; dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &sizeText); m_sizeUnits.cx = (sizeText.cx + 26) / 52; dc.SelectFont(hFontOld); return TRUE; } SIZE GetDialogBaseUnits() const { return m_sizeUnits; } INT MapDialogPixelsX(INT x) const { return ::MulDiv(x, 4, m_sizeUnits.cx); // Pixels X to DLU } INT MapDialogPixelsY(INT y) const { return ::MulDiv(y, 8, m_sizeUnits.cy); // Pixels Y to DLU } POINT MapDialogPixels(POINT pt) const { POINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) }; return out; } SIZE MapDialogPixels(SIZE input) const { SIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) }; return out; } RECT MapDialogPixels(const RECT& input) const { RECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) }; return out; } INT MapDialogUnitsX(INT x) const { return ::MulDiv(x, m_sizeUnits.cx, 4); // DLU to Pixels X } INT MapDialogUnitsY(INT y) const { return ::MulDiv(y, m_sizeUnits.cy, 8); // DLU to Pixels Y } POINT MapDialogUnits(POINT pt) const { POINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) }; return out; } SIZE MapDialogUnits(SIZE input) const { SIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) }; return out; } RECT MapDialogUnits(const RECT& input) const { RECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) }; return out; } }; /////////////////////////////////////////////////////////////////////////////// // CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX #if (_ATL_VER >= 0x800) typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX; typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX; #else // (_ATL_VER >= 0x800) typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX; #pragma pack(push, 4) struct DLGITEMTEMPLATEEX { DWORD helpID; DWORD exStyle; DWORD style; short x; short y; short cx; short cy; DWORD id; }; #pragma pack(pop) #endif // (_ATL_VER >= 0x800) template class CMemDlgTemplateT { public: enum StdCtrlType { CTRL_BUTTON = 0x0080, CTRL_EDIT = 0x0081, CTRL_STATIC = 0x0082, CTRL_LISTBOX = 0x0083, CTRL_SCROLLBAR = 0x0084, CTRL_COMBOBOX = 0x0085 }; HANDLE m_hData; LPBYTE m_pData; LPBYTE m_pPtr; SIZE_T m_cAllocated; CMemDlgTemplateT() : m_hData(NULL), m_pData(NULL), m_pPtr(NULL), m_cAllocated(0) { } ~CMemDlgTemplateT() { Reset(); } bool IsValid() const { return (m_pData != NULL); } bool IsTemplateEx() const { return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF); } LPDLGTEMPLATE GetTemplatePtr() { return reinterpret_cast(m_pData); } DLGTEMPLATEEX* GetTemplateExPtr() { return reinterpret_cast(m_pData); } void Reset() { if (IsValid()) { #ifndef UNDER_CE ::GlobalUnlock(m_pData); #endif ATLVERIFY(::GlobalFree(m_hData) == NULL); } m_hData = NULL; m_pData = NULL; m_pPtr = NULL; m_cAllocated = 0; } void Create(bool bDlgEx, LPCTSTR lpszCaption, const RECT& rc, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0, ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U) { Create(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, lpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr); } void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0, ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U) { // Should have DS_SETFONT style to set the dialog font name and size if (lpstrFontName != NULL) { dwStyle |= DS_SETFONT; } else { dwStyle &= ~DS_SETFONT; } if (bDlgEx) { DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight}; AddData(&dlg, sizeof(dlg)); } else { DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight}; AddData(&dlg, sizeof(dlg)); } #ifndef _WIN32_WCE if (Menu.m_lpstr == NULL) { WORD menuData = 0; AddData(&menuData, sizeof(WORD)); } else if (IS_INTRESOURCE(Menu.m_lpstr)) { WORD menuData[] = { 0xFFFF, LOWORD(Menu.m_lpstr) }; AddData(menuData, sizeof(menuData)); } else { AddString(Menu.m_lpstr); } #else // _WIN32_WCE // Windows CE doesn't support the addition of menus to a dialog box ATLASSERT(Menu.m_lpstr == NULL); Menu.m_lpstr; // avoid level 4 warning WORD menuData = 0; AddData(&menuData, sizeof(WORD)); #endif // _WIN32_WCE if (ClassName.m_lpstr == NULL) { WORD classData = 0; AddData(&classData, sizeof(WORD)); } else if (IS_INTRESOURCE(ClassName.m_lpstr)) { WORD classData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) }; AddData(classData, sizeof(classData)); } else { AddString(ClassName.m_lpstr); } // Set dialog caption AddString(lpszCaption); if (lpstrFontName != NULL) { AddData(&wFontSize, sizeof(wFontSize)); if (bDlgEx) { AddData(&wWeight, sizeof(wWeight)); AddData(&bItalic, sizeof(bItalic)); AddData(&bCharset, sizeof(bCharset)); } AddString(lpstrFontName); } } void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, const RECT& rc, DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) { AddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle, Text.m_lpstr, pCreationData, nCreationData, dwHelpID); } void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) { ATLASSERT(IsValid()); // DWORD align data const DWORD_PTR dwDwordAlignBits = sizeof(DWORD) - 1; m_pPtr = (LPBYTE)(((DWORD_PTR)m_pPtr + dwDwordAlignBits) & (~dwDwordAlignBits)); if (IsTemplateEx()) { DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData; dlg->cDlgItems++; DLGITEMTEMPLATEEX item = {dwHelpID, TWinTraits::GetWndExStyle(0) | dwExStyle, TWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId}; AddData(&item, sizeof(item)); } else { LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData; dlg->cdit++; DLGITEMTEMPLATE item = {TWinTraits::GetWndStyle(0) | dwStyle, TWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId}; AddData(&item, sizeof(item)); } ATLASSERT(ClassName.m_lpstr != NULL); if (IS_INTRESOURCE(ClassName.m_lpstr)) { WORD wData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) }; AddData(wData, sizeof(wData)); } else { AddString(ClassName.m_lpstr); } if (Text.m_lpstr == NULL) { WORD classData = 0; AddData(&classData, sizeof(WORD)); } else if (IS_INTRESOURCE(Text.m_lpstr)) { WORD wData[] = { 0xFFFF, LOWORD(Text.m_lpstr) }; AddData(wData, sizeof(wData)); } else { AddString(Text.m_lpstr); } AddData(&nCreationData, sizeof(nCreationData)); if ((nCreationData != 0)) { ATLASSERT(pCreationData != NULL); AddData(pCreationData, nCreationData * sizeof(WORD)); } } void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0) { AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID); } void AddData(LPCVOID pData, size_t nData) { ATLASSERT(pData != NULL); const SIZE_T ALLOCATION_INCREMENT = 1024; if (m_pData == NULL) { m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; m_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated); ATLASSERT(m_hData != NULL); #ifndef UNDER_CE m_pPtr = m_pData = static_cast(::GlobalLock(m_hData)); #else m_pPtr = m_pData = static_cast(m_hData); #endif ATLASSERT(m_pData != NULL); } else if (((m_pPtr - m_pData) + nData) > m_cAllocated) { SIZE_T ptrPos = (m_pPtr - m_pData); m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT; #ifndef UNDER_CE ::GlobalUnlock(m_pData); #endif m_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT); ATLASSERT(m_hData != NULL); #ifndef UNDER_CE m_pData = static_cast(::GlobalLock(m_hData)); #else m_pData = static_cast(m_hData); #endif ATLASSERT(m_pData != NULL); m_pPtr = m_pData + ptrPos; } SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData); m_pPtr += nData; } void AddString(LPCTSTR lpszStr) { if (lpszStr == NULL) { WCHAR szEmpty = 0; AddData(&szEmpty, sizeof(szEmpty)); } else { USES_CONVERSION; LPCWSTR lpstr = T2CW(lpszStr); int nSize = lstrlenW(lpstr) + 1; AddData(lpstr, nSize * sizeof(WCHAR)); } } }; typedef CMemDlgTemplateT CMemDlgTemplate; /////////////////////////////////////////////////////////////////////////////// // Dialog and control macros for indirect dialogs // for DLGTEMPLATE #define BEGIN_DIALOG(x, y, width, height) \ void DoInitTemplate() \ { \ bool bExTemplate = false; \ short nX = x, nY = y, nWidth = width, nHeight = height; \ LPCTSTR szCaption = NULL; \ DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ DWORD dwExStyle = 0; \ LPCTSTR szFontName = NULL; \ WORD wFontSize = 0; \ WORD wWeight = 0; \ BYTE bItalic = 0; \ BYTE bCharset = 0; \ DWORD dwHelpID = 0; \ ATL::_U_STRINGorID Menu = 0U; \ ATL::_U_STRINGorID ClassName = 0U; // for DLGTEMPLATEEX #define BEGIN_DIALOG_EX(x, y, width, height, helpID) \ void DoInitTemplate() \ { \ bool bExTemplate = true; \ short nX = x, nY = y, nWidth = width, nHeight = height; \ LPCTSTR szCaption = NULL; \ DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \ DWORD dwExStyle = 0; \ LPCTSTR szFontName = NULL; \ WORD wFontSize = 0; \ WORD wWeight = 0; \ BYTE bItalic = 0; \ BYTE bCharset = 0; \ DWORD dwHelpID = helpID; \ ATL::_U_STRINGorID Menu = 0U; \ ATL::_U_STRINGorID ClassName = 0U; #define END_DIALOG() \ m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \ }; #define DIALOG_CAPTION(caption) \ szCaption = caption; #define DIALOG_STYLE(style) \ dwStyle = style; #define DIALOG_EXSTYLE(exStyle) \ dwExStyle = exStyle; #define DIALOG_FONT(pointSize, typeFace) \ wFontSize = pointSize; \ szFontName = typeFace; #define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \ ATLASSERT(bExTemplate); \ wFontSize = pointsize; \ szFontName = typeface; \ wWeight = weight; \ bItalic = italic; \ bCharset = charset; #define DIALOG_MENU(menuName) \ Menu = menuName; #define DIALOG_CLASS(className) \ ClassName = className; #define BEGIN_CONTROLS_MAP() \ void DoInitControls() \ { #define END_CONTROLS_MAP() \ }; #define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0); #define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0); #define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0); #define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); #ifndef _WIN32_WCE #define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0); #endif // !_WIN32_WCE #define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0); #define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); #define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0); #define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0); #define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0); #define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0); #define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \ m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0); #define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \ m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0); /////////////////////////////////////////////////////////////////////////////// // CIndirectDialogImpl - dialogs with template in memory template class ATL_NO_VTABLE CIndirectDialogImpl : public ATL::CDialogImpl< T, TBase > { public: enum { IDD = 0 }; // no dialog template resource TDlgTemplate m_Template; void CreateTemplate() { T* pT = static_cast(this); pT->DoInitTemplate(); pT->DoInitControls(); } INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) { T* pT = static_cast(this); ATLASSERT(pT->m_hWnd == NULL); if(!m_Template.IsValid()) CreateTemplate(); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT); #ifdef _DEBUG m_bModal = true; #endif // _DEBUG return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); } HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) { T* pT = static_cast(this); ATLASSERT(pT->m_hWnd == NULL); if(!m_Template.IsValid()) CreateTemplate(); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT); #ifdef _DEBUG m_bModal = false; #endif // _DEBUG HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam); ATLASSERT(m_hWnd == hWnd); return hWnd; } // for CComControl HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL) { return Create(hWndParent, dwInitParam); } void DoInitTemplate() { ATLASSERT(FALSE); // MUST be defined in derived class } void DoInitControls() { ATLASSERT(FALSE); // MUST be defined in derived class } }; /////////////////////////////////////////////////////////////////////////////// // CPropertySheetWindow - client side for a property sheet class CPropertySheetWindow : public ATL::CWindow { public: // Constructors CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) { } CPropertySheetWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes int GetPageCount() const { ATLASSERT(::IsWindow(m_hWnd)); HWND hWndTabCtrl = GetTabControl(); ATLASSERT(hWndTabCtrl != NULL); return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L); } HWND GetActivePage() const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L); } int GetActiveIndex() const { ATLASSERT(::IsWindow(m_hWnd)); HWND hWndTabCtrl = GetTabControl(); ATLASSERT(hWndTabCtrl != NULL); return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L); } BOOL SetActivePage(int nPageIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L); } BOOL SetActivePage(HPROPSHEETPAGE hPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hPage != NULL); return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage); } BOOL SetActivePageByID(int nPageID) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID); } void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid ATLASSERT(lpszText != NULL); ::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText); } HWND GetTabControl() const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L); } void SetFinishText(LPCTSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); } void SetWizardButtons(DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); } // Operations BOOL AddPage(HPROPSHEETPAGE hPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hPage != NULL); return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); } BOOL AddPage(LPCPROPSHEETPAGE pPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pPage != NULL); HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); if(hPage == NULL) return FALSE; return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); } #ifndef _WIN32_WCE BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hPage != NULL); return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); } BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pPage != NULL); HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); if(hPage == NULL) return FALSE; return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage); } BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hPage != NULL); return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); } BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pPage != NULL); HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); if(hPage == NULL) return FALSE; return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage); } #endif // !_WIN32_WCE void RemovePage(int nPageIndex) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L); } void RemovePage(HPROPSHEETPAGE hPage) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(hPage != NULL); ::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage); } BOOL PressButton(int nButton) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L); } BOOL Apply() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L); } void CancelToClose() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L); } void SetModified(HWND hWndPage, BOOL bChanged = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(::IsWindow(hWndPage)); UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED; ::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L); } LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam); } void RebootSystem() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L); } void RestartWindows() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L); } BOOL IsDialogMessage(LPMSG lpMsg) { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg); } #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) int HwndToIndex(HWND hWnd) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L); } HWND IndexToHwnd(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L); } int PageToIndex(HPROPSHEETPAGE hPage) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage); } HPROPSHEETPAGE IndexToPage(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L); } int IdToIndex(int nID) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID); } int IndexToId(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L); } int GetResult() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L); } BOOL RecalcPageSizes() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L); } void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle); } void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) // Implementation - override to prevent usage HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) { ATLASSERT(FALSE); return NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CPropertySheetImpl - implements a property sheet template class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase > { public: PROPSHEETHEADER m_psh; ATL::CSimpleArray m_arrPages; #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific #ifndef PROPSHEET_LINK_SIZE #define PROPSHEET_LINK_SIZE 128 #endif // PROPSHEET_LINK_SIZE TCHAR m_szLink[PROPSHEET_LINK_SIZE]; static LPCTSTR m_pszTitle; static LPCTSTR m_pszLink; #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // Construction/Destruction CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) { memset(&m_psh, 0, sizeof(PROPSHEETHEADER)); m_psh.dwSize = sizeof(PROPSHEETHEADER); m_psh.dwFlags = PSH_USECALLBACK; m_psh.hInstance = ModuleHelper::GetResourceInstance(); m_psh.phpage = NULL; // will be set later m_psh.nPages = 0; // will be set later m_psh.pszCaption = title.m_lpstr; m_psh.nStartPage = uStartPage; m_psh.hwndParent = hWndParent; // if NULL, will be set in DoModal/Create m_psh.pfnCallback = T::PropSheetCallback; #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific m_psh.dwFlags |= PSH_MAXIMIZE; m_szLink[0] = 0; #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) } ~CPropertySheetImpl() { if(m_arrPages.GetSize() > 0) // sheet never created, destroy all pages { for(int i = 0; i < m_arrPages.GetSize(); i++) ::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]); } } // Callback function and overrideables static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam) { lParam; // avoid level 4 warning int nRet = 0; if(uMsg == PSCB_INITIALIZED) { ATLASSERT(hWnd != NULL); T* pT = (T*)ModuleHelper::ExtractCreateWndData(); // subclass the sheet window pT->SubclassWindow(hWnd); // remove page handles array pT->_CleanUpPages(); #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific m_pszTitle = pT->m_psh.pszCaption; if(*pT->m_szLink != 0) m_pszLink = pT->m_szLink; #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific pT->OnSheetInitialized(); } #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg else { switch(uMsg) { case PSCB_GETVERSION : nRet = COMCTL32_VERSION; break; case PSCB_GETTITLE : if(m_pszTitle != NULL) { lstrcpy((LPTSTR)lParam, m_pszTitle); m_pszTitle = NULL; } break; case PSCB_GETLINKTEXT: if(m_pszLink != NULL) { lstrcpy((LPTSTR)lParam, m_pszLink); m_pszLink = NULL; } break; default: break; } } #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) return nRet; } void OnSheetInitialized() { } // Create method HWND Create(HWND hWndParent = NULL) { ATLASSERT(m_hWnd == NULL); m_psh.dwFlags |= PSH_MODELESS; if(m_psh.hwndParent == NULL) m_psh.hwndParent = hWndParent; m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); m_psh.nPages = m_arrPages.GetSize(); T* pT = static_cast(this); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = pT->m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); HWND hWnd = (HWND)::PropertySheet(&m_psh); _CleanUpPages(); // ensure clean-up, required if call failed ATLASSERT(m_hWnd == hWnd); return hWnd; } INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow()) { ATLASSERT(m_hWnd == NULL); m_psh.dwFlags &= ~PSH_MODELESS; if(m_psh.hwndParent == NULL) m_psh.hwndParent = hWndParent; m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData(); m_psh.nPages = m_arrPages.GetSize(); T* pT = static_cast(this); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = pT->m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return -1; } #endif // (_ATL_VER >= 0x0800) ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT); INT_PTR nRet = ::PropertySheet(&m_psh); _CleanUpPages(); // ensure clean-up, required if call failed return nRet; } // implementation helper - clean up pages array void _CleanUpPages() { m_psh.nPages = 0; m_psh.phpage = NULL; m_arrPages.RemoveAll(); } // Attributes (extended overrides of client class methods) // These now can be called before the sheet is created // Note: Calling these after the sheet is created gives unpredictable results int GetPageCount() const { if(m_hWnd == NULL) // not created yet return m_arrPages.GetSize(); return TBase::GetPageCount(); } int GetActiveIndex() const { if(m_hWnd == NULL) // not created yet return m_psh.nStartPage; return TBase::GetActiveIndex(); } HPROPSHEETPAGE GetPage(int nPageIndex) const { ATLASSERT(m_hWnd == NULL); // can't do this after it's created return (HPROPSHEETPAGE)m_arrPages[nPageIndex]; } int GetPageIndex(HPROPSHEETPAGE hPage) const { ATLASSERT(m_hWnd == NULL); // can't do this after it's created return m_arrPages.Find((HPROPSHEETPAGE&)hPage); } BOOL SetActivePage(int nPageIndex) { if(m_hWnd == NULL) // not created yet { ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize()); m_psh.nStartPage = nPageIndex; return TRUE; } return TBase::SetActivePage(nPageIndex); } BOOL SetActivePage(HPROPSHEETPAGE hPage) { ATLASSERT(hPage != NULL); if (m_hWnd == NULL) // not created yet { int nPageIndex = GetPageIndex(hPage); if(nPageIndex == -1) return FALSE; return SetActivePage(nPageIndex); } return TBase::SetActivePage(hPage); } void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) { ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid ATLASSERT(lpszText != NULL); if(m_hWnd == NULL) { // set internal state m_psh.pszCaption = lpszText; // must exist until sheet is created m_psh.dwFlags &= ~PSH_PROPTITLE; m_psh.dwFlags |= nStyle; } else { // set external state TBase::SetTitle(lpszText, nStyle); } } #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field void SetLinkText(LPCTSTR lpszText) { ATLASSERT(lpszText != NULL); ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE); lstrcpy(m_szLink, lpszText); } #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) void SetWizardMode() { m_psh.dwFlags |= PSH_WIZARD; } void EnableHelp() { m_psh.dwFlags |= PSH_HASHELP; } // Operations BOOL AddPage(HPROPSHEETPAGE hPage) { ATLASSERT(hPage != NULL); BOOL bRet = FALSE; if(m_hWnd != NULL) bRet = TBase::AddPage(hPage); else // sheet not created yet, use internal data bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage); return bRet; } BOOL AddPage(LPCPROPSHEETPAGE pPage) { ATLASSERT(pPage != NULL); HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage); if(hPage == NULL) return FALSE; BOOL bRet = AddPage(hPage); if(!bRet) ::DestroyPropertySheetPage(hPage); return bRet; } BOOL RemovePage(HPROPSHEETPAGE hPage) { ATLASSERT(hPage != NULL); if (m_hWnd == NULL) // not created yet { int nPage = GetPageIndex(hPage); if(nPage == -1) return FALSE; return RemovePage(nPage); } TBase::RemovePage(hPage); return TRUE; } BOOL RemovePage(int nPageIndex) { BOOL bRet = TRUE; if(m_hWnd != NULL) TBase::RemovePage(nPageIndex); else // sheet not created yet, use internal data bRet = m_arrPages.RemoveAt(nPageIndex); return bRet; } #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) void SetHeader(LPCTSTR szbmHeader) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags &= ~PSH_WIZARD; m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97); m_psh.pszbmHeader = szbmHeader; } void SetHeader(HBITMAP hbmHeader) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags &= ~PSH_WIZARD; m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97); m_psh.hbmHeader = hbmHeader; } void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags &= ~PSH_WIZARD; m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97; m_psh.pszbmWatermark = szbmWatermark; if (hplWatermark != NULL) { m_psh.dwFlags |= PSH_USEHPLWATERMARK; m_psh.hplWatermark = hplWatermark; } } void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags &= ~PSH_WIZARD; m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97); m_psh.hbmWatermark = hbmWatermark; if (hplWatermark != NULL) { m_psh.dwFlags |= PSH_USEHPLWATERMARK; m_psh.hplWatermark = hplWatermark; } } void StretchWatermark(bool bStretchWatermark) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created if (bStretchWatermark) m_psh.dwFlags |= PSH_STRETCHWATERMARK; else m_psh.dwFlags &= ~PSH_STRETCHWATERMARK; } #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) // Message map and handlers BEGIN_MSG_MAP(CPropertySheetImpl) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) END_MSG_MAP() LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) && ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL)) DestroyWindow(); return lRet; } LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE)) SendMessage(WM_CLOSE); else bHandled = FALSE; return 0; } }; #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers template < class T, class TBase > LPCWSTR CPropertySheetImpl::m_pszTitle = NULL; template < class T, class TBase> LPCWSTR CPropertySheetImpl::m_pszLink = NULL; #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // for non-customized sheets class CPropertySheet : public CPropertySheetImpl { public: CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) : CPropertySheetImpl(title, uStartPage, hWndParent) { } }; /////////////////////////////////////////////////////////////////////////////// // CPropertyPageWindow - client side for a property page class CPropertyPageWindow : public ATL::CWindow { public: // Constructors CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd) { } CPropertyPageWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes CPropertySheetWindow GetPropertySheet() const { ATLASSERT(::IsWindow(m_hWnd)); return CPropertySheetWindow(GetParent()); } // Operations BOOL Apply() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); return GetPropertySheet().Apply(); } void CancelToClose() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetPropertySheet().CancelToClose(); } void SetModified(BOOL bChanged = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetPropertySheet().SetModified(m_hWnd, bChanged); } LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); return GetPropertySheet().QuerySiblings(wParam, lParam); } void RebootSystem() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetPropertySheet().RebootSystem(); } void RestartWindows() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetPropertySheet().RestartWindows(); } void SetWizardButtons(DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetPropertySheet().SetWizardButtons(dwFlags); } // Implementation - overrides to prevent usage HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) { ATLASSERT(FALSE); return NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CPropertyPageImpl - implements a property page template class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase > { public: PROPSHEETPAGE m_psp; operator PROPSHEETPAGE*() { return &m_psp; } // Construction CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) { // initialize PROPSHEETPAGE struct memset(&m_psp, 0, sizeof(PROPSHEETPAGE)); m_psp.dwSize = sizeof(PROPSHEETPAGE); m_psp.dwFlags = PSP_USECALLBACK; m_psp.hInstance = ModuleHelper::GetResourceInstance(); T* pT = static_cast(this); m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD); m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc; m_psp.pfnCallback = T::PropPageCallback; m_psp.lParam = (LPARAM)pT; if(title.m_lpstr != NULL) SetTitle(title); } // Callback function and overrideables static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { hWnd; // avoid level 4 warning ATLASSERT(hWnd == NULL); T* pT = (T*)ppsp->lParam; UINT uRet = 0; switch(uMsg) { case PSPCB_CREATE: { ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT; ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage); uRet = pT->OnPageCreate() ? 1 : 0; } break; #if (_WIN32_IE >= 0x0500) case PSPCB_ADDREF: pT->OnPageAddRef(); break; #endif // (_WIN32_IE >= 0x0500) case PSPCB_RELEASE: pT->OnPageRelease(); break; default: break; } return uRet; } bool OnPageCreate() { return true; // true - allow page to be created, false - prevent creation } #if (_WIN32_IE >= 0x0500) void OnPageAddRef() { } #endif // (_WIN32_IE >= 0x0500) void OnPageRelease() { } // Create method HPROPSHEETPAGE Create() { return ::CreatePropertySheetPage(&m_psp); } // Attributes void SetTitle(ATL::_U_STRINGorID title) { m_psp.pszTitle = title.m_lpstr; m_psp.dwFlags |= PSP_USETITLE; } #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) void SetHeaderTitle(LPCTSTR lpstrHeaderTitle) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psp.dwFlags |= PSP_USEHEADERTITLE; m_psp.pszHeaderTitle = lpstrHeaderTitle; } void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle) { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psp.dwFlags |= PSP_USEHEADERSUBTITLE; m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle; } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) // Operations void EnableHelp() { m_psp.dwFlags |= PSP_HASHELP; } // Message map and handlers BEGIN_MSG_MAP(CPropertyPageImpl) MESSAGE_HANDLER(WM_NOTIFY, OnNotify) END_MSG_MAP() // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification // handlers that return direct values without any restrictions LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { #ifndef _WIN32_WCE // This notification is sometimes received on Windows CE after the window is already destroyed ATLASSERT(::IsWindow(m_hWnd)); #endif NMHDR* pNMHDR = (NMHDR*)lParam; // don't handle messages not from the page/sheet itself if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd)) { bHandled = FALSE; return 1; } #ifdef _WIN32_WCE ATLASSERT(::IsWindow(m_hWnd)); #endif T* pT = static_cast(this); LRESULT lResult = 0; switch(pNMHDR->code) { #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS case PSN_SETACTIVE: lResult = pT->OnSetActive(); break; case PSN_KILLACTIVE: lResult = pT->OnKillActive(); break; case PSN_APPLY: lResult = pT->OnApply(); break; case PSN_RESET: pT->OnReset(); break; case PSN_QUERYCANCEL: lResult = pT->OnQueryCancel(); break; case PSN_WIZNEXT: lResult = pT->OnWizardNext(); break; case PSN_WIZBACK: lResult = pT->OnWizardBack(); break; case PSN_WIZFINISH: lResult = pT->OnWizardFinish(); break; case PSN_HELP: pT->OnHelp(); break; #ifndef _WIN32_WCE #if (_WIN32_IE >= 0x0400) case PSN_GETOBJECT: if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) bHandled = FALSE; break; #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) case PSN_TRANSLATEACCELERATOR: { LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam); } break; case PSN_QUERYINITIALFOCUS: { LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); } break; #endif // (_WIN32_IE >= 0x0500) #endif // !_WIN32_WCE #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS case PSN_SETACTIVE: lResult = pT->OnSetActive() ? 0 : -1; break; case PSN_KILLACTIVE: lResult = !pT->OnKillActive(); break; case PSN_APPLY: lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; break; case PSN_RESET: pT->OnReset(); break; case PSN_QUERYCANCEL: lResult = !pT->OnQueryCancel(); break; case PSN_WIZNEXT: lResult = pT->OnWizardNext(); break; case PSN_WIZBACK: lResult = pT->OnWizardBack(); break; case PSN_WIZFINISH: lResult = !pT->OnWizardFinish(); break; case PSN_HELP: pT->OnHelp(); break; #ifndef _WIN32_WCE #if (_WIN32_IE >= 0x0400) case PSN_GETOBJECT: if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam)) bHandled = FALSE; break; #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) case PSN_TRANSLATEACCELERATOR: { LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; } break; case PSN_QUERYINITIALFOCUS: { LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam; lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam); } break; #endif // (_WIN32_IE >= 0x0500) #endif // !_WIN32_WCE #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS default: bHandled = FALSE; // not handled } return lResult; } // Overridables // NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification // handlers that return direct values without any restrictions #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS int OnSetActive() { // 0 = allow activate // -1 = go back that was active // page ID = jump to page return 0; } BOOL OnKillActive() { // FALSE = allow deactivate // TRUE = prevent deactivation return FALSE; } int OnApply() { // PSNRET_NOERROR = apply OK // PSNRET_INVALID = apply not OK, return to this page // PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus return PSNRET_NOERROR; } void OnReset() { } BOOL OnQueryCancel() { // FALSE = allow cancel // TRUE = prevent cancel return FALSE; } int OnWizardBack() { // 0 = goto previous page // -1 = prevent page change // >0 = jump to page by dlg ID return 0; } int OnWizardNext() { // 0 = goto next page // -1 = prevent page change // >0 = jump to page by dlg ID return 0; } INT_PTR OnWizardFinish() { // FALSE = allow finish // TRUE = prevent finish // HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only) return FALSE; } void OnHelp() { } #ifndef _WIN32_WCE #if (_WIN32_IE >= 0x0400) BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) { return FALSE; // not processed } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) int OnTranslateAccelerator(LPMSG /*lpMsg*/) { // PSNRET_NOERROR - message not handled // PSNRET_MESSAGEHANDLED - message handled return PSNRET_NOERROR; } HWND OnQueryInitialFocus(HWND /*hWndFocus*/) { // NULL = set focus to default control // HWND = set focus to HWND return NULL; } #endif // (_WIN32_IE >= 0x0500) #endif // !_WIN32_WCE #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS BOOL OnSetActive() { return TRUE; } BOOL OnKillActive() { return TRUE; } BOOL OnApply() { return TRUE; } void OnReset() { } BOOL OnQueryCancel() { return TRUE; // ok to cancel } int OnWizardBack() { // 0 = goto previous page // -1 = prevent page change // >0 = jump to page by dlg ID return 0; } int OnWizardNext() { // 0 = goto next page // -1 = prevent page change // >0 = jump to page by dlg ID return 0; } BOOL OnWizardFinish() { return TRUE; } void OnHelp() { } #ifndef _WIN32_WCE #if (_WIN32_IE >= 0x0400) BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/) { return FALSE; // not processed } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/) { return FALSE; // not translated } HWND OnQueryInitialFocus(HWND /*hWndFocus*/) { return NULL; // default } #endif // (_WIN32_IE >= 0x0500) #endif // !_WIN32_WCE #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS }; // for non-customized pages template class CPropertyPage : public CPropertyPageImpl > { public: enum { IDD = t_wDlgTemplateID }; CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) { } DECLARE_EMPTY_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CAxPropertyPageImpl - property page that hosts ActiveX controls #ifndef _ATL_NO_HOSTING // Note: You must #include to use these classes template class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase > { public: // Data members HGLOBAL m_hInitData; HGLOBAL m_hDlgRes; HGLOBAL m_hDlgResSplit; // Constructor/destructor CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl< T, TBase >(title), m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL) { T* pT = static_cast(this); pT; // avoid level 4 warning // initialize ActiveX hosting and modify dialog template ATL::AtlAxWinInit(); HINSTANCE hInstance = ModuleHelper::GetResourceInstance(); LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD); HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG); if(hDlg != NULL) { HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT); BYTE* pInitData = NULL; if(hDlgInit != NULL) { m_hInitData = ::LoadResource(hInstance, hDlgInit); pInitData = (BYTE*)::LockResource(m_hInitData); } m_hDlgRes = ::LoadResource(hInstance, hDlg); DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes); LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData); if(lpDialogTemplate != pDlg) m_hDlgResSplit = GlobalHandle(lpDialogTemplate); // set up property page to use in-memory dialog template if(lpDialogTemplate != NULL) { m_psp.dwFlags |= PSP_DLGINDIRECT; m_psp.pResource = lpDialogTemplate; } else { ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!")); } } else { ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!")); } } ~CAxPropertyPageImpl() { if(m_hInitData != NULL) { UnlockResource(m_hInitData); FreeResource(m_hInitData); } if(m_hDlgRes != NULL) { UnlockResource(m_hDlgRes); FreeResource(m_hDlgRes); } if(m_hDlgResSplit != NULL) { ::GlobalFree(m_hDlgResSplit); } } // Methods // call this one to handle keyboard message for ActiveX controls BOOL PreTranslateMessage(LPMSG pMsg) { if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) && (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST)) return FALSE; // find a direct child of the dialog from the window that has focus HWND hWndCtl = ::GetFocus(); if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) { do { hWndCtl = ::GetParent(hWndCtl); } while (::GetParent(hWndCtl) != m_hWnd); } // give controls a chance to translate this message return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg); } // Overridables #if (_WIN32_IE >= 0x0500) // new default implementation for ActiveX hosting pages #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS int OnTranslateAccelerator(LPMSG lpMsg) { T* pT = static_cast(this); return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR; } #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS BOOL OnTranslateAccelerator(LPMSG lpMsg) { T* pT = static_cast(this); return pT->PreTranslateMessage(lpMsg); } #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS #endif // (_WIN32_IE >= 0x0500) // Support for new stuff in ATL7 #if (_ATL_VER >= 0x0700) int GetIDD() { return( static_cast(this)->IDD ); } virtual DLGPROC GetDialogProc() { return DialogProc; } static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd; if (uMsg == WM_INITDIALOG) { HRESULT hr; if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD()))) { ATLASSERT(FALSE); return FALSE; } } return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam); } // ActiveX controls creation virtual HRESULT CreateActiveXControls(UINT nID) { // Load dialog template and InitData HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT); BYTE* pInitData = NULL; HGLOBAL hData = NULL; HRESULT hr = S_OK; if (hDlgInit != NULL) { hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit); if (hData != NULL) pInitData = (BYTE*) ::LockResource(hData); } HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG); if (hDlg != NULL) { HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg); DLGTEMPLATE* pDlg = NULL; if (hResource != NULL) { pDlg = (DLGTEMPLATE*) ::LockResource(hResource); if (pDlg != NULL) { // Get first control on the template BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg); WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg); // Get first control on the dialog DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg); HWND hWndPrev = GetWindow(GW_CHILD); // Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order) for (WORD nItem = 0; nItem < nItems; nItem++) { DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id; if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx)) { BYTE* pData = NULL; DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData); ATL::CComPtr spStream; if (dwLen != 0) { HGLOBAL h = GlobalAlloc(GHND, dwLen); if (h != NULL) { BYTE* pBytes = (BYTE*) GlobalLock(h); BYTE* pSource = pData; SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen); GlobalUnlock(h); CreateStreamOnHGlobal(h, TRUE, &spStream); } else { hr = E_OUTOFMEMORY; break; } } ATL::CComBSTR bstrLicKey; hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str); if (SUCCEEDED(hr)) { ATL::CAxWindow2 wnd; // Get control caption. LPWSTR pszClassName = bDialogEx ? (LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) : (LPWSTR)(pItem + 1); // Get control rect. RECT rect = { 0 }; rect.left = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : pItem->x; rect.top = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : pItem->y; rect.right = rect.left + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : pItem->cx); rect.bottom = rect.top + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : pItem->cy); // Convert from dialog units to screen units MapDialogRect(&rect); // Create AxWindow with a NULL caption. wnd.Create(m_hWnd, &rect, NULL, (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : pItem->style) | WS_TABSTOP, bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : 0, bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id, NULL); if (wnd != NULL) { #ifndef _WIN32_WCE // Set the Help ID if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0) wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID); #endif // !_WIN32_WCE // Try to create the ActiveX control. hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey); if (FAILED(hr)) break; // Set the correct tab position. if (nItem == 0) hWndPrev = HWND_TOP; wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); hWndPrev = wnd; } else { hr = ATL::AtlHresultFromLastError(); } } } else { if (nItem != 0) hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT); } pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx); } } else hr = ATL::AtlHresultFromLastError(); } else hr = ATL::AtlHresultFromLastError(); } return hr; } // Event handling support HRESULT AdviseSinkMap(bool bAdvise) { if(!bAdvise && m_hWnd == NULL) { // window is gone, controls are already unadvised ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n")); return S_OK; } HRESULT hRet = E_NOTIMPL; __if_exists(T::_GetSinkMapFinder) { T* pT = static_cast(this); hRet = AtlAdviseSinkMap(pT, bAdvise); } return hRet; } // Message map and handlers typedef CPropertyPageImpl< T, TBase> _baseClass; BEGIN_MSG_MAP(CAxPropertyPageImpl) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) CHAIN_MSG_MAP(_baseClass) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { // initialize controls in dialog with DLGINIT resource section ExecuteDlgInit(static_cast(this)->IDD); AdviseSinkMap(true); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { AdviseSinkMap(false); bHandled = FALSE; return 1; } #endif // (_ATL_VER >= 0x0700) }; // for non-customized pages template class CAxPropertyPage : public CAxPropertyPageImpl > { public: enum { IDD = t_wDlgTemplateID }; CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl(title) { } #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) // not empty so we handle accelerators/create controls BEGIN_MSG_MAP(CAxPropertyPage) CHAIN_MSG_MAP(CAxPropertyPageImpl >) END_MSG_MAP() #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) DECLARE_EMPTY_MSG_MAP() #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) }; #endif // _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // Wizard97 Support #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) // Sample wizard dialog resources: // // IDD_WIZ97_INTERIOR_BLANK DIALOG 0, 0, 317, 143 // STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION // CAPTION "Wizard97 Property Page - Interior" // FONT 8, "MS Shell Dlg" // BEGIN // END // // IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193 // STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION // CAPTION "Wizard97 Property Page - Welcome/Complete" // FONT 8, "MS Shell Dlg", 0, 0, 0x0 // BEGIN // LTEXT "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8, // 195,24 // LTEXT "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)", // IDC_STATIC,115,40,195,16 // LTEXT "h",IDC_WIZ97_BULLET1,118,64,8,8 // LTEXT "List Item 1 (the h is turned into a bullet)",IDC_STATIC, // 127,63,122,8 // LTEXT "h",IDC_WIZ97_BULLET2,118,79,8,8 // LTEXT "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC, // 127,78,33,8 // CONTROL "&Do not show this Welcome page again", // IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX | // WS_TABSTOP,115,169,138,10 // END // // GUIDELINES DESIGNINFO // BEGIN // IDD_WIZ97_INTERIOR_BLANK, DIALOG // BEGIN // LEFTMARGIN, 7 // RIGHTMARGIN, 310 // VERTGUIDE, 21 // VERTGUIDE, 31 // VERTGUIDE, 286 // VERTGUIDE, 296 // TOPMARGIN, 7 // BOTTOMMARGIN, 136 // HORZGUIDE, 8 // END // // IDD_WIZ97_EXTERIOR_BLANK, DIALOG // BEGIN // RIGHTMARGIN, 310 // VERTGUIDE, 115 // VERTGUIDE, 118 // VERTGUIDE, 127 // TOPMARGIN, 7 // BOTTOMMARGIN, 186 // HORZGUIDE, 8 // HORZGUIDE, 32 // HORZGUIDE, 40 // HORZGUIDE, 169 // END // END /////////////////////////////////////////////////////////////////////////////// // CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet class CWizard97SheetWindow : public CPropertySheetWindow { public: // Constructors CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) { } CWizard97SheetWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Operations HFONT GetExteriorPageTitleFont(void) { ATLASSERT(::IsWindow(m_hWnd)); return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L); } HFONT GetBulletFont(void) { ATLASSERT(::IsWindow(m_hWnd)); return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L); } // Helpers static UINT GetMessage_GetExteriorPageTitleFont() { static UINT uGetExteriorPageTitleFont = 0; if(uGetExteriorPageTitleFont == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n")); ATLASSERT(FALSE); return 0; } if(uGetExteriorPageTitleFont == 0) uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12")); lock.Unlock(); } ATLASSERT(uGetExteriorPageTitleFont != 0); return uGetExteriorPageTitleFont; } static UINT GetMessage_GetBulletFont() { static UINT uGetBulletFont = 0; if(uGetBulletFont == 0) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n")); ATLASSERT(FALSE); return 0; } if(uGetBulletFont == 0) uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5")); lock.Unlock(); } ATLASSERT(uGetBulletFont != 0); return uGetBulletFont; } // Implementation - override to prevent usage HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) { ATLASSERT(FALSE); return NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CWizard97SheetImpl - implements a Wizard 97 style wizard sheet template class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase > { protected: // Typedefs typedef CWizard97SheetImpl< T, TBase > thisClass; typedef CPropertySheetImpl< T, TBase > baseClass; // Member variables CFont m_fontExteriorPageTitle; // Welcome and Completion page title font CFont m_fontBullet; // Bullet font (used on static text 'h' to produce a small bullet) bool m_bReceivedFirstSizeMessage; public: CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : baseClass(title, uStartPage, hWndParent), m_bReceivedFirstSizeMessage(false) { m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP); m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE); m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP); m_psh.dwFlags |= PSH_WIZARD97; baseClass::SetHeader(headerBitmap.m_lpstr); baseClass::SetWatermark(watermarkBitmap.m_lpstr); } // Overrides from base class void OnSheetInitialized() { T* pT = static_cast(this); pT->_InitializeFonts(); // We'd like to center the wizard here, but its too early. // Instead, we'll do CenterWindow upon our first WM_SIZE message } // Initialization void _InitializeFonts() { // Setup the Title and Bullet Font // (Property pages can send the "get external page title font" and "get bullet font" messages) // The derived class needs to do the actual SetFont for the dialog items) CFontHandle fontThisDialog = this->GetFont(); CClientDC dcScreen(NULL); LOGFONT titleLogFont = {0}; LOGFONT bulletLogFont = {0}; fontThisDialog.GetLogFont(&titleLogFont); fontThisDialog.GetLogFont(&bulletLogFont); // The Wizard 97 Spec recommends to do the Title Font // as Verdana Bold, 12pt. titleLogFont.lfCharSet = DEFAULT_CHARSET; titleLogFont.lfWeight = FW_BOLD; SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold")); INT titleFontPointSize = 12; titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont); // The Wizard 97 Spec recommends to do Bullets by having // static text of "h" in the Marlett font. bulletLogFont.lfCharSet = DEFAULT_CHARSET; bulletLogFont.lfWeight = FW_NORMAL; SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett")); INT bulletFontSize = 8; bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72); m_fontBullet.CreateFontIndirect(&bulletLogFont); } // Message Handling BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont) MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont) MESSAGE_HANDLER(WM_SIZE, OnSize) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)(HFONT)m_fontExteriorPageTitle; } LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return (LRESULT)(HFONT)m_fontBullet; } LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(!m_bReceivedFirstSizeMessage) { m_bReceivedFirstSizeMessage = true; this->CenterWindow(); } bHandled = FALSE; return 0; } }; // for non-customized sheets class CWizard97Sheet : public CWizard97SheetImpl { protected: // Typedefs typedef CWizard97Sheet thisClass; typedef CWizard97SheetImpl baseClass; public: CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) : baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent) { } BEGIN_MSG_MAP(thisClass) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CWizard97PageWindow - client side for a Wizard 97 style wizard page #define WIZARD97_EXTERIOR_CXDLG 317 #define WIZARD97_EXTERIOR_CYDLG 193 #define WIZARD97_INTERIOR_CXDLG 317 #define WIZARD97_INTERIOR_CYDLG 143 class CWizard97PageWindow : public CPropertyPageWindow { public: // Constructors CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) { } CWizard97PageWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes CWizard97SheetWindow GetPropertySheet() const { ATLASSERT(::IsWindow(m_hWnd)); return CWizard97SheetWindow(GetParent()); } // Operations HFONT GetExteriorPageTitleFont(void) { ATLASSERT(::IsWindow(m_hWnd)); return GetPropertySheet().GetExteriorPageTitleFont(); } HFONT GetBulletFont(void) { ATLASSERT(::IsWindow(m_hWnd)); return GetPropertySheet().GetBulletFont(); } // Implementation - overrides to prevent usage HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL) { ATLASSERT(FALSE); return NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CWizard97PageImpl - implements a Wizard 97 style wizard page template class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase > { protected: // Typedefs typedef CWizard97PageImpl< T, TBase > thisClass; typedef CPropertyPageImpl< T, TBase > baseClass; public: CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) { } // Message Handling BEGIN_MSG_MAP(thisClass) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page template class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase > { protected: // Typedefs typedef CWizard97ExteriorPageImpl< T, TBase > thisClass; typedef CPropertyPageImpl< T, TBase > baseClass; public: // Constructors CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) { m_psp.dwFlags |= PSP_HASHELP; m_psp.dwFlags |= PSP_HIDEHEADER; } // Message Handling BEGIN_MSG_MAP(thisClass) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page template class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase > { protected: // Typedefs typedef CWizard97InteriorPageImpl< T, TBase > thisClass; typedef CPropertyPageImpl< T, TBase > baseClass; public: // Constructors CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title) { m_psp.dwFlags |= PSP_HASHELP; m_psp.dwFlags &= ~PSP_HIDEHEADER; m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; // Be sure to have the derived class define this in the constructor. // We'll default it to something obvious in case its forgotten. baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class")); baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class.")); } // Message Handling BEGIN_MSG_MAP(thisClass) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() }; #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // Aero Wizard support #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CAeroWizardFrameWindow - client side for an Aero Wizard frame window class CAeroWizardFrameWindow : public CPropertySheetWindow { public: // Constructors CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd) { } CAeroWizardFrameWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Operations - new, Aero Wizard only void SetNextText(LPCWSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText); } void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) { ATLASSERT(::IsWindow(m_hWnd)); ::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); } void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) { ATLASSERT(::IsWindow(m_hWnd)); ::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons); } void SetButtonText(DWORD dwButton, LPCWSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText); } }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardFrameImpl - implements an Aero Wizard frame template class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl { public: // Constructor CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) : CPropertySheetImpl(title, uStartPage, hWndParent) { m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD; } // Operations void EnableResizing() { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags |= PSH_RESIZABLE; } void UseHeaderBitmap() { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags |= PSH_HEADERBITMAP; } void SetNoMargin() { ATLASSERT(m_hWnd == NULL); // can't do this after it's created m_psh.dwFlags |= PSH_NOMARGIN; } // Override to prevent use HWND Create(HWND /*hWndParent*/ = NULL) { ATLASSERT(FALSE); // not supported for Aero Wizard return NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardFrame - for non-customized frames class CAeroWizardFrame : public CAeroWizardFrameImpl { public: CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) : CAeroWizardFrameImpl(title, uStartPage, hWndParent) { } BEGIN_MSG_MAP(CAeroWizardFrame) MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl::OnCommand) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardPageWindow - client side for an Aero Wizard page class CAeroWizardPageWindow : public CPropertyPageWindow { public: // Constructors CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd) { } CAeroWizardPageWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Attributes CAeroWizardFrameWindow GetAeroWizardFrame() const { ATLASSERT(::IsWindow(m_hWnd)); // This is not really top-level frame window, but it processes all frame messages return CAeroWizardFrameWindow(GetParent()); } // Operations - new, Aero Wizard only void SetNextText(LPCWSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetAeroWizardFrame().SetNextText(lpszText); } void ShowWizardButtons(DWORD dwButtons, DWORD dwStates) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates); } void EnableWizardButtons(DWORD dwButtons, DWORD dwStates) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates); } void SetButtonText(DWORD dwButton, LPCWSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); GetAeroWizardFrame().SetButtonText(dwButton, lpszText); } }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardPageImpl - implements an Aero Wizard page template class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl { public: CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl(title) { } }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardPage - for non-customized pages template class CAeroWizardPage : public CAeroWizardPageImpl > { public: enum { IDD = t_wDlgTemplateID }; CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl(title) { } DECLARE_EMPTY_MSG_MAP() }; #ifndef _ATL_NO_HOSTING // Note: You must #include to use these classes /////////////////////////////////////////////////////////////////////////////// // CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls template class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase > { public: CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title) { } }; /////////////////////////////////////////////////////////////////////////////// // CAeroWizardAxPage - for non-customized pages template class CAeroWizardAxPage : public CAeroWizardAxPageImpl > { public: enum { IDD = t_wDlgTemplateID }; CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl(title) { } #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700) // not empty so we handle accelerators/create controls BEGIN_MSG_MAP(CAeroWizardAxPage) CHAIN_MSG_MAP(CAeroWizardAxPageImpl >) END_MSG_MAP() #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) DECLARE_EMPTY_MSG_MAP() #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)) }; #endif // _ATL_NO_HOSTING #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // TaskDialog support #if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // AtlTaskDialog - support for TaskDialog() function inline int AtlTaskDialog(HWND hWndParent, ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL) { int nRet = -1; #ifdef _WTL_TASKDIALOG_DIRECT USES_CONVERSION; HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), dwCommonButtons, IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr), &nRet); ATLVERIFY(SUCCEEDED(hRet)); #else // This allows apps to run on older versions of Windows typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton); HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); if(m_hCommCtrlDLL != NULL) { PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog"); if(pfnTaskDialog != NULL) { USES_CONVERSION; HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), IS_INTRESOURCE(ContentText.m_lpstr) ? (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), dwCommonButtons, IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr), &nRet); ATLVERIFY(SUCCEEDED(hRet)); } ::FreeLibrary(m_hCommCtrlDLL); } #endif return nRet; } /////////////////////////////////////////////////////////////////////////////// // CTaskDialogConfig - TASKDIALOGCONFIG wrapper class CTaskDialogConfig : public TASKDIALOGCONFIG { public: // Constructor CTaskDialogConfig() { Init(); } void Init() { memset(this, 0, sizeof(TASKDIALOGCONFIG)); // initialize structure to 0/NULL this->cbSize = sizeof(TASKDIALOGCONFIG); this->hInstance = ModuleHelper::GetResourceInstance(); } // Operations - setting values // common buttons void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtonsArg) { this->dwCommonButtons = dwCommonButtonsArg; } // window title text void SetWindowTitle(UINT nID) { this->pszWindowTitle = MAKEINTRESOURCEW(nID); } void SetWindowTitle(LPCWSTR lpstrWindowTitle) { this->pszWindowTitle = lpstrWindowTitle; } // main icon void SetMainIcon(HICON hIcon) { this->dwFlags |= TDF_USE_HICON_MAIN; this->hMainIcon = hIcon; } void SetMainIcon(UINT nID) { this->dwFlags &= ~TDF_USE_HICON_MAIN; this->pszMainIcon = MAKEINTRESOURCEW(nID); } void SetMainIcon(LPCWSTR lpstrMainIcon) { this->dwFlags &= ~TDF_USE_HICON_MAIN; this->pszMainIcon = lpstrMainIcon; } // main instruction text void SetMainInstructionText(UINT nID) { this->pszMainInstruction = MAKEINTRESOURCEW(nID); } void SetMainInstructionText(LPCWSTR lpstrMainInstruction) { this->pszMainInstruction = lpstrMainInstruction; } // content text void SetContentText(UINT nID) { this->pszContent = MAKEINTRESOURCEW(nID); } void SetContentText(LPCWSTR lpstrContent) { this->pszContent = lpstrContent; } // buttons void SetButtons(const TASKDIALOG_BUTTON* pButtonsArg, UINT cButtonsArg, int nDefaultButtonArg = 0) { this->pButtons = pButtonsArg; this->cButtons = cButtonsArg; if(nDefaultButtonArg != 0) this->nDefaultButton = nDefaultButtonArg; } void SetDefaultButton(int nDefaultButtonArg) { this->nDefaultButton = nDefaultButtonArg; } // radio buttons void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtonsArg, UINT cRadioButtonsArg, int nDefaultRadioButtonArg = 0) { this->pRadioButtons = pRadioButtonsArg; this->cRadioButtons = cRadioButtonsArg; if(nDefaultRadioButtonArg != 0) this->nDefaultRadioButton = nDefaultRadioButtonArg; } void SetDefaultRadioButton(int nDefaultRadioButtonArg) { this->nDefaultRadioButton = nDefaultRadioButtonArg; } // verification text void SetVerificationText(UINT nID) { this->pszVerificationText = MAKEINTRESOURCEW(nID); } void SetVerificationText(LPCWSTR lpstrVerificationText) { this->pszVerificationText = lpstrVerificationText; } // expanded information text void SetExpandedInformationText(UINT nID) { this->pszExpandedInformation = MAKEINTRESOURCEW(nID); } void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) { this->pszExpandedInformation = lpstrExpandedInformation; } // expanded control text void SetExpandedControlText(UINT nID) { this->pszExpandedControlText = MAKEINTRESOURCEW(nID); } void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) { this->pszExpandedControlText = lpstrExpandedControlText; } // collapsed control text void SetCollapsedControlText(UINT nID) { this->pszCollapsedControlText = MAKEINTRESOURCEW(nID); } void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) { this->pszCollapsedControlText = lpstrCollapsedControlText; } // footer icon void SetFooterIcon(HICON hIcon) { this->dwFlags |= TDF_USE_HICON_FOOTER; this->hFooterIcon = hIcon; } void SetFooterIcon(UINT nID) { this->dwFlags &= ~TDF_USE_HICON_FOOTER; this->pszFooterIcon = MAKEINTRESOURCEW(nID); } void SetFooterIcon(LPCWSTR lpstrFooterIcon) { this->dwFlags &= ~TDF_USE_HICON_FOOTER; this->pszFooterIcon = lpstrFooterIcon; } // footer text void SetFooterText(UINT nID) { this->pszFooter = MAKEINTRESOURCEW(nID); } void SetFooterText(LPCWSTR lpstrFooterText) { this->pszFooter = lpstrFooterText; } // width (in DLUs) void SetWidth(UINT cxWidthArg) { this->cxWidth = cxWidthArg; } // modify flags void ModifyFlags(DWORD dwRemove, DWORD dwAdd) { this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd; } }; /////////////////////////////////////////////////////////////////////////////// // CTaskDialogImpl - implements a Task Dialog template class ATL_NO_VTABLE CTaskDialogImpl { public: CTaskDialogConfig m_tdc; HWND m_hWnd; // used only in callback functions // Constructor CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL) { m_tdc.hwndParent = hWndParent; m_tdc.pfCallback = T::TaskDialogCallback; m_tdc.lpCallbackData = (LONG_PTR)static_cast(this); } // Operations HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL) { if(m_tdc.hwndParent == NULL) m_tdc.hwndParent = hWndParent; #ifdef _WTL_TASKDIALOG_DIRECT return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); #else // This allows apps to run on older versions of Windows typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked); HRESULT hRet = E_UNEXPECTED; HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); if(m_hCommCtrlDLL != NULL) { PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect"); if(pfnTaskDialogIndirect != NULL) hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked); ::FreeLibrary(m_hCommCtrlDLL); } return hRet; #endif } // Operations - setting values of TASKDIALOGCONFIG // common buttons void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons) { m_tdc.SetCommonButtons(dwCommonButtons); } // window title text void SetWindowTitle(UINT nID) { m_tdc.SetWindowTitle(nID); } void SetWindowTitle(LPCWSTR lpstrWindowTitle) { m_tdc.SetWindowTitle(lpstrWindowTitle); } // main icon void SetMainIcon(HICON hIcon) { m_tdc.SetMainIcon(hIcon); } void SetMainIcon(UINT nID) { m_tdc.SetMainIcon(nID); } void SetMainIcon(LPCWSTR lpstrMainIcon) { m_tdc.SetMainIcon(lpstrMainIcon); } // main instruction text void SetMainInstructionText(UINT nID) { m_tdc.SetMainInstructionText(nID); } void SetMainInstructionText(LPCWSTR lpstrMainInstruction) { m_tdc.SetMainInstructionText(lpstrMainInstruction); } // content text void SetContentText(UINT nID) { m_tdc.SetContentText(nID); } void SetContentText(LPCWSTR lpstrContent) { m_tdc.SetContentText(lpstrContent); } // buttons void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0) { m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); } void SetDefaultButton(int nDefaultButton) { m_tdc.SetDefaultButton(nDefaultButton); } // radio buttons void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0) { m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); } void SetDefaultRadioButton(int nDefaultRadioButton) { m_tdc.SetDefaultRadioButton(nDefaultRadioButton); } // verification text void SetVerificationText(UINT nID) { m_tdc.SetVerificationText(nID); } void SetVerificationText(LPCWSTR lpstrVerificationText) { m_tdc.SetVerificationText(lpstrVerificationText); } // expanded information text void SetExpandedInformationText(UINT nID) { m_tdc.SetExpandedInformationText(nID); } void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation) { m_tdc.SetExpandedInformationText(lpstrExpandedInformation); } // expanded control text void SetExpandedControlText(UINT nID) { m_tdc.SetExpandedControlText(nID); } void SetExpandedControlText(LPCWSTR lpstrExpandedControlText) { m_tdc.SetExpandedControlText(lpstrExpandedControlText); } // collapsed control text void SetCollapsedControlText(UINT nID) { m_tdc.SetCollapsedControlText(nID); } void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText) { m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); } // footer icon void SetFooterIcon(HICON hIcon) { m_tdc.SetFooterIcon(hIcon); } void SetFooterIcon(UINT nID) { m_tdc.SetFooterIcon(nID); } void SetFooterIcon(LPCWSTR lpstrFooterIcon) { m_tdc.SetFooterIcon(lpstrFooterIcon); } // footer text void SetFooterText(UINT nID) { m_tdc.SetFooterText(nID); } void SetFooterText(LPCWSTR lpstrFooterText) { m_tdc.SetFooterText(lpstrFooterText); } // width (in DLUs) void SetWidth(UINT cxWidth) { m_tdc.SetWidth(cxWidth); } // modify flags void ModifyFlags(DWORD dwRemove, DWORD dwAdd) { m_tdc.ModifyFlags(dwRemove, dwAdd); } // Implementation static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) { T* pT = (T*)lpRefData; ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd); BOOL bRet = FALSE; switch(uMsg) { case TDN_DIALOG_CONSTRUCTED: pT->m_hWnd = hWnd; pT->OnDialogConstructed(); break; case TDN_CREATED: pT->OnCreated(); break; case TDN_BUTTON_CLICKED: bRet = pT->OnButtonClicked((int)wParam); break; case TDN_RADIO_BUTTON_CLICKED: pT->OnRadioButtonClicked((int)wParam); break; case TDN_HYPERLINK_CLICKED: pT->OnHyperlinkClicked((LPCWSTR)lParam); break; case TDN_EXPANDO_BUTTON_CLICKED: pT->OnExpandoButtonClicked((wParam != 0)); break; case TDN_VERIFICATION_CLICKED: pT->OnVerificationClicked((wParam != 0)); break; case TDN_HELP: pT->OnHelp(); break; case TDN_TIMER: bRet = pT->OnTimer((DWORD)wParam); break; case TDN_NAVIGATED: pT->OnNavigated(); break; case TDN_DESTROYED: pT->OnDestroyed(); pT->m_hWnd = NULL; break; default: ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n")); break; } return (bRet != FALSE) ? S_OK : S_FALSE; } // Overrideables - notification handlers void OnDialogConstructed() { } void OnCreated() { } BOOL OnButtonClicked(int /*nButton*/) { return FALSE; // don't prevent dialog to close } void OnRadioButtonClicked(int /*nRadioButton*/) { } void OnHyperlinkClicked(LPCWSTR /*pszHREF*/) { } void OnExpandoButtonClicked(bool /*bExpanded*/) { } void OnVerificationClicked(bool /*bChecked*/) { } void OnHelp() { } BOOL OnTimer(DWORD /*dwTickCount*/) { return FALSE; // don't reset counter } void OnNavigated() { } void OnDestroyed() { } // Commands - valid to call only from handlers void NavigatePage(TASKDIALOGCONFIG& tdc) { ATLASSERT(m_hWnd != NULL); tdc.cbSize = sizeof(TASKDIALOGCONFIG); if(tdc.hwndParent == NULL) tdc.hwndParent = m_tdc.hwndParent; tdc.pfCallback = m_tdc.pfCallback; tdc.lpCallbackData = m_tdc.lpCallbackData; (TASKDIALOGCONFIG)m_tdc = tdc; ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc); } // modify TASKDIALOGCONFIG values, then call this to update task dialog void NavigatePage() { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc); } void ClickButton(int nButton) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L); } void SetMarqueeProgressBar(BOOL bMarquee) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L); } BOOL SetProgressBarState(int nNewState) { ATLASSERT(m_hWnd != NULL); return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L); } DWORD SetProgressBarRange(int nMinRange, int nMaxRange) { ATLASSERT(m_hWnd != NULL); return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange)); } int SetProgressBarPos(int nNewPos) { ATLASSERT(m_hWnd != NULL); return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L); } BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed) { ATLASSERT(m_hWnd != NULL); return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed); } void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText); } void ClickRadioButton(int nRadioButton) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L); } void EnableButton(int nButton, BOOL bEnable) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable); } void EnableRadioButton(int nButton, BOOL bEnable) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable); } void ClickVerification(BOOL bCheck, BOOL bFocus) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus); } void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText); } void SetButtonElevationRequiredState(int nButton, BOOL bElevation) { ATLASSERT(m_hWnd != NULL); ::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation); } void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon) { ATLASSERT(m_hWnd != NULL); #ifdef _DEBUG if(element == TDIE_ICON_MAIN) ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0); else if(element == TDIE_ICON_FOOTER) ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0); #endif // _DEBUG ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon); } void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon) { ATLASSERT(m_hWnd != NULL); #ifdef _DEBUG if(element == TDIE_ICON_MAIN) ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0); else if(element == TDIE_ICON_FOOTER) ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0); #endif // _DEBUG ::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon); } }; /////////////////////////////////////////////////////////////////////////////// // CTaskDialog - for non-customized task dialogs class CTaskDialog : public CTaskDialogImpl { public: CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl(hWndParent) { m_tdc.pfCallback = NULL; } }; #endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE) }; // namespace WTL #endif // __ATLDLGS_H__ ================================================ FILE: WTL/atldwm.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLDWM_H__ #define __ATLDWM_H__ #pragma once #ifdef _WIN32_WCE #error atldwm.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atldwm.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atldwm.h requires atlwin.h to be included first #endif #if (_WIN32_WINNT < 0x0600) #error atldwm.h requires _WIN32_WINNT >= 0x0600 #endif #ifndef _DWMAPI_H_ #include #endif #pragma comment(lib, "dwmapi.lib") // Note: To create an application that also runs on older versions of Windows, // use delay load of dwmapi.dll and ensure that no calls to the DWM API are // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, // and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the // project properties. #if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) #pragma comment(lib, "delayimp.lib") #pragma comment(linker, "/delayload:dwmapi.dll") #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD) /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CDwm // CDwmImpl // CDwmWindowT - CDwmWindow // CDwmThumbnailT // CDwmThumbnail // CDwmThumbnailHandle // CAeroControlImpl namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CDwm - wrapper for DWM handle class CDwm { public: // Data members static int m_nIsDwmSupported; // Constructor CDwm() { IsDwmSupported(); } // Dwm support helper static bool IsDwmSupported() { if(m_nIsDwmSupported == -1) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\n")); ATLASSERT(FALSE); return false; } if(m_nIsDwmSupported == -1) { HMODULE hDwmDLL = ::LoadLibrary(_T("dwmapi.dll")); m_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0; if(hDwmDLL != NULL) ::FreeLibrary(hDwmDLL); } lock.Unlock(); } ATLASSERT(m_nIsDwmSupported != -1); return (m_nIsDwmSupported == 1); } // Operations BOOL DwmIsCompositionEnabled() const { if(!IsDwmSupported()) return FALSE; BOOL bRes = FALSE; return (SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes) ? TRUE : FALSE; } BOOL DwmEnableComposition(UINT fEnable) { if(!IsDwmSupported()) return FALSE; return SUCCEEDED(::DwmEnableComposition(fEnable)) ? TRUE : FALSE; } BOOL DwmEnableMMCSS(BOOL fEnableMMCSS) { if(!IsDwmSupported()) return FALSE; return SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS)) ? TRUE : FALSE; } HRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend) { if(!IsDwmSupported()) return E_NOTIMPL; return ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend); } HRESULT DwmFlush() { if(!IsDwmSupported()) return E_NOTIMPL; return ::DwmFlush(); } }; __declspec(selectany) int CDwm::m_nIsDwmSupported = -1; /////////////////////////////////////////////////////////////////////////////// // CDwmImpl - DWM window support template class CDwmImpl : public TBase { public: HRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB); } HRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins); } HRESULT DwmExtendFrameIntoEntireClientArea() { MARGINS margins = { -1 }; return DwmExtendFrameIntoClientArea(&margins); } HRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo); } HRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); } HRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative); } HRESULT DwmSetDxFrameDuration(INT cRefreshes) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes); } HRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams); } HRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute); } HRESULT DwmAttachMilContent() { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmAttachMilContent(pT->m_hWnd); } HRESULT DwmDetachMilContent() { if(!IsDwmSupported()) return E_NOTIMPL; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DwmDetachMilContent(pT->m_hWnd); } }; template class CDwmWindowT : public TBase, public CDwmImpl > { public: CDwmWindowT(HWND hWnd = NULL) : TBase(hWnd) { } CDwmWindowT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } }; typedef CDwmWindowT CDwmWindow; /////////////////////////////////////////////////////////////////////////////// // CDwmThumbnail - provides DWM thumbnail support template class CDwmThumbnailT : public TBase { public: // Data members HTHUMBNAIL m_hThumbnail; // Constructor CDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail) { } ~CDwmThumbnailT() { if(t_bManaged && (m_hThumbnail != NULL)) Unregister(); } // Operations CDwmThumbnailT& operator =(HTHUMBNAIL hThumbnail) { Attach(hThumbnail); return *this; } void Attach(HTHUMBNAIL hThumbnailNew) { if(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew) Unregister(); m_hThumbnail = hThumbnailNew; } HTHUMBNAIL Detach() { HTHUMBNAIL hThumbnail = m_hThumbnail; m_hThumbnail = NULL; return hThumbnail; } HRESULT Register(HWND hwndDestination, HWND hwndSource) { ATLASSERT(::IsWindow(hwndDestination)); ATLASSERT(::IsWindow(hwndSource)); ATLASSERT(m_hThumbnail==NULL); if(!IsDwmSupported()) return E_NOTIMPL; return ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail); } HRESULT Unregister() { if(!IsDwmSupported()) return E_NOTIMPL; if(m_hThumbnail == NULL) return S_FALSE; HRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail); if(SUCCEEDED(Hr)) m_hThumbnail = NULL; return Hr; } operator HTHUMBNAIL() const { return m_hThumbnail; } bool IsNull() const { return (m_hThumbnail == NULL); } HRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties) { if(!IsDwmSupported()) return E_NOTIMPL; ATLASSERT(m_hThumbnail != NULL); return ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties); } // Attributes HRESULT QuerySourceSize(PSIZE pSize) { if(!IsDwmSupported()) return E_NOTIMPL; ATLASSERT(m_hThumbnail != NULL); return ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize); } }; typedef CDwmThumbnailT CDwmThumbnail; typedef CDwmThumbnailT CDwmThumbnailHandle; #ifdef __ATLTHEME_H__ /////////////////////////////////////////////////////////////////////////////// // CAeroControlImpl - Base class for controls on Glass template class CAeroControlImpl : public CThemeImpl, public CBufferedPaintImpl, public ATL::CWindowImpl { public: typedef CThemeImpl _themeClass; typedef CBufferedPaintImpl _baseClass; typedef ATL::CWindowImpl _windowClass; CAeroControlImpl() { m_PaintParams.dwFlags = BPPF_ERASE; } static LPCWSTR GetThemeName() { #ifdef _UNICODE return TBase::GetWndClassName(); #else ATLASSERT(!_T("Return UNICODE string of window classname / theme class")); return NULL; #endif // _UNICODE } // Message map and handlers BEGIN_MSG_MAP(CAeroControlImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) CHAIN_MSG_MAP(_themeClass) CHAIN_MSG_MAP(_baseClass) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->Init(); bHandled = FALSE; return 0; } LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(IsThemingSupported()) Invalidate(FALSE); bHandled = FALSE; return 0; } // Operations BOOL SubclassWindow(HWND hWnd) { ATLASSERT(m_hWnd == NULL); ATLASSERT(::IsWindow(hWnd)); BOOL bRet = _windowClass::SubclassWindow(hWnd); if(bRet) { T* pT = static_cast(this); pT->Init(); } return bRet; } // Implementation LRESULT DefWindowProc() { const ATL::_ATL_MSG* pMsg = m_pCurrentMsg; LRESULT lRes = 0; if(pMsg != NULL) lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); return lRes; } LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { T* pT = static_cast(this); LRESULT lRes = 0; if(::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) != FALSE) return lRes; return _windowClass::DefWindowProc(uMsg, wParam, lParam); } void DoBufferedPaint(HDC hDC, RECT& rcPaint) { T* pT = static_cast(this); HDC hDCPaint = NULL; RECT rcClient = { 0 }; GetClientRect(&rcClient); m_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint); ATLASSERT(hDCPaint != NULL); pT->DoAeroPaint(hDCPaint, rcClient, rcPaint); m_BufferedPaint.End(); } void DoPaint(HDC /*hdc*/, RECT& /*rcClient*/) { DefWindowProc(); } // Overridables void Init() { T* pT = static_cast(this); pT; // avoid level 4 warning SetThemeClassList(pT->GetThemeName()); if(m_lpstrThemeClassList != NULL) OpenThemeData(); } void DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint) { DefWindowProc(WM_PAINT, (WPARAM) hDC, 0L); m_BufferedPaint.MakeOpaque(&rcPaint); } }; #endif // __ATLTHEME_H__ }; // namespace WTL #endif // __ATLDWM_H__ ================================================ FILE: WTL/atlfind.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLFIND_H__ #define __ATLFIND_H__ #pragma once #ifdef _WIN32_WCE #error atlfind.h is not supported on Windows CE #endif #ifndef __ATLCTRLS_H__ #error atlfind.h requires atlctrls.h to be included first #endif #ifndef __ATLDLGS_H__ #error atlfind.h requires atldlgs.h to be included first #endif #if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__)) #error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING) #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CEditFindReplaceImplBase // CEditFindReplaceImpl // CRichEditFindReplaceImpl namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CEditFindReplaceImplBase - Base class for mixin classes that // help implement Find/Replace for CEdit or CRichEditCtrl based window classes. template class CEditFindReplaceImplBase { protected: // Typedefs typedef CEditFindReplaceImplBase thisClass; // Data members TFindReplaceDialog* m_pFindReplaceDialog; _CSTRING_NS::CString m_sFindNext, m_sReplaceWith; BOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown; LONG m_nInitialSearchPos; HCURSOR m_hOldCursor; // Enumerations enum TranslationTextItem { eText_OnReplaceAllMessage = 0, eText_OnReplaceAllTitle = 1, eText_OnTextNotFoundMessage = 2, eText_OnTextNotFoundTitle = 3 }; public: // Constructors CEditFindReplaceImplBase() : m_pFindReplaceDialog(NULL), m_bFindOnly(TRUE), m_bFirstSearch(TRUE), m_bMatchCase(FALSE), m_bWholeWord(FALSE), m_bFindDown(TRUE), m_nInitialSearchPos(0), m_hOldCursor(NULL) { } // Message Handlers BEGIN_MSG_MAP(thisClass) ALT_MSG_MAP(1) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd) COMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind) COMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat) COMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace) END_MSG_MAP() LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_pFindReplaceDialog != NULL) { m_pFindReplaceDialog->SendMessage(WM_CLOSE); ATLASSERT(m_pFindReplaceDialog == NULL); } bHandled = FALSE; return 0; } LRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); TFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam); if(pDialog == NULL) { ATLASSERT(FALSE); ::MessageBeep(MB_ICONERROR); return 1; } ATLASSERT(pDialog == m_pFindReplaceDialog); LPFINDREPLACE findReplace = (LPFINDREPLACE)lParam; if((m_pFindReplaceDialog != NULL) && (findReplace != NULL)) { if(pDialog->FindNext()) { pT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord()); } else if(pDialog->ReplaceCurrent()) { pT->OnReplaceSel(pDialog->GetFindString(), pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(), pDialog->GetReplaceString()); } else if(pDialog->ReplaceAll()) { pT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(), pDialog->MatchCase(), pDialog->MatchWholeWord()); } else if(pDialog->IsTerminating()) { // Dialog is going away (but hasn't gone away yet) // OnFinalMessage will "delete this" pT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog); m_pFindReplaceDialog = NULL; } } return 0; } LRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->FindReplace(TRUE); return 0; } LRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); // If the user is holding down SHIFT when hitting F3, we'll // search in reverse. Otherwise, we'll search forward. // (be sure to have an accelerator mapped to ID_EDIT_REPEAT // for both F3 and Shift+F3) m_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000); if(m_sFindNext.IsEmpty()) { pT->FindReplace(TRUE); } else { if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) pT->TextNotFound(m_sFindNext); } return 0; } LRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled) { T* pT = static_cast(this); DWORD style = pT->GetStyle(); if((style & ES_READONLY) != ES_READONLY) { pT->FindReplace(FALSE); } else { // Don't allow replace when the edit control is read only bHandled = FALSE; } return 0; } // Operations (overrideable) TFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace LPCTSTR lpszFindWhat, LPCTSTR lpszReplaceWith = NULL, DWORD dwFlags = FR_DOWN, HWND hWndParent = NULL) { // You can override all of this in a derived class TFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog(); if(findReplaceDialog == NULL) { ::MessageBeep(MB_ICONHAND); } else { HWND hWndFindReplace = findReplaceDialog->Create(bFindOnly, lpszFindWhat, lpszReplaceWith, dwFlags, hWndParent); if(hWndFindReplace == NULL) { delete findReplaceDialog; findReplaceDialog = NULL; } else { findReplaceDialog->SetActiveWindow(); findReplaceDialog->ShowWindow(SW_SHOW); } } return findReplaceDialog; } void AdjustDialogPosition(HWND hWndDialog) { ATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog)); T* pT = static_cast(this); LONG nStartChar = 0, nEndChar = 0; // Send EM_GETSEL so we can use both Edit and RichEdit // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); POINT point = pT->PosFromChar(nStartChar); ::ClientToScreen(pT->GetParent(), &point); CRect rect; ::GetWindowRect(hWndDialog, &rect); if(rect.PtInRect(point)) { if(point.y > rect.Height()) { rect.OffsetRect(0, point.y - rect.bottom - 20); } else { int nVertExt = GetSystemMetrics(SM_CYSCREEN); if(point.y + rect.Height() < nVertExt) rect.OffsetRect(0, 40 + point.y - rect.top); } ::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE); } } DWORD GetFindReplaceDialogFlags(void) const { DWORD dwFlags = 0; if(m_bFindDown) dwFlags |= FR_DOWN; if(m_bMatchCase) dwFlags |= FR_MATCHCASE; if(m_bWholeWord) dwFlags |= FR_WHOLEWORD; return dwFlags; } void FindReplace(BOOL bFindOnly) { T* pT = static_cast(this); m_bFirstSearch = TRUE; if(m_pFindReplaceDialog != NULL) { if(m_bFindOnly == bFindOnly) { m_pFindReplaceDialog->SetActiveWindow(); m_pFindReplaceDialog->ShowWindow(SW_SHOW); return; } else { m_pFindReplaceDialog->SendMessage(WM_CLOSE); ATLASSERT(m_pFindReplaceDialog == NULL); } } ATLASSERT(m_pFindReplaceDialog == NULL); _CSTRING_NS::CString findNext; pT->GetSelText(findNext); // if selection is empty or spans multiple lines use old find text if(findNext.IsEmpty() || (findNext.FindOneOf(_T("\n\r")) != -1)) findNext = m_sFindNext; _CSTRING_NS::CString replaceWith = m_sReplaceWith; DWORD dwFlags = pT->GetFindReplaceDialogFlags(); m_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly, findNext, replaceWith, dwFlags, pT->operator HWND()); ATLASSERT(m_pFindReplaceDialog != NULL); if(m_pFindReplaceDialog != NULL) m_bFindOnly = bFindOnly; } BOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/) { T* pT = static_cast(this); // check length first size_t nLen = lstrlen(lpszCompare); LONG nStartChar = 0, nEndChar = 0; // Send EM_GETSEL so we can use both Edit and RichEdit // (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&) ::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); if(nLen != (size_t)(nEndChar - nStartChar)) return FALSE; // length is the same, check contents _CSTRING_NS::CString selectedText; pT->GetSelText(selectedText); return (bMatchCase && selectedText.Compare(lpszCompare) == 0) || (!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0); } void TextNotFound(LPCTSTR lpszFind) { T* pT = static_cast(this); m_bFirstSearch = TRUE; pT->OnTextNotFound(lpszFind); } _CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const { _CSTRING_NS::CString text; switch(eItem) { case eText_OnReplaceAllMessage: text = _T("Replaced %d occurances of \"%s\" with \"%s\""); break; case eText_OnReplaceAllTitle: text = _T("Replace All"); break; case eText_OnTextNotFoundMessage: text = _T("Unable to find the text \"%s\""); break; case eText_OnTextNotFoundTitle: text = _T("Text not found"); break; } return text; } // Overrideable Handlers void OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord) { T* pT = static_cast(this); m_sFindNext = lpszFind; m_bMatchCase = bMatchCase; m_bWholeWord = bWholeWord; m_bFindDown = bFindDown; if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) pT->TextNotFound(m_sFindNext); else pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); } void OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace) { T* pT = static_cast(this); m_sFindNext = lpszFind; m_sReplaceWith = lpszReplace; m_bMatchCase = bMatchCase; m_bWholeWord = bWholeWord; m_bFindDown = bFindDown; if(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) pT->ReplaceSel(m_sReplaceWith); if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) pT->TextNotFound(m_sFindNext); else pT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND()); } void OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord) { T* pT = static_cast(this); m_sFindNext = lpszFind; m_sReplaceWith = lpszReplace; m_bMatchCase = bMatchCase; m_bWholeWord = bWholeWord; m_bFindDown = TRUE; // no selection or different than what looking for if(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord)) { if(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)) { pT->TextNotFound(m_sFindNext); return; } } pT->OnReplaceAllCoreBegin(); int replaceCount=0; do { ++replaceCount; pT->ReplaceSel(m_sReplaceWith); } while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown)); pT->OnReplaceAllCoreEnd(replaceCount); } void OnReplaceAllCoreBegin() { T* pT = static_cast(this); m_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); pT->HideSelection(TRUE, FALSE); } void OnReplaceAllCoreEnd(int replaceCount) { T* pT = static_cast(this); pT->HideSelection(FALSE, FALSE); ::SetCursor(m_hOldCursor); _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage); if(message.GetLength() > 0) { _CSTRING_NS::CString formattedMessage; formattedMessage.Format(message, replaceCount, (LPCTSTR)m_sFindNext, (LPCTSTR)m_sReplaceWith); if(m_pFindReplaceDialog != NULL) { m_pFindReplaceDialog->MessageBox(formattedMessage, pT->GetTranslationText(eText_OnReplaceAllTitle), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); } else { pT->MessageBox(formattedMessage, pT->GetTranslationText(eText_OnReplaceAllTitle), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); } } } void OnTextNotFound(LPCTSTR lpszFind) { T* pT = static_cast(this); _CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage); if(message.GetLength() > 0) { _CSTRING_NS::CString formattedMessage; formattedMessage.Format(message, lpszFind); if(m_pFindReplaceDialog != NULL) { m_pFindReplaceDialog->MessageBox(formattedMessage, pT->GetTranslationText(eText_OnTextNotFoundTitle), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); } else { pT->MessageBox(formattedMessage, pT->GetTranslationText(eText_OnTextNotFoundTitle), MB_OK | MB_ICONINFORMATION | MB_APPLMODAL); } } else { ::MessageBeep(MB_ICONHAND); } } void OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/) { } }; /////////////////////////////////////////////////////////////////////////////// // CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit // based window classes. // Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit. // Example: // class CMyEdit : public CWindowImpl, // public CEditFindReplaceImpl // { // public: // BEGIN_MSG_MAP(CMyEdit) // // your handlers... // CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl, 1) // END_MSG_MAP() // // other stuff... // }; template class CEditFindReplaceImpl : public CEditFindReplaceImplBase { protected: typedef CEditFindReplaceImpl thisClass; typedef CEditFindReplaceImplBase baseClass; // Data members LPTSTR m_pShadowBuffer; // Special shadow buffer only used in some cases. UINT m_nShadowSize; int m_bShadowBufferNeeded; // TRUE, FALSE, < 0 => Need to check public: // Constructors CEditFindReplaceImpl() : m_pShadowBuffer(NULL), m_nShadowSize(0), m_bShadowBufferNeeded(-1) { } virtual ~CEditFindReplaceImpl() { if(m_pShadowBuffer != NULL) { delete [] m_pShadowBuffer; m_pShadowBuffer = NULL; } } // Message Handlers BEGIN_MSG_MAP(thisClass) ALT_MSG_MAP(1) CHAIN_MSG_MAP_ALT(baseClass, 1) END_MSG_MAP() // Operations // Supported only for RichEdit, so this does nothing for Edit void HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE) { } // Operations (overrideable) BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) { T* pT = static_cast(this); ATLASSERT(lpszFind != NULL); ATLASSERT(*lpszFind != _T('\0')); UINT nLen = pT->GetBufferLength(); int nStartChar = 0, nEndChar = 0; pT->GetSel(nStartChar, nEndChar); UINT nStart = nStartChar; int iDir = bFindDown ? +1 : -1; // can't find a match before the first character if((nStart == 0) && (iDir < 0)) return FALSE; LPCTSTR lpszText = pT->LockBuffer(); bool isDBCS = false; #ifdef _MBCS CPINFO info = { 0 }; ::GetCPInfo(::GetOEMCP(), &info); isDBCS = (info.MaxCharSize > 1); #endif if(iDir < 0) { // always go back one for search backwards nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); } else if((nStartChar != nEndChar) && (pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord))) { // easy to go backward/forward with SBCS #ifndef _UNICODE if(::IsDBCSLeadByte(lpszText[nStart])) nStart++; #endif nStart += iDir; } // handle search with nStart past end of buffer UINT nLenFind = ::lstrlen(lpszFind); if((nStart + nLenFind - 1) >= nLen) { if((iDir < 0) && (nLen >= nLenFind)) { if(isDBCS) { // walk back to previous character n times nStart = nLen; int n = nLenFind; while(n--) { nStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart)); } } else { // single-byte character set is easy and fast nStart = nLen - nLenFind; } ATLASSERT((nStart + nLenFind - 1) <= nLen); } else { pT->UnlockBuffer(); return FALSE; } } // start the search at nStart LPCTSTR lpsz = lpszText + nStart; typedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2); CompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi; if(isDBCS) { // double-byte string search LPCTSTR lpszStop = NULL; if(iDir > 0) { // start at current and find _first_ occurrance lpszStop = lpszText + nLen - nLenFind + 1; } else { // start at top and find _last_ occurrance lpszStop = lpsz; lpsz = lpszText; } LPCTSTR lpszFound = NULL; while(lpsz <= lpszStop) { #ifndef _UNICODE if(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1]))) #else if(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1])) #endif { LPTSTR lpch = (LPTSTR)(lpsz + nLenFind); TCHAR chSave = *lpch; *lpch = _T('\0'); int nResult = (*pfnCompare)(lpsz, lpszFind); *lpch = chSave; if(nResult == 0) { lpszFound = lpsz; if(iDir > 0) break; } } lpsz = ::CharNext(lpsz); } pT->UnlockBuffer(); if(lpszFound != NULL) { int n = (int)(lpszFound - lpszText); pT->SetSel(n, n + nLenFind); return TRUE; } } else { // single-byte string search UINT nCompare = 0; if(iDir < 0) nCompare = (UINT)(lpsz - lpszText) + 1; else nCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1; while(nCompare > 0) { ATLASSERT(lpsz >= lpszText); ATLASSERT((lpsz + nLenFind - 1) <= (lpszText + nLen - 1)); LPSTR lpch = (LPSTR)(lpsz + nLenFind); char chSave = *lpch; *lpch = '\0'; int nResult = (*pfnCompare)(lpsz, lpszFind); *lpch = chSave; if(nResult == 0) { pT->UnlockBuffer(); int n = (int)(lpsz - lpszText); pT->SetSel(n, n + nLenFind); return TRUE; } // restore character at end of search *lpch = chSave; // move on to next substring nCompare--; lpsz += iDir; } pT->UnlockBuffer(); } return FALSE; } LPCTSTR LockBuffer() const { const T* pT = static_cast(this); ATLASSERT(pT->m_hWnd != NULL); BOOL useShadowBuffer = pT->UseShadowBuffer(); if(useShadowBuffer) { if((m_pShadowBuffer == NULL) || pT->GetModify()) { ATLASSERT((m_pShadowBuffer != NULL) || (m_nShadowSize == 0)); UINT nSize = pT->GetWindowTextLength() + 1; if(nSize > m_nShadowSize) { // need more room for shadow buffer T* pThisNoConst = const_cast(pT); delete[] m_pShadowBuffer; pThisNoConst->m_pShadowBuffer = NULL; pThisNoConst->m_nShadowSize = 0; pThisNoConst->m_pShadowBuffer = new TCHAR[nSize]; pThisNoConst->m_nShadowSize = nSize; } // update the shadow buffer with GetWindowText ATLASSERT(m_nShadowSize >= nSize); ATLASSERT(m_pShadowBuffer != NULL); pT->GetWindowText(m_pShadowBuffer, nSize); } return m_pShadowBuffer; } HLOCAL hLocal = pT->GetHandle(); ATLASSERT(hLocal != NULL); LPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal); ATLASSERT(lpszText != NULL); return lpszText; } void UnlockBuffer() const { const T* pT = static_cast(this); ATLASSERT(pT->m_hWnd != NULL); BOOL useShadowBuffer = pT->UseShadowBuffer(); if(!useShadowBuffer) { HLOCAL hLocal = pT->GetHandle(); ATLASSERT(hLocal != NULL); ::LocalUnlock(hLocal); } } UINT GetBufferLength() const { const T* pT = static_cast(this); ATLASSERT(pT->m_hWnd != NULL); UINT nLen = 0; LPCTSTR lpszText = pT->LockBuffer(); if(lpszText != NULL) nLen = ::lstrlen(lpszText); pT->UnlockBuffer(); return nLen; } LONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const { LPCTSTR lpsz = lpszText + nIndex; LPCTSTR lpszStop = lpszText + nLen; while(lpsz < lpszStop && *lpsz != _T('\r')) ++lpsz; return LONG(lpsz - lpszText); } LONG GetSelText(_CSTRING_NS::CString& strText) const { const T* pT = static_cast(this); int nStartChar = 0, nEndChar = 0; pT->GetSel(nStartChar, nEndChar); ATLASSERT((UINT)nEndChar <= pT->GetBufferLength()); LPCTSTR lpszText = pT->LockBuffer(); LONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar; SecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR)); strText.ReleaseBuffer(nLen); pT->UnlockBuffer(); return nLen; } BOOL UseShadowBuffer(void) const { const T* pT = static_cast(this); if(pT->m_bShadowBufferNeeded < 0) { T* pThisNoConst = const_cast(pT); #ifdef _versionhelpers_H_INCLUDED_ OSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) }; ovi.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; DWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); bool bWin9x = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE); #else // !_versionhelpers_H_INCLUDED_ OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) }; ::GetVersionEx(&ovi); bool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); #endif // _versionhelpers_H_INCLUDED_ if(bWin9x) { // Windows 95, 98, ME // Under Win9x, it is necessary to maintain a shadow buffer. // It is only updated when the control contents have been changed. pThisNoConst->m_bShadowBufferNeeded = TRUE; } else { // Windows NT, 2000, XP, etc. pThisNoConst->m_bShadowBufferNeeded = FALSE; #ifndef _UNICODE // On Windows XP (or later), if common controls version 6 is in use // (such as via theming), then EM_GETHANDLE will always return a UNICODE string. // If theming is enabled and Common Controls version 6 is in use, // you're really not suppose to superclass or subclass common controls // with an ANSI windows procedure (so its best to only theme if you use UNICODE). // Using a shadow buffer uses GetWindowText instead, so it solves // this problem for us (although it makes it a little less efficient). #ifdef _versionhelpers_H_INCLUDED_ if(::IsWindowsXPOrGreater()) #else // !_versionhelpers_H_INCLUDED_ if ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5)) #endif // _versionhelpers_H_INCLUDED_ { DWORD dwMajor = 0, dwMinor = 0; HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); if(SUCCEEDED(hRet)) { if(dwMajor >= 6) { pThisNoConst->m_bShadowBufferNeeded = TRUE; ATLTRACE2(atlTraceUI, 0, _T("Warning: You have compiled for MBCS/ANSI but are using common controls version 6 or later (likely through a manifest file).\r\n")); ATLTRACE2(atlTraceUI, 0, _T("If you use common controls version 6 or later, you should only do so for UNICODE builds.\r\n")); } } } #endif // !_UNICODE } } return (pT->m_bShadowBufferNeeded != FALSE); } }; /////////////////////////////////////////////////////////////////////////////// // CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl // based window classes. // Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl. // Example: // class CMyRichEdit : public CWindowImpl, // public CRichEditFindReplaceImpl // { // public: // BEGIN_MSG_MAP(CMyRichEdit) // // your handlers... // CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl, 1) // END_MSG_MAP() // // other stuff... // }; template class CRichEditFindReplaceImpl : public CEditFindReplaceImplBase { protected: typedef CRichEditFindReplaceImpl thisClass; typedef CEditFindReplaceImplBase baseClass; public: BEGIN_MSG_MAP(thisClass) ALT_MSG_MAP(1) CHAIN_MSG_MAP_ALT(baseClass, 1) END_MSG_MAP() // Operations (overrideable) BOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE) { T* pT = static_cast(this); ATLASSERT(lpszFind != NULL); FINDTEXTEX ft = { 0 }; pT->GetSel(ft.chrg); if(m_bFirstSearch) { if(bFindDown) m_nInitialSearchPos = ft.chrg.cpMin; else m_nInitialSearchPos = ft.chrg.cpMax; m_bFirstSearch = FALSE; } #if (_RICHEDIT_VER >= 0x0200) ft.lpstrText = (LPTSTR)lpszFind; #else // !(_RICHEDIT_VER >= 0x0200) USES_CONVERSION; ft.lpstrText = T2A((LPTSTR)lpszFind); #endif // !(_RICHEDIT_VER >= 0x0200) if(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection { if(bFindDown) { ft.chrg.cpMin++; } else { // won't wraparound backwards ft.chrg.cpMin = __max(ft.chrg.cpMin, 0); } } DWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0; dwFlags |= bWholeWord ? FR_WHOLEWORD : 0; ft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos; if(bFindDown) { if(m_nInitialSearchPos >= 0) ft.chrg.cpMax = pT->GetTextLength(); dwFlags |= FR_DOWN; ATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin); } else { if(m_nInitialSearchPos >= 0) ft.chrg.cpMax = 0; dwFlags &= ~FR_DOWN; ATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin); } BOOL bRet = FALSE; if(pT->FindAndSelect(dwFlags, ft) != -1) { bRet = TRUE; // we found the text } else if(m_nInitialSearchPos > 0) { // if the original starting point was not the beginning // of the buffer and we haven't already been here if(bFindDown) { ft.chrg.cpMin = 0; ft.chrg.cpMax = m_nInitialSearchPos; } else { ft.chrg.cpMin = pT->GetTextLength(); ft.chrg.cpMax = m_nInitialSearchPos; } m_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength(); bRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE; } return bRet; } long FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft) { T* pT = static_cast(this); LONG index = pT->FindText(dwFlags, ft); if(index != -1) // i.e. we found something pT->SetSel(ft.chrgText); return index; } }; }; // namespace WTL #endif // __ATLFIND_H__ ================================================ FILE: WTL/atlframe.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLFRAME_H__ #define __ATLFRAME_H__ #pragma once #ifndef __ATLAPP_H__ #error atlframe.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlframe.h requires atlwin.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CFrameWindowImpl // CMDIWindow // CMDIFrameWindowImpl // CMDIChildWindowImpl // COwnerDraw // CUpdateUIBase // CUpdateUI // CDynamicUpdateUI // CAutoUpdateUI // CDialogResize // CDoubleBufferImpl // CDoubleBufferWindowImpl // // Global functions: // AtlCreateSimpleToolBar() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CFrameWndClassInfo - Manages frame window Windows class information class CFrameWndClassInfo { public: #ifndef _WIN32_WCE enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs WNDCLASSEX m_wc; #else // CE specific enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string. WNDCLASS m_wc; #endif // !_WIN32_WCE LPCTSTR m_lpszOrigName; WNDPROC pWndProc; LPCTSTR m_lpszCursorID; BOOL m_bSystemCursor; ATOM m_atom; TCHAR m_szAutoName[cchAutoName]; UINT m_uCommonResourceID; #ifndef _WIN32_WCE ATOM Register(WNDPROC* pProc) { if (m_atom == 0) { CWindowCreateCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); ATLASSERT(FALSE); return 0; } if(m_atom == 0) { HINSTANCE hInst = ModuleHelper::GetModuleInstance(); if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); LPCTSTR lpsz = m_wc.lpszClassName; WNDPROC proc = m_wc.lpfnWndProc; WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; // try process local class first if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) { // try global class if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) { lock.Unlock(); return 0; } } m_wc = wc; pWndProc = m_wc.lpfnWndProc; m_wc.lpszClassName = lpsz; m_wc.lpfnWndProc = proc; } else { m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); } m_wc.hInstance = hInst; m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes if (m_wc.lpszClassName == NULL) { #if (_WIN32_WINNT >= 0x0500) || defined(_WIN64) SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc); #else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); #endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64)) m_wc.lpszClassName = m_szAutoName; } WNDCLASSEX wcTemp = m_wc; m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); if (m_atom == 0) { if(m_uCommonResourceID != 0) // use it if not zero { m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); } m_atom = ::RegisterClassEx(&m_wc); } } lock.Unlock(); } if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); ATLASSERT(pWndProc != NULL); *pProc = pWndProc; } return m_atom; } #else // CE specific ATOM Register(WNDPROC* pProc) { if (m_atom == 0) { CWindowCreateCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n")); ATLASSERT(FALSE); return 0; } if(m_atom == 0) { HINSTANCE hInst = ModuleHelper::GetModuleInstance(); if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); LPCTSTR lpsz = m_wc.lpszClassName; WNDPROC proc = m_wc.lpfnWndProc; WNDCLASS wc = { 0 }; // try process local class first if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc)) { // try global class if(!::GetClassInfo(NULL, m_lpszOrigName, &wc)) { lock.Unlock(); return 0; } } m_wc = wc; pWndProc = m_wc.lpfnWndProc; m_wc.lpszClassName = lpsz; m_wc.lpfnWndProc = proc; } else { #if defined(GWES_CURSOR) || defined(GWES_MCURSOR) m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); #else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) m_wc.hCursor = NULL; #endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR)) } m_wc.hInstance = hInst; m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes if (m_wc.lpszClassName == NULL) { wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc); m_wc.lpszClassName = m_szAutoName; } WNDCLASS wcTemp = m_wc; m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); if (m_atom == 0) { if(m_uCommonResourceID != 0) // use it if not zero m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); m_atom = ::RegisterClass(&m_wc); } } lock.Unlock(); } if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); ATLASSERT(pWndProc != NULL); *pProc = pWndProc; } return m_atom; } #endif // _WIN32_WCE }; /////////////////////////////////////////////////////////////////////////////// // Macros for declaring frame window WNDCLASS #ifndef _WIN32_WCE #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), style, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #else // CE specific #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { style, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { NULL, StartWindowProc, \ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \ OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CFrameWindowImpl // Client window command chaining macro (only for frame windows) #define CHAIN_CLIENT_COMMANDS() \ if(uMsg == WM_COMMAND && m_hWndClient != NULL) \ ::SendMessage(m_hWndClient, uMsg, wParam, lParam); // standard toolbar styles #define ATL_SIMPLE_TOOLBAR_STYLE \ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS) // toolbar in a rebar pane #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT) // standard rebar styles #if (_WIN32_IE >= 0x0400) #define ATL_SIMPLE_REBAR_STYLE \ (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE) #else #define ATL_SIMPLE_REBAR_STYLE \ (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS) #endif // !(_WIN32_IE >= 0x0400) // rebar without borders #if (_WIN32_IE >= 0x0400) #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER) #else #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \ (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER) #endif // !(_WIN32_IE >= 0x0400) // command bar support #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu struct _AtlFrameWnd_CmdBarPopupMenu { int cbSize; HMENU hMenu; UINT uFlags; int x; int y; LPTPMPARAMS lptpm; }; #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) template class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits > { public: DECLARE_FRAME_WND_CLASS(NULL, 0) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) struct _ChevronMenuInfo { HMENU hMenu; LPNMREBARCHEVRON lpnm; bool bCmdBar; }; #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) // Data members HWND m_hWndToolBar; HWND m_hWndStatusBar; HWND m_hWndClient; #ifdef _WIN32_WCE HWND m_hWndCECommandBar; #endif // _WIN32_WCE HACCEL m_hAccel; // Constructor CFrameWindowImplBase() : m_hWndToolBar(NULL), m_hWndStatusBar(NULL), m_hWndClient(NULL), #ifdef _WIN32_WCE m_hWndCECommandBar(NULL), #endif // _WIN32_WCE m_hAccel(NULL) { } // Methods HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam) { ATLASSERT(m_hWnd == NULL); #if (_ATL_VER >= 0x0800) // Allocate the thunk structure here, where we can fail gracefully. BOOL bRet = m_thunk.Init(NULL, NULL); if(bRet == FALSE) { ::SetLastError(ERROR_OUTOFMEMORY); return NULL; } #endif // (_ATL_VER >= 0x0800) if(atom == 0) return NULL; ModuleHelper::AddCreateWndData(&m_thunk.cd, this); if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD)) MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this; if(rect.m_lpRect == NULL) rect.m_lpRect = &TBase::rcDefault; HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName, dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu, ModuleHelper::GetModuleInstance(), lpCreateParam); ATLASSERT(hWnd == NULL || m_hWnd == hWnd); return hWnd; } static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { HINSTANCE hInst = ModuleHelper::GetResourceInstance(); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); if (hRsrc == NULL) return NULL; HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); if (hGlobal == NULL) return NULL; _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); if (pData == NULL) return NULL; ATLASSERT(pData->wVersion == 1); WORD* pItems = pData->items(); int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); CTempBuffer buff; TBBUTTON* pTBBtn = buff.Allocate(nItems); ATLASSERT(pTBBtn != NULL); if(pTBBtn == NULL) return NULL; const int cxSeparator = 8; // set initial separator (half width) if(bInitialSeparator) { pTBBtn[0].iBitmap = cxSeparator / 2; pTBBtn[0].idCommand = 0; pTBBtn[0].fsState = 0; pTBBtn[0].fsStyle = BTNS_SEP; pTBBtn[0].dwData = 0; pTBBtn[0].iString = 0; } int nBmp = 0; for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) { if(pItems[i] != 0) { pTBBtn[j].iBitmap = nBmp++; pTBBtn[j].idCommand = pItems[i]; pTBBtn[j].fsState = TBSTATE_ENABLED; pTBBtn[j].fsStyle = BTNS_BUTTON; pTBBtn[j].dwData = 0; pTBBtn[j].iString = 0; } else { pTBBtn[j].iBitmap = cxSeparator; pTBBtn[j].idCommand = 0; pTBBtn[j].fsState = 0; pTBBtn[j].fsStyle = BTNS_SEP; pTBBtn[j].dwData = 0; pTBBtn[j].iString = 0; } } #ifndef _WIN32_WCE HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); if(hWnd == NULL) { ATLASSERT(FALSE); return NULL; } #else // CE specific dwStyle; nID; // The toolbar must go onto the existing CommandBar or MenuBar HWND hWnd = hWndParent; #endif // _WIN32_WCE ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); // check if font is taller than our bitmaps CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L); if(font.IsNull()) font = (HFONT)::GetStockObject(SYSTEM_FONT); LOGFONT lf = { 0 }; font.GetLogFont(lf); WORD cyFontHeight = (WORD)abs(lf.lfHeight); #ifndef _WIN32_WCE WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID); if(bitsPerPixel > 4) { COLORREF crMask = CLR_DEFAULT; if(bitsPerPixel == 32) { // 32-bit color bitmap with alpha channel (valid for Windows XP and later) crMask = CLR_NONE; } HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); ATLASSERT(hImageList != NULL); ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList); } else #endif // !_WIN32_WCE { TBADDBITMAP tbab = { 0 }; tbab.hInst = hInst; tbab.nID = nResourceID; ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); } ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight))); const int cxyButtonMargin = 7; ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin)); return hWnd; } #ifndef _WIN32_WCE static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { // Ensure style combinations for proper rebar painting if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER) dwStyle &= ~WS_BORDER; else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER)) dwStyle |= CCS_NODIVIDER; // Create rebar window HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL); if(hWndReBar == NULL) { ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n")); return NULL; } // Initialize and send the REBARINFO structure REBARINFO rbi = { sizeof(REBARINFO), 0 }; if(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0) { ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n")); ::DestroyWindow(hWndReBar); return NULL; } return hWndReBar; } BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID); return (m_hWndToolBar != NULL); } static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) { ATLASSERT(::IsWindow(hWndReBar)); // must be already created #ifdef _DEBUG // block - check if this is really a rebar { TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 }; ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME)); ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0); } #endif // _DEBUG ATLASSERT(::IsWindow(hWndBand)); // must be already created // Get number of buttons on the toolbar int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L); // Set band info structure REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; #if (_WIN32_IE >= 0x0400) rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE; #else rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE; #endif // !(_WIN32_IE >= 0x0400) if(lpstrTitle != NULL) rbBand.fMask |= RBBIM_TEXT; rbBand.fStyle = RBBS_CHILDEDGE; #if (_WIN32_IE >= 0x0500) if(nBtnCount > 0) // add chevron style for toolbar with buttons rbBand.fStyle |= RBBS_USECHEVRON; #endif // (_WIN32_IE >= 0x0500) if(bNewRow) rbBand.fStyle |= RBBS_BREAK; rbBand.lpText = (LPTSTR)lpstrTitle; rbBand.hwndChild = hWndBand; if(nID == 0) // calc band ID nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L); rbBand.wID = nID; // Calculate the size of the band BOOL bRet = FALSE; RECT rcTmp = { 0 }; if(nBtnCount > 0) { bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp); ATLASSERT(bRet); rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right; rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; if(bFullWidthAlways) { rbBand.cxMinChild = rbBand.cx; } else if(lpstrTitle == NULL) { bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp); ATLASSERT(bRet); rbBand.cxMinChild = rcTmp.right; } else { rbBand.cxMinChild = 0; } } else // no buttons, either not a toolbar or really has no buttons { bRet = ::GetWindowRect(hWndBand, &rcTmp); ATLASSERT(bRet); rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left); rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0; rbBand.cyMinChild = rcTmp.bottom - rcTmp.top; } #if (_WIN32_IE >= 0x0400) rbBand.cxIdeal = rbBand.cx; #endif // (_WIN32_IE >= 0x0400) // Add the band LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); if(lRes == 0) { ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n")); return FALSE; } #if (_WIN32_IE >= 0x0501) DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L); ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS); #endif // (_WIN32_IE >= 0x0501) return TRUE; } BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE) { ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar ATLASSERT(::IsWindow(hWndBand)); // must be created return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways); } #if (_WIN32_IE >= 0x0400) void SizeSimpleReBarBands() { ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L); for(int i = 0; i < nCount; i++) { REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() }; rbBand.fMask = RBBIM_SIZE; BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand); ATLASSERT(bRet); RECT rect = { 0 }; ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect); rbBand.cx += rect.left + rect.right; bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand); ATLASSERT(bRet); } } #endif // (_WIN32_IE >= 0x0400) #endif // _WIN32_WCE #ifndef _WIN32_WCE BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) #else // CE specific BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) #endif // _WIN32_WCE { ATLASSERT(!::IsWindow(m_hWndStatusBar)); m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID); return (m_hWndStatusBar != NULL); } #ifndef _WIN32_WCE BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) #else // CE specific BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR) #endif // _WIN32_WCE { const int cchMax = 128; // max text length is 127 for status bars (+1 for null) TCHAR szText[cchMax] = { 0 }; ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); return CreateSimpleStatusBar(szText, dwStyle, nID); } #ifdef _WIN32_WCE BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1) { ATLASSERT(m_hWndCECommandBar == NULL); ATLASSERT(m_hWndToolBar == NULL); m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID); if(m_hWndCECommandBar == NULL) return FALSE; m_hWndToolBar = m_hWndCECommandBar; BOOL bRet = TRUE; if(pszMenu != NULL) bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton); bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0); return bRet; } #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0) { ATLASSERT(m_hWndCECommandBar == NULL); SHMENUBARINFO mbi = { 0 }; mbi.cbSize = sizeof(mbi); mbi.hwndParent = m_hWnd; mbi.dwFlags = dwFlags; mbi.nToolBarId = nToolBarId; mbi.hInstRes = ModuleHelper::GetResourceInstance(); mbi.nBmpId = nBmpId; mbi.cBmpImages = cBmpImages; mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar BOOL bRet = ::SHCreateMenuBar(&mbi); if(bRet != FALSE) { m_hWndCECommandBar = mbi.hwndMB; SizeToMenuBar(); } return bRet; } void SizeToMenuBar() // for menu bar only { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(::IsWindow(m_hWndCECommandBar)); RECT rect = { 0 }; GetWindowRect(&rect); RECT rectMB = { 0 }; ::GetWindowRect(m_hWndCECommandBar, &rectMB); int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top; SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE); } #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) #endif // _WIN32_WCE void UpdateLayout(BOOL bResizeBars = TRUE) { RECT rect = { 0 }; GetClientRect(&rect); // position bars and offset their dimensions UpdateBarsPosition(rect, bResizeBars); // resize client window if(m_hWndClient != NULL) ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE); } void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE) { // resize toolbar if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) { if(bResizeBars != FALSE) { ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); ::InvalidateRect(m_hWndToolBar, NULL, TRUE); } RECT rectTB = { 0 }; ::GetWindowRect(m_hWndToolBar, &rectTB); rect.top += rectTB.bottom - rectTB.top; } // resize status bar if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) { if(bResizeBars != FALSE) ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); RECT rectSB = { 0 }; ::GetWindowRect(m_hWndStatusBar, &rectSB); rect.bottom -= rectSB.bottom - rectSB.top; } } BOOL PreTranslateMessage(MSG* pMsg) { if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) return TRUE; return FALSE; } BEGIN_MSG_MAP(CFrameWindowImplBase) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) #ifndef _WIN32_WCE NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA) NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW) #endif // !_WIN32_WCE END_MSG_MAP() LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_hWndClient != NULL) // view will paint itself instead return 1; bHandled = FALSE; return 0; } #ifndef _WIN32_WCE LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; if(m_hWndStatusBar == NULL) return 1; WORD wFlags = HIWORD(wParam); if(wFlags == 0xFFFF && lParam == NULL) // menu closing { ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); } else { const int cchBuff = 256; TCHAR szBuff[cchBuff] = { 0 }; if(!(wFlags & MF_POPUP)) { WORD wID = LOWORD(wParam); // check for special cases if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items wID = ATL_IDS_MRU_FILE; else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows wID = ATL_IDS_MDICHILD; int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff); for(int i = 0; i < nRet; i++) { if(szBuff[i] == _T('\n')) { szBuff[i] = 0; break; } } } ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); } return 1; } #endif // !_WIN32_WCE LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) { if(m_hWndClient != NULL) ::SetFocus(m_hWndClient); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0) ::PostQuitMessage(1); bHandled = FALSE; return 1; } #ifndef _WIN32_WCE LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) { LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh; if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) { const int cchBuff = 256; char szBuff[cchBuff] = { 0 }; int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); for(int i = 0; i < nRet; i++) { if(szBuff[i] == '\n') { SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); break; } } #if (_WIN32_IE >= 0x0300) if(nRet > 0) // string was loaded, save it pDispInfo->uFlags |= TTF_DI_SETITEM; #endif // (_WIN32_IE >= 0x0300) } return 0; } LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) { LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh; if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND)) { const int cchBuff = 256; wchar_t szBuff[cchBuff] = { 0 }; int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff); for(int i = 0; i < nRet; i++) { if(szBuff[i] == L'\n') { SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE); break; } } #if (_WIN32_IE >= 0x0300) if(nRet > 0) // string was loaded, save it pDispInfo->uFlags |= TTF_DI_SETITEM; #endif // (_WIN32_IE >= 0x0300) } return 0; } #endif // !_WIN32_WCE // Implementation - chevron menu support #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) bool PrepareChevronMenu(_ChevronMenuInfo& cmi) { // get rebar and toolbar REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() }; rbbi.fMask = RBBIM_CHILD; BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi); ATLASSERT(bRet); // assume the band is a toolbar ATL::CWindow wnd = rbbi.hwndChild; int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT); if(nCount <= 0) // probably not a toolbar return false; // check if it's a command bar CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU); cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL); // build a menu from hidden items CMenuHandle menu; bRet = menu.CreatePopupMenu(); ATLASSERT(bRet); RECT rcClient = { 0 }; bRet = wnd.GetClientRect(&rcClient); ATLASSERT(bRet); for(int i = 0; i < nCount; i++) { TBBUTTON tbb = { 0 }; bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb); ATLASSERT(bRet); // skip hidden buttons if((tbb.fsState & TBSTATE_HIDDEN) != 0) continue; RECT rcButton = { 0 }; bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton); ATLASSERT(bRet); bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0); if((rcButton.right > rcClient.right) || (rcButton.bottom > rcClient.bottom)) { if(tbb.fsStyle & BTNS_SEP) { if(menu.GetMenuItemCount() > 0) menu.AppendMenu(MF_SEPARATOR); } else if(cmi.bCmdBar) { const int cchBuff = 200; TCHAR szBuff[cchBuff] = { 0 }; CMenuItemInfo mii; mii.fMask = MIIM_TYPE | MIIM_SUBMENU; mii.dwTypeData = szBuff; mii.cch = cchBuff; bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); // Note: CmdBar currently supports only drop-down items ATLASSERT(::IsMenu(mii.hSubMenu)); bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData); ATLASSERT(bRet); } else { // get button's text const int cchBuff = 200; TCHAR szBuff[cchBuff] = { 0 }; LPCTSTR lpstrText = szBuff; TBBUTTONINFO tbbi = { 0 }; tbbi.cbSize = sizeof(TBBUTTONINFO); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = szBuff; tbbi.cchText = cchBuff; if((wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1) || (szBuff[0] == 0)) { // no text for this button, try a resource string lpstrText = _T(""); int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff); for(int n = 0; n < nRet; n++) { if(szBuff[n] == _T('\n')) { lpstrText = &szBuff[n + 1]; break; } } } bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText); ATLASSERT(bRet); } } } if(menu.GetMenuItemCount() == 0) // no hidden buttons after all { menu.DestroyMenu(); ::MessageBeep((UINT)-1); return false; } cmi.hMenu = menu; return true; } void DisplayChevronMenu(_ChevronMenuInfo& cmi) { #ifndef TPM_VERPOSANIMATION const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag #endif // convert chevron rect to screen coordinates ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom }; wndFrom.MapWindowPoints(NULL, &pt, 1); RECT rc = cmi.lpnm->rc; wndFrom.MapWindowPoints(NULL, &rc); // set up flags and rect UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0); TPMPARAMS TPMParams = { 0 }; TPMParams.cbSize = sizeof(TPMPARAMS); TPMParams.rcExclude = rc; // check if this window has a command bar HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L); if(::IsWindow(hWndCmdBar)) { CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams }; ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu); } else { CMenuHandle menu = cmi.hMenu; menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams); } } void CleanupChevronMenu(_ChevronMenuInfo& cmi) { CMenuHandle menu = cmi.hMenu; // if menu is from a command bar, detach submenus so they are not destroyed if(cmi.bCmdBar) { for(int i = menu.GetMenuItemCount() - 1; i >=0; i--) menu.RemoveMenu(i, MF_BYPOSITION); } // destroy menu menu.DestroyMenu(); // convert chevron rect to screen coordinates ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom; RECT rc = cmi.lpnm->rc; wndFrom.MapWindowPoints(NULL, &rc); // eat next message if click is on the same button MSG msg = { 0 }; if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt)) ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE); } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) }; template class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > { public: HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) { ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); if(rect.m_lpRect == NULL) rect.m_lpRect = &TBase::rcDefault; return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); } HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { const int cchName = 256; TCHAR szWindowName[cchName] = { 0 }; #ifndef _WIN32_WCE ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); #else // CE specific ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); // This always needs to be NULL for Windows CE. // Frame Window menus have to go onto the CommandBar. // Use CreateSimpleCECommandBar HMENU hMenu = NULL; #endif // _WIN32_WCE T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; #ifndef _WIN32_WCE ATLASSERT(!::IsWindow(m_hWndToolBar)); m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); #else // CE specific HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); return (hWnd != NULL); #endif // _WIN32_WCE } #ifdef _WIN32_WCE // CE specific variant that returns the handle of the toolbar HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID); } #endif // _WIN32_WCE // message map and handlers typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass; BEGIN_MSG_MAP(CFrameWindowImpl) MESSAGE_HANDLER(WM_SIZE, OnSize) #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #endif // !_ATL_NO_REBAR_SUPPORT CHAIN_MSG_MAP(_baseClass) END_MSG_MAP() LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam != SIZE_MINIMIZED) { T* pT = static_cast(this); pT->UpdateLayout(); } bHandled = FALSE; return 1; } #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->UpdateLayout(FALSE); return 0; } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { T* pT = static_cast(this); _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; if(!pT->PrepareChevronMenu(cmi)) { bHandled = FALSE; return 1; } // display a popup menu with hidden items pT->DisplayChevronMenu(cmi); // cleanup pT->CleanupChevronMenu(cmi); return 0; } #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE) #endif // !_ATL_NO_REBAR_SUPPORT }; /////////////////////////////////////////////////////////////////////////////// // AtlCreateSimpleToolBar - helper for creating simple toolbars #ifndef _WIN32_WCE inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID); } #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CMDIWindow #ifndef _WIN32_WCE #ifndef _WTL_MDIWINDOWMENU_TEXT #define _WTL_MDIWINDOWMENU_TEXT _T("&Window") #endif class CMDIWindow : public ATL::CWindow { public: // Data members HWND m_hWndMDIClient; HMENU m_hMenu; // Constructors CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) { } CMDIWindow& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // Operations HWND MDIGetActive(BOOL* lpbMaximized = NULL) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); } void MDIActivate(HWND hWndChildToActivate) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToActivate)); ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); } void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild)); ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); } void MDIMaximize(HWND hWndChildToMaximize) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToMaximize)); ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); } void MDIRestore(HWND hWndChildToRestore) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToRestore)); ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0); } void MDIDestroy(HWND hWndChildToDestroy) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToDestroy)); ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); } BOOL MDICascade(UINT uFlags = 0) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); } BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); } void MDIIconArrange() { ATLASSERT(::IsWindow(m_hWndMDIClient)); ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); } HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); } HMENU MDIRefreshMenu() { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); } // Additional operations static HMENU GetStandardWindowMenu(HMENU hMenu) { int nCount = ::GetMenuItemCount(hMenu); if(nCount == -1) return NULL; int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); if(nLen == 0) return NULL; CTempBuffer buff; LPTSTR lpszText = buff.Allocate(nLen + 1); if(lpszText == NULL) return NULL; if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) return NULL; if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0) return NULL; return ::GetSubMenu(hMenu, nCount - 2); } void SetMDIFrameMenu() { HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); MDISetMenu(m_hMenu, hWindowMenu); MDIRefreshMenu(); ::DrawMenuBar(GetMDIFrame()); } HWND GetMDIFrame() const { return ::GetParent(m_hWndMDIClient); } }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CMDIFrameWindowImpl #ifndef _WIN32_WCE // MDI child command chaining macro (only for MDI frame windows) #define CHAIN_MDI_CHILD_COMMANDS() \ if(uMsg == WM_COMMAND) \ { \ HWND hWndChild = MDIGetActive(); \ if(hWndChild != NULL) \ ::SendMessage(hWndChild, uMsg, wParam, lParam); \ } template class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase { public: HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) { m_hMenu = hMenu; ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); if(rect.m_lpRect == NULL) rect.m_lpRect = &TBase::rcDefault; return CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam); } HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { const int cchName = 256; TCHAR szWindowName[cchName] = { 0 }; ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); } virtual WNDPROC GetWindowProc() { return MDIFrameWindowProc; } static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; // set a ptr to this message and save the old value #if (_ATL_VER >= 0x0700) ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; #else // !(_ATL_VER >= 0x0700) MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } }; const MSG* pOldMsg = pThis->m_pCurrentMsg; #endif // !(_ATL_VER >= 0x0700) pThis->m_pCurrentMsg = &msg; // pass to the message map to process LRESULT lRes = 0; BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); // restore saved value for the current message ATLASSERT(pThis->m_pCurrentMsg == &msg); pThis->m_pCurrentMsg = pOldMsg; // do the default processing if message was not handled if(!bRet) { if(uMsg != WM_NCDESTROY) { lRes = pThis->DefWindowProc(uMsg, wParam, lParam); } else { // unsubclass, if needed LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); lRes = pThis->DefWindowProc(uMsg, wParam, lParam); if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); #if (_ATL_VER >= 0x0700) // mark window as destryed pThis->m_dwState |= WINSTATE_DESTROYED; #else // !(_ATL_VER >= 0x0700) // clear out window handle HWND hWnd = pThis->m_hWnd; pThis->m_hWnd = NULL; // clean up after window is destroyed pThis->OnFinalMessage(hWnd); #endif // !(_ATL_VER >= 0x0700) } } #if (_ATL_VER >= 0x0700) if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL) { // clear out window handle HWND hWndThis = pThis->m_hWnd; pThis->m_hWnd = NULL; pThis->m_dwState &= ~WINSTATE_DESTROYED; // clean up after window is destroyed pThis->OnFinalMessage(hWndThis); } #endif // (_ATL_VER >= 0x0700) return lRes; } // Overriden to call DefWindowProc which uses DefFrameProc LRESULT DefWindowProc() { const MSG* pMsg = m_pCurrentMsg; LRESULT lRes = 0; if (pMsg != NULL) lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); return lRes; } LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam); } BOOL PreTranslateMessage(MSG* pMsg) { if(CFrameWindowImplBase::PreTranslateMessage(pMsg)) return TRUE; return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg); } HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) { DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; DWORD dwExStyle = WS_EX_CLIENTEDGE; CLIENTCREATESTRUCT ccs = { 0 }; ccs.hWindowMenu = hWindowMenu; ccs.idFirstChild = nFirstChildID; if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0) { // parent MDI frame's scroll styles move to the MDICLIENT dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL)); // fast way to turn off the scrollbar bits (without a resize) ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); } // Create MDICLIENT window m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), (LPVOID)&ccs); if (m_hWndClient == NULL) { ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n")); return NULL; } // Move it to the top of z-order ::BringWindowToTop(m_hWndClient); // set as MDI client window m_hWndMDIClient = m_hWndClient; // update to proper size T* pT = static_cast(this); pT->UpdateLayout(); return m_hWndClient; } typedef CFrameWindowImplBase _baseClass; BEGIN_MSG_MAP(CMDIFrameWindowImpl) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) #endif // (_WIN32_IE >= 0x0500) #endif // !_ATL_NO_REBAR_SUPPORT CHAIN_MSG_MAP(_baseClass) END_MSG_MAP() LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(wParam != SIZE_MINIMIZED) { T* pT = static_cast(this); pT->UpdateLayout(); } // message must be handled, otherwise DefFrameProc would resize the client again return 0; } LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { // don't allow CFrameWindowImplBase to handle this one return DefWindowProc(uMsg, wParam, lParam); } LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { SetMDIFrameMenu(); return 0; } #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->UpdateLayout(FALSE); return 0; } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { T* pT = static_cast(this); _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; if(!pT->PrepareChevronMenu(cmi)) { bHandled = FALSE; return 1; } // display a popup menu with hidden items pT->DisplayChevronMenu(cmi); // cleanup pT->CleanupChevronMenu(cmi); return 0; } #endif // (_WIN32_IE >= 0x0500) #endif // !_ATL_NO_REBAR_SUPPORT }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CMDIChildWindowImpl #ifndef _WIN32_WCE template class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase { public: HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nMenuID = 0, LPVOID lpCreateParam = NULL) { ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); if(nMenuID != 0) m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); dwExStyle |= WS_EX_MDICHILD; // force this one m_pfnSuperWindowProc = ::DefMDIChildProc; m_hWndMDIClient = hWndParent; ATLASSERT(::IsWindow(m_hWndMDIClient)); if(rect.m_lpRect == NULL) rect.m_lpRect = &TBase::rcDefault; // If the currently active MDI child is maximized, we want to create this one maximized too ATL::CWindow wndParent = hWndParent; BOOL bMaximized = FALSE; wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized); if(bMaximized) wndParent.SetRedraw(FALSE); HWND hWnd = CFrameWindowImplBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam); if(bMaximized) { // Maximize and redraw everything if(hWnd != NULL) MDIMaximize(hWnd); wndParent.SetRedraw(TRUE); wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); ::SetFocus(GetMDIFrame()); // focus will be set back to this window } else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus())) { ::SetFocus(hWnd); } return hWnd; } HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { const int cchName = 256; TCHAR szWindowName[cchName] = { 0 }; if(lpcstrWindowName == NULL) { ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName); lpcstrWindowName = szWindowName; } T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); } BOOL UpdateClientEdge(LPRECT lpRect = NULL) { // only adjust for active MDI child window HWND hWndChild = MDIGetActive(); if(hWndChild != NULL && hWndChild != m_hWnd) return FALSE; // need to adjust the client edge style as max/restore happens DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE); DWORD dwNewStyle = dwStyle; if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0)) dwNewStyle &= ~(WS_EX_CLIENTEDGE); else dwNewStyle |= WS_EX_CLIENTEDGE; if(dwStyle != dwNewStyle) { // SetWindowPos will not move invalid bits ::RedrawWindow(m_hWndMDIClient, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); // remove/add WS_EX_CLIENTEDGE to MDI client area ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS); // return new client area if (lpRect != NULL) ::GetClientRect(m_hWndMDIClient, lpRect); return TRUE; } return FALSE; } typedef CFrameWindowImplBase _baseClass; BEGIN_MSG_MAP(CMDIChildWindowImpl) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged) MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize) #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed) #endif // (_WIN32_IE >= 0x0500) #endif // !_ATL_NO_REBAR_SUPPORT CHAIN_MSG_MAP(_baseClass) END_MSG_MAP() LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { DefWindowProc(uMsg, wParam, lParam); // needed for MDI children if(wParam != SIZE_MINIMIZED) { T* pT = static_cast(this); pT->UpdateLayout(); } return 0; } LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { // update MDI client edge and adjust MDI child rect LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; if(!(lpWndPos->flags & SWP_NOSIZE)) { RECT rectClient = { 0 }; if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0)) { ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle()); lpWndPos->x = rectClient.left; lpWndPos->y = rectClient.top; lpWndPos->cx = rectClient.right - rectClient.left; lpWndPos->cy = rectClient.bottom - rectClient.top; } } bHandled = FALSE; return 1; } LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { LRESULT lRes = DefWindowProc(uMsg, wParam, lParam); // Activate this MDI window if needed if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT) { if(MDIGetActive() != m_hWnd) MDIActivate(m_hWnd); } return lRes; } LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam); } LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if((HWND)lParam == m_hWnd && m_hMenu != NULL) SetMDIFrameMenu(); else if((HWND)lParam == NULL) ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_hMenu != NULL) { ::DestroyMenu(m_hMenu); m_hMenu = NULL; } UpdateClientEdge(); bHandled = FALSE; return 1; } #ifndef _ATL_NO_REBAR_SUPPORT #if (_WIN32_IE >= 0x0400) LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->UpdateLayout(FALSE); return 0; } #endif // (_WIN32_IE >= 0x0400) #if (_WIN32_IE >= 0x0500) LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { T* pT = static_cast(this); _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false }; if(!pT->PrepareChevronMenu(cmi)) { bHandled = FALSE; return 1; } // display a popup menu with hidden items pT->DisplayChevronMenu(cmi); // cleanup pT->CleanupChevronMenu(cmi); return 0; } #endif // (_WIN32_IE >= 0x0500) #endif // !_ATL_NO_REBAR_SUPPORT }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // COwnerDraw - MI class for owner-draw support template class COwnerDraw { public: #if (_ATL_VER < 0x0700) BOOL m_bHandledOD; BOOL IsMsgHandled() const { return m_bHandledOD; } void SetMsgHandled(BOOL bHandled) { m_bHandledOD = bHandled; } #endif // (_ATL_VER < 0x0700) // Message map and handlers BEGIN_MSG_MAP(COwnerDraw< T >) MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) ALT_MSG_MAP(1) MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) END_MSG_MAP() LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->SetMsgHandled(TRUE); pT->DrawItem((LPDRAWITEMSTRUCT)lParam); bHandled = pT->IsMsgHandled(); return (LRESULT)TRUE; } LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->SetMsgHandled(TRUE); pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); bHandled = pT->IsMsgHandled(); return (LRESULT)TRUE; } LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->SetMsgHandled(TRUE); bHandled = pT->IsMsgHandled(); return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); } LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->SetMsgHandled(TRUE); pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); bHandled = pT->IsMsgHandled(); return (LRESULT)TRUE; } // Overrideables void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/) { // must be implemented ATLASSERT(FALSE); } void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(lpMeasureItemStruct->CtlType != ODT_MENU) { // return default height for a system font T* pT = static_cast(this); HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); CClientDC dc(hWnd); TEXTMETRIC tm = { 0 }; dc.GetTextMetrics(&tm); lpMeasureItemStruct->itemHeight = tm.tmHeight; } else lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); } int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/) { // all items are equal return 0; } void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/) { // default - nothing } }; /////////////////////////////////////////////////////////////////////////////// // Update UI macros // these build the Update UI map inside a class definition #define BEGIN_UPDATE_UI_MAP(thisClass) \ static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \ { \ static const _AtlUpdateUIMap theMap[] = \ { #define UPDATE_ELEMENT(nID, wType) \ { nID, wType }, #define END_UPDATE_UI_MAP() \ { (WORD)-1, 0 } \ }; \ return theMap; \ } /////////////////////////////////////////////////////////////////////////////// // CUpdateUI - manages UI elements updating class CUpdateUIBase { public: // constants enum { // UI element type UPDUI_MENUPOPUP = 0x0001, UPDUI_MENUBAR = 0x0002, UPDUI_CHILDWINDOW = 0x0004, UPDUI_TOOLBAR = 0x0008, UPDUI_STATUSBAR = 0x0010, // state UPDUI_ENABLED = 0x0000, UPDUI_DISABLED = 0x0100, UPDUI_CHECKED = 0x0200, UPDUI_CHECKED2 = 0x0400, UPDUI_RADIO = 0x0800, UPDUI_DEFAULT = 0x1000, UPDUI_TEXT = 0x2000, // internal state UPDUI_CLEARDEFAULT = 0x4000, }; // element data struct _AtlUpdateUIElement { HWND m_hWnd; WORD m_wType; bool operator ==(const _AtlUpdateUIElement& e) const { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); } }; // map data struct _AtlUpdateUIMap { WORD m_nID; WORD m_wType; bool operator ==(const _AtlUpdateUIMap& e) const { return (m_nID == e.m_nID && m_wType == e.m_wType); } }; // instance data #pragma warning(push) #pragma warning(disable: 4201) // nameless unions are part of C++ struct _AtlUpdateUIData { WORD m_wState; union { void* m_lpData; LPTSTR m_lpstrText; struct { WORD m_nIDFirst; WORD m_nIDLast; }; }; bool operator ==(const _AtlUpdateUIData& e) const { return (m_wState == e.m_wState && m_lpData == e.m_lpData); } }; #pragma warning(pop) ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data const _AtlUpdateUIMap* m_pUIMap; // static UI data _AtlUpdateUIData* m_pUIData; // instance UI data WORD m_wDirtyType; // global dirty flag bool m_bBlockAccelerators; // Constructor, destructor CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false) { } ~CUpdateUIBase() { if(m_pUIMap != NULL && m_pUIData != NULL) { const _AtlUpdateUIMap* pUIMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; while(pUIMap->m_nID != (WORD)-1) { if(pUIData->m_wState & UPDUI_TEXT) delete [] pUIData->m_lpstrText; pUIMap++; pUIData++; } delete [] m_pUIData; } } // Check for disabled commands bool UIGetBlockAccelerators() const { return m_bBlockAccelerators; } bool UISetBlockAccelerators(bool bBlock) { bool bOld = m_bBlockAccelerators; m_bBlockAccelerators = bBlock; return bOld; } // Add elements BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu) { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_MENUBAR; return m_UIElements.Add(e); } BOOL UIAddToolBar(HWND hWnd) // toolbar { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_TOOLBAR; return m_UIElements.Add(e); } BOOL UIAddStatusBar(HWND hWnd) // status bar { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_STATUSBAR; return m_UIElements.Add(e); } BOOL UIAddChildWindowContainer(HWND hWnd) // child window { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_CHILDWINDOW; return m_UIElements.Add(e); } // Message map for popup menu updates and accelerator blocking BEGIN_MSG_MAP(CUpdateUIBase) MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) MESSAGE_HANDLER(WM_COMMAND, OnCommand) END_MSG_MAP() LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; HMENU hMenu = (HMENU)wParam; if(hMenu == NULL) return 1; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return 1; const _AtlUpdateUIMap* pMap = m_pUIMap; while(pMap->m_nID != (WORD)-1) { if(pMap->m_wType & UPDUI_MENUPOPUP) { UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); if((pUIData->m_wState & UPDUI_RADIO) != 0) ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND); } pMap++; pUIData++; } return 0; } LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only { int nID = LOWORD(wParam); if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED) { ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID); bHandled = TRUE; // eat the command, UI item is disabled } } return 0; } // methods for setting UI element state BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { if(bEnable) { if(pUIData->m_wState & UPDUI_DISABLED) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~UPDUI_DISABLED; } } else { if(!(pUIData->m_wState & UPDUI_DISABLED)) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState |= UPDUI_DISABLED; } } if(bForceUpdate) pUIData->m_wState |= pMap->m_wType; if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { switch(nCheck) { case 0: if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2)) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); } break; case 1: if(!(pUIData->m_wState & UPDUI_CHECKED)) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~UPDUI_CHECKED2; pUIData->m_wState |= UPDUI_CHECKED; } break; case 2: if(!(pUIData->m_wState & UPDUI_CHECKED2)) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~UPDUI_CHECKED; pUIData->m_wState |= UPDUI_CHECKED2; } break; } if(bForceUpdate) pUIData->m_wState |= pMap->m_wType; if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } // variant that supports bool (checked/not-checked, no intermediate state) BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) { return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate); } BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { if(bRadio) { if(!(pUIData->m_wState & UPDUI_RADIO)) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState |= UPDUI_RADIO; } } else { if(pUIData->m_wState & UPDUI_RADIO) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~UPDUI_RADIO; } } if(bForceUpdate) pUIData->m_wState |= pMap->m_wType; if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } // for menu items BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState |= UPDUI_RADIO; pUIData->m_nIDFirst = (WORD)nIDFirst; pUIData->m_nIDLast = (WORD)nIDLast; if(bForceUpdate) pUIData->m_wState |= pMap->m_wType; if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; } else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast) { if(pUIData->m_wState & UPDUI_RADIO) { pUIData->m_wState &= ~pMap->m_wType; pUIData->m_wState &= ~UPDUI_RADIO; pUIData->m_nIDFirst = 0; pUIData->m_nIDLast = 0; } } if(pMap->m_nID == nIDLast) break; } return TRUE; } BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; if(lpstrText == NULL) lpstrText = _T(""); for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText)) { delete [] pUIData->m_lpstrText; pUIData->m_lpstrText = NULL; int nStrLen = lstrlen(lpstrText); ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]); if(pUIData->m_lpstrText == NULL) { ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n")); break; } SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText); pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); } if(bForceUpdate) pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType); if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { if(bDefault) { if((pUIData->m_wState & UPDUI_DEFAULT) == 0) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState |= UPDUI_DEFAULT; } } else { if((pUIData->m_wState & UPDUI_DEFAULT) != 0) { pUIData->m_wState |= pMap->m_wType; pUIData->m_wState &= ~UPDUI_DEFAULT; pUIData->m_wState |= UPDUI_CLEARDEFAULT; } } if(bForceUpdate) pUIData->m_wState |= pMap->m_wType; if(pUIData->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } // methods for complete state set/get BOOL UISetState(int nID, DWORD dwState) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) { pUIData->m_wState = (WORD)(dwState | pMap->m_wType); m_wDirtyType |= pMap->m_wType; break; // found } } return TRUE; } DWORD UIGetState(int nID) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return 0; for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++) { if(nID == (int)pMap->m_nID) return pUIData->m_wState; } return 0; } // methods for updating UI #ifndef _WIN32_WCE BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE) { if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; while(pMap->m_nID != (WORD)-1) { for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_MENUBAR) { HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd); if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu); } if(bMainMenu) ::DrawMenuBar(m_UIElements[i].m_hWnd); } pMap++; pUIData->m_wState &= ~UPDUI_MENUBAR; if(pUIData->m_wState & UPDUI_TEXT) { delete [] pUIData->m_lpstrText; pUIData->m_lpstrText = NULL; pUIData->m_wState &= ~UPDUI_TEXT; } pUIData++; } m_wDirtyType &= ~UPDUI_MENUBAR; return TRUE; } #endif // !_WIN32_WCE BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; while(pMap->m_nID != (WORD)-1) { for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) { if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); } } pMap++; pUIData->m_wState &= ~UPDUI_TOOLBAR; pUIData++; } m_wDirtyType &= ~UPDUI_TOOLBAR; return TRUE; } BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; while(pMap->m_nID != (WORD)-1) { for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) { if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); } } pMap++; pUIData->m_wState &= ~UPDUI_STATUSBAR; if(pUIData->m_wState & UPDUI_TEXT) { delete [] pUIData->m_lpstrText; pUIData->m_lpstrText = NULL; pUIData->m_wState &= ~UPDUI_TEXT; } pUIData++; } m_wDirtyType &= ~UPDUI_STATUSBAR; return TRUE; } BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; while(pMap->m_nID != (WORD)-1) { for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW) { if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW)) UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); } } pMap++; pUIData->m_wState &= ~UPDUI_CHILDWINDOW; if(pUIData->m_wState & UPDUI_TEXT) { delete [] pUIData->m_lpstrText; pUIData->m_lpstrText = NULL; pUIData->m_wState &= ~UPDUI_TEXT; } pUIData++; } m_wDirtyType &= ~UPDUI_CHILDWINDOW; return TRUE; } // internal element specific methods static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu) { #ifndef _WIN32_WCE if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0) { ::SetMenuDefaultItem(hMenu, (UINT)-1, 0); pUIData->m_wState &= ~UPDUI_CLEARDEFAULT; } #endif // !_WIN32_WCE CMenuItemInfo mii; mii.fMask = MIIM_STATE; mii.wID = nID; #ifndef _WIN32_WCE if((pUIData->m_wState & UPDUI_DISABLED) != 0) mii.fState |= MFS_DISABLED | MFS_GRAYED; else mii.fState |= MFS_ENABLED; if((pUIData->m_wState & UPDUI_CHECKED) != 0) mii.fState |= MFS_CHECKED; else mii.fState |= MFS_UNCHECKED; if((pUIData->m_wState & UPDUI_DEFAULT) != 0) mii.fState |= MFS_DEFAULT; #else // CE specific // ::SetMenuItemInfo() can't disable or check menu items // on Windows CE, so we have to do that directly UINT uEnable = MF_BYCOMMAND; if((pUIData->m_wState & UPDUI_DISABLED) != 0) uEnable |= MF_GRAYED; else uEnable |= MF_ENABLED; ::EnableMenuItem(hMenu, nID, uEnable); UINT uCheck = MF_BYCOMMAND; if((pUIData->m_wState & UPDUI_CHECKED) != 0) uCheck |= MF_CHECKED; else uCheck |= MF_UNCHECKED; ::CheckMenuItem(hMenu, nID, uCheck); #endif // _WIN32_WCE if((pUIData->m_wState & UPDUI_TEXT) != 0) { CMenuItemInfo miiNow; miiNow.fMask = MIIM_TYPE; miiNow.wID = nID; if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow)) { mii.fMask |= MIIM_TYPE; // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING #ifndef _WIN32_WCE mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING; #else // CE specific mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING; #endif // _WIN32_WCE mii.dwTypeData = pUIData->m_lpstrText; } } ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); } static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) { // Note: only handles enabled/disabled, checked state, and radio (press) ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); } static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) { // Note: only handles text if(pUIData->m_wState & UPDUI_TEXT) ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText); } static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) { HWND hChild = ::GetDlgItem(hWnd, nID); ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); // for check and radio, assume that window is a button int nCheck = BST_UNCHECKED; if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO) nCheck = BST_CHECKED; else if(pUIData->m_wState & UPDUI_CHECKED2) nCheck = BST_INDETERMINATE; ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); if(pUIData->m_wState & UPDUI_DEFAULT) { DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L); if(HIWORD(dwRet) == DC_HASDEFID) { HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet)); // remove BS_DEFPUSHBUTTON ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); } ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); } if(pUIData->m_wState & UPDUI_TEXT) ::SetWindowText(hChild, pUIData->m_lpstrText); } }; template class CUpdateUI : public CUpdateUIBase { public: CUpdateUI() { T* pT = static_cast(this); pT; const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); m_pUIMap = pMap; ATLASSERT(m_pUIMap != NULL); int nCount = 1; for( ; pMap->m_nID != (WORD)-1; nCount++) pMap++; // check for duplicates (debug only) #ifdef _DEBUG for(int i = 0; i < nCount; i++) { for(int j = 0; j < nCount; j++) { // shouldn't have duplicates in the update UI map if(i != j) ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID); } } #endif // _DEBUG ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); ATLASSERT(m_pUIData != NULL); if(m_pUIData != NULL) memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); } }; /////////////////////////////////////////////////////////////////////////////// // CDynamicUpdateUI - allows update elements to dynamically added and removed // in addition to a static update UI map template class CDynamicUpdateUI : public CUpdateUIBase { public: // Data members ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data // Constructor/destructor CDynamicUpdateUI() { T* pT = static_cast(this); pT; const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); ATLASSERT(pMap != NULL); for(;;) { BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap); ATLASSERT(bRet); if(bRet != FALSE) { _AtlUpdateUIData data = { 0, NULL }; bRet = m_arrUIData.Add(data); ATLASSERT(bRet); } if(pMap->m_nID == (WORD)-1) break; pMap++; } ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize()); #ifdef _DEBUG // check for duplicates (debug only) for(int i = 0; i < m_arrUIMap.GetSize(); i++) { for(int j = 0; j < m_arrUIMap.GetSize(); j++) { // shouldn't have duplicates in the update UI map if(i != j) ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID); } } #endif // _DEBUG // Set internal data pointers to point to the new data arrays m_pUIMap = m_arrUIMap.m_aT; m_pUIData = m_arrUIData.m_aT; } ~CDynamicUpdateUI() { for(int i = 0; i < m_arrUIData.GetSize(); i++) { if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) delete [] m_arrUIData[i].m_lpstrText; } // Reset internal data pointers (memory will be released by CSimpleArray d-tor) m_pUIMap = NULL; m_pUIData = NULL; } // Methods for dynamically adding and removing update elements bool UIAddUpdateElement(WORD nID, WORD wType) { // check for duplicates for(int i = 0; i < m_arrUIMap.GetSize(); i++) { // shouldn't have duplicates in the update UI map ATLASSERT(m_arrUIMap[i].m_nID != nID); if(m_arrUIMap[i].m_nID == nID) return false; } bool bRetVal = false; // Add new end element _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 }; BOOL bRet = m_arrUIMap.Add(uumEnd); ATLASSERT(bRet); if(bRet != FALSE) { _AtlUpdateUIData uud = { 0, NULL }; bRet = m_arrUIData.Add(uud); ATLASSERT(bRet); // Set new data to the previous end element if(bRet != FALSE) { int nSize = m_arrUIMap.GetSize(); _AtlUpdateUIMap uum = { nID, wType }; m_arrUIMap.SetAtIndex(nSize - 2, uum); m_arrUIData.SetAtIndex(nSize - 2, uud); // Set internal data pointers again, just in case that memory moved m_pUIMap = m_arrUIMap.m_aT; m_pUIData = m_arrUIData.m_aT; bRetVal = true; } } return bRetVal; } bool UIRemoveUpdateElement(WORD nID) { bool bRetVal = false; for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) { if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0) delete [] m_arrUIData[i].m_lpstrText; BOOL bRet = m_arrUIMap.RemoveAt(i); ATLASSERT(bRet); bRet = m_arrUIData.RemoveAt(i); ATLASSERT(bRet); bRetVal = true; break; } } return bRetVal; } }; /////////////////////////////////////////////////////////////////////////////// // CAutoUpdateUI : Automatic mapping of UI elements template class CAutoUpdateUI : public CDynamicUpdateUI { public: LPCTSTR UIGetText(int nID) { for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) return m_arrUIData[i].m_lpstrText; } return NULL; } // Element template bool UIAddElement(UINT nID) { // check for existing UI map element for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) { // set requested type m_arrUIMap[i].m_wType |= t_wType; return true; } } // Add element to UI map with requested type return UIAddUpdateElement((WORD)nID, t_wType); } template bool UIRemoveElement(UINT nID) { for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) // matching UI map element { WORD wType = m_arrUIMap[i].m_wType & ~t_wType; if (wType != 0) // has other types { m_arrUIMap[i].m_wType = wType; // keep other types return true; } else { return UIRemoveUpdateElement((WORD)nID); } } } return false; } // Menu bool UIAddMenu(HMENU hMenu, bool bSetText = false) { #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) using ATL::GetMenuString; #endif ATLASSERT(::IsMenu(hMenu)); MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU}; // Complete the UI map for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++) { if(mii.hSubMenu) { // Add submenu to UI map UIAddMenu(mii.hSubMenu, bSetText); } else if (mii.wID != 0) { // Add element to UI map UIAddElement(mii.wID); #if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) if (bSetText) { TCHAR sText[64] = { 0 }; if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION)) UISetText(mii.wID, sText); } #else bSetText; #endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) } } return true; } bool UIAddMenu(UINT uID, bool bSetText = false) { CMenu menu; ATLVERIFY(menu.LoadMenu(uID)); return UIAddMenu(menu, bSetText); } // ToolBar #if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) bool UIAddToolBar(HWND hWndToolBar) { ATLASSERT(::IsWindow(hWndToolBar)); TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX }; // Add toolbar buttons for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++) { if (tbbi.fsStyle ^ BTNS_SEP) UIAddElement(tbbi.idCommand); } // Add embedded controls if any if (::GetWindow(hWndToolBar, GW_CHILD)) UIAddChildWindowContainer(hWndToolBar); return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE); } #endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX)) // Container bool UIAddChildWindowContainer(HWND hWnd) { ATLASSERT(::IsWindow(hWnd)); // Add children controls if any for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT)) { int id = wCtl.GetDlgCtrlID(); if(id != 0) UIAddElement(id); } return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE); } // StatusBar BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) return TRUE; for(int i = 0; i < m_arrUIMap.GetSize(); i++) { for(int e = 0; e < m_UIElements.GetSize(); e++) { if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) && (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) && (m_arrUIData[i].m_wState & UPDUI_STATUSBAR)) { UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd); m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR; if(m_arrUIData[i].m_wState & UPDUI_TEXT) m_arrUIData[i].m_wState &= ~UPDUI_TEXT; } } } m_wDirtyType &= ~UPDUI_STATUSBAR; return TRUE; } bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1) { ATLASSERT(::IsWindow(hWndStatusBar)); // Add StatusBar panes for (int iPane = 0; iPane < nPanes; iPane++) UIAddElement(ID_DEFAULT_PANE + iPane); return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE); } // UI Map used if derived class has none BEGIN_UPDATE_UI_MAP(CAutoUpdateUI) END_UPDATE_UI_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CDialogResize - provides support for resizing dialog controls // (works for any window that has child controls) // Put CDialogResize in the list of base classes for a dialog (or even plain window), // then implement DLGRESIZE map by specifying controls and groups of control // and using DLSZ_* values to specify how are they supposed to be resized. // // Notes: // - Resizeable border (WS_THICKFRAME style) should be set in the dialog template // for top level dialogs (popup or overlapped), so that users can resize the dialog. // - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X, // DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined. // - Order of controls is important - group controls are resized and moved based // on the position of the previous control in a group. // dialog resize map macros #define BEGIN_DLGRESIZE_MAP(thisClass) \ static const _AtlDlgResizeMap* GetDlgResizeMap() \ { \ static const _AtlDlgResizeMap theMap[] = \ { #define END_DLGRESIZE_MAP() \ { -1, 0 }, \ }; \ return theMap; \ } #define DLGRESIZE_CONTROL(id, flags) \ { id, flags }, #define BEGIN_DLGRESIZE_GROUP() \ { -1, _DLSZ_BEGIN_GROUP }, #define END_DLGRESIZE_GROUP() \ { -1, _DLSZ_END_GROUP }, template class CDialogResize { public: // Data declarations and members enum { DLSZ_SIZE_X = 0x00000001, DLSZ_SIZE_Y = 0x00000002, DLSZ_MOVE_X = 0x00000004, DLSZ_MOVE_Y = 0x00000008, DLSZ_REPAINT = 0x00000010, DLSZ_CENTER_X = 0x00000020, DLSZ_CENTER_Y = 0x00000040, // internal use only _DLSZ_BEGIN_GROUP = 0x00001000, _DLSZ_END_GROUP = 0x00002000, _DLSZ_GRIPPER = 0x00004000 }; struct _AtlDlgResizeMap { int m_nCtlID; DWORD m_dwResizeFlags; }; struct _AtlDlgResizeData { int m_nCtlID; DWORD m_dwResizeFlags; RECT m_rect; int GetGroupCount() const { return (int)LOBYTE(HIWORD(m_dwResizeFlags)); } void SetGroupCount(int nCount) { ATLASSERT(nCount > 0 && nCount < 256); DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0)); m_dwResizeFlags &= 0xFF00FFFF; m_dwResizeFlags |= dwCount; } bool operator ==(const _AtlDlgResizeData& r) const { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); } }; ATL::CSimpleArray<_AtlDlgResizeData> m_arrData; SIZE m_sizeDialog; POINT m_ptMinTrackSize; bool m_bGripper; // Constructor CDialogResize() : m_bGripper(false) { m_sizeDialog.cx = 0; m_sizeDialog.cy = 0; m_ptMinTrackSize.x = -1; m_ptMinTrackSize.y = -1; } // Operations void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); DWORD dwStyle = pT->GetStyle(); #ifdef _DEBUG // Debug only: Check if top level dialogs have a resizeable border. if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0)) ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n")); #endif // _DEBUG // Force specified styles (default WS_CLIPCHILDREN reduces flicker) if((dwStyle & dwForceStyle) != dwForceStyle) pT->ModifyStyle(0, dwForceStyle); #ifndef _WIN32_WCE // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have. // Setting icon to NULL is required when XP themes are active. // Note: This will not prevent adding an icon for the dialog using SetIcon() if((dwStyle & WS_CHILD) == 0) { pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME); if(pT->GetIcon(FALSE) == NULL) pT->SetIcon(NULL, FALSE); } #endif // Cleanup in case of multiple initialization // block: first check for the gripper control, destroy it if needed { ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0) wndGripper.DestroyWindow(); } // clear out everything else m_arrData.RemoveAll(); m_sizeDialog.cx = 0; m_sizeDialog.cy = 0; m_ptMinTrackSize.x = -1; m_ptMinTrackSize.y = -1; // Get initial dialog client size RECT rectDlg = { 0 }; pT->GetClientRect(&rectDlg); m_sizeDialog.cx = rectDlg.right; m_sizeDialog.cy = rectDlg.bottom; #ifndef _WIN32_WCE // Create gripper if requested m_bGripper = false; if(bAddGripper) { // shouldn't exist already ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))); if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR))) { ATL::CWindow wndGripper; wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR); ATLASSERT(wndGripper.IsWindow()); if(wndGripper.IsWindow()) { m_bGripper = true; RECT rectCtl = { 0 }; wndGripper.GetWindowRect(&rectCtl); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; m_arrData.Add(data); } } } #else // CE specific bAddGripper; // avoid level 4 warning #endif // _WIN32_WCE // Get min track position if requested if(bUseMinTrackSize) { if((dwStyle & WS_CHILD) != 0) { RECT rect = { 0 }; pT->GetClientRect(&rect); m_ptMinTrackSize.x = rect.right - rect.left; m_ptMinTrackSize.y = rect.bottom - rect.top; } else { RECT rect = { 0 }; pT->GetWindowRect(&rect); m_ptMinTrackSize.x = rect.right - rect.left; m_ptMinTrackSize.y = rect.bottom - rect.top; } } // Walk the map and initialize data const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap(); ATLASSERT(pMap != NULL); int nGroupStart = -1; for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++) { if(pMap->m_nCtlID == -1) { switch(pMap->m_dwResizeFlags) { case _DLSZ_BEGIN_GROUP: ATLASSERT(nGroupStart == -1); nGroupStart = m_arrData.GetSize(); break; case _DLSZ_END_GROUP: { ATLASSERT(nGroupStart != -1); int nGroupCount = m_arrData.GetSize() - nGroupStart; m_arrData[nGroupStart].SetGroupCount(nGroupCount); nGroupStart = -1; } break; default: ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry")); break; } } else { // this ID conflicts with the default gripper one ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE); ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID); ATLASSERT(ctl.IsWindow()); RECT rectCtl = { 0 }; ctl.GetWindowRect(&rectCtl); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0; _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } }; m_arrData.Add(data); } } ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map")); } void DlgResize_UpdateLayout(int cxWidth, int cyHeight) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); // Restrict minimum size if requested if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) { if(cxWidth < m_ptMinTrackSize.x) cxWidth = m_ptMinTrackSize.x; if(cyHeight < m_ptMinTrackSize.y) cyHeight = m_ptMinTrackSize.y; } BOOL bVisible = pT->IsWindowVisible(); if(bVisible) pT->SetRedraw(FALSE); for(int i = 0; i < m_arrData.GetSize(); i++) { if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group { int nGroupCount = m_arrData[i].GetGroupCount(); ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize()); RECT rectGroup = m_arrData[i].m_rect; int j = 1; for(j = 1; j < nGroupCount; j++) { rectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left); rectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top); rectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right); rectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom); } for(j = 0; j < nGroupCount; j++) { _AtlDlgResizeData* pDataPrev = NULL; if(j > 0) pDataPrev = &(m_arrData[i + j - 1]); pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev); } i += nGroupCount - 1; // increment to skip all group controls } else // one control entry { RECT rectGroup = { 0 }; pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false); } } if(bVisible) pT->SetRedraw(TRUE); pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } // Message map and handlers BEGIN_MSG_MAP(CDialogResize) MESSAGE_HANDLER(WM_SIZE, OnSize) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) #endif // _WIN32_WCE END_MSG_MAP() LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); #ifndef _WIN32_WCE if(m_bGripper) { ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR); if(wParam == SIZE_MAXIMIZED) wndGripper.ShowWindow(SW_HIDE); else if(wParam == SIZE_RESTORED) wndGripper.ShowWindow(SW_SHOW); } #endif // _WIN32_WCE if(wParam != SIZE_MINIMIZED) { ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } return 0; } #ifndef _WIN32_WCE LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1) { LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam; lpMMI->ptMinTrackSize = m_ptMinTrackSize; } return 0; } #endif // _WIN32_WCE // Implementation bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, _AtlDlgResizeData* pDataPrev = NULL) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); ATL::CWindow ctl; RECT rectCtl = { 0 }; ctl = pT->GetDlgItem(data.m_nCtlID); if(!ctl.GetWindowRect(&rectCtl)) return false; ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2); if(bGroup) { if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) { int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx; int cxCtl = data.m_rect.right - data.m_rect.left; rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2; rectCtl.right = rectCtl.left + cxCtl; } else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) { rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0) { rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left); if(pDataPrev != NULL) { ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); RECT rcPrev = { 0 }; ctlPrev.GetWindowRect(&rcPrev); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right); rcPrev.right += dxAdjust; ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); } } else { rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left); } } if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) { int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy; int cyCtl = data.m_rect.bottom - data.m_rect.top; rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2; rectCtl.bottom = rectCtl.top + cyCtl; } else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) { rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0) { rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top); if(pDataPrev != NULL) { ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID); RECT rcPrev = { 0 }; ctlPrev.GetWindowRect(&rcPrev); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2); int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom); rcPrev.bottom += dxAdjust; ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE); } } else { rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top); } } } else // no group { if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0) { int cxCtl = data.m_rect.right - data.m_rect.left; rectCtl.left = (cxWidth - cxCtl) / 2; rectCtl.right = rectCtl.left + cxCtl; } else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0) { rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx); if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0) rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left); } if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0) { int cyCtl = data.m_rect.bottom - data.m_rect.top; rectCtl.top = (cyHeight - cyCtl) / 2; rectCtl.bottom = rectCtl.top + cyCtl; } else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0) { rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy); if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0) rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top); } } if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0) ctl.Invalidate(); if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0) ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE); return true; } }; /////////////////////////////////////////////////////////////////////////////// // CDoubleBufferImpl - Provides double-buffer painting support to any window template class CDoubleBufferImpl { public: // Overrideables void DoPaint(CDCHandle /*dc*/) { // must be implemented in a derived class ATLASSERT(FALSE); } // Message map and handlers BEGIN_MSG_MAP(CDoubleBufferImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) #endif // !_WIN32_WCE END_MSG_MAP() LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background painting needed } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); if(wParam != NULL) { RECT rect = { 0 }; pT->GetClientRect(&rect); CMemoryDC dcMem((HDC)wParam, rect); pT->DoPaint(dcMem.m_hDC); } else { CPaintDC dc(pT->m_hWnd); CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint); pT->DoPaint(dcMem.m_hDC); } return 0; } }; /////////////////////////////////////////////////////////////////////////////// // CDoubleBufferWindowImpl - Implements a double-buffer painting window template class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T > { public: BEGIN_MSG_MAP(CDoubleBufferWindowImpl) CHAIN_MSG_MAP(CDoubleBufferImpl< T >) END_MSG_MAP() }; // command bar support #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) #undef CBRM_GETMENU #undef CBRM_TRACKPOPUPMENU #undef CBRM_GETCMDBAR #undef CBRPOPUPMENU #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE) }; // namespace WTL #endif // __ATLFRAME_H__ ================================================ FILE: WTL/atlgdi.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLGDI_H__ #define __ATLGDI_H__ #pragma once #ifndef __ATLAPP_H__ #error atlgdi.h requires atlapp.h to be included first #endif // protect template members from windowsx.h macros #ifdef _INC_WINDOWSX #undef CopyRgn #undef CreateBrush #undef CreatePen #undef SelectBrush #undef SelectPen #undef SelectFont #undef SelectBitmap #endif // _INC_WINDOWSX // required libraries #if !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE) #pragma comment(lib, "msimg32.lib") #endif #if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) #pragma comment(lib, "opengl32.lib") #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CPenT // CBrushT // CLogFont // CFontT // CBitmapT // CPaletteT // CRgnT // CDCT // CPaintDC // CClientDC // CWindowDC // CMemoryDC // CEnhMetaFileInfo // CEnhMetaFileT // CEnhMetaFileDC // // Global functions: // AtlGetBitmapResourceInfo() // AtlGetBitmapResourceBitsPerPixel() // AtlIsAlphaBitmapResource() // AtlIsDib16() // AtlGetDibColorTableSize() // AtlGetDibNumColors(), // AtlGetDibBitmap() // AtlCopyBitmap() // AtlCreatePackedDib16() // AtlSetClipboardDib16() // AtlGetClipboardDib() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // Bitmap resource helpers to extract bitmap information for a bitmap resource inline LPBITMAPINFOHEADER AtlGetBitmapResourceInfo(HMODULE hModule, ATL::_U_STRINGorID image) { HRSRC hResource = ::FindResource(hModule, image.m_lpstr, RT_BITMAP); ATLASSERT(hResource != NULL); HGLOBAL hGlobal = ::LoadResource(hModule, hResource); ATLASSERT(hGlobal != NULL); LPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal); ATLASSERT(pBitmapInfoHeader != NULL); return pBitmapInfoHeader; } inline WORD AtlGetBitmapResourceBitsPerPixel(HMODULE hModule, ATL::_U_STRINGorID image) { LPBITMAPINFOHEADER pBitmapInfoHeader = AtlGetBitmapResourceInfo(hModule, image); ATLASSERT(pBitmapInfoHeader != NULL); return pBitmapInfoHeader->biBitCount; } inline WORD AtlGetBitmapResourceBitsPerPixel(ATL::_U_STRINGorID image) { return AtlGetBitmapResourceBitsPerPixel(ModuleHelper::GetResourceInstance(), image); } /////////////////////////////////////////////////////////////////////////////// // 32-bit (alpha channel) bitmap resource helper // Note: 32-bit (alpha channel) images work only on Windows XP with Common Controls version 6. // If you want your app to work on older version of Windows, load non-alpha images if Common // Controls version is less than 6. inline bool AtlIsAlphaBitmapResource(ATL::_U_STRINGorID image) { return (AtlGetBitmapResourceBitsPerPixel(image) == 32); } /////////////////////////////////////////////////////////////////////////////// // CPen template class CPenT { public: // Data members HPEN m_hPen; // Constructor/destructor/operators CPenT(HPEN hPen = NULL) : m_hPen(hPen) { } ~CPenT() { if(t_bManaged && m_hPen != NULL) DeleteObject(); } CPenT& operator =(HPEN hPen) { Attach(hPen); return *this; } void Attach(HPEN hPen) { if(t_bManaged && m_hPen != NULL && m_hPen != hPen) ::DeleteObject(m_hPen); m_hPen = hPen; } HPEN Detach() { HPEN hPen = m_hPen; m_hPen = NULL; return hPen; } operator HPEN() const { return m_hPen; } bool IsNull() const { return (m_hPen == NULL); } // Create methods HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor) { ATLASSERT(m_hPen == NULL); m_hPen = ::CreatePen(nPenStyle, nWidth, crColor); return m_hPen; } #ifndef _WIN32_WCE HPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL) { ATLASSERT(m_hPen == NULL); m_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle); return m_hPen; } #endif // !_WIN32_WCE HPEN CreatePenIndirect(LPLOGPEN lpLogPen) { ATLASSERT(m_hPen == NULL); m_hPen = ::CreatePenIndirect(lpLogPen); return m_hPen; } BOOL DeleteObject() { ATLASSERT(m_hPen != NULL); BOOL bRet = ::DeleteObject(m_hPen); if(bRet) m_hPen = NULL; return bRet; } // Attributes int GetLogPen(LOGPEN* pLogPen) const { ATLASSERT(m_hPen != NULL); return ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen); } bool GetLogPen(LOGPEN& LogPen) const { ATLASSERT(m_hPen != NULL); return (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN)); } #ifndef _WIN32_WCE int GetExtLogPen(EXTLOGPEN* pLogPen, int nSize = sizeof(EXTLOGPEN)) const { ATLASSERT(m_hPen != NULL); return ::GetObject(m_hPen, nSize, pLogPen); } bool GetExtLogPen(EXTLOGPEN& ExtLogPen, int nSize = sizeof(EXTLOGPEN)) const { ATLASSERT(m_hPen != NULL); int nRet = ::GetObject(m_hPen, nSize, &ExtLogPen); return ((nRet > 0) && (nRet <= nSize)); } #endif // !_WIN32_WCE }; typedef CPenT CPenHandle; typedef CPenT CPen; /////////////////////////////////////////////////////////////////////////////// // CBrush template class CBrushT { public: // Data members HBRUSH m_hBrush; // Constructor/destructor/operators CBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush) { } ~CBrushT() { if(t_bManaged && m_hBrush != NULL) DeleteObject(); } CBrushT& operator =(HBRUSH hBrush) { Attach(hBrush); return *this; } void Attach(HBRUSH hBrush) { if(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush) ::DeleteObject(m_hBrush); m_hBrush = hBrush; } HBRUSH Detach() { HBRUSH hBrush = m_hBrush; m_hBrush = NULL; return hBrush; } operator HBRUSH() const { return m_hBrush; } bool IsNull() const { return (m_hBrush == NULL); } // Create methods HBRUSH CreateSolidBrush(COLORREF crColor) { ATLASSERT(m_hBrush == NULL); m_hBrush = ::CreateSolidBrush(crColor); return m_hBrush; } #ifndef _WIN32_WCE HBRUSH CreateHatchBrush(int nIndex, COLORREF crColor) { ATLASSERT(m_hBrush == NULL); m_hBrush = ::CreateHatchBrush(nIndex, crColor); return m_hBrush; } #endif // !_WIN32_WCE #if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) HBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush) { ATLASSERT(m_hBrush == NULL); #ifndef _WIN32_WCE m_hBrush = ::CreateBrushIndirect(lpLogBrush); #else // CE specific m_hBrush = ATL::CreateBrushIndirect(lpLogBrush); #endif // _WIN32_WCE return m_hBrush; } #endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) HBRUSH CreatePatternBrush(HBITMAP hBitmap) { ATLASSERT(m_hBrush == NULL); m_hBrush = ::CreatePatternBrush(hBitmap); return m_hBrush; } HBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage) { ATLASSERT(hPackedDIB != NULL); const void* lpPackedDIB = GlobalLock(hPackedDIB); ATLASSERT(lpPackedDIB != NULL); m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); GlobalUnlock(hPackedDIB); return m_hBrush; } HBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage) { ATLASSERT(m_hBrush == NULL); m_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage); return m_hBrush; } HBRUSH CreateSysColorBrush(int nIndex) { ATLASSERT(m_hBrush == NULL); m_hBrush = ::GetSysColorBrush(nIndex); return m_hBrush; } BOOL DeleteObject() { ATLASSERT(m_hBrush != NULL); BOOL bRet = ::DeleteObject(m_hBrush); if(bRet) m_hBrush = NULL; return bRet; } // Attributes int GetLogBrush(LOGBRUSH* pLogBrush) const { ATLASSERT(m_hBrush != NULL); return ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush); } bool GetLogBrush(LOGBRUSH& LogBrush) const { ATLASSERT(m_hBrush != NULL); return (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH)); } }; typedef CBrushT CBrushHandle; typedef CBrushT CBrush; /////////////////////////////////////////////////////////////////////////////// // CFont class CLogFont : public LOGFONT { public: CLogFont() { memset(this, 0, sizeof(LOGFONT)); } CLogFont(const LOGFONT& lf) { Copy(&lf); } CLogFont(HFONT hFont) { ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); } HFONT CreateFontIndirect() { return ::CreateFontIndirect(this); } void SetBold() { lfWeight = FW_BOLD; } bool IsBold() const { return (lfWeight >= FW_BOLD); } void MakeBolder(int iScale = 1) { lfWeight += FW_BOLD * iScale; } void MakeLarger(int iScale) { if(lfHeight > 0) lfHeight += iScale; else lfHeight -= iScale; } void SetHeight(LONG nPointSize, HDC hDC = NULL) { HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); // For MM_TEXT mapping mode lfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC1, LOGPIXELSY), 72); if(hDC == NULL) ::ReleaseDC(NULL, hDC1); } LONG GetHeight(HDC hDC = NULL) const { HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); // For MM_TEXT mapping mode LONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC1, LOGPIXELSY)); if(hDC == NULL) ::ReleaseDC(NULL, hDC1); return nPointSize; } LONG GetDeciPointHeight(HDC hDC = NULL) const { HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); #ifndef _WIN32_WCE POINT ptOrg = { 0, 0 }; ::DPtoLP(hDC1, &ptOrg, 1); POINT pt = { 0, 0 }; pt.y = abs(lfHeight) + ptOrg.y; ::LPtoDP(hDC1, &pt,1); LONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point #else // CE specific // DP and LP are always the same on CE LONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC1, LOGPIXELSY)); // 72 points/inch, 10 decipoints/point #endif // _WIN32_WCE if(hDC == NULL) ::ReleaseDC(NULL, hDC1); return nDeciPoint; } void SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL) { HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); #ifndef _WIN32_WCE POINT pt = { 0, 0 }; pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720); // 72 points/inch, 10 decipoints/point ::DPtoLP(hDC1, &pt, 1); POINT ptOrg = { 0, 0 }; ::DPtoLP(hDC1, &ptOrg, 1); lfHeight = -abs(pt.y - ptOrg.y); #else // CE specific // DP and LP are always the same on CE lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720)); // 72 points/inch, 10 decipoints/point #endif // _WIN32_WCE if(hDC == NULL) ::ReleaseDC(NULL, hDC1); } #ifndef _WIN32_WCE void SetCaptionFont() { NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); Copy(&ncm.lfCaptionFont); } void SetMenuFont() { NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); Copy(&ncm.lfMenuFont); } void SetStatusFont() { NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); Copy(&ncm.lfStatusFont); } void SetMessageBoxFont() { NONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() }; ATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)); Copy(&ncm.lfMessageFont); } #endif // !_WIN32_WCE void Copy(const LOGFONT* pLogFont) { ATLASSERT(pLogFont != NULL); *(LOGFONT*)this = *pLogFont; } CLogFont& operator =(const CLogFont& src) { Copy(&src); return *this; } CLogFont& operator =(const LOGFONT& src) { Copy(&src); return *this; } CLogFont& operator =(HFONT hFont) { ATLASSERT(::GetObjectType(hFont) == OBJ_FONT); ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this); return *this; } bool operator ==(const LOGFONT& logfont) const { return(logfont.lfHeight == lfHeight && logfont.lfWidth == lfWidth && logfont.lfEscapement == lfEscapement && logfont.lfOrientation == lfOrientation && logfont.lfWeight == lfWeight && logfont.lfItalic == lfItalic && logfont.lfUnderline == lfUnderline && logfont.lfStrikeOut == lfStrikeOut && logfont.lfCharSet == lfCharSet && logfont.lfOutPrecision == lfOutPrecision && logfont.lfClipPrecision == lfClipPrecision && logfont.lfQuality == lfQuality && logfont.lfPitchAndFamily == lfPitchAndFamily && lstrcmp(logfont.lfFaceName, lfFaceName) == 0); } }; template class CFontT { public: // Data members HFONT m_hFont; // Constructor/destructor/operators CFontT(HFONT hFont = NULL) : m_hFont(hFont) { } ~CFontT() { if(t_bManaged && m_hFont != NULL) DeleteObject(); } CFontT& operator =(HFONT hFont) { Attach(hFont); return *this; } void Attach(HFONT hFont) { if(t_bManaged && m_hFont != NULL && m_hFont != hFont) ::DeleteObject(m_hFont); m_hFont = hFont; } HFONT Detach() { HFONT hFont = m_hFont; m_hFont = NULL; return hFont; } operator HFONT() const { return m_hFont; } bool IsNull() const { return (m_hFont == NULL); } // Create methods HFONT CreateFontIndirect(const LOGFONT* lpLogFont) { ATLASSERT(m_hFont == NULL); m_hFont = ::CreateFontIndirect(lpLogFont); return m_hFont; } #if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) HFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex) { ATLASSERT(m_hFont == NULL); m_hFont = ::CreateFontIndirectEx(penumlfex); return m_hFont; } #endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500) #if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) HFONT CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename) { ATLASSERT(m_hFont == NULL); #ifndef _WIN32_WCE m_hFont = ::CreateFont(nHeight, nWidth, nEscapement, nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, nCharSet, nOutPrecision, nClipPrecision, nQuality, nPitchAndFamily, lpszFacename); #else // CE specific m_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement, nOrientation, nWeight, bItalic, bUnderline, cStrikeOut, nCharSet, nOutPrecision, nClipPrecision, nQuality, nPitchAndFamily, lpszFacename); #endif // _WIN32_WCE return m_hFont; } #endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800) HFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false) { LOGFONT logFont = { 0 }; logFont.lfCharSet = DEFAULT_CHARSET; logFont.lfHeight = nPointSize; SecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE); if(bBold) logFont.lfWeight = FW_BOLD; if(bItalic) logFont.lfItalic = (BYTE)TRUE; return CreatePointFontIndirect(&logFont, hDC); } HFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL) { HDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL); // convert nPointSize to logical units based on hDC LOGFONT logFont = *lpLogFont; #ifndef _WIN32_WCE POINT pt = { 0, 0 }; pt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720); // 72 points/inch, 10 decipoints/point ::DPtoLP(hDC1, &pt, 1); POINT ptOrg = { 0, 0 }; ::DPtoLP(hDC1, &ptOrg, 1); logFont.lfHeight = -abs(pt.y - ptOrg.y); #else // CE specific // DP and LP are always the same on CE logFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720)); // 72 points/inch, 10 decipoints/point #endif // _WIN32_WCE if(hDC == NULL) ::ReleaseDC(NULL, hDC1); return CreateFontIndirect(&logFont); } BOOL DeleteObject() { ATLASSERT(m_hFont != NULL); BOOL bRet = ::DeleteObject(m_hFont); if(bRet) m_hFont = NULL; return bRet; } // Attributes int GetLogFont(LOGFONT* pLogFont) const { ATLASSERT(m_hFont != NULL); return ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont); } bool GetLogFont(LOGFONT& LogFont) const { ATLASSERT(m_hFont != NULL); return (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT)); } }; typedef CFontT CFontHandle; typedef CFontT CFont; /////////////////////////////////////////////////////////////////////////////// // CBitmap template class CBitmapT { public: // Data members HBITMAP m_hBitmap; // Constructor/destructor/operators CBitmapT(HBITMAP hBitmap = NULL) : m_hBitmap(hBitmap) { } ~CBitmapT() { if(t_bManaged && m_hBitmap != NULL) DeleteObject(); } CBitmapT& operator =(HBITMAP hBitmap) { Attach(hBitmap); return *this; } void Attach(HBITMAP hBitmap) { if(t_bManaged && m_hBitmap != NULL&& m_hBitmap != hBitmap) ::DeleteObject(m_hBitmap); m_hBitmap = hBitmap; } HBITMAP Detach() { HBITMAP hBitmap = m_hBitmap; m_hBitmap = NULL; return hBitmap; } operator HBITMAP() const { return m_hBitmap; } bool IsNull() const { return (m_hBitmap == NULL); } // Create and load methods HBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); return m_hBitmap; } HBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_ { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap)); return m_hBitmap; } #ifndef _WIN32_WCE HBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize); return m_hBitmap; } #endif // !_WIN32_WCE HBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits); return m_hBitmap; } #ifndef _WIN32_WCE HBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateBitmapIndirect(lpBitmap); return m_hBitmap; } #endif // !_WIN32_WCE HBITMAP CreateCompatibleBitmap(HDC hDC, int nWidth, int nHeight) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight); return m_hBitmap; } #ifndef _WIN32_WCE HBITMAP CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateDiscardableBitmap(hDC, nWidth, nHeight); return m_hBitmap; } #endif // !_WIN32_WCE BOOL DeleteObject() { ATLASSERT(m_hBitmap != NULL); BOOL bRet = ::DeleteObject(m_hBitmap); if(bRet) m_hBitmap = NULL; return bRet; } // Attributes int GetBitmap(BITMAP* pBitMap) const { ATLASSERT(m_hBitmap != NULL); return ::GetObject(m_hBitmap, sizeof(BITMAP), pBitMap); } bool GetBitmap(BITMAP& bm) const { ATLASSERT(m_hBitmap != NULL); return (::GetObject(m_hBitmap, sizeof(BITMAP), &bm) == sizeof(BITMAP)); } bool GetSize(SIZE& size) const { ATLASSERT(m_hBitmap != NULL); BITMAP bm = { 0 }; if(!GetBitmap(&bm)) return false; size.cx = bm.bmWidth; size.cy = bm.bmHeight; return true; } #ifndef _WIN32_WCE DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const { ATLASSERT(m_hBitmap != NULL); return ::GetBitmapBits(m_hBitmap, dwCount, lpBits); } #endif // !_WIN32_WCE #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) DWORD SetBitmapBits(DWORD dwCount, const void* lpBits) { ATLASSERT(m_hBitmap != NULL); return ::SetBitmapBits(m_hBitmap, dwCount, lpBits); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) #ifndef _WIN32_WCE BOOL GetBitmapDimension(LPSIZE lpSize) const { ATLASSERT(m_hBitmap != NULL); return ::GetBitmapDimensionEx(m_hBitmap, lpSize); } BOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL) { ATLASSERT(m_hBitmap != NULL); return ::SetBitmapDimensionEx(m_hBitmap, nWidth, nHeight, lpSize); } // DIB support HBITMAP CreateDIBitmap(HDC hDC, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateDIBitmap(hDC, lpbmih, dwInit, lpbInit, lpbmi, uColorUse); return m_hBitmap; } #endif // !_WIN32_WCE HBITMAP CreateDIBSection(HDC hDC, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset) { ATLASSERT(m_hBitmap == NULL); m_hBitmap = ::CreateDIBSection(hDC, lpbmi, uColorUse, ppvBits, hSection, dwOffset); return m_hBitmap; } #ifndef _WIN32_WCE int GetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const { ATLASSERT(m_hBitmap != NULL); return ::GetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); } int SetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) { ATLASSERT(m_hBitmap != NULL); return ::SetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); } #endif // !_WIN32_WCE }; typedef CBitmapT CBitmapHandle; typedef CBitmapT CBitmap; /////////////////////////////////////////////////////////////////////////////// // CPalette template class CPaletteT { public: // Data members HPALETTE m_hPalette; // Constructor/destructor/operators CPaletteT(HPALETTE hPalette = NULL) : m_hPalette(hPalette) { } ~CPaletteT() { if(t_bManaged && m_hPalette != NULL) DeleteObject(); } CPaletteT& operator =(HPALETTE hPalette) { Attach(hPalette); return *this; } void Attach(HPALETTE hPalette) { if(t_bManaged && m_hPalette != NULL && m_hPalette != hPalette) ::DeleteObject(m_hPalette); m_hPalette = hPalette; } HPALETTE Detach() { HPALETTE hPalette = m_hPalette; m_hPalette = NULL; return hPalette; } operator HPALETTE() const { return m_hPalette; } bool IsNull() const { return (m_hPalette == NULL); } // Create methods HPALETTE CreatePalette(LPLOGPALETTE lpLogPalette) { ATLASSERT(m_hPalette == NULL); m_hPalette = ::CreatePalette(lpLogPalette); return m_hPalette; } #ifndef _WIN32_WCE HPALETTE CreateHalftonePalette(HDC hDC) { ATLASSERT(m_hPalette == NULL); ATLASSERT(hDC != NULL); m_hPalette = ::CreateHalftonePalette(hDC); return m_hPalette; } #endif // !_WIN32_WCE BOOL DeleteObject() { ATLASSERT(m_hPalette != NULL); BOOL bRet = ::DeleteObject(m_hPalette); if(bRet) m_hPalette = NULL; return bRet; } // Attributes int GetEntryCount() const { ATLASSERT(m_hPalette != NULL); WORD nEntries = 0; ::GetObject(m_hPalette, sizeof(WORD), &nEntries); return (int)nEntries; } UINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const { ATLASSERT(m_hPalette != NULL); return ::GetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); } UINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) { ATLASSERT(m_hPalette != NULL); return ::SetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); } // Operations #ifndef _WIN32_WCE void AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) { ATLASSERT(m_hPalette != NULL); ::AnimatePalette(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors); } BOOL ResizePalette(UINT nNumEntries) { ATLASSERT(m_hPalette != NULL); return ::ResizePalette(m_hPalette, nNumEntries); } #endif // !_WIN32_WCE UINT GetNearestPaletteIndex(COLORREF crColor) const { ATLASSERT(m_hPalette != NULL); return ::GetNearestPaletteIndex(m_hPalette, crColor); } }; typedef CPaletteT CPaletteHandle; typedef CPaletteT CPalette; /////////////////////////////////////////////////////////////////////////////// // CRgn template class CRgnT { public: // Data members HRGN m_hRgn; // Constructor/destructor/operators CRgnT(HRGN hRgn = NULL) : m_hRgn(hRgn) { } ~CRgnT() { if(t_bManaged && m_hRgn != NULL) DeleteObject(); } CRgnT& operator =(HRGN hRgn) { Attach(hRgn); return *this; } void Attach(HRGN hRgn) { if(t_bManaged && m_hRgn != NULL && m_hRgn != hRgn) ::DeleteObject(m_hRgn); m_hRgn = hRgn; } HRGN Detach() { HRGN hRgn = m_hRgn; m_hRgn = NULL; return hRgn; } operator HRGN() const { return m_hRgn; } bool IsNull() const { return (m_hRgn == NULL); } // Create methods HRGN CreateRectRgn(int x1, int y1, int x2, int y2) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreateRectRgn(x1, y1, x2, y2); return m_hRgn; } HRGN CreateRectRgnIndirect(LPCRECT lpRect) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreateRectRgnIndirect(lpRect); return m_hRgn; } #ifndef _WIN32_WCE HRGN CreateEllipticRgn(int x1, int y1, int x2, int y2) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreateEllipticRgn(x1, y1, x2, y2); return m_hRgn; } HRGN CreateEllipticRgnIndirect(LPCRECT lpRect) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreateEllipticRgnIndirect(lpRect); return m_hRgn; } HRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreatePolygonRgn(lpPoints, nCount, nMode); return m_hRgn; } HRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode); return m_hRgn; } HRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3); return m_hRgn; } HRGN CreateFromPath(HDC hDC) { ATLASSERT(m_hRgn == NULL); ATLASSERT(hDC != NULL); m_hRgn = ::PathToRegion(hDC); return m_hRgn; } HRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData) { ATLASSERT(m_hRgn == NULL); m_hRgn = ::ExtCreateRegion(lpXForm, nCount, pRgnData); return m_hRgn; } #endif // !_WIN32_WCE BOOL DeleteObject() { ATLASSERT(m_hRgn != NULL); BOOL bRet = ::DeleteObject(m_hRgn); if(bRet) m_hRgn = NULL; return bRet; } // Operations void SetRectRgn(int x1, int y1, int x2, int y2) { ATLASSERT(m_hRgn != NULL); ::SetRectRgn(m_hRgn, x1, y1, x2, y2); } void SetRectRgn(LPCRECT lpRect) { ATLASSERT(m_hRgn != NULL); ::SetRectRgn(m_hRgn, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } int CombineRgn(HRGN hRgnSrc1, HRGN hRgnSrc2, int nCombineMode) { ATLASSERT(m_hRgn != NULL); return ::CombineRgn(m_hRgn, hRgnSrc1, hRgnSrc2, nCombineMode); } int CombineRgn(HRGN hRgnSrc, int nCombineMode) { ATLASSERT(m_hRgn != NULL); return ::CombineRgn(m_hRgn, m_hRgn, hRgnSrc, nCombineMode); } int CopyRgn(HRGN hRgnSrc) { ATLASSERT(m_hRgn != NULL); return ::CombineRgn(m_hRgn, hRgnSrc, NULL, RGN_COPY); } BOOL EqualRgn(HRGN hRgn) const { ATLASSERT(m_hRgn != NULL); return ::EqualRgn(m_hRgn, hRgn); } int OffsetRgn(int x, int y) { ATLASSERT(m_hRgn != NULL); return ::OffsetRgn(m_hRgn, x, y); } int OffsetRgn(POINT point) { ATLASSERT(m_hRgn != NULL); return ::OffsetRgn(m_hRgn, point.x, point.y); } int GetRgnBox(LPRECT lpRect) const { ATLASSERT(m_hRgn != NULL); return ::GetRgnBox(m_hRgn, lpRect); } BOOL PtInRegion(int x, int y) const { ATLASSERT(m_hRgn != NULL); return ::PtInRegion(m_hRgn, x, y); } BOOL PtInRegion(POINT point) const { ATLASSERT(m_hRgn != NULL); return ::PtInRegion(m_hRgn, point.x, point.y); } BOOL RectInRegion(LPCRECT lpRect) const { ATLASSERT(m_hRgn != NULL); return ::RectInRegion(m_hRgn, lpRect); } int GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const { ATLASSERT(m_hRgn != NULL); return (int)::GetRegionData(m_hRgn, nDataSize, lpRgnData); } }; typedef CRgnT CRgnHandle; typedef CRgnT CRgn; /////////////////////////////////////////////////////////////////////////////// // CDC - The device context class template class CDCT { public: // Data members HDC m_hDC; // Constructor/destructor/operators CDCT(HDC hDC = NULL) : m_hDC(hDC) { } ~CDCT() { if(t_bManaged && m_hDC != NULL) ::DeleteDC(Detach()); } CDCT& operator =(HDC hDC) { Attach(hDC); return *this; } void Attach(HDC hDC) { if(t_bManaged && m_hDC != NULL && m_hDC != hDC) ::DeleteDC(m_hDC); m_hDC = hDC; } HDC Detach() { HDC hDC = m_hDC; m_hDC = NULL; return hDC; } operator HDC() const { return m_hDC; } bool IsNull() const { return (m_hDC == NULL); } // Operations #ifndef _WIN32_WCE HWND WindowFromDC() const { ATLASSERT(m_hDC != NULL); return ::WindowFromDC(m_hDC); } #endif // !_WIN32_WCE CPenHandle GetCurrentPen() const { ATLASSERT(m_hDC != NULL); return CPenHandle((HPEN)::GetCurrentObject(m_hDC, OBJ_PEN)); } CBrushHandle GetCurrentBrush() const { ATLASSERT(m_hDC != NULL); return CBrushHandle((HBRUSH)::GetCurrentObject(m_hDC, OBJ_BRUSH)); } CPaletteHandle GetCurrentPalette() const { ATLASSERT(m_hDC != NULL); return CPaletteHandle((HPALETTE)::GetCurrentObject(m_hDC, OBJ_PAL)); } CFontHandle GetCurrentFont() const { ATLASSERT(m_hDC != NULL); return CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT)); } CBitmapHandle GetCurrentBitmap() const { ATLASSERT(m_hDC != NULL); return CBitmapHandle((HBITMAP)::GetCurrentObject(m_hDC, OBJ_BITMAP)); } HDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData) { ATLASSERT(m_hDC == NULL); m_hDC = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData); return m_hDC; } HDC CreateCompatibleDC(HDC hDC = NULL) { ATLASSERT(m_hDC == NULL); m_hDC = ::CreateCompatibleDC(hDC); return m_hDC; } BOOL DeleteDC() { if(m_hDC == NULL) return FALSE; BOOL bRet = ::DeleteDC(m_hDC); if(bRet) m_hDC = NULL; return bRet; } // Device-Context Functions int SaveDC() { ATLASSERT(m_hDC != NULL); return ::SaveDC(m_hDC); } BOOL RestoreDC(int nSavedDC) { ATLASSERT(m_hDC != NULL); return ::RestoreDC(m_hDC, nSavedDC); } int GetDeviceCaps(int nIndex) const { ATLASSERT(m_hDC != NULL); return ::GetDeviceCaps(m_hDC, nIndex); } #ifndef _WIN32_WCE UINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags) { ATLASSERT(m_hDC != NULL); return ::SetBoundsRect(m_hDC, lpRectBounds, flags); } UINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const { ATLASSERT(m_hDC != NULL); return ::GetBoundsRect(m_hDC, lpRectBounds, flags); } BOOL ResetDC(const DEVMODE* lpDevMode) { ATLASSERT(m_hDC != NULL); return ::ResetDC(m_hDC, lpDevMode) != NULL; } // Drawing-Tool Functions BOOL GetBrushOrg(LPPOINT lpPoint) const { ATLASSERT(m_hDC != NULL); return ::GetBrushOrgEx(m_hDC, lpPoint); } #endif // !_WIN32_WCE BOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::SetBrushOrgEx(m_hDC, x, y, lpPoint); } BOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL) { ATLASSERT(m_hDC != NULL); return ::SetBrushOrgEx(m_hDC, point.x, point.y, lpPointRet); } #ifndef _WIN32_WCE int EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData) { ATLASSERT(m_hDC != NULL); #ifdef STRICT return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, lpData); #else return ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData); #endif } #endif // !_WIN32_WCE // Type-safe selection helpers HPEN SelectPen(HPEN hPen) { ATLASSERT(m_hDC != NULL); #ifndef _WIN32_WCE ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN || ::GetObjectType(hPen) == OBJ_EXTPEN); #else // CE specific ATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN); #endif // _WIN32_WCE return (HPEN)::SelectObject(m_hDC, hPen); } HBRUSH SelectBrush(HBRUSH hBrush) { ATLASSERT(m_hDC != NULL); ATLASSERT(hBrush == NULL || ::GetObjectType(hBrush) == OBJ_BRUSH); return (HBRUSH)::SelectObject(m_hDC, hBrush); } HFONT SelectFont(HFONT hFont) { ATLASSERT(m_hDC != NULL); ATLASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT); return (HFONT)::SelectObject(m_hDC, hFont); } HBITMAP SelectBitmap(HBITMAP hBitmap) { ATLASSERT(m_hDC != NULL); ATLASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP); return (HBITMAP)::SelectObject(m_hDC, hBitmap); } int SelectRgn(HRGN hRgn) // special return for regions { ATLASSERT(m_hDC != NULL); ATLASSERT(hRgn == NULL || ::GetObjectType(hRgn) == OBJ_REGION); return PtrToInt(::SelectObject(m_hDC, hRgn)); } // Type-safe selection helpers for stock objects HPEN SelectStockPen(int nPen) { ATLASSERT(m_hDC != NULL); #if (_WIN32_WINNT >= 0x0500) ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); #else ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); #endif // !(_WIN32_WINNT >= 0x0500) return SelectPen((HPEN)::GetStockObject(nPen)); } HBRUSH SelectStockBrush(int nBrush) { #if (_WIN32_WINNT >= 0x0500) ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); #else ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); #endif // !(_WIN32_WINNT >= 0x0500) return SelectBrush((HBRUSH)::GetStockObject(nBrush)); } HFONT SelectStockFont(int nFont) { #ifndef _WIN32_WCE ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); #else // CE specific ATLASSERT(nFont == SYSTEM_FONT); #endif // _WIN32_WCE return SelectFont((HFONT)::GetStockObject(nFont)); } HPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground) { ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported return SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground); } // Color and Color Palette Functions COLORREF GetNearestColor(COLORREF crColor) const { ATLASSERT(m_hDC != NULL); return ::GetNearestColor(m_hDC, crColor); } HPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground) { ATLASSERT(m_hDC != NULL); return ::SelectPalette(m_hDC, hPalette, bForceBackground); } UINT RealizePalette() { ATLASSERT(m_hDC != NULL); return ::RealizePalette(m_hDC); } #ifndef _WIN32_WCE void UpdateColors() { ATLASSERT(m_hDC != NULL); ::UpdateColors(m_hDC); } #endif // !_WIN32_WCE // Drawing-Attribute Functions COLORREF GetBkColor() const { ATLASSERT(m_hDC != NULL); return ::GetBkColor(m_hDC); } int GetBkMode() const { ATLASSERT(m_hDC != NULL); return ::GetBkMode(m_hDC); } #ifndef _WIN32_WCE int GetPolyFillMode() const { ATLASSERT(m_hDC != NULL); return ::GetPolyFillMode(m_hDC); } int GetROP2() const { ATLASSERT(m_hDC != NULL); return ::GetROP2(m_hDC); } int GetStretchBltMode() const { ATLASSERT(m_hDC != NULL); return ::GetStretchBltMode(m_hDC); } #endif // !_WIN32_WCE COLORREF GetTextColor() const { ATLASSERT(m_hDC != NULL); return ::GetTextColor(m_hDC); } COLORREF SetBkColor(COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetBkColor(m_hDC, crColor); } int SetBkMode(int nBkMode) { ATLASSERT(m_hDC != NULL); return ::SetBkMode(m_hDC, nBkMode); } #ifndef _WIN32_WCE int SetPolyFillMode(int nPolyFillMode) { ATLASSERT(m_hDC != NULL); return ::SetPolyFillMode(m_hDC, nPolyFillMode); } #endif // !_WIN32_WCE int SetROP2(int nDrawMode) { ATLASSERT(m_hDC != NULL); return ::SetROP2(m_hDC, nDrawMode); } #ifndef _WIN32_WCE int SetStretchBltMode(int nStretchMode) { ATLASSERT(m_hDC != NULL); return ::SetStretchBltMode(m_hDC, nStretchMode); } #endif // !_WIN32_WCE COLORREF SetTextColor(COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetTextColor(m_hDC, crColor); } #ifndef _WIN32_WCE BOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const { ATLASSERT(m_hDC != NULL); return ::GetColorAdjustment(m_hDC, lpColorAdjust); } BOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust) { ATLASSERT(m_hDC != NULL); return ::SetColorAdjustment(m_hDC, lpColorAdjust); } // Mapping Functions int GetMapMode() const { ATLASSERT(m_hDC != NULL); return ::GetMapMode(m_hDC); } BOOL GetViewportOrg(LPPOINT lpPoint) const { ATLASSERT(m_hDC != NULL); return ::GetViewportOrgEx(m_hDC, lpPoint); } int SetMapMode(int nMapMode) { ATLASSERT(m_hDC != NULL); return ::SetMapMode(m_hDC, nMapMode); } #endif // !_WIN32_WCE // Viewport Origin BOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::SetViewportOrgEx(m_hDC, x, y, lpPoint); } BOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL) { ATLASSERT(m_hDC != NULL); return SetViewportOrg(point.x, point.y, lpPointRet); } #ifndef _WIN32_WCE BOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, lpPoint); } // Viewport Extent BOOL GetViewportExt(LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); return ::GetViewportExtEx(m_hDC, lpSize); } BOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL) { ATLASSERT(m_hDC != NULL); return ::SetViewportExtEx(m_hDC, x, y, lpSize); } BOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL) { ATLASSERT(m_hDC != NULL); return SetViewportExt(size.cx, size.cy, lpSizeRet); } BOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) { ATLASSERT(m_hDC != NULL); return ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); } #endif // !_WIN32_WCE // Window Origin #ifndef _WIN32_WCE BOOL GetWindowOrg(LPPOINT lpPoint) const { ATLASSERT(m_hDC != NULL); return ::GetWindowOrgEx(m_hDC, lpPoint); } BOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::SetWindowOrgEx(m_hDC, x, y, lpPoint); } BOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL) { ATLASSERT(m_hDC != NULL); return SetWindowOrg(point.x, point.y, lpPointRet); } BOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::OffsetWindowOrgEx(m_hDC, nWidth, nHeight, lpPoint); } // Window extent BOOL GetWindowExt(LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); return ::GetWindowExtEx(m_hDC, lpSize); } BOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL) { ATLASSERT(m_hDC != NULL); return ::SetWindowExtEx(m_hDC, x, y, lpSize); } BOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL) { ATLASSERT(m_hDC != NULL); return SetWindowExt(size.cx, size.cy, lpSizeRet); } BOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL) { ATLASSERT(m_hDC != NULL); return ::ScaleWindowExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize); } // Coordinate Functions BOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const { ATLASSERT(m_hDC != NULL); return ::DPtoLP(m_hDC, lpPoints, nCount); } BOOL DPtoLP(LPRECT lpRect) const { ATLASSERT(m_hDC != NULL); return ::DPtoLP(m_hDC, (LPPOINT)lpRect, 2); } BOOL DPtoLP(LPSIZE lpSize) const { SIZE sizeWinExt = { 0, 0 }; if(!GetWindowExt(&sizeWinExt)) return FALSE; SIZE sizeVpExt = { 0, 0 }; if(!GetViewportExt(&sizeVpExt)) return FALSE; lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx)); lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy)); return TRUE; } BOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const { ATLASSERT(m_hDC != NULL); return ::LPtoDP(m_hDC, lpPoints, nCount); } BOOL LPtoDP(LPRECT lpRect) const { ATLASSERT(m_hDC != NULL); return ::LPtoDP(m_hDC, (LPPOINT)lpRect, 2); } BOOL LPtoDP(LPSIZE lpSize) const { SIZE sizeWinExt = { 0, 0 }; if(!GetWindowExt(&sizeWinExt)) return FALSE; SIZE sizeVpExt = { 0, 0 }; if(!GetViewportExt(&sizeVpExt)) return FALSE; lpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx)); lpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy)); return TRUE; } // Special Coordinate Functions (useful for dealing with metafiles and OLE) #define HIMETRIC_INCH 2540 // HIMETRIC units per inch void DPtoHIMETRIC(LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); int nMapMode; if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) { // when using a constrained map mode, map against physical inch ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); DPtoLP(lpSize); ((CDCHandle*)this)->SetMapMode(nMapMode); } else { // map against logical inch for non-constrained mapping modes int cxPerInch = GetDeviceCaps(LOGPIXELSX); int cyPerInch = GetDeviceCaps(LOGPIXELSY); ATLASSERT(cxPerInch != 0 && cyPerInch != 0); lpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch); lpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch); } } void HIMETRICtoDP(LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); int nMapMode; if((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT) { // when using a constrained map mode, map against physical inch ((CDCHandle*)this)->SetMapMode(MM_HIMETRIC); LPtoDP(lpSize); ((CDCHandle*)this)->SetMapMode(nMapMode); } else { // map against logical inch for non-constrained mapping modes int cxPerInch = GetDeviceCaps(LOGPIXELSX); int cyPerInch = GetDeviceCaps(LOGPIXELSY); ATLASSERT(cxPerInch != 0 && cyPerInch != 0); lpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH); lpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH); } } void LPtoHIMETRIC(LPSIZE lpSize) const { LPtoDP(lpSize); DPtoHIMETRIC(lpSize); } void HIMETRICtoLP(LPSIZE lpSize) const { HIMETRICtoDP(lpSize); DPtoLP(lpSize); } #endif // !_WIN32_WCE // Region Functions BOOL FillRgn(HRGN hRgn, HBRUSH hBrush) { ATLASSERT(m_hDC != NULL); return ::FillRgn(m_hDC, hRgn, hBrush); } #ifndef _WIN32_WCE BOOL FrameRgn(HRGN hRgn, HBRUSH hBrush, int nWidth, int nHeight) { ATLASSERT(m_hDC != NULL); return ::FrameRgn(m_hDC, hRgn, hBrush, nWidth, nHeight); } BOOL InvertRgn(HRGN hRgn) { ATLASSERT(m_hDC != NULL); return ::InvertRgn(m_hDC, hRgn); } BOOL PaintRgn(HRGN hRgn) { ATLASSERT(m_hDC != NULL); return ::PaintRgn(m_hDC, hRgn); } #endif // !_WIN32_WCE // Clipping Functions int GetClipBox(LPRECT lpRect) const { ATLASSERT(m_hDC != NULL); return ::GetClipBox(m_hDC, lpRect); } int GetClipRgn(CRgn& region) const { ATLASSERT(m_hDC != NULL); if(region.IsNull()) region.CreateRectRgn(0, 0, 0, 0); int nRet = ::GetClipRgn(m_hDC, region); if(nRet != 1) region.DeleteObject(); return nRet; } #ifndef _WIN32_WCE BOOL PtVisible(int x, int y) const { ATLASSERT(m_hDC != NULL); return ::PtVisible(m_hDC, x, y); } BOOL PtVisible(POINT point) const { ATLASSERT(m_hDC != NULL); return ::PtVisible(m_hDC, point.x, point.y); } #endif // !_WIN32_WCE BOOL RectVisible(LPCRECT lpRect) const { ATLASSERT(m_hDC != NULL); return ::RectVisible(m_hDC, lpRect); } int SelectClipRgn(HRGN hRgn) { ATLASSERT(m_hDC != NULL); return ::SelectClipRgn(m_hDC, (HRGN)hRgn); } int ExcludeClipRect(int x1, int y1, int x2, int y2) { ATLASSERT(m_hDC != NULL); return ::ExcludeClipRect(m_hDC, x1, y1, x2, y2); } int ExcludeClipRect(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); return ::ExcludeClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } #ifndef _WIN32_WCE int ExcludeUpdateRgn(HWND hWnd) { ATLASSERT(m_hDC != NULL); return ::ExcludeUpdateRgn(m_hDC, hWnd); } #endif // !_WIN32_WCE int IntersectClipRect(int x1, int y1, int x2, int y2) { ATLASSERT(m_hDC != NULL); return ::IntersectClipRect(m_hDC, x1, y1, x2, y2); } int IntersectClipRect(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); return ::IntersectClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } #ifndef _WIN32_WCE int OffsetClipRgn(int x, int y) { ATLASSERT(m_hDC != NULL); return ::OffsetClipRgn(m_hDC, x, y); } int OffsetClipRgn(SIZE size) { ATLASSERT(m_hDC != NULL); return ::OffsetClipRgn(m_hDC, size.cx, size.cy); } int SelectClipRgn(HRGN hRgn, int nMode) { ATLASSERT(m_hDC != NULL); return ::ExtSelectClipRgn(m_hDC, hRgn, nMode); } #endif // !_WIN32_WCE // Line-Output Functions #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) BOOL GetCurrentPosition(LPPOINT lpPoint) const { ATLASSERT(m_hDC != NULL); return ::GetCurrentPositionEx(m_hDC, lpPoint); } BOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL) { ATLASSERT(m_hDC != NULL); return ::MoveToEx(m_hDC, x, y, lpPoint); } BOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL) { ATLASSERT(m_hDC != NULL); return MoveTo(point.x, point.y, lpPointRet); } BOOL LineTo(int x, int y) { ATLASSERT(m_hDC != NULL); return ::LineTo(m_hDC, x, y); } BOOL LineTo(POINT point) { ATLASSERT(m_hDC != NULL); return LineTo(point.x, point.y); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) #ifndef _WIN32_WCE BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { ATLASSERT(m_hDC != NULL); return ::Arc(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); } BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { ATLASSERT(m_hDC != NULL); return ::Arc(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); } #endif // !_WIN32_WCE BOOL Polyline(const POINT* lpPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::Polyline(m_hDC, lpPoints, nCount); } #ifndef _WIN32_WCE BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle) { ATLASSERT(m_hDC != NULL); return ::AngleArc(m_hDC, x, y, nRadius, fStartAngle, fSweepAngle); } BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { ATLASSERT(m_hDC != NULL); return ::ArcTo(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); } BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { ATLASSERT(m_hDC != NULL); return ArcTo(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); } int GetArcDirection() const { ATLASSERT(m_hDC != NULL); return ::GetArcDirection(m_hDC); } int SetArcDirection(int nArcDirection) { ATLASSERT(m_hDC != NULL); return ::SetArcDirection(m_hDC, nArcDirection); } BOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolyDraw(m_hDC, lpPoints, lpTypes, nCount); } BOOL PolylineTo(const POINT* lpPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolylineTo(m_hDC, lpPoints, nCount); } BOOL PolyPolyline(const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolyPolyline(m_hDC, lpPoints, lpPolyPoints, nCount); } BOOL PolyBezier(const POINT* lpPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolyBezier(m_hDC, lpPoints, nCount); } BOOL PolyBezierTo(const POINT* lpPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolyBezierTo(m_hDC, lpPoints, nCount); } #endif // !_WIN32_WCE // Simple Drawing Functions BOOL FillRect(LPCRECT lpRect, HBRUSH hBrush) { ATLASSERT(m_hDC != NULL); return ::FillRect(m_hDC, lpRect, hBrush); } BOOL FillRect(LPCRECT lpRect, int nColorIndex) { ATLASSERT(m_hDC != NULL); #ifndef _WIN32_WCE return ::FillRect(m_hDC, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1)); #else // CE specific return ::FillRect(m_hDC, lpRect, ::GetSysColorBrush(nColorIndex)); #endif // _WIN32_WCE } #ifndef _WIN32_WCE BOOL FrameRect(LPCRECT lpRect, HBRUSH hBrush) { ATLASSERT(m_hDC != NULL); return ::FrameRect(m_hDC, lpRect, hBrush); } #endif // !_WIN32_WCE #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) BOOL InvertRect(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); return ::InvertRect(m_hDC, lpRect); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) BOOL DrawIcon(int x, int y, HICON hIcon) { ATLASSERT(m_hDC != NULL); #ifndef _WIN32_WCE return ::DrawIcon(m_hDC, x, y, hIcon); #else // CE specific return ::DrawIconEx(m_hDC, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL); #endif // _WIN32_WCE } BOOL DrawIcon(POINT point, HICON hIcon) { ATLASSERT(m_hDC != NULL); #ifndef _WIN32_WCE return ::DrawIcon(m_hDC, point.x, point.y, hIcon); #else // CE specific return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL); #endif // _WIN32_WCE } BOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hDC != NULL); return ::DrawIconEx(m_hDC, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } BOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hDC != NULL); return ::DrawIconEx(m_hDC, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } #ifndef _WIN32_WCE BOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH hBrush = NULL) { ATLASSERT(m_hDC != NULL); return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP); } BOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH hBrush = NULL) { ATLASSERT(m_hDC != NULL); return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON); } BOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH hBrush = NULL) { ATLASSERT(m_hDC != NULL); return ::DrawState(m_hDC, hBrush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT)); } BOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH hBrush = NULL) { ATLASSERT(m_hDC != NULL); return ::DrawState(m_hDC, hBrush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX); } #endif // !_WIN32_WCE // Ellipse and Polygon Functions #ifndef _WIN32_WCE BOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { ATLASSERT(m_hDC != NULL); return ::Chord(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); } BOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { ATLASSERT(m_hDC != NULL); return ::Chord(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); } #endif // !_WIN32_WCE void DrawFocusRect(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); ::DrawFocusRect(m_hDC, lpRect); } BOOL Ellipse(int x1, int y1, int x2, int y2) { ATLASSERT(m_hDC != NULL); return ::Ellipse(m_hDC, x1, y1, x2, y2); } BOOL Ellipse(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); return ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } #ifndef _WIN32_WCE BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { ATLASSERT(m_hDC != NULL); return ::Pie(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4); } BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd) { ATLASSERT(m_hDC != NULL); return ::Pie(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y); } #endif // !_WIN32_WCE BOOL Polygon(const POINT* lpPoints, int nCount) { ATLASSERT(m_hDC != NULL); return ::Polygon(m_hDC, lpPoints, nCount); } #ifndef _WIN32_WCE BOOL PolyPolygon(const POINT* lpPoints, const INT* lpPolyCounts, int nCount) { ATLASSERT(m_hDC != NULL); return ::PolyPolygon(m_hDC, lpPoints, lpPolyCounts, nCount); } #endif // !_WIN32_WCE BOOL Rectangle(int x1, int y1, int x2, int y2) { ATLASSERT(m_hDC != NULL); return ::Rectangle(m_hDC, x1, y1, x2, y2); } BOOL Rectangle(LPCRECT lpRect) { ATLASSERT(m_hDC != NULL); return ::Rectangle(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); } BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3) { ATLASSERT(m_hDC != NULL); return ::RoundRect(m_hDC, x1, y1, x2, y2, x3, y3); } BOOL RoundRect(LPCRECT lpRect, POINT point) { ATLASSERT(m_hDC != NULL); return ::RoundRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y); } // Bitmap Functions BOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop) { ATLASSERT(m_hDC != NULL); return ::PatBlt(m_hDC, x, y, nWidth, nHeight, dwRop); } BOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, DWORD dwRop) { ATLASSERT(m_hDC != NULL); return ::BitBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop); } BOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop) { ATLASSERT(m_hDC != NULL); return ::StretchBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop); } COLORREF GetPixel(int x, int y) const { ATLASSERT(m_hDC != NULL); return ::GetPixel(m_hDC, x, y); } COLORREF GetPixel(POINT point) const { ATLASSERT(m_hDC != NULL); return ::GetPixel(m_hDC, point.x, point.y); } COLORREF SetPixel(int x, int y, COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetPixel(m_hDC, x, y, crColor); } COLORREF SetPixel(POINT point, COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetPixel(m_hDC, point.x, point.y, crColor); } #ifndef _WIN32_WCE BOOL FloodFill(int x, int y, COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::FloodFill(m_hDC, x, y, crColor); } BOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType) { ATLASSERT(m_hDC != NULL); return ::ExtFloodFill(m_hDC, x, y, crColor, nFillType); } #endif // !_WIN32_WCE BOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop) { ATLASSERT(m_hDC != NULL); return ::MaskBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop); } #ifndef _WIN32_WCE BOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask) { ATLASSERT(m_hDC != NULL); return ::PlgBlt(m_hDC, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask); } BOOL SetPixelV(int x, int y, COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetPixelV(m_hDC, x, y, crColor); } BOOL SetPixelV(POINT point, COLORREF crColor) { ATLASSERT(m_hDC != NULL); return ::SetPixelV(m_hDC, point.x, point.y, crColor); } #endif // !_WIN32_WCE #if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) #ifndef _WIN32_WCE BOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) { ATLASSERT(m_hDC != NULL); return ::TransparentBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); } #else // CE specific BOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent) { ATLASSERT(m_hDC != NULL); return ::TransparentImage(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent); } #endif // _WIN32_WCE #if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420)) BOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode) { ATLASSERT(m_hDC != NULL); return ::GradientFill(m_hDC, pVertices, nVertices, pMeshElements, nMeshElements, dwMode); } BOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal) { ATLASSERT(m_hDC != NULL); TRIVERTEX arrTvx[2] = { { 0 }, { 0 } }; arrTvx[0].x = rect.left; arrTvx[0].y = rect.top; arrTvx[0].Red = MAKEWORD(0, GetRValue(clr1)); arrTvx[0].Green = MAKEWORD(0, GetGValue(clr1)); arrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1)); arrTvx[0].Alpha = 0; arrTvx[1].x = rect.right; arrTvx[1].y = rect.bottom; arrTvx[1].Red = MAKEWORD(0, GetRValue(clr2)); arrTvx[1].Green = MAKEWORD(0, GetGValue(clr2)); arrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2)); arrTvx[1].Alpha = 0; GRADIENT_RECT gr = { 0, 1 }; return ::GradientFill(m_hDC, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420) #if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) BOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf) { ATLASSERT(m_hDC != NULL); return ::AlphaBlend(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500) #endif // !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE) // Extra bitmap functions // Helper function for painting a disabled toolbar or menu bitmap // This function can take either an HBITMAP (for SS) or a DC with // the bitmap already painted (for cmdbar) BOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc, HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE), HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT), HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW)) { ATLASSERT(m_hDC != NULL || hBitmap != NULL); ATLASSERT(nWidth > 0 && nHeight > 0); // Create a generic DC for all BitBlts CDCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(m_hDC); ATLASSERT(dc.m_hDC != NULL); if(dc.m_hDC == NULL) return FALSE; // Create a DC for the monochrome DIB section CDC dcBW = ::CreateCompatibleDC(m_hDC); ATLASSERT(dcBW.m_hDC != NULL); if(dcBW.m_hDC == NULL) { if(hSrcDC == NULL) dc.DeleteDC(); return FALSE; } // Create the monochrome DIB section with a black and white palette struct RGBBWBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[2]; }; RGBBWBITMAPINFO rgbBWBitmapInfo = { { sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 }, { { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } } }; VOID* pbitsBW; CBitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0); ATLASSERT(bmpBW.m_hBitmap != NULL); if(bmpBW.m_hBitmap == NULL) { if(hSrcDC == NULL) dc.DeleteDC(); return FALSE; } // Attach the monochrome DIB section and the bitmap to the DCs HBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW); HBITMAP hbmOldDC = NULL; if(hBitmap != NULL) hbmOldDC = dc.SelectBitmap(hBitmap); // Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white { CDC dcTemp1 = ::CreateCompatibleDC(m_hDC); CDC dcTemp2 = ::CreateCompatibleDC(m_hDC); CBitmap bmpTemp1; bmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight); CBitmap bmpTemp2; bmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL); HBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1); HBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2); // Let's copy our image, it will be altered dcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY); // All dark gray pixels will become white, the others black dcTemp1.SetBkColor(RGB(128, 128, 128)); dcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); // Do an XOR to set to black these white pixels dcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT); // BitBlt the bitmap into the monochrome DIB section // The DIB section will do a true monochrome conversion // The magenta background being closer to white will become white dcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY); // Cleanup dcTemp1.SelectBitmap(hOldBmp1); dcTemp2.SelectBitmap(hOldBmp2); } // Paint the destination rectangle using hBrushBackground if(hBrushBackground != NULL) { RECT rc = { x, y, x + nWidth, y + nHeight }; FillRect(&rc, hBrushBackground); } // BitBlt the black bits in the monochrome bitmap into hBrush3DEffect color in the destination DC // The magic ROP comes from the Charles Petzold's book HBRUSH hOldBrush = SelectBrush(hBrush3DEffect); BitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); // BitBlt the black bits in the monochrome bitmap into hBrushDisabledImage color in the destination DC SelectBrush(hBrushDisabledImage); BitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A); SelectBrush(hOldBrush); dcBW.SelectBitmap(hbmOldBW); dc.SelectBitmap(hbmOldDC); if(hSrcDC == NULL) dc.DeleteDC(); return TRUE; } // Text Functions #ifndef _WIN32_WCE BOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1) { ATLASSERT(m_hDC != NULL); if(nCount == -1) nCount = lstrlen(lpszString); return ::TextOut(m_hDC, x, y, lpszString, nCount); } #endif // !_WIN32_WCE BOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL) { ATLASSERT(m_hDC != NULL); if(nCount == -1) nCount = lstrlen(lpszString); return ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths); } #ifndef _WIN32_WCE SIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0) { ATLASSERT(m_hDC != NULL); if(nCount == -1) nCount = lstrlen(lpszString); LONG lRes = ::TabbedTextOut(m_hDC, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin); SIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) }; return size; } #endif // !_WIN32_WCE int DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) { ATLASSERT(m_hDC != NULL); #ifndef _WIN32_WCE ATLASSERT((uFormat & DT_MODIFYSTRING) == 0); #endif // !_WIN32_WCE return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); } int DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat) { ATLASSERT(m_hDC != NULL); return ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat); } #ifndef _WIN32_WCE int DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL) { ATLASSERT(m_hDC != NULL); return ::DrawTextEx(m_hDC, lpstrText, cchText, lpRect, uFormat, lpDTParams); } #endif // !_WIN32_WCE #if (_WIN32_WINNT >= 0x0501) int DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset) { ATLASSERT(m_hDC != NULL); // This function is present only if comctl32.dll version 6 is loaded; // we use LoadLibrary/GetProcAddress to allow apps compiled with // _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl int nRet = 0; HMODULE hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll")); ATLASSERT(hCommCtrlDLL != NULL); if(hCommCtrlDLL != NULL) { typedef int (WINAPI *PFN_DrawShadowText)(HDC hDC, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset); PFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, "DrawShadowText"); ATLASSERT(pfnDrawShadowText != NULL); // this function requires CommCtrl6 if(pfnDrawShadowText != NULL) nRet = pfnDrawShadowText(m_hDC, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset); ::FreeLibrary(hCommCtrlDLL); } return nRet; } #endif // (_WIN32_WINNT >= 0x0501) BOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); if(nCount == -1) nCount = lstrlen(lpszString); return ::GetTextExtentPoint32(m_hDC, lpszString, nCount, lpSize); } BOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL) { ATLASSERT(m_hDC != NULL); return ::GetTextExtentExPoint(m_hDC, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize); } #ifndef _WIN32_WCE DWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const { ATLASSERT(m_hDC != NULL); if(nCount == -1) nCount = lstrlen(lpszString); return ::GetTabbedTextExtent(m_hDC, lpszString, nCount, nTabPositions, lpnTabStopPositions); } BOOL GrayString(HBRUSH hBrush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight) { ATLASSERT(m_hDC != NULL); return ::GrayString(m_hDC, hBrush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight); } #endif // !_WIN32_WCE #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) UINT GetTextAlign() const { ATLASSERT(m_hDC != NULL); return ::GetTextAlign(m_hDC); } UINT SetTextAlign(UINT nFlags) { ATLASSERT(m_hDC != NULL); return ::SetTextAlign(m_hDC, nFlags); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) int GetTextFace(LPTSTR lpszFacename, int nCount) const { ATLASSERT(m_hDC != NULL); return ::GetTextFace(m_hDC, nCount, lpszFacename); } int GetTextFaceLen() const { ATLASSERT(m_hDC != NULL); return ::GetTextFace(m_hDC, 0, NULL); } #ifndef _ATL_NO_COM #ifdef _OLEAUTO_H_ BOOL GetTextFace(BSTR& bstrFace) const { USES_CONVERSION; ATLASSERT(m_hDC != NULL); ATLASSERT(bstrFace == NULL); int nLen = GetTextFaceLen(); if(nLen == 0) return FALSE; CTempBuffer buff; LPTSTR lpszText = buff.Allocate(nLen); if(lpszText == NULL) return FALSE; if(!GetTextFace(lpszText, nLen)) return FALSE; bstrFace = ::SysAllocString(T2OLE(lpszText)); return (bstrFace != NULL) ? TRUE : FALSE; } #endif #endif // !_ATL_NO_COM #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetTextFace(_CSTRING_NS::CString& strFace) const { ATLASSERT(m_hDC != NULL); int nLen = GetTextFaceLen(); if(nLen == 0) return 0; LPTSTR lpstr = strFace.GetBufferSetLength(nLen); if(lpstr == NULL) return 0; int nRet = GetTextFace(lpstr, nLen); strFace.ReleaseBuffer(); return nRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const { ATLASSERT(m_hDC != NULL); return ::GetTextMetrics(m_hDC, lpMetrics); } #ifndef _WIN32_WCE int SetTextJustification(int nBreakExtra, int nBreakCount) { ATLASSERT(m_hDC != NULL); return ::SetTextJustification(m_hDC, nBreakExtra, nBreakCount); } int GetTextCharacterExtra() const { ATLASSERT(m_hDC != NULL); return ::GetTextCharacterExtra(m_hDC); } int SetTextCharacterExtra(int nCharExtra) { ATLASSERT(m_hDC != NULL); return ::SetTextCharacterExtra(m_hDC, nCharExtra); } #endif // !_WIN32_WCE // Advanced Drawing BOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags) { ATLASSERT(m_hDC != NULL); return ::DrawEdge(m_hDC, lpRect, nEdge, nFlags); } BOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState) { ATLASSERT(m_hDC != NULL); return ::DrawFrameControl(m_hDC, lpRect, nType, nState); } // Scrolling Functions BOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate) { ATLASSERT(m_hDC != NULL); return ::ScrollDC(m_hDC, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate); } // Font Functions #ifndef _WIN32_WCE BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const { ATLASSERT(m_hDC != NULL); return ::GetCharWidth(m_hDC, nFirstChar, nLastChar, lpBuffer); } // GetCharWidth32 is not supported under Win9x BOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const { ATLASSERT(m_hDC != NULL); return ::GetCharWidth32(m_hDC, nFirstChar, nLastChar, lpBuffer); } DWORD SetMapperFlags(DWORD dwFlag) { ATLASSERT(m_hDC != NULL); return ::SetMapperFlags(m_hDC, dwFlag); } BOOL GetAspectRatioFilter(LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); return ::GetAspectRatioFilterEx(m_hDC, lpSize); } BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const { ATLASSERT(m_hDC != NULL); return ::GetCharABCWidths(m_hDC, nFirstChar, nLastChar, lpabc); } DWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const { ATLASSERT(m_hDC != NULL); return ::GetFontData(m_hDC, dwTable, dwOffset, lpData, cbData); } int GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const { ATLASSERT(m_hDC != NULL); return ::GetKerningPairs(m_hDC, nPairs, lpkrnpair); } UINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const { ATLASSERT(m_hDC != NULL); return ::GetOutlineTextMetrics(m_hDC, cbData, lpotm); } DWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const { ATLASSERT(m_hDC != NULL); return ::GetGlyphOutline(m_hDC, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2); } BOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const { ATLASSERT(m_hDC != NULL); return ::GetCharABCWidthsFloat(m_hDC, nFirstChar, nLastChar, lpABCF); } BOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const { ATLASSERT(m_hDC != NULL); return ::GetCharWidthFloat(m_hDC, nFirstChar, nLastChar, lpFloatBuffer); } #endif // !_WIN32_WCE // Printer/Device Escape Functions #ifndef _WIN32_WCE int Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData) { ATLASSERT(m_hDC != NULL); return ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData); } #endif // !_WIN32_WCE int Escape(int nEscape, int nInputSize, LPCSTR lpszInputData, int nOutputSize, LPSTR lpszOutputData) { ATLASSERT(m_hDC != NULL); return ::ExtEscape(m_hDC, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData); } #ifndef _WIN32_WCE int DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData) { ATLASSERT(m_hDC != NULL); return ::DrawEscape(m_hDC, nEscape, nInputSize, lpszInputData); } #endif // !_WIN32_WCE // Escape helpers #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) int StartDoc(LPCTSTR lpszDocName) // old Win3.0 version { DOCINFO di = { 0 }; di.cbSize = sizeof(DOCINFO); di.lpszDocName = lpszDocName; return StartDoc(&di); } int StartDoc(LPDOCINFO lpDocInfo) { ATLASSERT(m_hDC != NULL); return ::StartDoc(m_hDC, lpDocInfo); } int StartPage() { ATLASSERT(m_hDC != NULL); return ::StartPage(m_hDC); } int EndPage() { ATLASSERT(m_hDC != NULL); return ::EndPage(m_hDC); } int SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int)) { ATLASSERT(m_hDC != NULL); return ::SetAbortProc(m_hDC, (ABORTPROC)lpfn); } int AbortDoc() { ATLASSERT(m_hDC != NULL); return ::AbortDoc(m_hDC); } int EndDoc() { ATLASSERT(m_hDC != NULL); return ::EndDoc(m_hDC); } #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc)) // MetaFile Functions #ifndef _WIN32_WCE BOOL PlayMetaFile(HMETAFILE hMF) { ATLASSERT(m_hDC != NULL); if(::GetDeviceCaps(m_hDC, TECHNOLOGY) == DT_METAFILE) { // playing metafile in metafile, just use core windows API return ::PlayMetaFile(m_hDC, hMF); } // for special playback, lParam == pDC return ::EnumMetaFile(m_hDC, hMF, EnumMetaFileProc, (LPARAM)this); } BOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds) { ATLASSERT(m_hDC != NULL); return ::PlayEnhMetaFile(m_hDC, hEnhMetaFile, lpBounds); } BOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only { ATLASSERT(m_hDC != NULL); return ::GdiComment(m_hDC, nDataSize, pCommentData); } // Special handling for metafile playback static int CALLBACK EnumMetaFileProc(HDC hDC, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam) { CDCHandle* pDC = (CDCHandle*)lParam; switch (pMetaRec->rdFunction) { case META_SETMAPMODE: pDC->SetMapMode((int)(short)pMetaRec->rdParm[0]); break; case META_SETWINDOWEXT: pDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SETWINDOWORG: pDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SETVIEWPORTEXT: pDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SETVIEWPORTORG: pDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SCALEWINDOWEXT: pDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SCALEVIEWPORTEXT: pDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], (int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_OFFSETVIEWPORTORG: pDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]); break; case META_SAVEDC: pDC->SaveDC(); break; case META_RESTOREDC: pDC->RestoreDC((int)(short)pMetaRec->rdParm[0]); break; case META_SETBKCOLOR: pDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); break; case META_SETTEXTCOLOR: pDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]); break; // need to watch out for SelectObject(HFONT), for custom font mapping case META_SELECTOBJECT: { HGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]]; UINT nObjType = ::GetObjectType(hObject); if(nObjType == 0) { // object type is unknown, determine if it is a font HFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT); HFONT hFontOld = (HFONT)::SelectObject(pDC->m_hDC, hStockFont); HGDIOBJ hObjOld = ::SelectObject(pDC->m_hDC, hObject); if(hObjOld == hStockFont) { // got the stock object back, so must be selecting a font pDC->SelectFont((HFONT)hObject); break; // don't play the default record } else { // didn't get the stock object back, so restore everything ::SelectObject(pDC->m_hDC, hFontOld); ::SelectObject(pDC->m_hDC, hObjOld); } // and fall through to PlayMetaFileRecord... } else if(nObjType == OBJ_FONT) { // play back as CDCHandle::SelectFont(HFONT) pDC->SelectFont((HFONT)hObject); break; // don't play the default record } } // fall through... default: ::PlayMetaFileRecord(hDC, pHandleTable, pMetaRec, nHandles); break; } return 1; } #endif // !_WIN32_WCE // Path Functions #ifndef _WIN32_WCE BOOL AbortPath() { ATLASSERT(m_hDC != NULL); return ::AbortPath(m_hDC); } BOOL BeginPath() { ATLASSERT(m_hDC != NULL); return ::BeginPath(m_hDC); } BOOL CloseFigure() { ATLASSERT(m_hDC != NULL); return ::CloseFigure(m_hDC); } BOOL EndPath() { ATLASSERT(m_hDC != NULL); return ::EndPath(m_hDC); } BOOL FillPath() { ATLASSERT(m_hDC != NULL); return ::FillPath(m_hDC); } BOOL FlattenPath() { ATLASSERT(m_hDC != NULL); return ::FlattenPath(m_hDC); } BOOL StrokeAndFillPath() { ATLASSERT(m_hDC != NULL); return ::StrokeAndFillPath(m_hDC); } BOOL StrokePath() { ATLASSERT(m_hDC != NULL); return ::StrokePath(m_hDC); } BOOL WidenPath() { ATLASSERT(m_hDC != NULL); return ::WidenPath(m_hDC); } BOOL GetMiterLimit(PFLOAT pfMiterLimit) const { ATLASSERT(m_hDC != NULL); return ::GetMiterLimit(m_hDC, pfMiterLimit); } BOOL SetMiterLimit(float fMiterLimit) { ATLASSERT(m_hDC != NULL); return ::SetMiterLimit(m_hDC, fMiterLimit, NULL); } int GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const { ATLASSERT(m_hDC != NULL); return ::GetPath(m_hDC, lpPoints, lpTypes, nCount); } BOOL SelectClipPath(int nMode) { ATLASSERT(m_hDC != NULL); return ::SelectClipPath(m_hDC, nMode); } #endif // !_WIN32_WCE // Misc Helper Functions static CBrushHandle PASCAL GetHalftoneBrush() { HBRUSH halftoneBrush = NULL; WORD grayPattern[8] = { 0 }; for(int i = 0; i < 8; i++) grayPattern[i] = (WORD)(0x5555 << (i & 1)); HBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern); if(grayBitmap != NULL) { halftoneBrush = ::CreatePatternBrush(grayBitmap); DeleteObject(grayBitmap); } return CBrushHandle(halftoneBrush); } void DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL) { // first, determine the update region and select it CRgn rgnOutside; rgnOutside.CreateRectRgnIndirect(lpRect); RECT rect = *lpRect; ::InflateRect(&rect, -size.cx, -size.cy); ::IntersectRect(&rect, &rect, lpRect); CRgn rgnInside; rgnInside.CreateRectRgnIndirect(&rect); CRgn rgnNew; rgnNew.CreateRectRgn(0, 0, 0, 0); rgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR); HBRUSH hBrushOld = NULL; CBrush brushHalftone; if(hBrush == NULL) brushHalftone = hBrush = CDCHandle::GetHalftoneBrush(); if(hBrushLast == NULL) hBrushLast = hBrush; CRgn rgnLast; CRgn rgnUpdate; if(lpRectLast != NULL) { // find difference between new region and old region rgnLast.CreateRectRgn(0, 0, 0, 0); rgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom); rect = *lpRectLast; ::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy); ::IntersectRect(&rect, &rect, lpRectLast); rgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom); rgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR); // only diff them if brushes are the same if(hBrush == hBrushLast) { rgnUpdate.CreateRectRgn(0, 0, 0, 0); rgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR); } } if(hBrush != hBrushLast && lpRectLast != NULL) { // brushes are different -- erase old region first SelectClipRgn(rgnLast); GetClipBox(&rect); hBrushOld = SelectBrush(hBrushLast); PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); SelectBrush(hBrushOld); hBrushOld = NULL; } // draw into the update/new region SelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate); GetClipBox(&rect); hBrushOld = SelectBrush(hBrush); PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); // cleanup DC if(hBrushOld != NULL) SelectBrush(hBrushOld); SelectClipRgn(NULL); } void FillSolidRect(LPCRECT lpRect, COLORREF clr) { ATLASSERT(m_hDC != NULL); COLORREF clrOld = ::SetBkColor(m_hDC, clr); ATLASSERT(clrOld != CLR_INVALID); if(clrOld != CLR_INVALID) { ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL); ::SetBkColor(m_hDC, clrOld); } } void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr) { ATLASSERT(m_hDC != NULL); RECT rect = { x, y, x + cx, y + cy }; FillSolidRect(&rect, clr); } void Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight) { Draw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left, lpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight); } void Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight) { FillSolidRect(x, y, cx - 1, 1, clrTopLeft); FillSolidRect(x, y, 1, cy - 1, clrTopLeft); FillSolidRect(x + cx, y, -1, cy, clrBottomRight); FillSolidRect(x, y + cy, cx, -1, clrBottomRight); } // DIB support #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) int SetDIBitsToDevice(int x, int y, DWORD dwWidth, DWORD dwHeight, int xSrc, int ySrc, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse) { ATLASSERT(m_hDC != NULL); return ::SetDIBitsToDevice(m_hDC, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410) #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) int StretchDIBits(int x, int y, int nWidth, int nHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse, DWORD dwRop) { ATLASSERT(m_hDC != NULL); return ::StretchDIBits(m_hDC, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop); } UINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const { ATLASSERT(m_hDC != NULL); return ::GetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); } UINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors) { ATLASSERT(m_hDC != NULL); return ::SetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors); } #endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) // OpenGL support #if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) int ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd) { ATLASSERT(m_hDC != NULL); return ::ChoosePixelFormat(m_hDC, ppfd); } int DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) { ATLASSERT(m_hDC != NULL); return ::DescribePixelFormat(m_hDC, iPixelFormat, nBytes, ppfd); } int GetPixelFormat() const { ATLASSERT(m_hDC != NULL); return ::GetPixelFormat(m_hDC); } BOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd) { ATLASSERT(m_hDC != NULL); return ::SetPixelFormat(m_hDC, iPixelFormat, ppfd); } BOOL SwapBuffers() { ATLASSERT(m_hDC != NULL); return ::SwapBuffers(m_hDC); } HGLRC wglCreateContext() { ATLASSERT(m_hDC != NULL); return ::wglCreateContext(m_hDC); } HGLRC wglCreateLayerContext(int iLayerPlane) { ATLASSERT(m_hDC != NULL); return ::wglCreateLayerContext(m_hDC, iLayerPlane); } BOOL wglMakeCurrent(HGLRC hglrc) { ATLASSERT(m_hDC != NULL); return ::wglMakeCurrent(m_hDC, hglrc); } BOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase) { ATLASSERT(m_hDC != NULL); return ::wglUseFontBitmaps(m_hDC, dwFirst, dwCount, listBase); } BOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf) { ATLASSERT(m_hDC != NULL); return ::wglUseFontOutlines(m_hDC, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf); } BOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd) { ATLASSERT(m_hDC != NULL); return ::wglDescribeLayerPlane(m_hDC, iPixelFormat, iLayerPlane, nBytes, plpd); } int wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr) { ATLASSERT(m_hDC != NULL); return ::wglSetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); } int wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr) { ATLASSERT(m_hDC != NULL); return ::wglGetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr); } BOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize) { ATLASSERT(m_hDC != NULL); return ::wglRealizeLayerPalette(m_hDC, iLayerPlane, bRealize); } BOOL wglSwapLayerBuffers(UINT uPlanes) { ATLASSERT(m_hDC != NULL); return ::wglSwapLayerBuffers(m_hDC, uPlanes); } #endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE) // New for Windows 2000 only #if (_WIN32_WINNT >= 0x0500) COLORREF GetDCPenColor() const { ATLASSERT(m_hDC != NULL); return ::GetDCPenColor(m_hDC); } COLORREF SetDCPenColor(COLORREF clr) { ATLASSERT(m_hDC != NULL); return ::SetDCPenColor(m_hDC, clr); } COLORREF GetDCBrushColor() const { ATLASSERT(m_hDC != NULL); return ::GetDCBrushColor(m_hDC); } COLORREF SetDCBrushColor(COLORREF clr) { ATLASSERT(m_hDC != NULL); return ::SetDCBrushColor(m_hDC, clr); } #ifndef _WIN32_WCE DWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const { ATLASSERT(m_hDC != NULL); return ::GetFontUnicodeRanges(m_hDC, lpgs); } #endif // !_WIN32_WCE DWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const { ATLASSERT(m_hDC != NULL); return ::GetGlyphIndices(m_hDC, lpstr, cch, pgi, dwFlags); } BOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); return ::GetTextExtentPointI(m_hDC, pgiIn, cgi, lpSize); } BOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const { ATLASSERT(m_hDC != NULL); return ::GetTextExtentExPointI(m_hDC, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize); } BOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const { ATLASSERT(m_hDC != NULL); return ::GetCharWidthI(m_hDC, giFirst, cgi, pgi, lpBuffer); } BOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const { ATLASSERT(m_hDC != NULL); return ::GetCharABCWidthsI(m_hDC, giFirst, cgi, pgi, lpabc); } #endif // (_WIN32_WINNT >= 0x0500) // New for Windows 2000 and Windows 98 #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) BOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries) { ATLASSERT(m_hDC != NULL); return ::ColorCorrectPalette(m_hDC, hPalette, dwFirstEntry, dwNumOfEntries); } #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) }; typedef CDCT CDCHandle; typedef CDCT CDC; /////////////////////////////////////////////////////////////////////////////// // CDC Helpers class CPaintDC : public CDC { public: // Data members HWND m_hWnd; PAINTSTRUCT m_ps; // Constructor/destructor CPaintDC(HWND hWnd) { ATLASSERT(::IsWindow(hWnd)); m_hWnd = hWnd; m_hDC = ::BeginPaint(hWnd, &m_ps); } ~CPaintDC() { ATLASSERT(m_hDC != NULL); ATLASSERT(::IsWindow(m_hWnd)); ::EndPaint(m_hWnd, &m_ps); Detach(); } }; class CClientDC : public CDC { public: // Data members HWND m_hWnd; // Constructor/destructor CClientDC(HWND hWnd) { ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); m_hWnd = hWnd; m_hDC = ::GetDC(hWnd); } ~CClientDC() { ATLASSERT(m_hDC != NULL); ::ReleaseDC(m_hWnd, Detach()); } }; class CWindowDC : public CDC { public: // Data members HWND m_hWnd; // Constructor/destructor CWindowDC(HWND hWnd) { ATLASSERT(hWnd == NULL || ::IsWindow(hWnd)); m_hWnd = hWnd; m_hDC = ::GetWindowDC(hWnd); } ~CWindowDC() { ATLASSERT(m_hDC != NULL); ::ReleaseDC(m_hWnd, Detach()); } }; class CMemoryDC : public CDC { public: // Data members HDC m_hDCOriginal; RECT m_rcPaint; CBitmap m_bmp; HBITMAP m_hBmpOld; // Constructor/destructor CMemoryDC(HDC hDC, const RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL) { m_rcPaint = rcPaint; CreateCompatibleDC(m_hDCOriginal); ATLASSERT(m_hDC != NULL); m_bmp.CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top); ATLASSERT(m_bmp.m_hBitmap != NULL); m_hBmpOld = SelectBitmap(m_bmp); SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top); } ~CMemoryDC() { ::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY); SelectBitmap(m_hBmpOld); } }; /////////////////////////////////////////////////////////////////////////////// // Enhanced metafile support #ifndef _WIN32_WCE class CEnhMetaFileInfo { public: // Data members HENHMETAFILE m_hEMF; BYTE* m_pBits; TCHAR* m_pDesc; ENHMETAHEADER m_header; PIXELFORMATDESCRIPTOR m_pfd; // Constructor/destructor CEnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), m_hEMF(hEMF) { } ~CEnhMetaFileInfo() { delete [] m_pBits; delete [] m_pDesc; } // Operations BYTE* GetEnhMetaFileBits() { ATLASSERT(m_hEMF != NULL); UINT nBytes = ::GetEnhMetaFileBits(m_hEMF, 0, NULL); delete [] m_pBits; m_pBits = NULL; ATLTRY(m_pBits = new BYTE[nBytes]); if (m_pBits != NULL) ::GetEnhMetaFileBits(m_hEMF, nBytes, m_pBits); return m_pBits; } LPTSTR GetEnhMetaFileDescription() { ATLASSERT(m_hEMF != NULL); UINT nLen = ::GetEnhMetaFileDescription(m_hEMF, 0, NULL); delete [] m_pDesc; m_pDesc = NULL; ATLTRY(m_pDesc = new TCHAR[nLen]); if (m_pDesc != NULL) nLen = ::GetEnhMetaFileDescription(m_hEMF, nLen, m_pDesc); return m_pDesc; } ENHMETAHEADER* GetEnhMetaFileHeader() { ATLASSERT(m_hEMF != NULL); memset(&m_header, 0, sizeof(m_header)); m_header.iType = EMR_HEADER; m_header.nSize = sizeof(ENHMETAHEADER); UINT n = ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), &m_header); return (n != 0) ? &m_header : NULL; } PIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat() { ATLASSERT(m_hEMF != NULL); memset(&m_pfd, 0, sizeof(m_pfd)); UINT n = ::GetEnhMetaFilePixelFormat(m_hEMF, sizeof(m_pfd), &m_pfd); return (n != 0) ? &m_pfd : NULL; } }; template class CEnhMetaFileT { public: // Data members HENHMETAFILE m_hEMF; // Constructor/destructor CEnhMetaFileT(HENHMETAFILE hEMF = NULL) : m_hEMF(hEMF) { } ~CEnhMetaFileT() { if(t_bManaged && m_hEMF != NULL) DeleteObject(); } // Operations CEnhMetaFileT& operator =(HENHMETAFILE hEMF) { Attach(hEMF); return *this; } void Attach(HENHMETAFILE hEMF) { if(t_bManaged && m_hEMF != NULL && m_hEMF != hEMF) DeleteObject(); m_hEMF = hEMF; } HENHMETAFILE Detach() { HENHMETAFILE hEMF = m_hEMF; m_hEMF = NULL; return hEMF; } operator HENHMETAFILE() const { return m_hEMF; } bool IsNull() const { return (m_hEMF == NULL); } BOOL DeleteObject() { ATLASSERT(m_hEMF != NULL); BOOL bRet = ::DeleteEnhMetaFile(m_hEMF); m_hEMF = NULL; return bRet; } UINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const { ATLASSERT(m_hEMF != NULL); return ::GetEnhMetaFileBits(m_hEMF, cbBuffer, lpbBuffer); } UINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const { ATLASSERT(m_hEMF != NULL); return ::GetEnhMetaFileDescription(m_hEMF, cchBuffer, lpszDescription); } UINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const { ATLASSERT(m_hEMF != NULL); lpemh->iType = EMR_HEADER; lpemh->nSize = sizeof(ENHMETAHEADER); return ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), lpemh); } UINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const { ATLASSERT(m_hEMF != NULL); return ::GetEnhMetaFilePaletteEntries(m_hEMF, cEntries, lppe); } UINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const { ATLASSERT(m_hEMF != NULL); return ::GetEnhMetaFilePixelFormat(m_hEMF, cbBuffer, ppfd); } }; typedef CEnhMetaFileT CEnhMetaFileHandle; typedef CEnhMetaFileT CEnhMetaFile; class CEnhMetaFileDC : public CDC { public: // Constructor/destructor CEnhMetaFileDC() { } CEnhMetaFileDC(HDC hdc, LPCRECT lpRect) { Create(hdc, NULL, lpRect, NULL); ATLASSERT(m_hDC != NULL); } CEnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) { Create(hdcRef, lpFilename, lpRect, lpDescription); ATLASSERT(m_hDC != NULL); } ~CEnhMetaFileDC() { HENHMETAFILE hEMF = Close(); if (hEMF != NULL) ::DeleteEnhMetaFile(hEMF); } // Operations void Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription) { ATLASSERT(m_hDC == NULL); m_hDC = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription); } HENHMETAFILE Close() { HENHMETAFILE hEMF = NULL; if (m_hDC != NULL) { hEMF = ::CloseEnhMetaFile(m_hDC); m_hDC = NULL; } return hEMF; } }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // WinCE compatible clipboard CF_DIB format support functions #ifndef _WTL_NO_DIB16 #define DIBINFO16_BITFIELDS { 31744, 992, 31 } // DIBINFO16 - To avoid color table problems in WinCE we only create this type of Dib struct DIBINFO16 // a BITMAPINFO with 2 additional color bitfields { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[3]; DIBINFO16(SIZE size) { BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), size.cx, size.cy, 1, 16, BI_BITFIELDS, (DWORD)(2 * size.cx * size.cy), 0, 0, 3 }; DWORD dw[3] = DIBINFO16_BITFIELDS ; bmiHeader = bmih; SecureHelper::memcpy_x(bmiColors, sizeof(bmiColors), dw, 3 * sizeof(DWORD)); } }; // AtlxxxDibxxx minimal packed DIB implementation and helpers to copy and paste CF_DIB inline bool AtlIsDib16(LPBITMAPINFOHEADER pbmih) { return (pbmih->biBitCount == 16) && (pbmih->biCompression == BI_BITFIELDS); } inline int AtlGetDibColorTableSize(LPBITMAPINFOHEADER pbmih) { switch (pbmih->biBitCount) { case 2: case 4: case 8: return pbmih->biClrUsed ? pbmih->biClrUsed : 1 << pbmih->biBitCount; case 24: break; case 16: case 32: return pbmih->biCompression == BI_BITFIELDS ? 3 : 0; default: ATLASSERT(FALSE); // should never come here } return 0; } inline int AtlGetDibNumColors(LPBITMAPINFOHEADER pbmih) { switch (pbmih->biBitCount) { case 2: case 4: case 8: if (pbmih->biClrUsed) return pbmih->biClrUsed; else break; case 16: if (pbmih->biCompression == BI_BITFIELDS ) return 1 << 15; else break; case 24: break; case 32: if (pbmih->biCompression == BI_BITFIELDS ) return 1 << 24; else break; default: ATLASSERT(FALSE); } return 1 << pbmih->biBitCount; } inline HBITMAP AtlGetDibBitmap(LPBITMAPINFO pbmi) { CDC dc(NULL); void* pBits = NULL; LPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD); HBITMAP hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL); if (hbm != NULL) { int cbBits = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biHeight * pbmi->bmiHeader.biBitCount / 8; SecureHelper::memcpy_x(pBits, cbBits, pDibBits, pbmi->bmiHeader.biSizeImage); } return hbm; } inline HBITMAP AtlCopyBitmap(HBITMAP hbm, SIZE sizeDst, bool bAsBitmap = false) { CDC hdcSrc = CreateCompatibleDC(NULL); CDC hdcDst = CreateCompatibleDC(NULL); CBitmapHandle hbmOld = NULL, hbmOld2 = NULL, bmSrc = hbm; CBitmap bmNew = NULL; SIZE sizeSrc = { 0 }; bmSrc.GetSize(sizeSrc); hbmOld = hdcSrc.SelectBitmap(bmSrc); if (bAsBitmap) { bmNew.CreateCompatibleBitmap(hdcSrc, sizeDst.cx, sizeDst.cy); } else { DIBINFO16 dib16(sizeDst); LPVOID pBits = NULL; bmNew = CreateDIBSection(hdcDst, (const BITMAPINFO*)&dib16, DIB_RGB_COLORS, &pBits, NULL, NULL); } ATLASSERT(!bmNew.IsNull()); hbmOld2 = hdcDst.SelectBitmap(bmNew); BOOL bOK = FALSE; if ((sizeDst.cx == sizeSrc.cx) && (sizeDst.cy == sizeSrc.cy)) bOK = hdcDst.BitBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, SRCCOPY); else bOK = hdcDst.StretchBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, sizeSrc.cx, sizeSrc.cy, SRCCOPY); hdcSrc.SelectBitmap(hbmOld); hdcDst.SelectBitmap(hbmOld2); if (bOK == FALSE) bmNew.DeleteObject(); return bmNew.Detach(); } inline HLOCAL AtlCreatePackedDib16(HBITMAP hbm, SIZE size) { DIBSECTION ds = { 0 }; LPBYTE pDib = NULL; bool bCopied = false; bool bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); if ((bOK == FALSE) || (ds.dsBm.bmBits == NULL) || (AtlIsDib16(&ds.dsBmih) == FALSE) || (ds.dsBmih.biWidth != size.cx ) || (ds.dsBmih.biHeight != size.cy )) { if ((hbm = AtlCopyBitmap(hbm, size)) != NULL) { bCopied = true; bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds); } else { bOK = FALSE; } } if((bOK != FALSE) && (AtlIsDib16(&ds.dsBmih) != FALSE) && (ds.dsBm.bmBits != NULL)) { pDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage); if (pDib != NULL) { SecureHelper::memcpy_x(pDib, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage, &ds.dsBmih, sizeof(DIBINFO16)); SecureHelper::memcpy_x(pDib + sizeof(DIBINFO16), ds.dsBmih.biSizeImage, ds.dsBm.bmBits, ds.dsBmih.biSizeImage); } } if (bCopied == true) DeleteObject(hbm); return (HLOCAL)pDib; } inline bool AtlSetClipboardDib16(HBITMAP hbm, SIZE size, HWND hWnd) { ATLASSERT(::IsWindow(hWnd)); BOOL bOK = OpenClipboard(hWnd); if (bOK != FALSE) { bOK = EmptyClipboard(); if (bOK != FALSE) { HLOCAL hDib = AtlCreatePackedDib16(hbm, size); if (hDib != NULL) { bOK = SetClipboardData(CF_DIB, hDib) != NULL; if (bOK == FALSE) LocalFree(hDib); } else { bOK = FALSE; } } CloseClipboard(); } return (bOK != FALSE); } inline HBITMAP AtlGetClipboardDib(HWND hWnd) { ATLASSERT(::IsWindow(hWnd) != FALSE); HBITMAP hbm = NULL; if (OpenClipboard(hWnd) != FALSE) { LPBITMAPINFO pbmi = (LPBITMAPINFO)GetClipboardData(CF_DIB); if (pbmi != NULL) hbm = AtlGetDibBitmap(pbmi); CloseClipboard(); } return hbm; } #endif // _WTL_NO_DIB16 }; // namespace WTL #endif // __ATLGDI_H__ ================================================ FILE: WTL/atlmisc.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLMISC_H__ #define __ATLMISC_H__ #pragma once #ifndef __ATLAPP_H__ #error atlmisc.h requires atlapp.h to be included first #endif #ifdef _ATL_TMP_NO_CSTRING #define _WTL_NO_CSTRING #endif #if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) #error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined #endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING) #if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) #define _WTL_USE_CSTRING #endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING) #ifndef _WTL_NO_CSTRING #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) #error Cannot use CString floating point formatting with _ATL_MIN_CRT defined #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT) #endif // !_WTL_NO_CSTRING /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CSize // CPoint // CRect // CString // // CRecentDocumentListBase // CRecentDocumentList // CFindFile // // Global functions: // AtlGetStockPen() // AtlGetStockBrush() // AtlGetStockFont() // AtlGetStockPalette() // // AtlCompactPath() namespace WTL { #ifndef _WTL_NO_WTYPES // forward declarations class CSize; class CPoint; class CRect; /////////////////////////////////////////////////////////////////////////////// // CSize - Wrapper for Windows SIZE structure. class CSize : public SIZE { public: // Constructors CSize() { cx = 0; cy = 0; } CSize(int initCX, int initCY) { cx = initCX; cy = initCY; } CSize(SIZE initSize) { *(SIZE*)this = initSize; } CSize(POINT initPt) { *(POINT*)this = initPt; } CSize(DWORD dwSize) { cx = (short)LOWORD(dwSize); cy = (short)HIWORD(dwSize); } // Operations BOOL operator ==(SIZE size) const { return (cx == size.cx && cy == size.cy); } BOOL operator !=(SIZE size) const { return (cx != size.cx || cy != size.cy); } void operator +=(SIZE size) { cx += size.cx; cy += size.cy; } void operator -=(SIZE size) { cx -= size.cx; cy -= size.cy; } void SetSize(int CX, int CY) { cx = CX; cy = CY; } // Operators returning CSize values CSize operator +(SIZE size) const { return CSize(cx + size.cx, cy + size.cy); } CSize operator -(SIZE size) const { return CSize(cx - size.cx, cy - size.cy); } CSize operator -() const { return CSize(-cx, -cy); } // Operators returning CPoint values CPoint operator +(POINT point) const; CPoint operator -(POINT point) const; // Operators returning CRect values CRect operator +(const RECT* lpRect) const; CRect operator -(const RECT* lpRect) const; }; /////////////////////////////////////////////////////////////////////////////// // CPoint - Wrapper for Windows POINT structure. class CPoint : public POINT { public: // Constructors CPoint() { x = 0; y = 0; } CPoint(int initX, int initY) { x = initX; y = initY; } CPoint(POINT initPt) { *(POINT*)this = initPt; } CPoint(SIZE initSize) { *(SIZE*)this = initSize; } CPoint(DWORD dwPoint) { x = (short)LOWORD(dwPoint); y = (short)HIWORD(dwPoint); } // Operations void Offset(int xOffset, int yOffset) { x += xOffset; y += yOffset; } void Offset(POINT point) { x += point.x; y += point.y; } void Offset(SIZE size) { x += size.cx; y += size.cy; } BOOL operator ==(POINT point) const { return (x == point.x && y == point.y); } BOOL operator !=(POINT point) const { return (x != point.x || y != point.y); } void operator +=(SIZE size) { x += size.cx; y += size.cy; } void operator -=(SIZE size) { x -= size.cx; y -= size.cy; } void operator +=(POINT point) { x += point.x; y += point.y; } void operator -=(POINT point) { x -= point.x; y -= point.y; } void SetPoint(int X, int Y) { x = X; y = Y; } // Operators returning CPoint values CPoint operator +(SIZE size) const { return CPoint(x + size.cx, y + size.cy); } CPoint operator -(SIZE size) const { return CPoint(x - size.cx, y - size.cy); } CPoint operator -() const { return CPoint(-x, -y); } CPoint operator +(POINT point) const { return CPoint(x + point.x, y + point.y); } // Operators returning CSize values CSize operator -(POINT point) const { return CSize(x - point.x, y - point.y); } // Operators returning CRect values CRect operator +(const RECT* lpRect) const; CRect operator -(const RECT* lpRect) const; }; /////////////////////////////////////////////////////////////////////////////// // CRect - Wrapper for Windows RECT structure. class CRect : public RECT { public: // Constructors CRect() { left = 0; top = 0; right = 0; bottom = 0; } CRect(int l, int t, int r, int b) { left = l; top = t; right = r; bottom = b; } CRect(const RECT& srcRect) { ::CopyRect(this, &srcRect); } CRect(LPCRECT lpSrcRect) { ::CopyRect(this, lpSrcRect); } CRect(POINT point, SIZE size) { right = (left = point.x) + size.cx; bottom = (top = point.y) + size.cy; } CRect(POINT topLeft, POINT bottomRight) { left = topLeft.x; top = topLeft.y; right = bottomRight.x; bottom = bottomRight.y; } // Attributes (in addition to RECT members) int Width() const { return right - left; } int Height() const { return bottom - top; } CSize Size() const { return CSize(right - left, bottom - top); } CPoint& TopLeft() { return *((CPoint*)this); } CPoint& BottomRight() { return *((CPoint*)this + 1); } const CPoint& TopLeft() const { return *((CPoint*)this); } const CPoint& BottomRight() const { return *((CPoint*)this + 1); } CPoint CenterPoint() const { return CPoint((left + right) / 2, (top + bottom) / 2); } // convert between CRect and LPRECT/LPCRECT (no need for &) operator LPRECT() { return this; } operator LPCRECT() const { return this; } BOOL IsRectEmpty() const { return ::IsRectEmpty(this); } BOOL IsRectNull() const { return (left == 0 && right == 0 && top == 0 && bottom == 0); } BOOL PtInRect(POINT point) const { return ::PtInRect(this, point); } // Operations void SetRect(int x1, int y1, int x2, int y2) { ::SetRect(this, x1, y1, x2, y2); } void SetRect(POINT topLeft, POINT bottomRight) { ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); } void SetRectEmpty() { ::SetRectEmpty(this); } void CopyRect(LPCRECT lpSrcRect) { ::CopyRect(this, lpSrcRect); } BOOL EqualRect(LPCRECT lpRect) const { return ::EqualRect(this, lpRect); } void InflateRect(int x, int y) { ::InflateRect(this, x, y); } void InflateRect(SIZE size) { ::InflateRect(this, size.cx, size.cy); } void InflateRect(LPCRECT lpRect) { left -= lpRect->left; top -= lpRect->top; right += lpRect->right; bottom += lpRect->bottom; } void InflateRect(int l, int t, int r, int b) { left -= l; top -= t; right += r; bottom += b; } void DeflateRect(int x, int y) { ::InflateRect(this, -x, -y); } void DeflateRect(SIZE size) { ::InflateRect(this, -size.cx, -size.cy); } void DeflateRect(LPCRECT lpRect) { left += lpRect->left; top += lpRect->top; right -= lpRect->right; bottom -= lpRect->bottom; } void DeflateRect(int l, int t, int r, int b) { left += l; top += t; right -= r; bottom -= b; } void OffsetRect(int x, int y) { ::OffsetRect(this, x, y); } void OffsetRect(SIZE size) { ::OffsetRect(this, size.cx, size.cy); } void OffsetRect(POINT point) { ::OffsetRect(this, point.x, point.y); } void NormalizeRect() { int nTemp; if (left > right) { nTemp = left; left = right; right = nTemp; } if (top > bottom) { nTemp = top; top = bottom; bottom = nTemp; } } // absolute position of rectangle void MoveToY(int y) { bottom = Height() + y; top = y; } void MoveToX(int x) { right = Width() + x; left = x; } void MoveToXY(int x, int y) { MoveToX(x); MoveToY(y); } void MoveToXY(POINT pt) { MoveToX(pt.x); MoveToY(pt.y); } // operations that fill '*this' with result BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2) { return ::IntersectRect(this, lpRect1, lpRect2); } BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2) { return ::UnionRect(this, lpRect1, lpRect2); } BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2) { return ::SubtractRect(this, lpRectSrc1, lpRectSrc2); } // Additional Operations void operator =(const RECT& srcRect) { ::CopyRect(this, &srcRect); } BOOL operator ==(const RECT& rect) const { return ::EqualRect(this, &rect); } BOOL operator !=(const RECT& rect) const { return !::EqualRect(this, &rect); } void operator +=(POINT point) { ::OffsetRect(this, point.x, point.y); } void operator +=(SIZE size) { ::OffsetRect(this, size.cx, size.cy); } void operator +=(LPCRECT lpRect) { InflateRect(lpRect); } void operator -=(POINT point) { ::OffsetRect(this, -point.x, -point.y); } void operator -=(SIZE size) { ::OffsetRect(this, -size.cx, -size.cy); } void operator -=(LPCRECT lpRect) { DeflateRect(lpRect); } void operator &=(const RECT& rect) { ::IntersectRect(this, this, &rect); } void operator |=(const RECT& rect) { ::UnionRect(this, this, &rect); } // Operators returning CRect values CRect operator +(POINT pt) const { CRect rect(*this); ::OffsetRect(&rect, pt.x, pt.y); return rect; } CRect operator -(POINT pt) const { CRect rect(*this); ::OffsetRect(&rect, -pt.x, -pt.y); return rect; } CRect operator +(LPCRECT lpRect) const { CRect rect(this); rect.InflateRect(lpRect); return rect; } CRect operator +(SIZE size) const { CRect rect(*this); ::OffsetRect(&rect, size.cx, size.cy); return rect; } CRect operator -(SIZE size) const { CRect rect(*this); ::OffsetRect(&rect, -size.cx, -size.cy); return rect; } CRect operator -(LPCRECT lpRect) const { CRect rect(this); rect.DeflateRect(lpRect); return rect; } CRect operator &(const RECT& rect2) const { CRect rect; ::IntersectRect(&rect, this, &rect2); return rect; } CRect operator |(const RECT& rect2) const { CRect rect; ::UnionRect(&rect, this, &rect2); return rect; } CRect MulDiv(int nMultiplier, int nDivisor) const { return CRect( ::MulDiv(left, nMultiplier, nDivisor), ::MulDiv(top, nMultiplier, nDivisor), ::MulDiv(right, nMultiplier, nDivisor), ::MulDiv(bottom, nMultiplier, nDivisor)); } }; // CSize implementation inline CPoint CSize::operator +(POINT point) const { return CPoint(cx + point.x, cy + point.y); } inline CPoint CSize::operator -(POINT point) const { return CPoint(cx - point.x, cy - point.y); } inline CRect CSize::operator +(const RECT* lpRect) const { return CRect(lpRect) + *this; } inline CRect CSize::operator -(const RECT* lpRect) const { return CRect(lpRect) - *this; } // CPoint implementation inline CRect CPoint::operator +(const RECT* lpRect) const { return CRect(lpRect) + *this; } inline CRect CPoint::operator -(const RECT* lpRect) const { return CRect(lpRect) - *this; } #endif // !_WTL_NO_WTYPES // WTL::CSize or ATL::CSize scalar operators #if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) template inline CSize operator *(SIZE s, Num n) { return CSize((int)(s.cx * n), (int)(s.cy * n)); }; template inline void operator *=(SIZE & s, Num n) { s = s * n; }; template inline CSize operator /(SIZE s, Num n) { return CSize((int)(s.cx / n), (int)(s.cy / n)); }; template inline void operator /=(SIZE & s, Num n) { s = s / n; }; #endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__)) /////////////////////////////////////////////////////////////////////////////// // CString - String class #ifndef _WTL_NO_CSTRING struct CStringData { long nRefs; // reference count int nDataLength; int nAllocLength; // TCHAR data[nAllocLength] TCHAR* data() { return (TCHAR*)(this + 1); } }; // Globals // For an empty string, m_pchData will point here // (note: avoids special case of checking for NULL m_pchData) // empty string data (and locked) _declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 }; _declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData; _declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData)); class CString { public: // Constructors CString() { Init(); } CString(const CString& stringSrc) { ATLASSERT(stringSrc.GetData()->nRefs != 0); if (stringSrc.GetData()->nRefs >= 0) { ATLASSERT(stringSrc.GetData() != _atltmpDataNil); m_pchData = stringSrc.m_pchData; InterlockedIncrement(&GetData()->nRefs); } else { Init(); *this = stringSrc.m_pchData; } } CString(TCHAR ch, int nRepeat = 1) { ATLASSERT(!_istlead(ch)); // can't create a lead byte string Init(); if (nRepeat >= 1) { if(AllocBuffer(nRepeat)) { #ifdef _UNICODE for (int i = 0; i < nRepeat; i++) m_pchData[i] = ch; #else memset(m_pchData, ch, nRepeat); #endif } } } CString(LPCTSTR lpsz) { Init(); if (lpsz != NULL && HIWORD(lpsz) == NULL) { UINT nID = LOWORD((DWORD_PTR)lpsz); if (!LoadString(nID)) ATLTRACE2(atlTraceUI, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID); } else { int nLen = SafeStrlen(lpsz); if (nLen != 0) { if(AllocBuffer(nLen)) SecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR)); } } } #ifdef _UNICODE CString(LPCSTR lpsz) { Init(); #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; #else int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; #endif if (nSrcLen != 0) { if(AllocBuffer(nSrcLen)) { _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); ReleaseBuffer(); } } } #else // !_UNICODE CString(LPCWSTR lpsz) { Init(); int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; if (nSrcLen != 0) { if(AllocBuffer(nSrcLen * 2)) { _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); ReleaseBuffer(); } } } #endif // !_UNICODE CString(LPCTSTR lpch, int nLength) { Init(); if (nLength != 0) { if(AllocBuffer(nLength)) SecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR)); } } #ifdef _UNICODE CString(LPCSTR lpsz, int nLength) { Init(); if (nLength != 0) { if(AllocBuffer(nLength)) { int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength + 1); ReleaseBuffer((n >= 0) ? n : -1); } } } #else // !_UNICODE CString(LPCWSTR lpsz, int nLength) { Init(); if (nLength != 0) { if(((nLength * 2) > nLength) && AllocBuffer(nLength * 2)) { int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, (nLength * 2) + 1, NULL, NULL); ReleaseBuffer((n >= 0) ? n : -1); } } } #endif // !_UNICODE CString(const unsigned char* lpsz) { Init(); *this = (LPCSTR)lpsz; } // Attributes & Operations int GetLength() const // as an array of characters { return GetData()->nDataLength; } BOOL IsEmpty() const { return GetData()->nDataLength == 0; } void Empty() // free up the data { if (GetData()->nDataLength == 0) return; if (GetData()->nRefs >= 0) Release(); else *this = _T(""); ATLASSERT(GetData()->nDataLength == 0); ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0); } TCHAR GetAt(int nIndex) const // 0 based { ATLASSERT(nIndex >= 0); ATLASSERT(nIndex < GetData()->nDataLength); return m_pchData[nIndex]; } TCHAR operator [](int nIndex) const // same as GetAt { // same as GetAt ATLASSERT(nIndex >= 0); ATLASSERT(nIndex < GetData()->nDataLength); return m_pchData[nIndex]; } void SetAt(int nIndex, TCHAR ch) { ATLASSERT(nIndex >= 0); ATLASSERT(nIndex < GetData()->nDataLength); CopyBeforeWrite(); m_pchData[nIndex] = ch; } operator LPCTSTR() const // as a C string { return m_pchData; } // overloaded assignment CString& operator =(const CString& stringSrc) { if (m_pchData != stringSrc.m_pchData) { if ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0) { // actual copy necessary since one of the strings is locked AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData); } else { // can just copy references around Release(); ATLASSERT(stringSrc.GetData() != _atltmpDataNil); m_pchData = stringSrc.m_pchData; InterlockedIncrement(&GetData()->nRefs); } } return *this; } CString& operator =(TCHAR ch) { ATLASSERT(!_istlead(ch)); // can't set single lead byte AssignCopy(1, &ch); return *this; } #ifdef _UNICODE CString& operator =(char ch) { *this = (TCHAR)ch; return *this; } #endif CString& operator =(LPCTSTR lpsz) { ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); AssignCopy(SafeStrlen(lpsz), lpsz); return *this; } #ifdef _UNICODE CString& operator =(LPCSTR lpsz) { #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) int nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0; #else int nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0; #endif if(AllocBeforeWrite(nSrcLen)) { _mbstowcsz(m_pchData, lpsz, nSrcLen + 1); ReleaseBuffer(); } return *this; } #else // !_UNICODE CString& operator =(LPCWSTR lpsz) { int nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0; if(AllocBeforeWrite(nSrcLen * 2)) { _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1); ReleaseBuffer(); } return *this; } #endif // !_UNICODE CString& operator =(const unsigned char* lpsz) { *this = (LPCSTR)lpsz; return *this; } // string concatenation CString& operator +=(const CString& string) { ConcatInPlace(string.GetData()->nDataLength, string.m_pchData); return *this; } CString& operator +=(TCHAR ch) { ConcatInPlace(1, &ch); return *this; } #ifdef _UNICODE CString& operator +=(char ch) { *this += (TCHAR)ch; return *this; } #endif CString& operator +=(LPCTSTR lpsz) { ATLASSERT(lpsz == NULL || _IsValidString(lpsz)); ConcatInPlace(SafeStrlen(lpsz), lpsz); return *this; } friend CString __stdcall operator +(const CString& string1, const CString& string2); friend CString __stdcall operator +(const CString& string, TCHAR ch); friend CString __stdcall operator +(TCHAR ch, const CString& string); #ifdef _UNICODE friend CString __stdcall operator +(const CString& string, char ch); friend CString __stdcall operator +(char ch, const CString& string); #endif friend CString __stdcall operator +(const CString& string, LPCTSTR lpsz); friend CString __stdcall operator +(LPCTSTR lpsz, const CString& string); // string comparison int Compare(LPCTSTR lpsz) const // straight character (MBCS/Unicode aware) { return _cstrcmp(m_pchData, lpsz); } int CompareNoCase(LPCTSTR lpsz) const // ignore case (MBCS/Unicode aware) { return _cstrcmpi(m_pchData, lpsz); } #ifndef _WIN32_WCE // CString::Collate is often slower than Compare but is MBSC/Unicode // aware as well as locale-sensitive with respect to sort order. int Collate(LPCTSTR lpsz) const // NLS aware { return _cstrcoll(m_pchData, lpsz); } int CollateNoCase(LPCTSTR lpsz) const // ignore case { return _cstrcolli(m_pchData, lpsz); } #endif // !_WIN32_WCE // simple sub-string extraction CString Mid(int nFirst, int nCount) const { // out-of-bounds requests return sensible things if (nFirst < 0) nFirst = 0; if (nCount < 0) nCount = 0; if (nFirst + nCount > GetData()->nDataLength) nCount = GetData()->nDataLength - nFirst; if (nFirst > GetData()->nDataLength) nCount = 0; CString dest; AllocCopy(dest, nCount, nFirst, 0); return dest; } CString Mid(int nFirst) const { return Mid(nFirst, GetData()->nDataLength - nFirst); } CString Left(int nCount) const { if (nCount < 0) nCount = 0; else if (nCount > GetData()->nDataLength) nCount = GetData()->nDataLength; CString dest; AllocCopy(dest, nCount, 0, 0); return dest; } CString Right(int nCount) const { if (nCount < 0) nCount = 0; else if (nCount > GetData()->nDataLength) nCount = GetData()->nDataLength; CString dest; AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0); return dest; } CString SpanIncluding(LPCTSTR lpszCharSet) const // strspn equivalent { ATLASSERT(_IsValidString(lpszCharSet)); return Left(_cstrspn(m_pchData, lpszCharSet)); } CString SpanExcluding(LPCTSTR lpszCharSet) const // strcspn equivalent { ATLASSERT(_IsValidString(lpszCharSet)); return Left(_cstrcspn(m_pchData, lpszCharSet)); } // upper/lower/reverse conversion void MakeUpper() { CopyBeforeWrite(); CharUpper(m_pchData); } void MakeLower() { CopyBeforeWrite(); CharLower(m_pchData); } void MakeReverse() { CopyBeforeWrite(); _cstrrev(m_pchData); } // trimming whitespace (either side) void TrimRight() { CopyBeforeWrite(); // find beginning of trailing spaces by starting at beginning (DBCS aware) LPTSTR lpsz = m_pchData; LPTSTR lpszLast = NULL; while (*lpsz != _T('\0')) { if (_cstrisspace(*lpsz)) { if (lpszLast == NULL) lpszLast = lpsz; } else { lpszLast = NULL; } lpsz = ::CharNext(lpsz); } if (lpszLast != NULL) { // truncate at trailing space start *lpszLast = _T('\0'); GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); } } void TrimLeft() { CopyBeforeWrite(); // find first non-space character LPCTSTR lpsz = m_pchData; while (_cstrisspace(*lpsz)) lpsz = ::CharNext(lpsz); // fix up data and length int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); GetData()->nDataLength = nDataLength; } // remove continuous occurrences of chTarget starting from right void TrimRight(TCHAR chTarget) { // find beginning of trailing matches // by starting at beginning (DBCS aware) CopyBeforeWrite(); LPTSTR lpsz = m_pchData; LPTSTR lpszLast = NULL; while (*lpsz != _T('\0')) { if (*lpsz == chTarget) { if (lpszLast == NULL) lpszLast = lpsz; } else lpszLast = NULL; lpsz = ::CharNext(lpsz); } if (lpszLast != NULL) { // truncate at left-most matching character *lpszLast = _T('\0'); GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); } } // remove continuous occcurrences of characters in passed string, starting from right void TrimRight(LPCTSTR lpszTargetList) { // find beginning of trailing matches by starting at beginning (DBCS aware) CopyBeforeWrite(); LPTSTR lpsz = m_pchData; LPTSTR lpszLast = NULL; while (*lpsz != _T('\0')) { TCHAR* pNext = ::CharNext(lpsz); if(pNext > lpsz + 1) { if (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL) { if (lpszLast == NULL) lpszLast = lpsz; } else { lpszLast = NULL; } } else { if (_cstrchr(lpszTargetList, *lpsz) != NULL) { if (lpszLast == NULL) lpszLast = lpsz; } else { lpszLast = NULL; } } lpsz = pNext; } if (lpszLast != NULL) { // truncate at left-most matching character *lpszLast = _T('\0'); GetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData); } } // remove continuous occurrences of chTarget starting from left void TrimLeft(TCHAR chTarget) { // find first non-matching character CopyBeforeWrite(); LPCTSTR lpsz = m_pchData; while (chTarget == *lpsz) lpsz = ::CharNext(lpsz); if (lpsz != m_pchData) { // fix up data and length int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); GetData()->nDataLength = nDataLength; } } // remove continuous occcurrences of characters in passed string, starting from left void TrimLeft(LPCTSTR lpszTargets) { // if we're not trimming anything, we're not doing any work if (SafeStrlen(lpszTargets) == 0) return; CopyBeforeWrite(); LPCTSTR lpsz = m_pchData; while (*lpsz != _T('\0')) { TCHAR* pNext = ::CharNext(lpsz); if(pNext > lpsz + 1) { if (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL) break; } else { if (_cstrchr(lpszTargets, *lpsz) == NULL) break; } lpsz = pNext; } if (lpsz != m_pchData) { // fix up data and length int nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData); SecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR)); GetData()->nDataLength = nDataLength; } } // advanced manipulation // replace occurrences of chOld with chNew int Replace(TCHAR chOld, TCHAR chNew) { int nCount = 0; // short-circuit the nop case if (chOld != chNew) { // otherwise modify each character that matches in the string CopyBeforeWrite(); LPTSTR psz = m_pchData; LPTSTR pszEnd = psz + GetData()->nDataLength; while (psz < pszEnd) { // replace instances of the specified character only if (*psz == chOld) { *psz = chNew; nCount++; } psz = ::CharNext(psz); } } return nCount; } // replace occurrences of substring lpszOld with lpszNew; // empty lpszNew removes instances of lpszOld int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew) { // can't have empty or NULL lpszOld int nSourceLen = SafeStrlen(lpszOld); if (nSourceLen == 0) return 0; int nReplacementLen = SafeStrlen(lpszNew); // loop once to figure out the size of the result string int nCount = 0; LPTSTR lpszStart = m_pchData; LPTSTR lpszEnd = m_pchData + GetData()->nDataLength; LPTSTR lpszTarget = NULL; while (lpszStart < lpszEnd) { while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) { nCount++; lpszStart = lpszTarget + nSourceLen; } lpszStart += lstrlen(lpszStart) + 1; } // if any changes were made, make them if (nCount > 0) { CopyBeforeWrite(); // if the buffer is too small, just allocate a new buffer (slow but sure) int nOldLength = GetData()->nDataLength; int nNewLength = nOldLength + (nReplacementLen - nSourceLen) * nCount; if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1) { CStringData* pOldData = GetData(); LPTSTR pstr = m_pchData; if(!AllocBuffer(nNewLength)) return -1; SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR)); CString::Release(pOldData); } // else, we just do it in-place lpszStart = m_pchData; lpszEnd = m_pchData + GetData()->nDataLength; // loop again to actually do the work while (lpszStart < lpszEnd) { while ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL) { int nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen); int cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData); SecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR)); SecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR)); lpszStart = lpszTarget + nReplacementLen; lpszStart[nBalance] = _T('\0'); nOldLength += (nReplacementLen - nSourceLen); } lpszStart += lstrlen(lpszStart) + 1; } ATLASSERT(m_pchData[nNewLength] == _T('\0')); GetData()->nDataLength = nNewLength; } return nCount; } // remove occurrences of chRemove int Remove(TCHAR chRemove) { CopyBeforeWrite(); LPTSTR pstrSource = m_pchData; LPTSTR pstrDest = m_pchData; LPTSTR pstrEnd = m_pchData + GetData()->nDataLength; while (pstrSource < pstrEnd) { if (*pstrSource != chRemove) { *pstrDest = *pstrSource; pstrDest = ::CharNext(pstrDest); } pstrSource = ::CharNext(pstrSource); } *pstrDest = _T('\0'); int nCount = (int)(DWORD_PTR)(pstrSource - pstrDest); GetData()->nDataLength -= nCount; return nCount; } // insert character at zero-based index; concatenates if index is past end of string int Insert(int nIndex, TCHAR ch) { CopyBeforeWrite(); if (nIndex < 0) nIndex = 0; int nNewLength = GetData()->nDataLength; if (nIndex > nNewLength) nIndex = nNewLength; nNewLength++; if (GetData()->nAllocLength < nNewLength) { CStringData* pOldData = GetData(); LPTSTR pstr = m_pchData; if(!AllocBuffer(nNewLength)) return -1; SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR)); CString::Release(pOldData); } // move existing bytes down SecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR)); m_pchData[nIndex] = ch; GetData()->nDataLength = nNewLength; return nNewLength; } // insert substring at zero-based index; concatenates if index is past end of string int Insert(int nIndex, LPCTSTR pstr) { if (nIndex < 0) nIndex = 0; int nInsertLength = SafeStrlen(pstr); int nNewLength = GetData()->nDataLength; if (nInsertLength > 0) { CopyBeforeWrite(); if (nIndex > nNewLength) nIndex = nNewLength; nNewLength += nInsertLength; if (GetData()->nAllocLength < nNewLength) { CStringData* pOldData = GetData(); LPTSTR pstrTmp = m_pchData; if(!AllocBuffer(nNewLength)) return -1; SecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstrTmp, (pOldData->nDataLength + 1) * sizeof(TCHAR)); CString::Release(pOldData); } // move existing bytes down SecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR)); SecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR)); GetData()->nDataLength = nNewLength; } return nNewLength; } // delete nCount characters starting at zero-based index int Delete(int nIndex, int nCount = 1) { if (nIndex < 0) nIndex = 0; int nLength = GetData()->nDataLength; if (nCount > 0 && nIndex < nLength) { if((nIndex + nCount) > nLength) nCount = nLength - nIndex; CopyBeforeWrite(); int nBytesToCopy = nLength - (nIndex + nCount) + 1; SecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR)); nLength -= nCount; GetData()->nDataLength = nLength; } return nLength; } // searching (return starting index, or -1 if not found) // look for a single character match int Find(TCHAR ch) const // like "C" strchr { return Find(ch, 0); } int ReverseFind(TCHAR ch) const { // find last single character LPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch); // return -1 if not found, distance from beginning otherwise return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); } int Find(TCHAR ch, int nStart) const // starting at index { int nLength = GetData()->nDataLength; if (nStart < 0 || nStart >= nLength) return -1; // find first single character LPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch); // return -1 if not found and index otherwise return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); } int FindOneOf(LPCTSTR lpszCharSet) const { ATLASSERT(_IsValidString(lpszCharSet)); LPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet); return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); } // look for a specific sub-string // find a sub-string (like strstr) int Find(LPCTSTR lpszSub) const // like "C" strstr { return Find(lpszSub, 0); } int Find(LPCTSTR lpszSub, int nStart) const // starting at index { ATLASSERT(_IsValidString(lpszSub)); int nLength = GetData()->nDataLength; if (nStart < 0 || nStart > nLength) return -1; // find first matching substring LPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub); // return -1 for not found, distance from beginning otherwise return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData); } // Concatentation for non strings CString& Append(int n) { const int cchBuff = 12; TCHAR szBuffer[cchBuff] = { 0 }; SecureHelper::wsprintf_x(szBuffer, cchBuff, _T("%d"), n); ConcatInPlace(SafeStrlen(szBuffer), szBuffer); return *this; } // simple formatting // formatting (using wsprintf style formatting) BOOL __cdecl Format(LPCTSTR lpszFormat, ...) { ATLASSERT(_IsValidString(lpszFormat)); va_list argList; va_start(argList, lpszFormat); BOOL bRet = FormatV(lpszFormat, argList); va_end(argList); return bRet; } BOOL __cdecl Format(UINT nFormatID, ...) { CString strFormat; BOOL bRet = strFormat.LoadString(nFormatID); ATLASSERT(bRet != 0); va_list argList; va_start(argList, nFormatID); bRet = FormatV(strFormat, argList); va_end(argList); return bRet; } BOOL FormatV(LPCTSTR lpszFormat, va_list argList) { ATLASSERT(_IsValidString(lpszFormat)); enum _FormatModifiers { FORCE_ANSI = 0x10000, FORCE_UNICODE = 0x20000, FORCE_INT64 = 0x40000 }; va_list argListSave = argList; // make a guess at the maximum length of the resulting string int nMaxLen = 0; for (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) { // handle '%' character, but watch out for '%%' if (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%')) { nMaxLen += (int)(::CharNext(lpsz) - lpsz); continue; } int nItemLen = 0; // handle '%' character with format int nWidth = 0; for (; *lpsz != _T('\0'); lpsz = ::CharNext(lpsz)) { // check for valid flags if (*lpsz == _T('#')) nMaxLen += 2; // for '0x' else if (*lpsz == _T('*')) nWidth = va_arg(argList, int); else if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' ')) ; else // hit non-flag character break; } // get width and skip it if (nWidth == 0) { // width indicated by nWidth = _cstrtoi(lpsz); for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) ; } ATLASSERT(nWidth >= 0); int nPrecision = 0; if (*lpsz == _T('.')) { // skip past '.' separator (width.precision) lpsz = ::CharNext(lpsz); // get precision and skip it if (*lpsz == _T('*')) { nPrecision = va_arg(argList, int); lpsz = ::CharNext(lpsz); } else { nPrecision = _cstrtoi(lpsz); for (; *lpsz != _T('\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz)) ; } ATLASSERT(nPrecision >= 0); } // should be on type modifier or specifier int nModifier = 0; if(lpsz[0] == _T('I')) { if((lpsz[1] == _T('6')) && (lpsz[2] == _T('4'))) { lpsz += 3; nModifier = FORCE_INT64; } else if((lpsz[1] == _T('3')) && (lpsz[2] == _T('2'))) { lpsz += 3; } else { lpsz++; if(sizeof(size_t) == 8) nModifier = FORCE_INT64; } } else { switch (*lpsz) { // modifiers that affect size case _T('h'): nModifier = FORCE_ANSI; lpsz = ::CharNext(lpsz); break; case _T('l'): nModifier = FORCE_UNICODE; lpsz = ::CharNext(lpsz); break; // modifiers that do not affect size case _T('F'): case _T('N'): case _T('L'): lpsz = ::CharNext(lpsz); break; } } // now should be on specifier switch (*lpsz | nModifier) { // single characters case _T('c'): case _T('C'): nItemLen = 2; va_arg(argList, TCHAR); break; case _T('c') | FORCE_ANSI: case _T('C') | FORCE_ANSI: nItemLen = 2; va_arg(argList, char); break; case _T('c') | FORCE_UNICODE: case _T('C') | FORCE_UNICODE: nItemLen = 2; va_arg(argList, WCHAR); break; // strings case _T('s'): { LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR); if (pstrNextArg == NULL) { nItemLen = 6; // "(null)" } else { nItemLen = lstrlen(pstrNextArg); nItemLen = __max(1, nItemLen); } break; } case _T('S'): { #ifndef _UNICODE LPWSTR pstrNextArg = va_arg(argList, LPWSTR); if (pstrNextArg == NULL) { nItemLen = 6; // "(null)" } else { nItemLen = (int)wcslen(pstrNextArg); nItemLen = __max(1, nItemLen); } #else // _UNICODE LPCSTR pstrNextArg = va_arg(argList, LPCSTR); if (pstrNextArg == NULL) { nItemLen = 6; // "(null)" } else { #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) nItemLen = ATL::lstrlenA(pstrNextArg); #else nItemLen = lstrlenA(pstrNextArg); #endif nItemLen = __max(1, nItemLen); } #endif // _UNICODE break; } case _T('s') | FORCE_ANSI: case _T('S') | FORCE_ANSI: { LPCSTR pstrNextArg = va_arg(argList, LPCSTR); if (pstrNextArg == NULL) { nItemLen = 6; // "(null)" } else { #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800) nItemLen = ATL::lstrlenA(pstrNextArg); #else nItemLen = lstrlenA(pstrNextArg); #endif nItemLen = __max(1, nItemLen); } break; } case _T('s') | FORCE_UNICODE: case _T('S') | FORCE_UNICODE: { LPWSTR pstrNextArg = va_arg(argList, LPWSTR); if (pstrNextArg == NULL) { nItemLen = 6; // "(null)" } else { nItemLen = (int)wcslen(pstrNextArg); nItemLen = __max(1, nItemLen); } break; } } // adjust nItemLen for strings if (nItemLen != 0) { nItemLen = __max(nItemLen, nWidth); if (nPrecision != 0) nItemLen = __min(nItemLen, nPrecision); } else { switch (*lpsz) { // integers case _T('d'): case _T('i'): case _T('u'): case _T('x'): case _T('X'): case _T('o'): if (nModifier & FORCE_INT64) va_arg(argList, __int64); else va_arg(argList, int); nItemLen = 32; nItemLen = __max(nItemLen, nWidth + nPrecision); break; #ifndef _ATL_USE_CSTRING_FLOAT case _T('e'): case _T('E'): case _T('f'): case _T('g'): case _T('G'): ATLASSERT(!"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class."); #ifndef _DEBUG ::OutputDebugString(_T("Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.")); #ifndef _WIN32_WCE ::DebugBreak(); #else // CE specific DebugBreak(); #endif // _WIN32_WCE #endif // !_DEBUG break; #else // _ATL_USE_CSTRING_FLOAT case _T('e'): case _T('E'): case _T('g'): case _T('G'): va_arg(argList, double); nItemLen = 128; nItemLen = __max(nItemLen, nWidth + nPrecision); break; case _T('f'): { double f = va_arg(argList, double); // 312 == strlen("-1+(309 zeroes).") // 309 zeroes == max precision of a double // 6 == adjustment in case precision is not specified, // which means that the precision defaults to 6 int cchLen = __max(nWidth, 312 + nPrecision + 6); CTempBuffer buff; LPTSTR pszTemp = buff.Allocate(cchLen); if(pszTemp != NULL) { SecureHelper::sprintf_x(pszTemp, cchLen, _T("%*.*f"), nWidth, nPrecision + 6, f); nItemLen = (int)_tcslen(pszTemp); } else { nItemLen = cchLen; } } break; #endif // _ATL_USE_CSTRING_FLOAT case _T('p'): va_arg(argList, void*); nItemLen = 32; nItemLen = __max(nItemLen, nWidth + nPrecision); break; // no output case _T('n'): va_arg(argList, int*); break; default: ATLASSERT(FALSE); // unknown formatting option } } // adjust nMaxLen for output nItemLen nMaxLen += nItemLen; } if(GetBuffer(nMaxLen) == NULL) return FALSE; #ifndef _ATL_USE_CSTRING_FLOAT int nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); #else // _ATL_USE_CSTRING_FLOAT int nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave); #endif // _ATL_USE_CSTRING_FLOAT nRet; // ref ATLASSERT(nRet <= GetAllocLength()); ReleaseBuffer(); va_end(argListSave); return TRUE; } // formatting for localization (uses FormatMessage API) // formatting (using FormatMessage style formatting) BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...) { // format message into temporary buffer lpszTemp va_list argList; va_start(argList, lpszFormat); LPTSTR lpszTemp = NULL; BOOL bRet = TRUE; if ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL)) bRet = FALSE; // assign lpszTemp into the resulting string and free the temporary *this = lpszTemp; LocalFree(lpszTemp); va_end(argList); return bRet; } BOOL __cdecl FormatMessage(UINT nFormatID, ...) { // get format string from string table CString strFormat; BOOL bRetTmp = strFormat.LoadString(nFormatID); bRetTmp; // ref ATLASSERT(bRetTmp != 0); // format message into temporary buffer lpszTemp va_list argList; va_start(argList, nFormatID); LPTSTR lpszTemp = NULL; BOOL bRet = TRUE; if ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL)) bRet = FALSE; // assign lpszTemp into the resulting string and free lpszTemp *this = lpszTemp; LocalFree(lpszTemp); va_end(argList); return bRet; } // Windows support BOOL LoadString(UINT nID) // load from string resource (255 chars max.) { #ifdef _UNICODE const int CHAR_FUDGE = 1; // one TCHAR unused is good enough #else const int CHAR_FUDGE = 2; // two BYTES unused for case of DBC last char #endif // try fixed buffer first (to avoid wasting space in the heap) TCHAR szTemp[256] = { 0 }; int nCount = sizeof(szTemp) / sizeof(szTemp[0]); int nLen = _LoadString(nID, szTemp, nCount); if (nCount - nLen > CHAR_FUDGE) { *this = szTemp; return (nLen > 0); } // try buffer size of 512, then larger size until entire string is retrieved int nSize = 256; do { nSize += 256; LPTSTR lpstr = GetBuffer(nSize - 1); if(lpstr == NULL) { nLen = 0; break; } nLen = _LoadString(nID, lpstr, nSize); } while (nSize - nLen <= CHAR_FUDGE); ReleaseBuffer(); return (nLen > 0); } #ifndef _UNICODE // ANSI <-> OEM support (convert string in place) void AnsiToOem() { CopyBeforeWrite(); ::AnsiToOem(m_pchData, m_pchData); } void OemToAnsi() { CopyBeforeWrite(); ::OemToAnsi(m_pchData, m_pchData); } #endif #ifndef _ATL_NO_COM // OLE BSTR support (use for OLE automation) BSTR AllocSysString() const { #if defined(_UNICODE) || defined(OLE2ANSI) BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength); #else int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, NULL, NULL); BSTR bstr = ::SysAllocStringLen(NULL, nLen); if(bstr != NULL) MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen); #endif return bstr; } BSTR SetSysString(BSTR* pbstr) const { #if defined(_UNICODE) || defined(OLE2ANSI) ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength); #else int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, NULL, NULL); if(::SysReAllocStringLen(pbstr, NULL, nLen)) MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen); #endif ATLASSERT(*pbstr != NULL); return *pbstr; } #endif // !_ATL_NO_COM // Access to string implementation buffer as "C" character array LPTSTR GetBuffer(int nMinBufLength) { ATLASSERT(nMinBufLength >= 0); if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength) { // we have to grow the buffer CStringData* pOldData = GetData(); int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it if (nMinBufLength < nOldLen) nMinBufLength = nOldLen; if(!AllocBuffer(nMinBufLength)) return NULL; SecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR)); GetData()->nDataLength = nOldLen; CString::Release(pOldData); } ATLASSERT(GetData()->nRefs <= 1); // return a pointer to the character storage for this string ATLASSERT(m_pchData != NULL); return m_pchData; } void ReleaseBuffer(int nNewLength = -1) { CopyBeforeWrite(); // just in case GetBuffer was not called if (nNewLength == -1) nNewLength = lstrlen(m_pchData); // zero terminated ATLASSERT(nNewLength <= GetData()->nAllocLength); GetData()->nDataLength = nNewLength; m_pchData[nNewLength] = _T('\0'); } LPTSTR GetBufferSetLength(int nNewLength) { ATLASSERT(nNewLength >= 0); if(GetBuffer(nNewLength) == NULL) return NULL; GetData()->nDataLength = nNewLength; m_pchData[nNewLength] = _T('\0'); return m_pchData; } void FreeExtra() { ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); if (GetData()->nDataLength != GetData()->nAllocLength) { CStringData* pOldData = GetData(); if(AllocBuffer(GetData()->nDataLength)) { SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR)); ATLASSERT(m_pchData[GetData()->nDataLength] == _T('\0')); CString::Release(pOldData); } } ATLASSERT(GetData() != NULL); } // Use LockBuffer/UnlockBuffer to turn refcounting off LPTSTR LockBuffer() { LPTSTR lpsz = GetBuffer(0); if(lpsz != NULL) GetData()->nRefs = -1; return lpsz; } void UnlockBuffer() { ATLASSERT(GetData()->nRefs == -1); if (GetData() != _atltmpDataNil) GetData()->nRefs = 1; } // Implementation public: ~CString() // free any attached data { if (GetData() != _atltmpDataNil) { if (InterlockedDecrement(&GetData()->nRefs) <= 0) delete[] (BYTE*)GetData(); } } int GetAllocLength() const { return GetData()->nAllocLength; } static BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1) { return (lpsz != NULL) ? TRUE : FALSE; } protected: LPTSTR m_pchData; // pointer to ref counted string data // implementation helpers CStringData* GetData() const { ATLASSERT(m_pchData != NULL); return ((CStringData*)m_pchData) - 1; } void Init() { m_pchData = _GetEmptyString().m_pchData; } BOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const { // will clone the data attached to this string // allocating 'nExtraLen' characters // Places results in uninitialized string 'dest' // Will copy the part or all of original data to start of new string BOOL bRet = FALSE; int nNewLen = nCopyLen + nExtraLen; if (nNewLen == 0) { dest.Init(); bRet = TRUE; } else if(nNewLen >= nCopyLen) { if(dest.AllocBuffer(nNewLen)) { SecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR)); bRet = TRUE; } } return bRet; } // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length BOOL AllocBuffer(int nLen) { ATLASSERT(nLen >= 0); ATLASSERT(nLen <= INT_MAX - 1); // max size (enough room for 1 extra) if (nLen == 0) { Init(); } else { CStringData* pData = NULL; ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]); if(pData == NULL) return FALSE; pData->nRefs = 1; pData->data()[nLen] = _T('\0'); pData->nDataLength = nLen; pData->nAllocLength = nLen; m_pchData = pData->data(); } return TRUE; } // Assignment operators // All assign a new value to the string // (a) first see if the buffer is big enough // (b) if enough room, copy on top of old buffer, set size and type // (c) otherwise free old string data, and create a new one // // All routines return the new string (but as a 'const CString&' so that // assigning it again will cause a copy, eg: s1 = s2 = "hi there". // void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData) { if(AllocBeforeWrite(nSrcLen)) { SecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); GetData()->nDataLength = nSrcLen; m_pchData[nSrcLen] = _T('\0'); } } // Concatenation // NOTE: "operator +" is done as friend functions for simplicity // There are three variants: // CString + CString // and for ? = TCHAR, LPCTSTR // CString + ? // ? + CString BOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data) { // -- master concatenation routine // Concatenate two sources // -- assume that 'this' is a new CString object BOOL bRet = TRUE; int nNewLen = nSrc1Len + nSrc2Len; if(nNewLen < nSrc1Len || nNewLen < nSrc2Len) { bRet = FALSE; } else if(nNewLen != 0) { bRet = AllocBuffer(nNewLen); if (bRet) { SecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR)); SecureHelper::memcpy_x(m_pchData + nSrc1Len, (nNewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR)); } } return bRet; } void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData) { // -- the main routine for += operators // concatenating an empty string is a no-op! if (nSrcLen == 0) return; // if the buffer is too small, or we have a width mis-match, just // allocate a new buffer (slow but sure) if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength) { // we have to grow the buffer, use the ConcatCopy routine CStringData* pOldData = GetData(); if (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData)) { ATLASSERT(pOldData != NULL); CString::Release(pOldData); } } else { // fast concatenation when buffer big enough SecureHelper::memcpy_x(m_pchData + GetData()->nDataLength, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR)); GetData()->nDataLength += nSrcLen; ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength); m_pchData[GetData()->nDataLength] = _T('\0'); } } void CopyBeforeWrite() { if (GetData()->nRefs > 1) { CStringData* pData = GetData(); Release(); if(AllocBuffer(pData->nDataLength)) SecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR)); } ATLASSERT(GetData()->nRefs <= 1); } BOOL AllocBeforeWrite(int nLen) { BOOL bRet = TRUE; if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength) { Release(); bRet = AllocBuffer(nLen); } ATLASSERT(GetData()->nRefs <= 1); return bRet; } void Release() { if (GetData() != _atltmpDataNil) { ATLASSERT(GetData()->nRefs != 0); if (InterlockedDecrement(&GetData()->nRefs) <= 0) delete[] (BYTE*)GetData(); Init(); } } static void PASCAL Release(CStringData* pData) { if (pData != _atltmpDataNil) { ATLASSERT(pData->nRefs != 0); if (InterlockedDecrement(&pData->nRefs) <= 0) delete[] (BYTE*)pData; } } static int PASCAL SafeStrlen(LPCTSTR lpsz) { return (lpsz == NULL) ? 0 : lstrlen(lpsz); } static int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf) { #ifdef _DEBUG // LoadString without annoying warning from the Debug kernel if the // segment containing the string is not present if (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID >> 4) + 1), RT_STRING) == NULL) { lpszBuf[0] = _T('\0'); return 0; // not found } #endif // _DEBUG int nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID, lpszBuf, nMaxBuf); if (nLen == 0) lpszBuf[0] = _T('\0'); return nLen; } static const CString& __stdcall _GetEmptyString() { return *(CString*)&_atltmpPchNil; } // CString conversion helpers static int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count) { if (count == 0 && mbstr != NULL) return 0; int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL); ATLASSERT(mbstr == NULL || result <= (int)count); if ((mbstr != NULL) && (result > 0)) mbstr[result - 1] = 0; return result; } static int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count) { if (count == 0 && wcstr != NULL) return 0; int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count); ATLASSERT(wcstr == NULL || result <= (int)count); if ((wcstr != NULL) && (result > 0)) wcstr[result - 1] = 0; return result; } // Helpers to avoid CRT startup code #ifdef _ATL_MIN_CRT static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) { // strchr for '\0' should succeed while (*p != 0) { if (*p == ch) break; p = ::CharNext(p); } return (*p == ch) ? p : NULL; } static TCHAR* _cstrrev(TCHAR* pStr) { // optimize NULL, zero-length, and single-char case if ((pStr == NULL) || (pStr[0] == _T('\0')) || (pStr[1] == _T('\0'))) return pStr; TCHAR* p = pStr; while (*p != 0) { TCHAR* pNext = ::CharNext(p); if(pNext > p + 1) { char p1 = *(char*)p; *(char*)p = *(char*)(p + 1); *(char*)(p + 1) = p1; } p = pNext; } p--; TCHAR* q = pStr; while (q < p) { TCHAR t = *q; *q = *p; *p = t; q++; p--; } return pStr; } static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) { int nLen = lstrlen(pCharSet); if (nLen == 0) return (TCHAR*)pStr; const TCHAR* pRet = NULL; const TCHAR* pCur = pStr; while((pCur = _cstrchr(pCur, *pCharSet)) != NULL) { if(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0) { pRet = pCur; break; } pCur = ::CharNext(pCur); } return pRet; } static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) { int nRet = 0; const TCHAR* p = pStr; while (*p != 0) { const TCHAR* pNext = ::CharNext(p); if(pNext > p + 1) { if(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL) break; nRet += 2; } else { if(_cstrchr(pCharSet, *p) == NULL) break; nRet++; } p = pNext; } return nRet; } static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) { int nRet = 0; TCHAR* p = (TCHAR*)pStr; while (*p != 0) { TCHAR* pNext = ::CharNext(p); if(pNext > p + 1) { if(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL) break; nRet += 2; } else { if(_cstrchr(pCharSet, *p) != NULL) break; nRet++; } p = pNext; } return nRet; } static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) { int n = _cstrcspn(p, lpszCharSet); return (p[n] != 0) ? &p[n] : NULL; } static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) { return lstrcmp(pstrOne, pstrOther); } static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) { return lstrcmpi(pstrOne, pstrOther); } static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) { int nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1); ATLASSERT(nRet != 0); return nRet - 2; // convert to strcmp convention } static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) { int nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1); ATLASSERT(nRet != 0); return nRet - 2; // convert to strcmp convention } #else // !_ATL_MIN_CRT static const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch) { return _tcschr(p, ch); } static TCHAR* _cstrrev(TCHAR* pStr) { return _tcsrev(pStr); } static const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet) { return _tcsstr(pStr, pCharSet); } static int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet) { return (int)_tcsspn(pStr, pCharSet); } static int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet) { return (int)_tcscspn(pStr, pCharSet); } static const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet) { return _tcspbrk(p, lpszCharSet); } static int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther) { return _tcscmp(pstrOne, pstrOther); } static int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther) { return _tcsicmp(pstrOne, pstrOther); } #ifndef _WIN32_WCE static int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther) { return _tcscoll(pstrOne, pstrOther); } static int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther) { return _tcsicoll(pstrOne, pstrOther); } #endif // !_WIN32_WCE #endif // !_ATL_MIN_CRT static const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch) { return MinCrtHelper::_strrchr(p, ch); } static int _cstrisdigit(TCHAR ch) { return MinCrtHelper::_isdigit(ch); } static int _cstrisspace(TCHAR ch) { return MinCrtHelper::_isspace(ch); } static int _cstrtoi(const TCHAR* nptr) { return MinCrtHelper::_atoi(nptr); } static const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2) { const TCHAR* lpsz = NULL; while (*p != 0) { if (*p == ch1 && *(p + 1) == ch2) { lpsz = p; break; } p = ::CharNext(p); } return lpsz; } }; // Compare helpers inline bool __stdcall operator ==(const CString& s1, const CString& s2) { return s1.Compare(s2) == 0; } inline bool __stdcall operator ==(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) == 0; } inline bool __stdcall operator ==(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) == 0; } inline bool __stdcall operator !=(const CString& s1, const CString& s2) { return s1.Compare(s2) != 0; } inline bool __stdcall operator !=(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) != 0; } inline bool __stdcall operator !=(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) != 0; } inline bool __stdcall operator <(const CString& s1, const CString& s2) { return s1.Compare(s2) < 0; } inline bool __stdcall operator <(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) < 0; } inline bool __stdcall operator <(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) > 0; } inline bool __stdcall operator >(const CString& s1, const CString& s2) { return s1.Compare(s2) > 0; } inline bool __stdcall operator >(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) > 0; } inline bool __stdcall operator >(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) < 0; } inline bool __stdcall operator <=(const CString& s1, const CString& s2) { return s1.Compare(s2) <= 0; } inline bool __stdcall operator <=(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) <= 0; } inline bool __stdcall operator <=(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) >= 0; } inline bool __stdcall operator >=(const CString& s1, const CString& s2) { return s1.Compare(s2) >= 0; } inline bool __stdcall operator >=(const CString& s1, LPCTSTR s2) { return s1.Compare(s2) >= 0; } inline bool __stdcall operator >=(LPCTSTR s1, const CString& s2) { return s2.Compare(s1) <= 0; } // CString "operator +" functions inline CString __stdcall operator +(const CString& string1, const CString& string2) { CString s; s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData); return s; } inline CString __stdcall operator +(const CString& string, TCHAR ch) { CString s; s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch); return s; } inline CString __stdcall operator +(TCHAR ch, const CString& string) { CString s; s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData); return s; } #ifdef _UNICODE inline CString __stdcall operator +(const CString& string, char ch) { return string + (TCHAR)ch; } inline CString __stdcall operator +(char ch, const CString& string) { return (TCHAR)ch + string; } #endif // _UNICODE inline CString __stdcall operator +(const CString& string, LPCTSTR lpsz) { ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); CString s; s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz); return s; } inline CString __stdcall operator +(LPCTSTR lpsz, const CString& string) { ATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz)); CString s; s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData); return s; } #endif // !_WTL_NO_CSTRING /////////////////////////////////////////////////////////////////////////////// // CRecentDocumentList - MRU List Support #ifndef _WIN32_WCE #ifndef _WTL_MRUEMPTY_TEXT #define _WTL_MRUEMPTY_TEXT _T("(empty)") #endif // forward declaration inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen); template class CRecentDocumentListBase { public: // Declarations struct _DocEntry { TCHAR szDocName[t_cchItemLen]; bool operator ==(const _DocEntry& de) const { return (lstrcmpi(szDocName, de.szDocName) == 0); } }; enum { m_nMaxEntries_Min = 2, m_nMaxEntries_Max = t_nLastID - t_nFirstID + 1, m_cchMaxItemLen_Min = 6, m_cchMaxItemLen_Max = t_cchItemLen, m_cchItemNameLen = 11 }; // Data members ATL::CSimpleArray<_DocEntry> m_arrDocs; int m_nMaxEntries; // default is 4 HMENU m_hMenu; TCHAR m_szNoEntries[t_cchItemLen]; int m_cchMaxItemLen; // Constructor CRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1) { // These ASSERTs verify values of the template arguments ATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min); ATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min); } // Attributes HMENU GetMenuHandle() const { return m_hMenu; } void SetMenuHandle(HMENU hMenu) { ATLASSERT(hMenu == NULL || ::IsMenu(hMenu)); m_hMenu = hMenu; if(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0)) { T* pT = static_cast(this); pT; // avoid level 4 warning SecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE); } } int GetMaxEntries() const { return m_nMaxEntries; } void SetMaxEntries(int nMaxEntries) { ATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_nMaxEntries_Max); if(nMaxEntries < m_nMaxEntries_Min) nMaxEntries = m_nMaxEntries_Min; else if(nMaxEntries > m_nMaxEntries_Max) nMaxEntries = m_nMaxEntries_Max; m_nMaxEntries = nMaxEntries; } int GetMaxItemLength() const { return m_cchMaxItemLen; } void SetMaxItemLength(int cchMaxLen) { ATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1); if(cchMaxLen != -1) { if(cchMaxLen < m_cchMaxItemLen_Min) cchMaxLen = m_cchMaxItemLen_Min; else if(cchMaxLen > m_cchMaxItemLen_Max) cchMaxLen = m_cchMaxItemLen_Max; } m_cchMaxItemLen = cchMaxLen; T* pT = static_cast(this); pT->UpdateMenu(); } // Operations BOOL AddToList(LPCTSTR lpstrDocName) { _DocEntry de; errno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE); if(nRet != 0 && nRet != STRUNCATE) return FALSE; for(int i = 0; i < m_arrDocs.GetSize(); i++) { if(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0) { m_arrDocs.RemoveAt(i); break; } } if(m_arrDocs.GetSize() == m_nMaxEntries) m_arrDocs.RemoveAt(0); BOOL bRet = m_arrDocs.Add(de); if(bRet) { T* pT = static_cast(this); bRet = pT->UpdateMenu(); } return bRet; } // This function is deprecated because it is not safe. // Use the version below that accepts the buffer length. #if (_MSC_VER >= 1300) __declspec(deprecated) #endif BOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/) { ATLASSERT(FALSE); return FALSE; } BOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength) { int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) return FALSE; if(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength) return FALSE; SecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName); return TRUE; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName) { int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) return FALSE; strDocName = m_arrDocs[nIndex].szDocName; return TRUE; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL RemoveFromList(int nItemID) { int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; BOOL bRet = m_arrDocs.RemoveAt(nIndex); if(bRet) { T* pT = static_cast(this); bRet = pT->UpdateMenu(); } return bRet; } BOOL MoveToTop(int nItemID) { int nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1; if(nIndex < 0 || nIndex >= m_arrDocs.GetSize()) return FALSE; _DocEntry de; de = m_arrDocs[nIndex]; m_arrDocs.RemoveAt(nIndex); BOOL bRet = m_arrDocs.Add(de); if(bRet) { T* pT = static_cast(this); bRet = pT->UpdateMenu(); } return bRet; } BOOL ReadFromRegistry(LPCTSTR lpstrRegKey) { T* pT = static_cast(this); CRegKeyEx rkParent; CRegKeyEx rk; LONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey); if(lRet != ERROR_SUCCESS) return FALSE; lRet = rk.Open(rkParent, pT->GetRegKeyName()); if(lRet != ERROR_SUCCESS) return FALSE; DWORD dwRet = 0; lRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet); if(lRet != ERROR_SUCCESS) return FALSE; SetMaxEntries(dwRet); m_arrDocs.RemoveAll(); TCHAR szRetString[t_cchItemLen] = { 0 }; _DocEntry de; for(int nItem = m_nMaxEntries; nItem > 0; nItem--) { TCHAR szBuff[m_cchItemNameLen] = { 0 }; SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); ULONG ulCount = t_cchItemLen; lRet = rk.QueryStringValue(szBuff, szRetString, &ulCount); if(lRet == ERROR_SUCCESS) { SecureHelper::strcpy_x(de.szDocName, _countof(de.szDocName), szRetString); m_arrDocs.Add(de); } } rk.Close(); rkParent.Close(); return pT->UpdateMenu(); } BOOL WriteToRegistry(LPCTSTR lpstrRegKey) { T* pT = static_cast(this); pT; // avoid level 4 warning CRegKeyEx rkParent; CRegKeyEx rk; LONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey); if(lRet != ERROR_SUCCESS) return FALSE; lRet = rk.Create(rkParent, pT->GetRegKeyName()); if(lRet != ERROR_SUCCESS) return FALSE; lRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries); ATLASSERT(lRet == ERROR_SUCCESS); // set new values int nItem; for(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--) { TCHAR szBuff[m_cchItemNameLen] = { 0 }; SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); TCHAR szDocName[t_cchItemLen] = { 0 }; GetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen); lRet = rk.SetStringValue(szBuff, szDocName); ATLASSERT(lRet == ERROR_SUCCESS); } // delete unused keys for(nItem = m_arrDocs.GetSize() + 1; nItem <= m_nMaxEntries_Max; nItem++) { TCHAR szBuff[m_cchItemNameLen] = { 0 }; SecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem); rk.DeleteValue(szBuff); } rk.Close(); rkParent.Close(); return TRUE; } // Implementation BOOL UpdateMenu() { if(m_hMenu == NULL) return FALSE; ATLASSERT(::IsMenu(m_hMenu)); int nItems = ::GetMenuItemCount(m_hMenu); int nInsertPoint = 0; for(int i = 0; i < nItems; i++) { CMenuItemInfo mi; mi.fMask = MIIM_ID; ::GetMenuItemInfo(m_hMenu, i, TRUE, &mi); if (mi.wID == t_nFirstID) { nInsertPoint = i; break; } } ATLASSERT(nInsertPoint < nItems && "You need a menu item with an ID = t_nFirstID"); for(int j = t_nFirstID; j < (t_nFirstID + m_nMaxEntries); j++) { // keep the first one as an insertion point if (j != t_nFirstID) ::DeleteMenu(m_hMenu, j, MF_BYCOMMAND); } TCHAR szItemText[t_cchItemLen + 6] = { 0 }; // add space for &, 2 digits, and a space int nSize = m_arrDocs.GetSize(); int nItem = 0; if(nSize > 0) { for(nItem = 0; nItem < nSize; nItem++) { if(m_cchMaxItemLen == -1) { SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName); } else { TCHAR szBuff[t_cchItemLen] = { 0 }; T* pT = static_cast(this); pT; // avoid level 4 warning bool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen); bRet; // avoid level 4 warning ATLASSERT(bRet); SecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T("&%i %s"), nItem + 1, szBuff); } ::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText); } } else // empty { ::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries); ::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED); nItem++; } ::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION); return TRUE; } // Overrideables // override to provide a different method of compacting document names static bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) { return AtlCompactPath(lpstrOut, lpstrIn, cchLen); } static LPCTSTR GetRegKeyName() { return _T("Recent Document List"); } static LPCTSTR GetRegCountName() { return _T("DocumentCount"); } static LPCTSTR GetRegItemName() { // Note: This string is a format string used with wsprintf(). // Resulting formatted string must be m_cchItemNameLen or less // characters long, including the terminating null character. return _T("Document%i"); } static LPCTSTR GetMRUEmptyText() { return _WTL_MRUEMPTY_TEXT; } }; class CRecentDocumentList : public CRecentDocumentListBase { public: // nothing here }; #endif // _WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CFindFile - file search helper class class CFindFile { public: // Data members WIN32_FIND_DATA m_fd; TCHAR m_lpszRoot[MAX_PATH]; TCHAR m_chDirSeparator; HANDLE m_hFind; BOOL m_bFound; // Constructor/destructor CFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\')), m_bFound(FALSE) { } ~CFindFile() { Close(); } // Attributes ULONGLONG GetFileSize() const { ATLASSERT(m_hFind != NULL); ULARGE_INTEGER nFileSize = { 0 }; if(m_bFound) { nFileSize.LowPart = m_fd.nFileSizeLow; nFileSize.HighPart = m_fd.nFileSizeHigh; } else { nFileSize.QuadPart = 0; } return nFileSize.QuadPart; } BOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const { ATLASSERT(m_hFind != NULL); if(lstrlen(m_fd.cFileName) >= cchLength) return FALSE; if(m_bFound) SecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cFileName); return m_bFound; } BOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const { ATLASSERT(m_hFind != NULL); int nLen = lstrlen(m_lpszRoot); #ifndef _WIN32_WCE ATLASSERT(nLen > 0); if(nLen == 0) return FALSE; bool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/')); #else // CE specific // allow diskless devices (nLen == 0) bool bAddSep = ((nLen == 0) || (m_lpszRoot[nLen - 1] != _T('\\') && m_lpszRoot[nLen - 1] !=_T('/'))); #endif // _WIN32_WCE if((lstrlen(m_lpszRoot) + (bAddSep ? 1 : 0)) >= cchLength) return FALSE; SecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot); if(bAddSep) { TCHAR szSeparator[2] = { m_chDirSeparator, 0 }; SecureHelper::strcat_x(lpstrFilePath, cchLength, szSeparator); } SecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName); return TRUE; } #ifndef _WIN32_WCE BOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const { ATLASSERT(m_hFind != NULL); TCHAR szBuff[MAX_PATH] = { 0 }; if(!GetFileName(szBuff, MAX_PATH)) return FALSE; if(lstrlen(szBuff) >= cchLength || cchLength < 1) return FALSE; // find the last dot LPTSTR pstrDot = MinCrtHelper::_strrchr(szBuff, _T('.')); if(pstrDot != NULL) *pstrDot = 0; SecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff); return TRUE; } #endif // !_WIN32_WCE BOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const { ATLASSERT(m_hFind != NULL); TCHAR szBuff[MAX_PATH] = { 0 }; if(!GetFilePath(szBuff, MAX_PATH)) return FALSE; LPCTSTR lpstrFileURLPrefix = _T("file://"); if(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength) return FALSE; SecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPrefix); SecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff); return TRUE; } BOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const { ATLASSERT(m_hFind != NULL); if(lstrlen(m_lpszRoot) >= cchLength) return FALSE; SecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot); return TRUE; } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) _CSTRING_NS::CString GetFileName() const { ATLASSERT(m_hFind != NULL); _CSTRING_NS::CString ret; if(m_bFound) ret = m_fd.cFileName; return ret; } _CSTRING_NS::CString GetFilePath() const { ATLASSERT(m_hFind != NULL); _CSTRING_NS::CString strResult = m_lpszRoot; int nLen = strResult.GetLength(); #ifndef _WIN32_WCE ATLASSERT(nLen > 0); if(nLen == 0) return strResult; if((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/'))) #else // CE specific // allow diskless devices (nLen == 0) if((nLen == 0) || ((strResult[nLen - 1] != _T('\\')) && (strResult[nLen - 1] != _T('/')))) #endif // _WIN32_WCE strResult += m_chDirSeparator; strResult += GetFileName(); return strResult; } #ifndef _WIN32_WCE _CSTRING_NS::CString GetFileTitle() const { ATLASSERT(m_hFind != NULL); _CSTRING_NS::CString strResult; GetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH); strResult.ReleaseBuffer(); return strResult; } #endif // !_WIN32_WCE _CSTRING_NS::CString GetFileURL() const { ATLASSERT(m_hFind != NULL); _CSTRING_NS::CString strResult("file://"); strResult += GetFilePath(); return strResult; } _CSTRING_NS::CString GetRoot() const { ATLASSERT(m_hFind != NULL); _CSTRING_NS::CString str = m_lpszRoot; return str; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) BOOL GetLastWriteTime(FILETIME* pTimeStamp) const { ATLASSERT(m_hFind != NULL); ATLASSERT(pTimeStamp != NULL); if(m_bFound && pTimeStamp != NULL) { *pTimeStamp = m_fd.ftLastWriteTime; return TRUE; } return FALSE; } BOOL GetLastAccessTime(FILETIME* pTimeStamp) const { ATLASSERT(m_hFind != NULL); ATLASSERT(pTimeStamp != NULL); if(m_bFound && pTimeStamp != NULL) { *pTimeStamp = m_fd.ftLastAccessTime; return TRUE; } return FALSE; } BOOL GetCreationTime(FILETIME* pTimeStamp) const { ATLASSERT(m_hFind != NULL); if(m_bFound && pTimeStamp != NULL) { *pTimeStamp = m_fd.ftCreationTime; return TRUE; } return FALSE; } BOOL MatchesMask(DWORD dwMask) const { ATLASSERT(m_hFind != NULL); if(m_bFound) return ((m_fd.dwFileAttributes & dwMask) != 0); return FALSE; } BOOL IsDots() const { ATLASSERT(m_hFind != NULL); // return TRUE if the file name is "." or ".." and // the file is a directory BOOL bResult = FALSE; if(m_bFound && IsDirectory()) { if(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\0')))) bResult = TRUE; } return bResult; } BOOL IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } BOOL IsDirectory() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } BOOL IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } BOOL IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } BOOL IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } BOOL IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } BOOL IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } BOOL IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } // Operations BOOL FindFile(LPCTSTR pstrName = NULL) { Close(); if(pstrName == NULL) { pstrName = _T("*.*"); } else if(lstrlen(pstrName) >= MAX_PATH) { ATLASSERT(FALSE); return FALSE; } SecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName); m_hFind = ::FindFirstFile(pstrName, &m_fd); if(m_hFind == INVALID_HANDLE_VALUE) return FALSE; #ifndef _WIN32_WCE bool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRoot, NULL) != 0); #else // CE specific errno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lpszRoot), pstrName, _TRUNCATE); bool bFullPath = (nRet == 0 || nRet == STRUNCATE); #endif // _WIN32_WCE // passed name isn't a valid path but was found by the API ATLASSERT(bFullPath); if(!bFullPath) { Close(); ::SetLastError(ERROR_INVALID_NAME); return FALSE; } else { // find the last forward or backward whack LPTSTR pstrBack = MinCrtHelper::_strrchr(m_lpszRoot, _T('\\')); LPTSTR pstrFront = MinCrtHelper::_strrchr(m_lpszRoot, _T('/')); if(pstrFront != NULL || pstrBack != NULL) { if(pstrFront == NULL) pstrFront = m_lpszRoot; if(pstrBack == NULL) pstrBack = m_lpszRoot; // from the start to the last whack is the root if(pstrFront >= pstrBack) *pstrFront = _T('\0'); else *pstrBack = _T('\0'); } } m_bFound = TRUE; return TRUE; } BOOL FindNextFile() { ATLASSERT(m_hFind != NULL); if(m_hFind == NULL) return FALSE; if(!m_bFound) return FALSE; m_bFound = ::FindNextFile(m_hFind, &m_fd); return m_bFound; } void Close() { m_bFound = FALSE; if(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE) { ::FindClose(m_hFind); m_hFind = NULL; } } }; /////////////////////////////////////////////////////////////////////////////// // Global functions for stock GDI objects inline HPEN AtlGetStockPen(int nPen) { #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN); #else ATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN); #endif return (HPEN)::GetStockObject(nPen); } inline HBRUSH AtlGetStockBrush(int nBrush) { #if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE) ATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH); #else ATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH); #endif return (HBRUSH)::GetStockObject(nBrush); } inline HFONT AtlGetStockFont(int nFont) { #ifndef _WIN32_WCE ATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT); #else // CE specific ATLASSERT(nFont == SYSTEM_FONT); #endif // _WIN32_WCE return (HFONT)::GetStockObject(nFont); } inline HPALETTE AtlGetStockPalette(int nPalette) { ATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported return (HPALETTE)::GetStockObject(nPalette); } /////////////////////////////////////////////////////////////////////////////// // Global function for compacting a path by replacing parts with ellipsis // helper for multi-byte character sets inline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar) { #ifndef _UNICODE int i = nChar; for( ; i > 0; i--) { if(!::IsDBCSLeadByte(lpstr[i - 1])) break; } return ((nChar > 0) && (((nChar - i) & 1) != 0)); #else // _UNICODE lpstr; nChar; return false; #endif // _UNICODE } inline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen) { ATLASSERT(lpstrOut != NULL); ATLASSERT(lpstrIn != NULL); ATLASSERT(cchLen > 0); LPCTSTR szEllipsis = _T("..."); const int cchEndEllipsis = 3; const int cchMidEllipsis = 4; if(lstrlen(lpstrIn) < cchLen) { SecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn); return true; } lpstrOut[0] = 0; // check if the separator is a slash or a backslash TCHAR chSlash = _T('\\'); for(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr)) { if((*lpstr == _T('/')) || (*lpstr == _T('\\'))) chSlash = *lpstr; } // find the filename portion of the path LPCTSTR lpstrFileName = lpstrIn; for(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath)) { if((pPath[0] == _T('\\') || pPath[0] == _T(':') || pPath[0] == _T('/')) && pPath[1] && pPath[1] != _T('\\') && pPath[1] != _T('/')) lpstrFileName = pPath + 1; } int cchFileName = lstrlen(lpstrFileName); // handle just the filename without a path if(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis) { bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0); if(bRet) { #ifndef _UNICODE if(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis)) lpstrOut[cchLen - cchEndEllipsis - 1] = 0; #endif // _UNICODE SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); } return bRet; } // handle just ellipsis if((cchLen < (cchMidEllipsis + cchEndEllipsis))) { for(int i = 0; i < cchLen - 1; i++) lpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.'); lpstrOut[cchLen - 1] = 0; return true; } // calc how much we have to copy int cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1; if(cchToCopy < 0) cchToCopy = 0; #ifndef _UNICODE if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy)) cchToCopy--; #endif // _UNICODE bool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0); if(!bRet) return false; // add ellipsis SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); TCHAR szSlash[2] = { chSlash, 0 }; SecureHelper::strcat_x(lpstrOut, cchLen, szSlash); // add filename (and ellipsis, if needed) if(cchLen > (cchMidEllipsis + cchFileName)) { SecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName); } else { cchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1; #ifndef _UNICODE if(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy)) cchToCopy--; #endif // _UNICODE bRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0); if(bRet) SecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis); } return bRet; } }; // namespace WTL #endif // __ATLMISC_H__ ================================================ FILE: WTL/atlprint.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLPRINT_H__ #define __ATLPRINT_H__ #pragma once #ifdef _WIN32_WCE #error atlprint.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atlprint.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlprint.h requires atlwin.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CPrinterInfo // CPrinterT // CDevModeT // CPrinterDC // CPrintJobInfo // CPrintJob // CPrintPreview // CPrintPreviewWindowImpl // CPrintPreviewWindow // CZoomPrintPreviewWindowImpl // CZoomPrintPreviewWindow namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures // and provided by ::GetPrinter. template class _printer_info { public: typedef void infotype; }; template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; }; template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; }; template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; }; template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; }; template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; }; template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; }; template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; }; // these are not in the old (vc6.0) headers #ifdef _ATL_USE_NEW_PRINTER_INFO template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; }; template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; }; #endif // _ATL_USE_NEW_PRINTER_INFO template class CPrinterInfo { public: // Data members typename _printer_info::infotype* m_pi; // Constructor/destructor CPrinterInfo() : m_pi(NULL) { } CPrinterInfo(HANDLE hPrinter) : m_pi(NULL) { GetPrinterInfo(hPrinter); } ~CPrinterInfo() { Cleanup(); } // Operations bool GetPrinterInfo(HANDLE hPrinter) { Cleanup(); return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo); } // Implementation void Cleanup() { delete [] (BYTE*)m_pi; m_pi = NULL; } static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex) { ATLASSERT(pi != NULL); DWORD dw = 0; BYTE* pb = NULL; ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw); if (dw > 0) { ATLTRY(pb = new BYTE[dw]); if (pb != NULL) { memset(pb, 0, dw); DWORD dwNew; if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew)) { delete [] pb; pb = NULL; } } } *pi = pb; return (pb != NULL); } }; /////////////////////////////////////////////////////////////////////////////// // CPrinter - Wrapper class for a HANDLE to a printer template class CPrinterT { public: // Data members HANDLE m_hPrinter; // Constructor/destructor CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter) { } ~CPrinterT() { ClosePrinter(); } // Operations CPrinterT& operator =(HANDLE hPrinter) { if (hPrinter != m_hPrinter) { ClosePrinter(); m_hPrinter = hPrinter; } return *this; } bool IsNull() const { return (m_hPrinter == NULL); } bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL) { bool b = false; DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames); if (pdn != NULL) { LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset; b = OpenPrinter(lpszPrinterName, pDevMode); ::GlobalUnlock(hDevNames); } return b; } bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL) { ClosePrinter(); PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); return (m_hPrinter != NULL); } bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs) { ClosePrinter(); ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs); return (m_hPrinter != NULL); } bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL) { ClosePrinter(); const int cchBuff = 512; TCHAR buffer[cchBuff] = { 0 }; ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff); int nLen = lstrlen(buffer); if (nLen != 0) { LPTSTR lpsz = buffer; while (*lpsz) { if (*lpsz == _T(',')) { *lpsz = 0; break; } lpsz = CharNext(lpsz); } PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); } return m_hPrinter != NULL; } void ClosePrinter() { if (m_hPrinter != NULL) { if (t_bManaged) ::ClosePrinter(m_hPrinter); m_hPrinter = NULL; } } bool PrinterProperties(HWND hWnd = NULL) { if (hWnd == NULL) hWnd = ::GetActiveWindow(); return !!::PrinterProperties(hWnd, m_hPrinter); } HANDLE CopyToHDEVNAMES() const { HANDLE h = NULL; CPrinterInfo<5> pinfon5; CPrinterInfo<2> pinfon2; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfon5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfon5.m_pi->pPrinterName; else if (pinfon2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfon2.m_pi->pPrinterName; if (lpszPrinterName != NULL) { int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR); h = ::GlobalAlloc(GMEM_MOVEABLE, nLen); BYTE* pv = (BYTE*)::GlobalLock(h); DEVNAMES* pdev = (DEVNAMES*)pv; if (pv != NULL) { memset(pv, 0, nLen); pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR); pv = pv + sizeof(DEVNAMES); // now points to end SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName); ::GlobalUnlock(h); } } return h; } HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const { CPrinterInfo<5> pinfo5; CPrinterInfo<2> pinfo2; HDC hDC = NULL; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfo5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo5.m_pi->pPrinterName; else if (pinfo2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo2.m_pi->pPrinterName; if (lpszPrinterName != NULL) hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm); return hDC; } HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const { CPrinterInfo<5> pinfo5; CPrinterInfo<2> pinfo2; HDC hDC = NULL; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfo5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo5.m_pi->pPrinterName; else if (pinfo2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo2.m_pi->pPrinterName; if (lpszPrinterName != NULL) hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm); return hDC; } void Attach(HANDLE hPrinter) { ClosePrinter(); m_hPrinter = hPrinter; } HANDLE Detach() { HANDLE hPrinter = m_hPrinter; m_hPrinter = NULL; return hPrinter; } operator HANDLE() const { return m_hPrinter; } }; typedef CPrinterT CPrinterHandle; typedef CPrinterT CPrinter; /////////////////////////////////////////////////////////////////////////////// // CDevMode - Wrapper class for DEVMODE template class CDevModeT { public: // Data members HANDLE m_hDevMode; DEVMODE* m_pDevMode; // Constructor/destructor CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode) { m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; } ~CDevModeT() { Cleanup(); } // Operations CDevModeT& operator =(HANDLE hDevMode) { Attach(hDevMode); return *this; } void Attach(HANDLE hDevModeNew) { Cleanup(); m_hDevMode = hDevModeNew; m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; } HANDLE Detach() { if (m_hDevMode != NULL) ::GlobalUnlock(m_hDevMode); HANDLE hDevMode = m_hDevMode; m_hDevMode = NULL; return hDevMode; } bool IsNull() const { return (m_hDevMode == NULL); } bool CopyFromPrinter(HANDLE hPrinter) { CPrinterInfo<2> pinfo; bool b = pinfo.GetPrinterInfo(hPrinter); if (b) b = CopyFromDEVMODE(pinfo.m_pi->pDevMode); return b; } bool CopyFromDEVMODE(const DEVMODE* pdm) { if (pdm == NULL) return false; int nSize = pdm->dmSize + pdm->dmDriverExtra; HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); if (h != NULL) { void* p = ::GlobalLock(h); SecureHelper::memcpy_x(p, nSize, pdm, nSize); ::GlobalUnlock(h); } Attach(h); return (h != NULL); } bool CopyFromHDEVMODE(HANDLE hdm) { bool b = false; if (hdm != NULL) { DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm); b = CopyFromDEVMODE(pdm); ::GlobalUnlock(hdm); } return b; } HANDLE CopyToHDEVMODE() { if ((m_hDevMode == NULL) || (m_pDevMode == NULL)) return NULL; int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra; HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); if (h != NULL) { void* p = ::GlobalLock(h); SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize); ::GlobalUnlock(h); } return h; } // If this devmode was for another printer, this will create a new devmode // based on the existing devmode, but retargeted at the new printer bool UpdateForNewPrinter(HANDLE hPrinter) { bool bRet = false; LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0); CTempBuffer buff; DEVMODE* pdm = buff.AllocateBytes(nLen); if(pdm != NULL) { memset(pdm, 0, nLen); LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); if (l == IDOK) bRet = CopyFromDEVMODE(pdm); } return bRet; } bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL) { CPrinterInfo<1> pi; pi.GetPrinterInfo(hPrinter); if (hWnd == NULL) hWnd = ::GetActiveWindow(); bool bRet = false; LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0); CTempBuffer buff; DEVMODE* pdm = buff.AllocateBytes(nLen); if(pdm != NULL) { memset(pdm, 0, nLen); LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT); if (l == IDOK) bRet = CopyFromDEVMODE(pdm); } return bRet; } operator HANDLE() const { return m_hDevMode; } operator DEVMODE*() const { return m_pDevMode; } // Implementation void Cleanup() { if (m_hDevMode != NULL) { ::GlobalUnlock(m_hDevMode); if(t_bManaged) ::GlobalFree(m_hDevMode); m_hDevMode = NULL; } } }; typedef CDevModeT CDevModeHandle; typedef CDevModeT CDevMode; /////////////////////////////////////////////////////////////////////////////// // CPrinterDC class CPrinterDC : public CDC { public: // Constructors/destructor CPrinterDC() { CPrinter printer; printer.OpenDefaultPrinter(); Attach(printer.CreatePrinterDC()); ATLASSERT(m_hDC != NULL); } CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL) { CPrinterHandle p; p.Attach(hPrinter); Attach(p.CreatePrinterDC(pdm)); ATLASSERT(m_hDC != NULL); } ~CPrinterDC() { DeleteDC(); } }; /////////////////////////////////////////////////////////////////////////////// // CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc) // Handles aborting, background printing // Defines callbacks used by CPrintJob (not a COM interface) class ATL_NO_VTABLE IPrintJobInfo { public: virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc. virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc. virtual void PrePrintPage(UINT nPage, HDC hDC) = 0; virtual bool PrintPage(UINT nPage, HDC hDC) = 0; virtual void PostPrintPage(UINT nPage, HDC hDC) = 0; // If you want per page devmodes, return the DEVMODE* to use for nPage. // You can optimize by only returning a new DEVMODE* when it is different // from the one for nLastPage, otherwise return NULL. // When nLastPage==0, the current DEVMODE* will be the default passed to // StartPrintJob. // Note: During print preview, nLastPage will always be "0". virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0; virtual bool IsValidPage(UINT nPage) = 0; }; // Provides a default implementatin for IPrintJobInfo // Typically, MI'd into a document or view class class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo { public: virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc { } virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc { } virtual void PrePrintPage(UINT /*nPage*/, HDC hDC) { m_nPJState = ::SaveDC(hDC); } virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0; virtual void PostPrintPage(UINT /*nPage*/, HDC hDC) { RestoreDC(hDC, m_nPJState); } virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/) { return NULL; } virtual bool IsValidPage(UINT /*nPage*/) { return true; } // Implementation - data int m_nPJState; }; class CPrintJob { public: // Data members CPrinterHandle m_printer; IPrintJobInfo* m_pInfo; DEVMODE* m_pDefDevMode; DOCINFO m_docinfo; int m_nJobID; bool m_bCancel; bool m_bComplete; unsigned long m_nStartPage; unsigned long m_nEndPage; // Constructor/destructor CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true) { } ~CPrintJob() { ATLASSERT(IsJobComplete()); // premature destruction? } // Operations bool IsJobComplete() const { return m_bComplete; } bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pInfo, LPCTSTR lpszDocName, unsigned long nStartPage, unsigned long nEndPage, bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL) { ATLASSERT(m_bComplete); // previous job not done yet? if (pInfo == NULL) return false; memset(&m_docinfo, 0, sizeof(m_docinfo)); m_docinfo.cbSize = sizeof(m_docinfo); m_docinfo.lpszDocName = lpszDocName; m_pInfo = pInfo; m_nStartPage = nStartPage; m_nEndPage = nEndPage; m_printer.Attach(hPrinter); m_pDefDevMode = pDefaultDevMode; m_bComplete = false; if(bPrintToFile) m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:"); if (!bBackground) { m_bComplete = true; return StartHelper(); } // Create a thread and return DWORD dwThreadID = 0; #if !defined(_ATL_MIN_CRT) && defined(_MT) HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID); #else HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID); #endif if (hThread == NULL) return false; ::CloseHandle(hThread); return true; } // Implementation static DWORD WINAPI StartProc(void* p) { CPrintJob* pThis = (CPrintJob*)p; pThis->StartHelper(); pThis->m_bComplete = true; return 0; } bool StartHelper() { CDC dcPrinter; dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode)); if (dcPrinter.IsNull()) return false; m_nJobID = ::StartDoc(dcPrinter, &m_docinfo); if (m_nJobID <= 0) return false; m_pInfo->BeginPrintJob(dcPrinter); // print all the pages now unsigned long nLastPage = 0; for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++) { if (!m_pInfo->IsValidPage(nPage)) break; DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage); if (pdm != NULL) dcPrinter.ResetDC(pdm); dcPrinter.StartPage(); m_pInfo->PrePrintPage(nPage, dcPrinter); if (!m_pInfo->PrintPage(nPage, dcPrinter)) m_bCancel = true; m_pInfo->PostPrintPage(nPage, dcPrinter); dcPrinter.EndPage(); if (m_bCancel) break; nLastPage = nPage; } m_pInfo->EndPrintJob(dcPrinter, m_bCancel); if (m_bCancel) ::AbortDoc(dcPrinter); else ::EndDoc(dcPrinter); m_nJobID = 0; return true; } // Cancels a print job. Can be called asynchronously. void CancelPrintJob() { m_bCancel = true; } }; /////////////////////////////////////////////////////////////////////////////// // CPrintPreview - Adds print preview support to an existing window class CPrintPreview { public: // Data members IPrintJobInfo* m_pInfo; CPrinterHandle m_printer; CEnhMetaFile m_meta; DEVMODE* m_pDefDevMode; DEVMODE* m_pCurDevMode; SIZE m_sizeCurPhysOffset; // Constructor CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL) { m_sizeCurPhysOffset.cx = 0; m_sizeCurPhysOffset.cy = 0; } // Operations void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji) { m_printer.Attach(hPrinter); m_pDefDevMode = pDefaultDevMode; m_pInfo = pji; m_nCurPage = 0; m_pCurDevMode = NULL; } void SetEnhMetaFile(HENHMETAFILE hEMF) { m_meta = hEMF; } void SetPage(int nPage) { if (!m_pInfo->IsValidPage(nPage)) return; m_nCurPage = nPage; m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage); if (m_pCurDevMode == NULL) m_pCurDevMode = m_pDefDevMode; CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode); int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX); int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY); RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) }; m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX); m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY); CEnhMetaFileDC dcMeta(dcPrinter, &rcMM); m_pInfo->PrePrintPage(nPage, dcMeta); m_pInfo->PrintPage(nPage, dcMeta); m_pInfo->PostPrintPage(nPage, dcMeta); m_meta.Attach(dcMeta.Close()); } void GetPageRect(RECT& rc, LPRECT prc) { int x1 = rc.right-rc.left; int y1 = rc.bottom - rc.top; if ((x1 < 0) || (y1 < 0)) return; CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); // Compute whether we are OK vertically or horizontally int x2 = pmh->szlDevice.cx; int y2 = pmh->szlDevice.cy; int y1p = MulDiv(x1, y2, x2); int x1p = MulDiv(y1, x2, y2); ATLASSERT((x1p <= x1) || (y1p <= y1)); if (x1p <= x1) { prc->left = rc.left + (x1 - x1p) / 2; prc->right = prc->left + x1p; prc->top = rc.top; prc->bottom = rc.bottom; } else { prc->left = rc.left; prc->right = rc.right; prc->top = rc.top + (y1 - y1p) / 2; prc->bottom = prc->top + y1p; } } // Painting helpers void DoPaint(CDCHandle dc) { // this one is not used } void DoPaint(CDCHandle dc, RECT& rc) { CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); dc.PlayMetaFile(m_meta, &rc); } // Implementation - data int m_nCurPage; }; /////////////////////////////////////////////////////////////////////////////// // CPrintPreviewWindow - Implements a print preview window template class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl, public CPrintPreview { public: DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1) enum { m_cxOffset = 10, m_cyOffset = 10 }; // Constructor CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0) { } // Operations void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji, int nMinPage, int nMaxPage) { CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji); m_nMinPage = nMinPage; m_nMaxPage = nMaxPage; } bool NextPage() { if (m_nCurPage == m_nMaxPage) return false; SetPage(m_nCurPage + 1); Invalidate(); return true; } bool PrevPage() { if (m_nCurPage == m_nMinPage) return false; if (m_nCurPage == 0) return false; SetPage(m_nCurPage - 1); Invalidate(); return true; } // Message map and handlers BEGIN_MSG_MAP(CPrintPreviewWindowImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) END_MSG_MAP() LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no need for the background } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); RECT rc = { 0 }; if(wParam != NULL) { pT->DoPrePaint((HDC)wParam, rc); pT->DoPaint((HDC)wParam, rc); } else { CPaintDC dc(m_hWnd); pT->DoPrePaint(dc.m_hDC, rc); pT->DoPaint(dc.m_hDC, rc); } return 0; } // Painting helper void DoPrePaint(CDCHandle dc, RECT& rc) { RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcArea = rcClient; T* pT = static_cast(this); pT; // avoid level 4 warning ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); if (rcArea.left > rcArea.right) rcArea.right = rcArea.left; if (rcArea.top > rcArea.bottom) rcArea.bottom = rcArea.top; GetPageRect(rcArea, &rc); CRgn rgn1, rgn2; rgn1.CreateRectRgnIndirect(&rc); rgn2.CreateRectRgnIndirect(&rcClient); rgn2.CombineRgn(rgn1, RGN_DIFF); dc.SelectClipRgn(rgn2); dc.FillRect(&rcClient, COLOR_BTNSHADOW); dc.SelectClipRgn(NULL); dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); } // Implementation - data int m_nMinPage; int m_nMaxPage; }; class CPrintPreviewWindow : public CPrintPreviewWindowImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) }; /////////////////////////////////////////////////////////////////////////////// // CZoomPrintPreviewWindowImpl - Implements print preview window with zooming #ifdef __ATLSCRL_H__ template class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > { public: bool m_bSized; CZoomPrintPreviewWindowImpl() { SetScrollExtendedStyle(SCRL_DISABLENOSCROLL); InitZoom(); } // should be called to reset data members before recreating window void InitZoom() { m_bSized = false; m_nZoomMode = ZOOMMODE_OFF; m_fZoomScaleMin = 1.0; m_fZoomScale = 1.0; } BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl) MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; POINT ptOffset = m_ptOffset; SIZE sizeAll = m_sizeAll; SetScrollSize(sizeClient); if(sizeAll.cx > 0) ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx); if(sizeAll.cy > 0) ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy); SetScrollOffset(ptOffset); CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled); if(!m_bSized) { m_bSized = true; T* pT = static_cast(this); pT->ShowScrollBar(SB_HORZ, TRUE); pT->ShowScrollBar(SB_VERT, TRUE); } return 0; } LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); RECT rc = { 0 }; if(wParam != NULL) { CDCHandle dc = (HDC)wParam; int nMapModeSav = dc.GetMapMode(); dc.SetMapMode(MM_ANISOTROPIC); SIZE szWindowExt = { 0, 0 }; dc.SetWindowExt(m_sizeLogAll, &szWindowExt); SIZE szViewportExt = { 0, 0 }; dc.SetViewportExt(m_sizeAll, &szViewportExt); POINT ptViewportOrg = { 0, 0 }; dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); pT->DoPrePaint(dc, rc); pT->DoPaint(dc, rc); dc.SetMapMode(nMapModeSav); dc.SetWindowExt(szWindowExt); dc.SetViewportExt(szViewportExt); dc.SetViewportOrg(ptViewportOrg); } else { CPaintDC dc(pT->m_hWnd); pT->PrepareDC(dc.m_hDC); pT->DoPrePaint(dc.m_hDC, rc); pT->DoPaint(dc.m_hDC, rc); } return 0; } // Painting helpers void DoPaint(CDCHandle dc) { // this one is not used } void DoPrePaint(CDCHandle dc, RECT& rc) { RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcArea = rcClient; T* pT = static_cast(this); pT; // avoid level 4 warning ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); if (rcArea.left > rcArea.right) rcArea.right = rcArea.left; if (rcArea.top > rcArea.bottom) rcArea.bottom = rcArea.top; GetPageRect(rcArea, &rc); HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY); dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY); dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY); dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY); dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH)); dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY); dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW)); dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY); dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY); dc.SelectBrush(hbrOld); } void DoPaint(CDCHandle dc, RECT& rc) { CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); dc.PlayMetaFile(m_meta, &rc); } }; class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) }; #endif // __ATLSCRL_H__ }; // namespace WTL #endif // __ATLPRINT_H__ ================================================ FILE: WTL/atlres.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLRES_H__ #define __ATLRES_H__ #pragma once #if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__) #error Use atlresCE.h instead of atlres.h for Windows CE #endif #ifdef RC_INVOKED #ifndef _INC_WINDOWS #define _INC_WINDOWS #ifndef _WIN32_WCE #define VS_VERSION_INFO 1 #ifdef APSTUDIO_INVOKED #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols #endif // APSTUDIO_INVOKED #ifndef WINVER #define WINVER 0x0400 // default to Windows Version 4.0 #endif // !WINVER #include // operation messages sent to DLGINIT #define LB_ADDSTRING (WM_USER+1) #define CB_ADDSTRING (WM_USER+3) #endif // !_WIN32_WCE #ifdef APSTUDIO_INVOKED #undef APSTUDIO_HIDDEN_SYMBOLS #endif // APSTUDIO_INVOKED #ifdef IDC_STATIC #undef IDC_STATIC #endif // IDC_STATIC #define IDC_STATIC (-1) #endif // !_INC_WINDOWS #endif // RC_INVOKED #ifdef APSTUDIO_INVOKED #define APSTUDIO_HIDDEN_SYMBOLS #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////// // ATL resource types #ifndef RC_INVOKED #define RT_DLGINIT MAKEINTRESOURCE(240) #define RT_TOOLBAR MAKEINTRESOURCE(241) #endif // RC_INVOKED /////////////////////////////////////////////////////////////////////////////// #ifdef APSTUDIO_INVOKED #undef APSTUDIO_HIDDEN_SYMBOLS #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////// // Standard window components #define ID_SEPARATOR 0 // special separator value #define ID_DEFAULT_PANE 0 // default status bar pane #ifndef RC_INVOKED // code only // standard control bars (IDW = window ID) #define ATL_IDW_TOOLBAR 0xE800 // main Toolbar for window #define ATL_IDW_STATUS_BAR 0xE801 // Status bar window #define ATL_IDW_COMMAND_BAR 0xE802 // Command bar window // parts of a frame window #define ATL_IDW_CLIENT 0xE900 #define ATL_IDW_PANE_FIRST 0xE900 // first pane (256 max) #define ATL_IDW_PANE_LAST 0xE9FF #define ATL_IDW_HSCROLL_FIRST 0xEA00 // first Horz scrollbar (16 max) #define ATL_IDW_VSCROLL_FIRST 0xEA10 // first Vert scrollbar (16 max) #define ATL_IDW_SIZE_BOX 0xEA20 // size box for splitters #define ATL_IDW_PANE_SAVE 0xEA21 // to shift ATL_IDW_PANE_FIRST // bands for a rebar #define ATL_IDW_BAND_FIRST 0xEB00 #define ATL_IDW_BAND_LAST 0xEBFF #endif // !RC_INVOKED /////////////////////////////////////////////////////////////////////////////// // Standard Commands // File commands #define ID_FILE_NEW 0xE100 #define ID_FILE_OPEN 0xE101 #define ID_FILE_CLOSE 0xE102 #define ID_FILE_SAVE 0xE103 #define ID_FILE_SAVE_AS 0xE104 #define ID_FILE_PAGE_SETUP 0xE105 #define ID_FILE_PRINT_SETUP 0xE106 #define ID_FILE_PRINT 0xE107 #define ID_FILE_PRINT_DIRECT 0xE108 #define ID_FILE_PRINT_PREVIEW 0xE109 #define ID_FILE_UPDATE 0xE10A #define ID_FILE_SAVE_COPY_AS 0xE10B #define ID_FILE_SEND_MAIL 0xE10C #define ID_FILE_MRU_FIRST 0xE110 #define ID_FILE_MRU_FILE1 0xE110 // range - 16 max #define ID_FILE_MRU_FILE2 0xE111 #define ID_FILE_MRU_FILE3 0xE112 #define ID_FILE_MRU_FILE4 0xE113 #define ID_FILE_MRU_FILE5 0xE114 #define ID_FILE_MRU_FILE6 0xE115 #define ID_FILE_MRU_FILE7 0xE116 #define ID_FILE_MRU_FILE8 0xE117 #define ID_FILE_MRU_FILE9 0xE118 #define ID_FILE_MRU_FILE10 0xE119 #define ID_FILE_MRU_FILE11 0xE11A #define ID_FILE_MRU_FILE12 0xE11B #define ID_FILE_MRU_FILE13 0xE11C #define ID_FILE_MRU_FILE14 0xE11D #define ID_FILE_MRU_FILE15 0xE11E #define ID_FILE_MRU_FILE16 0xE11F #define ID_FILE_MRU_LAST 0xE11F // Edit commands #define ID_EDIT_CLEAR 0xE120 #define ID_EDIT_CLEAR_ALL 0xE121 #define ID_EDIT_COPY 0xE122 #define ID_EDIT_CUT 0xE123 #define ID_EDIT_FIND 0xE124 #define ID_EDIT_PASTE 0xE125 #define ID_EDIT_PASTE_LINK 0xE126 #define ID_EDIT_PASTE_SPECIAL 0xE127 #define ID_EDIT_REPEAT 0xE128 #define ID_EDIT_REPLACE 0xE129 #define ID_EDIT_SELECT_ALL 0xE12A #define ID_EDIT_UNDO 0xE12B #define ID_EDIT_REDO 0xE12C #define ID_EDIT_DELETE ID_EDIT_CLEAR #define ID_EDIT_FIND_NEXT ID_EDIT_REPEAT #define ID_EDIT_FIND_PREVIOUS 0xE12D // Window commands #define ID_WINDOW_NEW 0xE130 #define ID_WINDOW_ARRANGE 0xE131 #define ID_WINDOW_CASCADE 0xE132 #define ID_WINDOW_TILE_HORZ 0xE133 #define ID_WINDOW_TILE_VERT 0xE134 #define ID_WINDOW_SPLIT 0xE135 #ifndef RC_INVOKED // code only #define ATL_IDM_WINDOW_FIRST 0xE130 #define ATL_IDM_WINDOW_LAST 0xE13F #define ATL_IDM_FIRST_MDICHILD 0xFF00 // window list starts here #define ATL_IDM_LAST_MDICHILD 0xFFFD #endif // !RC_INVOKED // TabView #define ID_WINDOW_TABFIRST 0xFF00 // = ATL_IDM_FIRST_MDICHILD #define ID_WINDOW_TABLAST 0xFFFD #define ID_WINDOW_SHOWTABLIST 0xFFFE // Help and App commands #define ID_APP_ABOUT 0xE140 #define ID_APP_EXIT 0xE141 #define ID_HELP_INDEX 0xE142 #define ID_HELP_FINDER 0xE143 #define ID_HELP_USING 0xE144 #define ID_CONTEXT_HELP 0xE145 // shift-F1 // special commands for processing help #define ID_HELP 0xE146 // first attempt for F1 #define ID_DEFAULT_HELP 0xE147 // last attempt // Misc #define ID_NEXT_PANE 0xE150 #define ID_PREV_PANE 0xE151 #define ID_PANE_CLOSE 0xE152 #define ID_PANE_NEXT ID_NEXT_PANE #define ID_PANE_PREVIOUS ID_PREV_PANE // Format #define ID_FORMAT_FONT 0xE160 // Scroll #define ID_SCROLL_UP 0xE170 #define ID_SCROLL_DOWN 0xE171 #define ID_SCROLL_PAGE_UP 0xE172 #define ID_SCROLL_PAGE_DOWN 0xE173 #define ID_SCROLL_TOP 0xE174 #define ID_SCROLL_BOTTOM 0xE175 #define ID_SCROLL_LEFT 0xE176 #define ID_SCROLL_RIGHT 0xE177 #define ID_SCROLL_PAGE_LEFT 0xE178 #define ID_SCROLL_PAGE_RIGHT 0xE179 #define ID_SCROLL_ALL_LEFT 0xE17A #define ID_SCROLL_ALL_RIGHT 0xE17B // OLE commands #define ID_OLE_INSERT_NEW 0xE200 #define ID_OLE_EDIT_LINKS 0xE201 #define ID_OLE_EDIT_CONVERT 0xE202 #define ID_OLE_EDIT_CHANGE_ICON 0xE203 #define ID_OLE_EDIT_PROPERTIES 0xE204 #define ID_OLE_VERB_FIRST 0xE210 // range - 16 max #ifndef RC_INVOKED // code only #define ID_OLE_VERB_LAST 0xE21F #endif // !RC_INVOKED // View commands (same number used as IDW used for toolbar and status bar) #define ID_VIEW_TOOLBAR 0xE800 #define ID_VIEW_STATUS_BAR 0xE801 #define ID_VIEW_REFRESH 0xE803 #define ID_VIEW_RIBBON 0xE804 /////////////////////////////////////////////////////////////////////////////// // Standard control IDs #ifdef IDC_STATIC #undef IDC_STATIC #endif // IDC_STATIC #define IDC_STATIC (-1) // all static controls /////////////////////////////////////////////////////////////////////////////// // Standard string error/warnings // idle status bar message #define ATL_IDS_IDLEMESSAGE 0xE001 #ifndef RC_INVOKED // code only #define ATL_IDS_SCFIRST 0xEF00 #endif // !RC_INVOKED #define ATL_IDS_SCSIZE 0xEF00 #define ATL_IDS_SCMOVE 0xEF01 #define ATL_IDS_SCMINIMIZE 0xEF02 #define ATL_IDS_SCMAXIMIZE 0xEF03 #define ATL_IDS_SCNEXTWINDOW 0xEF04 #define ATL_IDS_SCPREVWINDOW 0xEF05 #define ATL_IDS_SCCLOSE 0xEF06 #define ATL_IDS_SCRESTORE 0xEF12 #define ATL_IDS_SCTASKLIST 0xEF13 #define ATL_IDS_MDICHILD 0xEF1F #define ATL_IDS_MRU_FILE 0xEFDA /////////////////////////////////////////////////////////////////////////////// // Misc. control IDs // Property Sheet control id's (determined with Spy++) #define ID_APPLY_NOW 0x3021 #define ID_WIZBACK 0x3023 #define ID_WIZNEXT 0x3024 #define ID_WIZFINISH 0x3025 #define ATL_IDC_TAB_CONTROL 0x3020 #endif // __ATLRES_H__ ================================================ FILE: WTL/atlresce.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLRESCE_H__ #define __ATLRESCE_H__ #pragma once #ifndef _WIN32_WCE #error atlresCE.h is only for Windows CE #endif #ifdef RC_INVOKED #ifndef _INC_WINDOWS #define VS_VERSION_INFO 1 #ifdef APSTUDIO_INVOKED #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols #endif // APSTUDIO_INVOKED #ifndef WINVER #define WINVER 0x0400 // default to Windows Version 4.0 #endif // !WINVER #if !defined(WCEOLE_ENABLE_DIALOGEX) #define DIALOGEX DIALOG DISCARDABLE #endif #include #define SHMENUBAR RCDATA #if defined(SHELLSDK_MODULES_AYGSHELL) #include #else #define NOMENU 0xFFFF #define IDS_SHNEW 1 #define IDM_SHAREDNEW 10 #define IDM_SHAREDNEWDEFAULT 11 #endif #ifndef I_IMAGENONE #define I_IMAGENONE (-2) #endif #include #endif // !_INC_WINDOWS #endif // RC_INVOKED #include "atlres.h" #ifdef APSTUDIO_INVOKED #undef APSTUDIO_HIDDEN_SYMBOLS #endif // APSTUDIO_INVOKED // Visual Studio dialog editor bug fix #ifndef DS_FIXEDSYS #define DS_FIXEDSYS 0 #endif #define IDC_INFOSTATIC 0xFFFE // == IDC_STATIC -1 /////////////////////////////////////////////////////////////////////////////// // Smartphone and PPC 2005 Resource IDs // Command and associated string resource IDs #define ID_MENU_OK 0xE790 #define ID_MENU_CANCEL 0xE791 #define ID_MENU 0xE792 #define ID_ACTION 0xE793 #define ID_VIEW_FULLSCREEN 0xE802 // MenuBar resource IDs #define ATL_IDM_MENU_DONE 0xE701 #define ATL_IDM_MENU_CANCEL 0xE702 #define ATL_IDM_MENU_DONECANCEL 0xE703 // Default device MenuBar control ID and MenuBar resource ID #define ATL_IDW_MENU_BAR 0xE802 // SmartPhone spinned controls ID offset for CSpinCtrl #define ATL_IDW_SPIN_ID 9999 #endif // __ATLRESCE_H__ ================================================ FILE: WTL/atlribbon.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLRIBBON_H__ #define __ATLRIBBON_H__ #pragma once #if (_MSC_VER < 1500) #error atlribbon.h requires Visual C++ 2008 compiler or higher #endif #ifndef _UNICODE #error atlribbon.h requires the Unicode character set #endif #if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7) #error atlribbon.h requires the Windows 7 SDK or higher #endif #ifdef _WIN32_WCE #error atlribbon.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atlribbon.h requires atlapp.h to be included first #endif #if (_ATL_VER < 0x0700) #include #pragma comment(lib, "shlwapi.lib") #endif #include // for RecentDocumentList classes #include // for Frame and UpdateUI classes #include // required for atlctrlw.h #include // for CCommandBarCtrl #if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__) #pragma warning(push) #pragma warning(disable: 4530) // unwind semantics not enabled #include #pragma warning(pop) #endif #include #pragma comment(lib, "dwmapi.lib") #include #include #pragma comment(lib, "propsys.lib") #include // for CHARFORMAT2 /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CRibbonUpdateUI : Automatic mapping of ribbon UI elements // // RibbonUI::Text // RibbonUI::CharFormat // RibbonUI::ICtrl // RibbonUI::CtrlImpl // RibbonUI::CommandCtrlImpl // RibbonUI::ItemProperty // RibbonUI::CollectionImplBase // RibbonUI::CollectionImpl // RibbonUI::TextCollectionImpl // RibbonUI::ItemCollectionImpl // RibbonUI::ComboCollectionImpl // RibbonUI::CommandCollectionImpl // RibbonUI::ToolbarCollectionImpl // RibbonUI::SimpleCollectionImpl // RibbonUI::CollectionCtrlImpl // RibbonUI::ToolbarGalleryCtrlImpl // RibbonUI::SimpleCollectionCtrlImpl // RibbonUI::RecentItemsCtrlImpl // RibbonUI::FontCtrlImpl // RibbonUI::ColorCtrlImpl // RibbonUI::SpinnerCtrlImpl // // RibbonUI::CRibbonImpl // CRibbonImpl::CRibbonComboCtrl // CRibbonImpl::CRibbonItemGalleryCtrl // CRibbonImpl::CRibbonCommandGalleryCtrl // CRibbonImpl::CRibbonToolbarGalleryCtrl // CRibbonImpl::CRibbonSimpleComboCtrl // CRibbonImpl::CRibbonSimpleGalleryCtrl // CRibbonImpl::CRibbonRecentItemsCtrl // CRibbonImpl::CRibbonColorCtrl // CRibbonImpl::CRibbonFontCtrl // CRibbonImpl::CRibbonSpinnerCtrl // CRibbonImpl::CRibbonFloatSpinnerCtrl // CRibbonImpl::CRibbonCommandCtrl // // CRibbonFrameWindowImplBase // CRibbonFrameWindowImpl // CRibbonMDIFrameWindowImpl // CRibbonPersist // // Global functions: // RibbonUI::SetPropertyVal() // RibbonUI::GetImage() // Constants #ifndef RIBBONUI_MAX_TEXT #define RIBBONUI_MAX_TEXT 128 #endif #define TWIPS_PER_POINT 20 // For font size namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CRibbonUpdateUI : Automatic mapping of ribbon UI elements template class CRibbonUpdateUI : public CAutoUpdateUI { public: enum { UPDUI_RIBBON = 0x0080, UPDUI_PERSIST = 0x0020 }; bool IsRibbonElement(const _AtlUpdateUIMap& UIMap) { return (UIMap.m_wType & UPDUI_RIBBON) != 0; } bool IsRibbonID(UINT nID) { for(int i = 0; i < m_arrUIMap.GetSize(); i++) { if(m_arrUIMap[i].m_nID == nID) return IsRibbonElement(m_arrUIMap[i]); } return false; } // Element bool UIAddRibbonElement(UINT nID) { return UIAddElement(nID); } bool UIRemoveRibbonElement(UINT nID) { return UIRemoveElement(nID); } bool UIPersistElement(UINT nID, bool bPersist = true) { return bPersist ? UIAddElement(nID) : UIRemoveElement(nID); } // methods for Ribbon elements BOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate); if (pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label)); return bRes; } BOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE) { CTempBuffer sText(RIBBONUI_MAX_TEXT); int nRet = AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT); if(nRet > 0) UISetText(nID, sText, bForceUpdate); return (nRet > 0) ? TRUE : FALSE; } LPCTSTR UIGetText(int nID) { T* pT = static_cast(this); LPCTSTR sUI = CAutoUpdateUI::UIGetText(nID); // replace 'tab' by 'space' for RibbonUI elements if (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\t')) { static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; wcscpy_s(sText, sUI); WCHAR* pch = wcschr(sText, L'\t'); if (pch != NULL) *pch = L' '; return sText; } else { return sUI; } } BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate); if (pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable)); return bRes; } BOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE) { if ((nCheck == 0) || (nCheck == 1)) return UISetCheck(nID, nCheck != 0, bForceUpdate); else return CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate); } BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE) { T* pT = static_cast(this); BOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate); if (bRes && pT->IsRibbonUI() && IsRibbonID(nID)) bRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck)); return bRes; } }; /////////////////////////////////////////////////////////////////////////////// // RibbonUI namespace // namespace RibbonUI { // Minimal string allocation support for various PROPERTYKEY values #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) typedef _CSTRING_NS::CString Text; #else class Text : public std::wstring { public: Text(std::wstring& s) : std::wstring(s) { } Text(LPCWSTR s) : std::wstring(s) { } Text() { } bool IsEmpty() { return empty(); } operator LPCWSTR() { return c_str(); } Text& operator =(LPCWSTR s) { return static_cast(std::wstring::operator =(s)); } }; #endif // PROPERTYKEY enum and helpers enum k_KEY { // state k_Enabled = 1, k_BooleanValue = 200, // text properties k_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6, // image properties k_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10, // collection properties k_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104, // collection item properties k_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106, // combo control property k_StringValue = 202, // spinner control properties k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208, // font control properties k_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304, k_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308, k_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312, k_FontProperties_DeltaSize = 313, // recent items properties k_RecentItems = 350, k_Pinned = 351, // color control properties k_Color = 400, k_ColorType = 401, k_ColorMode, k_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406, k_NoColorLabel = 407, k_MoreColorsLabel = 408, k_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412, // Ribbon state k_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100, // Ribbon UI colors k_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002 }; inline k_KEY k_(REFPROPERTYKEY key) { return (k_KEY)key.fmtid.Data1; } // PROPERTYKEY value assignment and specializations // template HRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv) { switch (k_(key)) { case k_Enabled: case k_BooleanValue: return InitPropVariantFromBoolean(val, ppv); default: return UIInitPropertyFromUInt32(key, val, ppv); } } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv) { return SetPropertyVal(key, (LONG)val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv) { HRESULT hr = UIInitPropertyFromImage(key, val, ppv); ATLVERIFY(val->Release() == 1); return hr; } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv) { return UIInitPropertyFromInterface(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv) { return UIInitPropertyFromInterface(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv) { return UIInitPropertyFromIUnknownArray(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv) { return UIInitPropertyFromDecimal(key, *val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv) { return UIInitPropertyFromBoolean(key, val, ppv); } inline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv) { return UIInitPropertyFromString(key, val, ppv); } // CharFormat helper struct for RibbonUI font control // struct CharFormat : CHARFORMAT2 { // Default constructor CharFormat() { cbSize = sizeof(CHARFORMAT2); Reset(); } // Copy constructor CharFormat(const CharFormat& cf) { ::CopyMemory(this, &cf, sizeof(CHARFORMAT2)); } // Assign operator CharFormat& operator =(const CharFormat& cf) { ::CopyMemory(this, &cf, sizeof(CHARFORMAT2)); return (*this); } void Reset() { uValue = dwMask = dwEffects = 0; PropVariantInit(&propvar); } void operator <<(IPropertyStore* pStore) { if (pStore == NULL) { ATLASSERT(FALSE); return; } static void (CharFormat::*Getk_[])(IPropertyStore*) = { &CharFormat::Getk_Family, &CharFormat::Getk_FontProperties_Size, &CharFormat::Getk_MaskEffectBold, &CharFormat::Getk_MaskEffectItalic, &CharFormat::Getk_MaskEffectUnderline, &CharFormat::Getk_MaskEffectStrikeout, &CharFormat::Getk_VerticalPositioning, &CharFormat::Getk_Color, &CharFormat::Getk_ColorBack, &CharFormat::Getk_ColorType, &CharFormat::Getk_ColorTypeBack, }; DWORD nProps = 0; Reset(); ATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps))); for (DWORD iProp = 0; iProp < nProps; iProp++) { PROPERTYKEY key; ATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key))); ATLASSERT(k_(key) >= k_FontProperties_Family); if (k_(key) <= k_FontProperties_BackgroundColorType) (this->*Getk_[k_(key) - k_FontProperties_Family])(pStore); } } void operator >>(IPropertyStore* pStore) { if (pStore == NULL) { ATLASSERT(FALSE); return; } PutFace(pStore); PutSize(pStore); PutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore); PutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore); PutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore); PutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore); PutVerticalPos(pStore); PutColor(pStore); PutBackColor(pStore); } private: PROPVARIANT propvar; UINT uValue; // Getk_ functions void Getk_Family(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar))) { PropVariantToString(propvar, szFaceName, LF_FACESIZE); if (*szFaceName) dwMask |= CFM_FACE; } } void Getk_FontProperties_Size(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar))) { DECIMAL decSize = { 0 }; UIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize); DOUBLE dSize = 0; VarR8FromDec(&decSize, &dSize); if (dSize > 0) { dwMask |= CFM_SIZE; yHeight = (LONG)(dSize * TWIPS_PER_POINT); } } } void Getk_MaskEffectBold(IPropertyStore* pStore) { Getk_MaskEffectAll(pStore, CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold); } void Getk_MaskEffectItalic(IPropertyStore* pStore) { Getk_MaskEffectAll(pStore, CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic); } void Getk_MaskEffectUnderline(IPropertyStore* pStore) { Getk_MaskEffectAll(pStore, CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline); } void Getk_MaskEffectStrikeout(IPropertyStore* pStore) { Getk_MaskEffectAll(pStore, CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough); } void Getk_MaskEffectAll(IPropertyStore* pStore, DWORD _dwMask, DWORD _dwEffects, REFPROPERTYKEY key) { if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &uValue); if ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE) { dwMask |= _dwMask; dwEffects |= ((UI_FONTPROPERTIES)uValue == UI_FONTPROPERTIES_SET) ? _dwEffects : 0; } } } void Getk_VerticalPositioning(IPropertyStore* pStore) { if (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar))) { UIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue); UI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue; if ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE)) { dwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT); if (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET) { dwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT; } } } } void Getk_Color(IPropertyStore* pStore) { Getk_ColorAll(pStore, CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor); } void Getk_ColorBack(IPropertyStore* pStore) { Getk_ColorAll(pStore, CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor); } void Getk_ColorAll(IPropertyStore* pStore, DWORD _dwMask, REFPROPERTYKEY key) { UINT32 color = 0; if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &color); dwMask |= _dwMask; if (_dwMask == CFM_COLOR) crTextColor = color; else crBackColor = color; } } void Getk_ColorType(IPropertyStore* pStore) { Getk_ColorTypeAll(pStore, CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColor); } void Getk_ColorTypeBack(IPropertyStore* pStore) { Getk_ColorTypeAll(pStore, CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColor); } void Getk_ColorTypeAll(IPropertyStore* pStore, DWORD _dwMask, DWORD _dwEffects, UI_SWATCHCOLORTYPE _type, REFPROPERTYKEY key) { if (SUCCEEDED(pStore->GetValue(key, &propvar))) { UIPropertyToUInt32(key, propvar, &uValue); if (_type == (UI_SWATCHCOLORTYPE)uValue) { dwMask |= _dwMask; dwEffects |= _dwEffects; } } } // Put functions void PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore) { PROPVARIANT var; UI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE; if ((dwMask & dwMaskVal) != 0) uProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET; SetPropertyVal(key, uProp, &var); pStore->SetValue(key, var); } void PutVerticalPos(IPropertyStore* pStore) { PROPVARIANT var; UI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE; if ((dwMask & CFE_SUBSCRIPT) != 0) { if ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT)) uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; else uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; } else if ((dwMask & CFM_OFFSET) != 0) { if (yOffset > 0) uProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT; else if (yOffset < 0) uProp = UI_FONTVERTICALPOSITION_SUBSCRIPT; } SetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &var); pStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, var); } void PutFace(IPropertyStore* pStore) { PROPVARIANT var; SetPropertyVal(UI_PKEY_FontProperties_Family, dwMask & CFM_FACE ? szFaceName : L"", &var); pStore->SetValue(UI_PKEY_FontProperties_Family, var); } void PutSize(IPropertyStore* pStore) { PROPVARIANT var; DECIMAL decVal; if ((dwMask & CFM_SIZE) != 0) VarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal); else VarDecFromI4(0, &decVal); SetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &var); pStore->SetValue(UI_PKEY_FontProperties_Size, var); } void PutColor(IPropertyStore* pStore) { if ((dwMask & CFM_COLOR) != 0) { if ((dwEffects & CFE_AUTOCOLOR) == 0) { SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); SetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar); } else { SetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar); pStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar); } } } void PutBackColor(IPropertyStore* pStore) { if (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0)) { SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); SetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar); } else { SetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar); pStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar); } } }; // IUIImage helper // inline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner) { ATLASSERT(hbm); IUIImage* pIUII = NULL; ATL::CComPtr pIFB; if SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory)) ATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII))); return pIUII; } /////////////////////////////////////////////////////////////////////////////// // Ribbon control classes // RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes // struct ICtrl { virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) = 0; virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0; }; // RibbonUI::CtrlImpl base class for all ribbon controls // template class ATL_NO_VTABLE CtrlImpl : public ICtrl { protected: T* m_pWndRibbon; public: typedef T WndRibbon; CtrlImpl() : m_pWndRibbon(T::pWndRibbon) { } WndRibbon& GetWndRibbon() { return *m_pWndRibbon; } static WORD GetID() { return t_ID; } Text m_sTxt[5]; // Operations HRESULT Invalidate() { return GetWndRibbon().InvalidateCtrl(GetID()); } HRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) { return GetWndRibbon().InvalidateProperty(GetID(), key, flags); } HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false) { ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); m_sTxt[k_(key) - k_LabelDescription] = sTxt; return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } // Implementation template HRESULT SetProperty(REFPROPERTYKEY key, V val) { return GetWndRibbon().SetProperty(GetID(), key, val); } HRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription)); const INT iText = k_(key) - k_LabelDescription; if (m_sTxt[iText].IsEmpty()) if (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key)) m_sTxt[iText] = sText; return !m_sTxt[iText].IsEmpty() ? SetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) : S_OK; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT(nCmdID == t_ID); return GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == t_ID); const INT iMax = k_TooltipTitle - k_LabelDescription; const INT iVal = k_(key) - k_LabelDescription; return (iVal <= iMax) && (iVal >= 0) ? OnGetText(key, ppropvarNewValue) : GetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } }; // CommandCtrlImpl base class for most ribbon controls // template class CommandCtrlImpl : public CtrlImpl { public: CBitmap m_hbm[4]; HRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false) { ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); m_hbm[k_(key) - k_LargeImage].Attach(hbm); return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } HRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage)); const INT iImage = k_(key) - k_LargeImage; if (m_hbm[iImage].IsNull()) m_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key); return m_hbm[iImage].IsNull() ? E_NOTIMPL : SetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv); } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); return (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ? OnGetImage(key, ppropvarNewValue) : CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon collection base classes // ItemProperty class: ribbon callback for each item in a collection // #pragma warning(push) #pragma warning(disable: 4512) // assignment operator could not be generated template class ItemProperty : public IUISimplePropertySet { public: ItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection) { } const UINT m_Index; TCollection* m_pCollection; // IUISimplePropertySet method. STDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value) { return m_pCollection->OnGetItem(m_Index, key, value); } // IUnknown methods. STDMETHODIMP_(ULONG) AddRef() { return 1; } STDMETHODIMP_(ULONG) Release() { return 1; } STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet))) { *ppv = this; return S_OK; } else { return E_NOINTERFACE; } } }; #pragma warning(pop) // CollectionImplBase: base class for all RibbonUI collections // template class CollectionImplBase { typedef CollectionImplBase thisClass; public: CollectionImplBase() { for (int i = 0; i < t_size; i++) m_apItems[i] = new ItemProperty(i, static_cast(this)); } ~CollectionImplBase() { for (int i = 0; i < t_size; i++) delete m_apItems[i]; } // Data members ItemProperty* m_apItems[t_size]; }; // CollectionImpl: handles categories and collecton resizing // template class CollectionImpl : public CollectionImplBase, t_items + t_categories> { typedef CollectionImpl thisClass; public: typedef thisClass Collection; CollectionImpl() : m_size(t_items) { ::FillMemory(m_auItemCat, sizeof(m_auItemCat), 0xff); // UI_COLLECTION_INVALIDINDEX } UINT32 m_auItemCat[t_items]; Text m_asCatName[__max(t_categories, 1)]; size_t m_size; // Operations HRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false) { ATLASSERT((uItem < t_items) && (uCat < t_categories)); m_auItemCat[uItem] = uCat; return bUpdate ? InvalidateItems() : S_OK; } HRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false) { ATLASSERT(uCat < t_categories); m_asCatName[uCat] = sText; return bUpdate ? InvalidateCategories() : S_OK; } HRESULT Resize(size_t size, bool bUpdate = false) { ATLASSERT(size <= t_items); m_size = size; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uIndex < t_items + t_categories); TCtrl* pCtrl = static_cast(this); return uIndex < t_items ? pCtrl->DoGetItem(uIndex, key, value) : pCtrl->DoGetCategory(uIndex - t_items, key, value); } HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(k_(key) == k_CategoryId); UINT32 uCat = UI_COLLECTION_INVALIDINDEX; if (t_categories != 0) { if (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem); } uCat = m_auItemCat[uItem]; } return SetPropertyVal(key, uCat, value); } HRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value) { HRESULT hr = S_OK; switch (k_(key)) { case k_Label: if (m_asCatName[uCat].IsEmpty()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat); } hr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value); break; case k_CategoryId: hr = SetPropertyVal(key, uCat, value); break; default: ATLASSERT(FALSE); break; } return hr; } HRESULT InvalidateItems() { return static_cast(this)->Invalidate(UI_PKEY_ItemsSource); } HRESULT InvalidateCategories() { return static_cast(this)->Invalidate(UI_PKEY_Categories); } HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/) { ATLASSERT(nCmdID == TCtrl::GetID()); nCmdID; // avoid level 4 warning HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ItemsSource: { ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICollection); hr = pIUICollection->Clear(); for (UINT i = 0; i < m_size; i++) { if FAILED(hr = pIUICollection->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; case k_Categories: if (t_categories != 0) { ATL::CComQIPtr pIUICategory(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICategory.p); hr = pIUICategory->Clear(); for (UINT i = t_items; i < (t_items + t_categories); i++) { if FAILED(hr = pIUICategory->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; } return hr; } }; // TextCollectionImpl: handles item labels and selection // template class TextCollectionImpl : public CollectionImpl { typedef TextCollectionImpl thisClass; public: typedef thisClass TextCollection; TextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX) { } Text m_asText[t_items]; UINT m_uSelected; // Operations HRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false) { ATLASSERT(uItem < t_items); m_asText[uItem] = sText; return bUpdate ? InvalidateItems() : S_OK; } UINT GetSelected() { return m_uSelected; } HRESULT Select(UINT uItem, bool bUpdate = false) { ATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX)); m_uSelected = uItem; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); return bUpdate ? ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); if (k_(key) == k_Label) { if (m_asText[uItem].IsEmpty()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem); } return SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value); } else { return Collection::DoGetItem(uItem, key, value); } } HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == TCtrl::GetID()); if (k_(key) == k_SelectedItem) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); UINT uSel = UI_COLLECTION_INVALIDINDEX; if ((m_uSelected == UI_COLLECTION_INVALIDINDEX) && ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel)) m_uSelected = uSel; return SetPropertyVal(key, m_uSelected, ppropvarNewValue); } else { return Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } } }; // ItemCollectionImpl: handles item image // template class ItemCollectionImpl : public TextCollectionImpl { typedef ItemCollectionImpl thisClass; public: typedef thisClass ItemCollection; ItemCollectionImpl() { ::ZeroMemory(m_aBitmap, sizeof(m_aBitmap)); } CBitmap m_aBitmap[t_items]; // Operations HRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false) { ATLASSERT(uIndex < t_items); m_aBitmap[uIndex] = hbm; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); if (k_(key) == k_ItemImage) { if (m_aBitmap[uItem].IsNull()) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem); } return m_aBitmap[uItem].IsNull() ? E_NOTIMPL : SetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value); } else { return TextCollection::DoGetItem(uItem, key, value); } } }; // ComboCollectionImpl: handles combo text // template class ComboCollectionImpl : public ItemCollectionImpl { typedef ComboCollectionImpl thisClass; public: typedef thisClass ComboCollection; // Operations HRESULT SetComboText(LPCWSTR sText) { TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); return ribbon.IsRibbonUI() ? ribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) : S_OK; } LPCWSTR GetComboText() { static WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 }; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); PROPVARIANT var; if (ribbon.IsRibbonUI()) { HRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var); hr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT); return sCombo; } return NULL; } }; // CommandCollectionImpl: handles RibbonUI command collection controls // template class CommandCollectionImpl : public CollectionImpl { typedef CommandCollectionImpl thisClass; public: typedef thisClass CommandCollection; CommandCollectionImpl() { ::ZeroMemory(m_auCmd, sizeof(m_auCmd)); ::ZeroMemory(m_aCmdType, sizeof(m_aCmdType)); } UINT32 m_auCmd[t_items]; BYTE m_aCmdType[t_items]; // Operations HRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false) { ATLASSERT(uItem < t_items); if (uCommandID == m_auCmd[uItem]) return S_OK; TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); m_auCmd[uItem] = uCommandID; if (uCommandID != 0) ribbon.UIAddRibbonElement(uCommandID); return bUpdate ? InvalidateItems() : S_OK; } HRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false) { ATLASSERT(uItem < t_items); m_aCmdType[uItem] = (BYTE)type; return bUpdate ? InvalidateItems() : S_OK; } // Implementation HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_items); TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); HRESULT hr = E_FAIL; switch (k_(key)) { case k_CommandId: if (m_auCmd[uItem] == 0) SetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem)); hr = SetPropertyVal(key, m_auCmd[uItem], value); break; case k_CommandType: if (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN) SetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem)); hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); break; case k_CategoryId: default: hr = Collection::DoGetItem(uItem, key, value); break; } return hr; } HRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false) { ATLASSERT(FALSE); return S_OK; } }; // SimpleCollectionImpl: collection class for ribbon simple collection controls // template class SimpleCollectionImpl : public CollectionImplBase, t_size> { typedef SimpleCollectionImpl thisClass; public: typedef CollectionImplBase CollectionBase; typedef thisClass SimpleCollection; // Implementation HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < t_size); TCtrl::WndRibbon& ribbon = static_cast(this)->GetWndRibbon(); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ItemImage: if (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem)) hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value); break; case k_Label: if (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem)) hr = SetPropertyVal(key, (LPCWSTR)sText, value); break; case k_CommandType: hr = SetPropertyVal(key, t_CommandType, value); break; case k_CommandId: hr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value); break; case k_CategoryId: hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); break; default: ATLASSERT(FALSE); break; } return hr; } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon collection control classes // CollectionCtrlImpl: specializable class for ribbon collection controls // template class CollectionCtrlImpl : public CommandCtrlImpl, public TCollection { typedef CollectionCtrlImpl thisClass; public: typedef CommandCtrlImpl CommandCtrl; typedef TCollection Collection; // Implementation virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue); HRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); if FAILED(hr) hr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level4 warning if (key == NULL) // gallery button pressed { GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); return S_OK; } ATLASSERT(k_(*key) == k_SelectedItem); ATLASSERT(ppropvarValue); HRESULT hr = S_OK; UINT32 uSel = 0xffff; hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); if (SUCCEEDED(hr)) { if (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel)) TCollection::Select(uSel); } return hr; } }; // ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls // template class ToolbarGalleryCtrlImpl : public CollectionCtrlImpl, t_size>> { public: ToolbarGalleryCtrlImpl() { CResource tbres; ATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB)); _AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock(); ATLASSERT(pData); ATLASSERT(pData->wVersion == 1); WORD* pItems = pData->items(); INT j = 0; for (int i = 0; (i < pData->wItemCount) && (j < t_size); i++) { if (pItems[i] != 0) { m_aCmdType[j] = UI_COMMANDTYPE_ACTION; m_auCmd[j++] = pItems[i]; } } if (j < t_size) Resize(j); } HRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT(uItem < m_size); ATLASSERT(m_auCmd[uItem]); HRESULT hr = E_FAIL; switch (k_(key)) { case k_CommandId: hr = SetPropertyVal(key, m_auCmd[uItem], value); break; case k_CommandType: hr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value); break; case k_CategoryId: hr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value); break; default: ATLASSERT(FALSE); break; } return hr; } }; // SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls // template class SimpleCollectionCtrlImpl : public CommandCtrlImpl, public SimpleCollectionImpl, t_size, t_CommandType> { typedef SimpleCollectionCtrlImpl thisClass; public: typedef thisClass SimpleCollection; SimpleCollectionCtrlImpl() : m_uSelected(0) { } UINT m_uSelected; HRESULT Select(UINT uItem, bool bUpdate = false) { ATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX)); m_uSelected = uItem; return bUpdate ? GetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) : S_OK; } // Implementation virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue != NULL); HRESULT hr = S_OK; switch (k_(key)) { case k_ItemsSource: { ATL::CComQIPtr pIUICollection(ppropvarCurrentValue->punkVal); ATLASSERT(pIUICollection.p); hr = pIUICollection->Clear(); for (UINT i = 0; i < t_size; i++) { if FAILED(hr = pIUICollection->Add(m_apItems[i])) break; } ATLASSERT(SUCCEEDED(hr)); } break; case k_SelectedItem: hr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue); break; default: hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning HRESULT hr = S_OK; if (key == NULL) // gallery button pressed { GetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX); return hr; } ATLASSERT(k_(*key) == k_SelectedItem); ATLASSERT(ppropvarValue); if SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected)) GetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected); return hr; } }; // RecentItemsCtrlImpl // template class RecentItemsCtrlImpl : public CtrlImpl, public CollectionImplBase, TDocList::m_nMaxEntries_Max>, public TDocList { typedef RecentItemsCtrlImpl thisClass; public: typedef thisClass RecentItems; // Implementation HRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value) { ATLASSERT((INT)uItem < GetMaxEntries()); LPCWSTR sPath = m_arrDocs[uItem].szDocName; HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_Label: hr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value); break; case k_LabelDescription: hr = SetPropertyVal(key, sPath, value); break; default: ATLASSERT(FALSE); break; } return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT(nCmdID == GetID()); ATLASSERT(ppropvarNewValue); HRESULT hr = S_OK; switch (k_(key)) { case k_RecentItems: if (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize())) { const int iLastIndex = m_arrDocs.GetSize() - 1; for (LONG i = 0; i <= iLastIndex; i++) SafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order hr = SetPropertyVal(key, psa, ppropvarNewValue); SafeArrayDestroy(psa); } break; default: hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT(nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning ATLASSERT((key) && (k_(*key) == k_SelectedItem)); ATLASSERT(ppropvarValue); UINT32 uSel = 0xffff; HRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel); if SUCCEEDED(hr) { ATLASSERT(uSel < (UINT)GetMaxEntries()); GetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel); } return hr; } }; /////////////////////////////////////////////////////////////////////////////// // Ribbon stand-alone control classes // FontCtrlImpl // template class FontCtrlImpl : public CtrlImpl { public: CharFormat m_cf; // Implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT ((key) && (k_(*key) == k_FontProperties)); key; // avoid level 4 warning HRESULT hr = E_INVALIDARG; switch (verb) { case UI_EXECUTIONVERB_PREVIEW: case UI_EXECUTIONVERB_EXECUTE: ATLASSERT(pCommandExecutionProperties); PROPVARIANT propvar; if (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar))) m_cf << ATL::CComQIPtr(propvar.punkVal); break; case UI_EXECUTIONVERB_CANCELPREVIEW: ATLASSERT(ppropvarValue); ATL::CComPtr pStore; if (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore))) m_cf << pStore; break; } if (SUCCEEDED(hr)) GetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf); else ATLASSERT(FALSE); return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { if ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf))) { ATL::CComQIPtr pStore(ppropvarCurrentValue->punkVal); m_cf >> pStore; return SetPropertyVal(key, pStore.p, ppropvarNewValue); } else { return CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } } }; // ColorCtrlImpl // template class ColorCtrlImpl : public CommandCtrlImpl { public: ColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/ { } COLORREF m_color; UINT32 m_colorType; // value in UI_SWATCHCOLORTYPE Text m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel ATL::CSimpleArray m_aColors[2]; ATL::CSimpleArray m_aTooltips[2]; // Operations HRESULT SetColor(COLORREF color, bool bUpdate = false) { if (m_colorType != UI_SWATCHCOLORTYPE_RGB) SetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate); m_color = color; return bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK; } HRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false) { m_colorType = type; return bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK; } HRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false) { ATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel)); m_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel; return bUpdate ? SetProperty(key, sLabel) : S_OK; } HRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false) { ATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors)); const INT ic = k_(key) - k_ThemeColors; m_aColors[ic].RemoveAll(); while (*pColor != 0x800080) /*MAGENTA*/ m_aColors[ic].Add(*pColor++); if (bUpdate) { PROPVARIANT var; if SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var)) return SetProperty(key, var); else return E_INVALIDARG; } else { return S_OK; } } HRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false) { ATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips)); const INT ic = k_(key) - k_ThemeColorsTooltips; m_aTooltips[ic].RemoveAll(); while (*ppsTT) m_aTooltips[ic].Add(*ppsTT++); if (bUpdate) { PROPVARIANT var; if SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var)) return SetProperty(key, var); else return E_INVALIDARG; } else { return S_OK; } } // Implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT (key && (k_(*key) == k_ColorType)); key; // avoid level 4 warning ATLASSERT (ppropvarValue); HRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType); ATLASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB)) { ATLASSERT(pCommandExecutionProperties); PROPVARIANT var; if SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var)) hr = PropVariantToUInt32(var, &m_color); } if SUCCEEDED(hr) GetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color); else ATLASSERT(FALSE); // something was wrong return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_ColorType: hr = SetPropertyVal(key, m_colorType, ppropvarNewValue); break; case k_Color: if (m_color == 0x800080) /*MAGENTA*/ m_color = GetWndRibbon().OnRibbonQueryColor(GetID()); hr = SetPropertyVal(key, m_color, ppropvarNewValue); break; case k_ColorMode: break; case k_ThemeColorsCategoryLabel: case k_StandardColorsCategoryLabel: case k_RecentColorsCategoryLabel: case k_AutomaticColorLabel: case k_NoColorLabel: case k_MoreColorsLabel: { const UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel; if (m_sLabels[iLabel].IsEmpty()) if (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key)) m_sLabels[iLabel] = psLabel; if (!m_sLabels[iLabel].IsEmpty()) hr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue); } break; case k_ThemeColors: case k_StandardColors: { const INT ic = k_(key) - k_ThemeColors; if (!m_aColors[ic].GetSize()) if (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key)) SetColorArray(key, pColor); if (INT iMax = m_aColors[ic].GetSize()) hr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue); } break; case k_ThemeColorsTooltips: case k_StandardColorsTooltips: { const INT ic = k_(key) - k_ThemeColorsTooltips; if (m_aTooltips[ic].GetSize() == 0) if (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key)) SetColorTooltips(key, ppsTT); if (INT iMax = m_aTooltips[ic].GetSize()) hr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue); } break; default: hr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } }; // SpinnerCtrlImpl // template class SpinnerCtrlImpl : public CtrlImpl { public: SpinnerCtrlImpl() { m_Values[0] = m_Values[2] = m_Values[4] = 0; m_Values[1] = 100; m_Values[3] = 1; } V m_Values[5]; // k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces Text m_FormatString; Text m_RepresentativeString; // Operations HRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false) { return SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate); } HRESULT SetMin(V vMin, bool bUpdate = false) { return SetValue(UI_PKEY_MinValue, vMin, bUpdate); } HRESULT SetMax(V vMax, bool bUpdate = false) { return SetValue(UI_PKEY_MaxValue, vMax, bUpdate); } HRESULT SetVal(V vVal, bool bUpdate = false) { return SetValue(UI_PKEY_DecimalValue, vVal, bUpdate); } HRESULT SetIncrement(V vIncrement, bool bUpdate = false) { return SetValue(UI_PKEY_Increment, vIncrement, bUpdate); } HRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false) { return SetText(UI_PKEY_FormatString, sFormat, bUpdate); } HRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false) { return SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate); } // Implementation HRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false) { switch (k_(key)) { case k_FormatString: m_FormatString = sText; break; case k_RepresentativeString: m_RepresentativeString = sText; break; default: return CtrlImpl::SetText(key, sText, bUpdate); } return bUpdate ? GetWndRibbon().InvalidateProperty(GetID(), key) : S_OK; } HRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false) { ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; m_Values[iVal] = val; if (bUpdate) { if(k_(key) == k_DecimalValue) { DECIMAL decVal; InitDecimal(val, &decVal); return SetProperty(key, &decVal); } else { return GetWndRibbon().InvalidateProperty(GetID(), key); } } else { return S_OK; } } HRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal) { return GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal) ? S_OK : S_FALSE; } HRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal) { return GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal) ? S_OK : S_FALSE; } HRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv) { ATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue)); const INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue; QueryValue(key, m_Values + iVal); if (k_(key) == k_DecimalPlaces) { return SetPropertyVal(key, m_Values[iVal], ppv); } else { DECIMAL decVal; InitDecimal(m_Values[iVal], &decVal); return SetPropertyVal(key, &decVal, ppv); } } HRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv) { if (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key)) sVal = sNew; return SetPropertyVal(key, (LPCWSTR)sVal, ppv); } virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { ATLASSERT (nCmdID == GetID()); nCmdID; // avoid level 4 warning ATLASSERT (key && (k_(*key) == k_DecimalValue)); key; // avoid level 4 warning ATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning DECIMAL decVal; HRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal); hr = InitVal(m_Values[0], &decVal); GetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]); return hr; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { ATLASSERT (nCmdID == GetID()); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_DecimalPlaces: case k_DecimalValue: case k_Increment: case k_MaxValue: case k_MinValue: hr = OnGetValue(key, ppropvarNewValue); break; case k_FormatString: if (m_FormatString.IsEmpty()) return OnGetText(key, m_FormatString, ppropvarNewValue); break; case k_RepresentativeString: if (m_RepresentativeString.IsEmpty()) return OnGetText(key, m_RepresentativeString, ppropvarNewValue); break; default: hr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); break; } return hr; } // decimal conversion helpers static HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal) { return ::VarDecFromI4(val, pDecimal); } static HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal) { return ::VarDecFromR8(val, pDecimal); } static HRESULT InitVal(LONG& val, const DECIMAL* pDecimal) { return ::VarI4FromDec(pDecimal, &val); } static HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal) { return ::VarR8FromDec(pDecimal, &val); } }; // CRibbonImpl Ribbon implementation class // template class CRibbonImpl : public CRibbonUpdateUI, public ICtrl, public IUIApplication, public IUICommandHandler { typedef CRibbonImpl thisClass; public: typedef thisClass Ribbon; typedef T WndRibbon; CRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL) { #ifdef _DEBUG m_cRef = 1; #endif pWndRibbon = static_cast(this); HRESULT hr = ::CoInitialize(NULL); if(SUCCEEDED(hr)) if (RunTimeHelper::IsRibbonUIAvailable()) hr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework); else ATLTRACE2(atlTraceUI, 0, _T("Ribbon UI not available\n")); if FAILED(hr) ATLTRACE2(atlTraceUI, 0, _T("Ribbon construction failed\n")); ATLASSERT(SUCCEEDED(hr)); } ~CRibbonImpl() { ::GlobalFree(m_hgRibbonSettings); m_pIUIFramework.Release(); ::CoUninitialize(); } ICtrl& GetRibbonCtrl(UINT) { return static_cast(*this); } ATL::CComPtr m_pIUIFramework; HGLOBAL m_hgRibbonSettings; bool m_bRibbonUI; bool IsRibbonUI() { return m_bRibbonUI; } IUIFramework* GetIUIFrameworkPtr() { return m_pIUIFramework; } template I* GetRibbonViewPtr(UINT32 uID) { ATLASSERT(m_pIUIFramework); ATL::CComPtr pI; return m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ? pI : NULL; } IUIRibbon* GetRibbonPtr() { return GetRibbonViewPtr(0); } IUIContextualUI* GetMenuPtr(UINT32 uID) { ATLASSERT(uID); return GetRibbonViewPtr(uID); } UINT GetRibbonHeight() { ATLASSERT(IsRibbonUI()); UINT32 cy = 0; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) pIUIRibbon->GetHeight(&cy); return cy; } HRESULT CreateRibbon(LPCWSTR sResName = L"APPLICATION_RIBBON") { T* pT = static_cast(this); ATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI()); ATLASSERT(pT->IsWindow()); HRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this); if (hr == S_OK) hr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName); return hr; } HRESULT DestroyRibbon() { T* pT = static_cast(this); ATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI()); ATLASSERT(pT->IsWindow()); HRESULT hRes = m_pIUIFramework->Destroy(); if (!RunTimeHelper::IsWin7()) pT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround return hRes; } // Ribbon persistency HRESULT operator >>(IStream* pIStream) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(pIStream); HRESULT hr = E_FAIL; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) { const LARGE_INTEGER li0 = { 0 }; pIStream->Seek(li0, STREAM_SEEK_SET, NULL); hr = pIUIRibbon->SaveSettingsToStream(pIStream); pIStream->Commit(STGC_DEFAULT); } return hr; } HRESULT operator <<(IStream* pIStream) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(pIStream); HRESULT hr = E_FAIL; if (ATL::CComPtr pIUIRibbon = GetRibbonPtr()) { const LARGE_INTEGER li0 = { 0 }; pIStream->Seek(li0, STREAM_SEEK_SET, NULL); hr = pIUIRibbon->LoadSettingsFromStream(pIStream); } return hr; } void ResetRibbonSettings() { if (m_hgRibbonSettings != NULL) { ::GlobalFree(m_hgRibbonSettings); m_hgRibbonSettings = NULL; } } HRESULT SaveRibbonSettings() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(static_cast(this)->IsWindow()); HRESULT hr = E_FAIL; ATL::CComPtr pIStream; if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) hr = *this >> pIStream; if (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL)) hr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings); if FAILED(hr) ResetRibbonSettings(); return hr; } HRESULT RestoreRibbonSettings() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(m_hgRibbonSettings); ATLASSERT(static_cast(this)->IsWindow()); HRESULT hr = E_FAIL; ATL::CComPtr pIStream; if SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream)) hr = *this << pIStream; if FAILED(hr) ResetRibbonSettings(); return hr; } // QAT dock states UI_CONTROLDOCK GetQATDock() { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); UINT32 uDock = 0; PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) && SUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock))) return (UI_CONTROLDOCK)uDock; ATLASSERT(FALSE); // something was wrong return (UI_CONTROLDOCK)0; } bool SetQATDock(UI_CONTROLDOCK dockState) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar))); ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } // Ribbon display states bool GetRibbonDisplayState(REFPROPERTYKEY key) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) { BOOL bState = FALSE; if SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState)) return (bState != FALSE); } ATLASSERT(FALSE); // something was wrong return false; } bool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized)); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar))); ATL::CComQIPtrpIPS(GetRibbonPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } bool IsRibbonMinimized() { return GetRibbonDisplayState(UI_PKEY_Minimized); } bool MinimizeRibbon(bool bMinimize = true) { return SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize); } bool IsRibbonHidden() { return !GetRibbonDisplayState(UI_PKEY_Viewable); } bool HideRibbon(bool bHide = true) { return SetRibbonDisplayState(UI_PKEY_Viewable, !bHide); } // Ribbon colors UI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); PROPVARIANT propvar; ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar))) { UINT32 color = 0; if SUCCEEDED(UIPropertyToUInt32(key, propvar, &color)) return color; } ATLASSERT(FALSE); // something was wrong return 0; } bool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color) { ATLASSERT(GetIUIFrameworkPtr()); ATLASSERT(IsRibbonUI()); ATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor)); PROPVARIANT propvar; ATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar))); ATL::CComQIPtrpIPS(GetIUIFrameworkPtr()); if ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar))) { pIPS->Commit(); return true; } ATLASSERT(FALSE); // something was wrong return false; } // Ribbon modes HRESULT SetRibbonModes(INT32 iModes) { ATLASSERT(IsRibbonUI()); return GetIUIFrameworkPtr()->SetModes(iModes); } // Ribbon contextual tab UI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID) { ATLASSERT(GetIUIFrameworkPtr()); PROPVARIANT propvar; if (IsRibbonUI() && SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar))) { UINT uav; if (SUCCEEDED(PropVariantToUInt32(propvar, &uav))) { CUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); CUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE); return (UI_CONTEXTAVAILABILITY)uav; } } return UI_CONTEXTAVAILABILITY_NOTAVAILABLE; } HRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav) { CUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE); CUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE); return SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav)); } // Ribbon context menu bool HasRibbonMenu(UINT32 uID) { ATL::CComPtr pI = GetMenuPtr(uID); return pI != NULL; } HRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y) { ATLASSERT(HasRibbonMenu(uID)); return IsRibbonUI() ? ATL::CComPtr(GetMenuPtr(uID))->ShowAtLocation(x, y) : E_FAIL; } HRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam) { return TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } // Overrideables HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/) { return DefRibbonQueryImage(nCmdID); } LPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) { return DefRibbonQueryText(nCmdID, key); } bool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) { return DefRibbonQueryState(nCmdID, key); } UI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID) { DWORD dwState = UIGetState(nCmdID); return ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ? UI_CONTEXTAVAILABILITY_NOTAVAILABLE : (((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ? UI_CONTEXTAVAILABILITY_ACTIVE : UI_CONTEXTAVAILABILITY_AVAILABLE); } LPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/) { return NULL; } LPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/) { return L"Category"; } UINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) { return 0; } LPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemText(uCtrlID, uItem); } bool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/) { return false; } HBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemImage(uCtrlID, uItem); } UINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryItemCommand(uCtrlID, uItem); } UI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/) { return UI_COMMANDTYPE_ACTION; } LPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath) { return ::PathFindFileName(sPath); } bool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/) { return false; } bool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/) { return false; } bool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/) { return false; } COLORREF OnRibbonQueryColor(UINT /*nCmdID*/) { return 0x800080; /*MAGENTA*/ } LPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } COLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } LPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/) { return NULL; } bool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem) { DefCommandExecute(MAKELONG(uCtrlID, verb), uItem); return true; } void OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) { DefRibbonColorCtrlExecute(uCtrlID, verb, uType, color); } void OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf) { DefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf); } void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal) { DefCommandExecute(uCtrlID, *pVal); } void OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal) { DefCommandExecute(uCtrlID, (LPARAM)pVal); } void OnRibbonCommandExecute(UINT32 uCmdID) { DefCommandExecute(uCmdID); } // Default implementations HBITMAP DefRibbonQueryImage(UINT nCmdID) { return AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION); } bool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key) { DWORD dwState = UIGetState(nCmdID); bool bRet = false; switch (k_(key)) { case k_BooleanValue: bRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED; break; case k_Enabled: bRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED; break; default: ATLASSERT(FALSE); break; } return bRet; } LPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key) { static WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 }; if (k_(key) == k_Label) return UIGetText(nCmdID); if (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT)) { PWCHAR pTitle = wcschr(sText, L'\n'); switch (k_(key)) { case k_Keytip: if (PWCHAR pAmp = wcschr(sText, L'&')) pTitle = pAmp; if (pTitle != NULL) *(pTitle + 2) = NULL; // fall through case k_TooltipTitle: return pTitle ? ++pTitle : NULL; case k_TooltipDescription: case k_LabelDescription: if (pTitle != NULL) *pTitle = NULL; return sText; } } return NULL; } LPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription); } HBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem) { return DefRibbonQueryImage(uCtrlID + 1 + uItem); } UINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem) { return uCtrlID + 1 + uItem; } void DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color) { switch(uType) { case UI_SWATCHCOLORTYPE_RGB: break; case UI_SWATCHCOLORTYPE_AUTOMATIC: color = ::GetSysColor(COLOR_WINDOWTEXT); break; case UI_SWATCHCOLORTYPE_NOCOLOR: color = ::GetSysColor(COLOR_WINDOW); break; default: ATLASSERT(FALSE); break; } DefCommandExecute(MAKELONG(uCtrlID, verb), color); } void DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0) { static_cast(this)->PostMessage(WM_COMMAND, uCmd, lParam); } // Elements setting helpers HRESULT InvalidateCtrl(UINT32 nID) { return IsRibbonUI() ? GetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) : E_FAIL; } HRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY) { return IsRibbonUI() ? GetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) : E_FAIL; } template HRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val) { if (IsRibbonUI()) { PROPVARIANT var; if (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var))) { return SetProperty(wID, key, var); } return E_INVALIDARG; } else { return E_FAIL; } } template <> HRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var) { return IsRibbonUI() ? GetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) : E_FAIL; } // Interfaces // IUIApplication STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32) { switch (verb) { case UI_VIEWVERB_CREATE: m_bRibbonUI = true; if (m_hgRibbonSettings != NULL) RestoreRibbonSettings(); break; case UI_VIEWVERB_SIZE: static_cast(this)->UpdateLayout(FALSE); break; case UI_VIEWVERB_DESTROY: SaveRibbonSettings(); m_bRibbonUI = false; break; } return S_OK; } STDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler) { UIAddRibbonElement(nCmdID); if (typeID == UI_COMMANDTYPE_CONTEXT) CUpdateUIBase::UIEnable(nCmdID, false); *ppCommandHandler = this; return S_OK; } STDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*) { UIRemoveRibbonElement(nCmdID); return S_OK; } // IUICommandHandler STDMETHODIMP Execute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* pCommandExecutionProperties) { T* pT =static_cast(this); return pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties); } STDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) { T* pT =static_cast(this); return pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue); } #ifdef _DEBUG // IUnknown methods (heavyweight) STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) Release() { LONG cRef = InterlockedDecrement(&m_cRef); if (cRef == 0) // NoOp for breakpoint { cRef = 0; } return cRef; } STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if (ppv == NULL) { return E_POINTER; } else if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUICommandHandler)) || (iid == __uuidof(IUIApplication))) { *ppv = this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } } LONG m_cRef; #else // IUnknown methods (lightweight) STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUICommandHandler)) || (iid == __uuidof(IUIApplication))) { *ppv = this; return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE AddRef() { return 1; } ULONG STDMETHODCALLTYPE Release() { return 1; } #endif // CRibbonImpl ICtrl implementation virtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue, IUISimplePropertySet* /*pCommandExecutionProperties*/) { if (key != NULL) { if(k_(*key) != k_BooleanValue) { ATLTRACE2(atlTraceUI, 0, _T("Control ID %d is not handled\n"), nCmdID); return E_NOTIMPL; } BOOL bChecked = FALSE; ATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked))); CUpdateUIBase::UISetCheck(nCmdID, bChecked); } ATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE); verb; // avoid level 4 warning static_cast(this)->OnRibbonCommandExecute(nCmdID); return S_OK; } virtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, const PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue) { T* pT = static_cast(this); HRESULT hr = E_NOTIMPL; switch (k_(key)) { case k_LargeImage: case k_LargeHighContrastImage: case k_SmallImage: case k_SmallHighContrastImage: if (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key)) hr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue); break; case k_Label: case k_Keytip: case k_TooltipTitle: case k_TooltipDescription: case k_LabelDescription: if (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key)) hr = SetPropertyVal(key, sText, ppropvarNewValue); break; case k_BooleanValue: case k_Enabled: hr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue); break; case k_ContextAvailable: hr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue); break; } return hr; } // CRibbonImpl::CRibbonXXXCtrl specialized classes //CRibbonComboCtrl template class CRibbonComboCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonComboCtrl() { } }; // CRibbonItemGalleryCtrl template class CRibbonItemGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonItemGalleryCtrl() { } }; // CRibbonCommandGalleryCtrl template class CRibbonCommandGalleryCtrl : public CollectionCtrlImpl, t_items, t_categories>> { public: CRibbonCommandGalleryCtrl() { } }; // CRibbonToolbarGalleryCtrl template class CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl { }; // CRibbonSimpleComboCtrl template class CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl { }; // CRibbonSimpleGalleryCtrl template class CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl { }; //CRibbonRecentItemsCtrl template class CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl { public: CRibbonRecentItemsCtrl() { } }; // CRibbonColorCtrl template class CRibbonColorCtrl : public ColorCtrlImpl { public: CRibbonColorCtrl() { } }; //CRibbonFontCtrl template class CRibbonFontCtrl : public FontCtrlImpl { public: CRibbonFontCtrl() { } }; // CRibbonSpinnerCtrl template class CRibbonSpinnerCtrl : public SpinnerCtrlImpl { public: CRibbonSpinnerCtrl() { } }; // CRibbonFloatSpinnerCtrl template class CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl { public: CRibbonFloatSpinnerCtrl() { m_Values[4] = 1; // 1 decimal } }; // CRibbonCommandCtrl template class CRibbonCommandCtrl : public CommandCtrlImpl { public: CRibbonCommandCtrl() { } }; // Control classes access to T instance (re-initialized in constructor) static T* pWndRibbon; }; template __declspec(selectany) T* CRibbonImpl::pWndRibbon; // Control map element #pragma warning(push) #pragma warning(disable: 4510 610 4512) // missing default constructor, can't be instatiated, assignment operator could not be generated typedef struct { UINT uID; ICtrl& ctrl; } _ribbonCtrl; #pragma warning(pop) }; // namespace RibbonUI /////////////////////////////////////////////////////////////////////////////// // RibbonUI Control map // Control map macros #define BEGIN_RIBBON_CONTROL_MAP(theClass) \ WTL::RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \ { \ WTL::RibbonUI::_ribbonCtrl _ctrls[] = \ { #define RIBBON_CONTROL(member) {member.GetID(), static_cast(member)}, #define END_RIBBON_CONTROL_MAP() \ {0, *this} \ }; \ int i = 0; \ for(; i < _countof(_ctrls) - 1; i++) \ if (_ctrls[i].uID == id) \ break; \ return _ctrls[i].ctrl; \ } // Control message map macros #define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_COMBO_CONTROL_HANDLER(id, func) \ RIBBON_GALLERY_CONTROL_HANDLER(id, func) #define RIBBON_FONT_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_COLOR_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == wParam) \ { \ bHandled = TRUE; \ lResult = func((WORD)wParam, (LONG)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \ if(uMsg == WM_COMMAND && id == wParam) \ { \ bHandled = TRUE; \ lResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } // Handler prototypes /* LRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); LRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled); LRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled); LRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled); LRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled); LRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled); */ /////////////////////////////////////////////////////////////////////////////// // Ribbon frame classes // CRibbonFrameWindowImplBase // template class ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl { typedef TFrameImpl baseFrame; bool m_bUseCommandBarBitmaps; bool m_bWin7Fix; public: // Construction CRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) : m_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false) { __if_not_exists(T::m_CmdBar) { m_bUseCommandBarBitmaps = false; } } // Win7 Aero fix helpers void ResetFrame() { const MARGINS margins = { 0 }; ::DwmExtendFrameIntoClientArea(m_hWnd, &margins); } INT CalcWin7Fix() { ResetFrame(); RECT rc = { 0 }; ::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0)); return -rc.top; } bool NeedWin7Fix() { BOOL bComp = FALSE; return m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp; } // Operations bool UseCommandBarBitmaps(bool bUse) { __if_exists(T::m_CmdBar) { return m_bUseCommandBarBitmaps = bUse; } __if_not_exists(T::m_CmdBar) { bUse; // avoid level 4 warning return false; } } bool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L"APPLICATION_RIBBON") { if (!RunTimeHelper::IsRibbonUIAvailable()) return false; ATLASSERT(GetIUIFrameworkPtr()); if (IsRibbonUI() == bShow) return bShow; bool bVisible = (IsWindowVisible() != FALSE); if(bVisible && !bShow) SetRedraw(FALSE); if (bShow && ::IsWindow(m_hWndToolBar)) { ::ShowWindow(m_hWndToolBar, SW_HIDE); UpdateLayout(); } m_bWin7Fix = !bShow; HRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon(); m_bWin7Fix = SUCCEEDED(hr) && !bShow; if (SUCCEEDED(hr)) { if(::IsWindow(m_hWndToolBar) && !bShow) { ::ShowWindow(m_hWndToolBar, SW_SHOWNA); UpdateLayout(); } else if (bShow) { PostMessage(WM_SIZE); SetRibbonModes(imodes); } } if(bVisible && !bShow) { SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); } return SUCCEEDED(hr) ? bShow : !bShow; } // Overrideables HBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key) { if ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps) { if (HBITMAP hbm = GetCommandBarBitmap(nCmdID)) return (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); } return DefRibbonQueryImage(nCmdID); } BEGIN_MSG_MAP(CRibbonFrameWindowImplBase) if (!IsRibbonUI() && NeedWin7Fix()) { MESSAGE_HANDLER(WM_SIZING, OnSizing) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) MESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize) } CHAIN_MSG_MAP(CRibbonUpdateUI) CHAIN_MSG_MAP(baseFrame) END_MSG_MAP() // Message handlers for Win7 Aero LRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { switch (wParam) { case WMSZ_TOP: case WMSZ_TOPLEFT: case WMSZ_TOPRIGHT: SetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); break; default: DefWindowProc(); break; } return 1; // handled } LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if (wParam != SIZE_MINIMIZED) SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); bHandled = FALSE; return 1; } LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam != WA_INACTIVE) SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); bHandled = FALSE; return 1; } LRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { ATLASSERT(!IsRibbonUI() && NeedWin7Fix()); LRESULT lRet = DefWindowProc(); if(wParam) { LPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam; pParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix(); } return lRet; } // Overrides void UpdateLayout(BOOL bResizeBars = TRUE) { RECT rect = { 0 }; GetClientRect(&rect); if (IsRibbonUI() && !IsRibbonHidden()) { rect.top += GetRibbonHeight(); } else if (!IsRibbonUI() && NeedWin7Fix()) { ResetFrame(); } // position bars and offset their dimensions UpdateBarsPosition(rect, bResizeBars); // resize client window if(m_hWndClient != NULL) ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE); } // Implementation HBITMAP GetCommandBarBitmap(UINT nCmdID) { __if_exists (T::m_CmdBar) { ATLASSERT(RunTimeHelper::IsVista()); T* pT =static_cast(this); int nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID); return (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex]; } __if_not_exists (T::m_CmdBar) { nCmdID; // avoid level 4 warning return NULL; } } }; // CRibbonFrameWindowImpl // template class ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase> { }; // CRibbonMDIFrameWindowImpl // template class ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase> { }; /////////////////////////////////////////////////////////////////////////////// // CRibbonPersist helper for RibbonUI persistency class CRibbonPersist { public: CRibbonPersist(LPCWSTR sAppKey) { ATLASSERT(sAppKey && *sAppKey); m_Key.Create(HKEY_CURRENT_USER, sAppKey); ATLASSERT(m_Key.m_hKey); } CRegKeyEx m_Key; LONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL) { CRegKeyEx key; const DWORD dwUI = bRibbonUI; LONG lRet = key.Create(m_Key, L"Ribbon"); if(lRet != ERROR_SUCCESS) return lRet; lRet = key.SetDWORDValue(L"UI", dwUI); if(lRet != ERROR_SUCCESS) return lRet; if (hgSettings != NULL) { LPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings); if (pVal != NULL) { lRet = key.SetBinaryValue(L"Settings", pVal, (ULONG)::GlobalSize(hgSettings)); ::GlobalUnlock(hgSettings); } else { lRet = GetLastError(); } } return lRet; } LONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings) { ATLASSERT(hgSettings == NULL); CRegKeyEx key; LONG lRet = key.Open(m_Key, L"Ribbon"); if(lRet != ERROR_SUCCESS) return lRet; DWORD dwUI = 0xffff; lRet = key.QueryDWORDValue(L"UI", dwUI); if(lRet == ERROR_SUCCESS) bRibbonUI = dwUI == 1; else return lRet; ULONG ulSize = 0; lRet = key.QueryBinaryValue(L"Settings", NULL, &ulSize); if (lRet == ERROR_SUCCESS) { ATLASSERT(ulSize != 0); hgSettings = ::GlobalAlloc(GHND, ulSize); if (hgSettings != NULL) { LPBYTE pData = (LPBYTE)::GlobalLock(hgSettings); if (pData != NULL) { lRet = key.QueryBinaryValue(L"Settings", pData, &ulSize); } else { lRet = GetLastError(); ::GlobalFree(hgSettings); hgSettings = NULL; } } else { lRet = GetLastError(); } } return lRet; } LONG Delete() { return m_Key.DeleteSubKey(L"Ribbon"); } }; } // namespace WTL #endif // __ATLRIBBON_H__ ================================================ FILE: WTL/atlscrl.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLSCRL_H__ #define __ATLSCRL_H__ #pragma once #ifndef __ATLAPP_H__ #error atlscrl.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlscrl.h requires atlwin.h to be included first #endif #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) #include #endif #ifndef GET_WHEEL_DELTA_WPARAM #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CScrollImpl // CScrollWindowImpl // CMapScrollImpl // CMapScrollWindowImpl // CFSBWindowT // CZoomScrollImpl // CZoomScrollWindowImpl // CScrollContainerImpl // CScrollContainer namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CScrollImpl - Provides scrolling support to any window // Scroll extended styles #define SCRL_SCROLLCHILDREN 0x00000001 #define SCRL_ERASEBACKGROUND 0x00000002 #define SCRL_NOTHUMBTRACKING 0x00000004 #if (WINVER >= 0x0500) #define SCRL_SMOOTHSCROLL 0x00000008 #endif // (WINVER >= 0x0500) #define SCRL_DISABLENOSCROLLV 0x00000010 #define SCRL_DISABLENOSCROLLH 0x00000020 #define SCRL_DISABLENOSCROLL (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH) template class CScrollImpl { public: enum { uSCROLL_FLAGS = SW_INVALIDATE }; POINT m_ptOffset; SIZE m_sizeAll; SIZE m_sizeLine; SIZE m_sizePage; SIZE m_sizeClient; int m_zDelta; // current wheel value int m_nWheelLines; // number of lines to scroll on wheel #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) // Note that this message must be forwarded from a top level window UINT m_uMsgMouseWheel; // MSH_MOUSEWHEEL #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) int m_zHDelta; // current horizontal wheel value int m_nHWheelChars; // number of chars to scroll on horizontal wheel UINT m_uScrollFlags; DWORD m_dwExtendedStyle; // scroll specific extended styles // Constructor CScrollImpl() : m_zDelta(0), m_nWheelLines(3), #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) m_uMsgMouseWheel(0U), #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) m_zHDelta(0), m_nHWheelChars(3), m_uScrollFlags(0U), m_dwExtendedStyle(0) { m_ptOffset.x = 0; m_ptOffset.y = 0; m_sizeAll.cx = 0; m_sizeAll.cy = 0; m_sizePage.cx = 0; m_sizePage.cy = 0; m_sizeLine.cx = 0; m_sizeLine.cy = 0; m_sizeClient.cx = 0; m_sizeClient.cy = 0; SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND); } // Attributes & Operations DWORD GetScrollExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); // cache scroll flags T* pT = static_cast(this); pT; // avoid level 4 warning m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0); #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0); #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) return dwPrevStyle; } // offset operations void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->AdjustScrollOffset(x, y); int dx = m_ptOffset.x - x; int dy = m_ptOffset.y - y; m_ptOffset.x = x; m_ptOffset.y = y; // block: set horizontal scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_POS; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nPos = m_ptOffset.x; pT->SetScrollInfo(SB_HORZ, &si, bRedraw); } // block: set vertical scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_POS; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nPos = m_ptOffset.y; pT->SetScrollInfo(SB_VERT, &si, bRedraw); } // Move all children if needed if(IsScrollingChildren() && (dx != 0 || dy != 0)) { for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) { RECT rect = { 0 }; ::GetWindowRect(hWndChild, &rect); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); } } if(bRedraw) pT->Invalidate(); } void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) { SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); } void GetScrollOffset(POINT& ptOffset) const { ptOffset = m_ptOffset; } // size operations void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); m_sizeAll.cx = cx; m_sizeAll.cy = cy; int x = 0; int y = 0; if(!bResetOffset) { x = m_ptOffset.x; y = m_ptOffset.y; pT->AdjustScrollOffset(x, y); } int dx = m_ptOffset.x - x; int dy = m_ptOffset.y - y; m_ptOffset.x = x; m_ptOffset.y = y; // block: set horizontal scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nMin = 0; si.nMax = m_sizeAll.cx - 1; si.nPage = m_sizeClient.cx; si.nPos = m_ptOffset.x; pT->SetScrollInfo(SB_HORZ, &si, bRedraw); } // block: set vertical scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nMin = 0; si.nMax = m_sizeAll.cy - 1; si.nPage = m_sizeClient.cy; si.nPos = m_ptOffset.y; pT->SetScrollInfo(SB_VERT, &si, bRedraw); } // Move all children if needed if(IsScrollingChildren() && (dx != 0 || dy != 0)) { for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) { RECT rect = { 0 }; ::GetWindowRect(hWndChild, &rect); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); } } SetScrollLine(0, 0); SetScrollPage(0, 0); if(bRedraw) pT->Invalidate(); } void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) { SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset); } void GetScrollSize(SIZE& sizeWnd) const { sizeWnd = m_sizeAll; } // line operations void SetScrollLine(int cxLine, int cyLine) { ATLASSERT(cxLine >= 0 && cyLine >= 0); ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100); m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100); } void SetScrollLine(SIZE sizeLine) { SetScrollLine(sizeLine.cx, sizeLine.cy); } void GetScrollLine(SIZE& sizeLine) const { sizeLine = m_sizeLine; } // page operations void SetScrollPage(int cxPage, int cyPage) { ATLASSERT(cxPage >= 0 && cyPage >= 0); ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10); m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10); } void SetScrollPage(SIZE sizePage) { SetScrollPage(sizePage.cx, sizePage.cy); } void GetScrollPage(SIZE& sizePage) const { sizePage = m_sizePage; } // commands void ScrollLineDown() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollLineUp() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollPageDown() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollPageUp() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollTop() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollBottom() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); } void ScrollLineRight() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } void ScrollLineLeft() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } void ScrollPageRight() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } void ScrollPageLeft() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } void ScrollAllLeft() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } void ScrollAllRight() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); } // scroll to make point/view/window visible void ScrollToView(POINT pt) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); RECT rect = { pt.x, pt.y, pt.x, pt.y }; pT->ScrollToView(rect); } void ScrollToView(RECT& rect) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); RECT rcClient = { 0 }; pT->GetClientRect(&rcClient); int x = m_ptOffset.x; if(rect.left < m_ptOffset.x) x = rect.left; else if(rect.right > (m_ptOffset.x + rcClient.right)) x = rect.right - rcClient.right; int y = m_ptOffset.y; if(rect.top < m_ptOffset.y) y = rect.top; else if(rect.bottom > (m_ptOffset.y + rcClient.bottom)) y = rect.bottom - rcClient.bottom; SetScrollOffset(x, y); } void ScrollToView(HWND hWnd) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); RECT rect = { 0 }; ::GetWindowRect(hWnd, &rect); ::OffsetRect(&rect, m_ptOffset.x, m_ptOffset.y); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); ScrollToView(rect); } BEGIN_MSG_MAP(CScrollImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_VSCROLL, OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_PAINT, OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) #endif // !_WIN32_WCE // standard scroll commands ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->GetSystemSettings(); bHandled = FALSE; return 1; } LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); return 0; } LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); return 0; } LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE) uMsg; int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); #else int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam; #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)) int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN); m_zDelta += zDelta; // cumulative int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines; if(m_sizeAll.cy > m_sizeClient.cy) { for(int i = 0; i < zTotal; i += WHEEL_DELTA) { pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); pT->UpdateWindow(); } } else if(m_sizeAll.cx > m_sizeClient.cx) // can't scroll vertically, scroll horizontally { for(int i = 0; i < zTotal; i += WHEEL_DELTA) { pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); pT->UpdateWindow(); } } m_zDelta %= WHEEL_DELTA; return 0; } LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT); m_zHDelta += zDelta; // cumulative int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars; if(m_sizeAll.cx > m_sizeClient.cx) { for(int i = 0; i < zTotal; i += WHEEL_DELTA) { pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); pT->UpdateWindow(); } } m_zHDelta %= WHEEL_DELTA; return 0; } LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { GetSystemSettings(); return 0; } LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); pT->DoSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); bHandled = FALSE; return 1; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); if(wParam != NULL) { CDCHandle dc = (HDC)wParam; POINT ptViewportOrg = { 0, 0 }; dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); pT->DoPaint(dc); dc.SetViewportOrg(ptViewportOrg); } else { CPaintDC dc(pT->m_hWnd); dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); pT->DoPaint(dc.m_hDC); } return 0; } // scrolling handlers LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollLineUp(); return 0; } LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollLineDown(); return 0; } LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollPageUp(); return 0; } LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollPageDown(); return 0; } LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollTop(); return 0; } LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollBottom(); return 0; } LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollLineLeft(); return 0; } LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollLineRight(); return 0; } LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollPageLeft(); return 0; } LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollPageRight(); return 0; } LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollAllLeft(); return 0; } LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { ScrollAllRight(); return 0; } // Overrideables void DoPaint(CDCHandle /*dc*/) { // must be implemented in a derived class ATLASSERT(FALSE); } // Implementation void DoSize(int cx, int cy) { m_sizeClient.cx = cx; m_sizeClient.cy = cy; T* pT = static_cast(this); // block: set horizontal scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = m_sizeAll.cx - 1; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nPage = m_sizeClient.cx; si.nPos = m_ptOffset.x; pT->SetScrollInfo(SB_HORZ, &si, TRUE); } // block: set vertical scroll bar { SCROLLINFO si = { sizeof(SCROLLINFO) }; si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = m_sizeAll.cy - 1; if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) si.fMask |= SIF_DISABLENOSCROLL; si.nPage = m_sizeClient.cy; si.nPos = m_ptOffset.y; pT->SetScrollInfo(SB_VERT, &si, TRUE); } int x = m_ptOffset.x; int y = m_ptOffset.y; if(pT->AdjustScrollOffset(x, y)) { // Children will be moved in SetScrollOffset, if needed pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN)); SetScrollOffset(x, y, FALSE); } } void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine) { T* pT = static_cast(this); RECT rect = { 0 }; pT->GetClientRect(&rect); int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right; int cxyMax = cxySizeAll - cxyClient; if(cxyMax < 0) // can't scroll, client area is bigger return; bool bUpdate = true; int cxyScroll = 0; switch(nScrollCode) { case SB_TOP: // top or all left cxyScroll = cxyOffset; cxyOffset = 0; break; case SB_BOTTOM: // bottom or all right cxyScroll = cxyOffset - cxyMax; cxyOffset = cxyMax; break; case SB_LINEUP: // line up or line left if(cxyOffset >= cxySizeLine) { cxyScroll = cxySizeLine; cxyOffset -= cxySizeLine; } else { cxyScroll = cxyOffset; cxyOffset = 0; } break; case SB_LINEDOWN: // line down or line right if(cxyOffset < cxyMax - cxySizeLine) { cxyScroll = -cxySizeLine; cxyOffset += cxySizeLine; } else { cxyScroll = cxyOffset - cxyMax; cxyOffset = cxyMax; } break; case SB_PAGEUP: // page up or page left if(cxyOffset >= cxySizePage) { cxyScroll = cxySizePage; cxyOffset -= cxySizePage; } else { cxyScroll = cxyOffset; cxyOffset = 0; } break; case SB_PAGEDOWN: // page down or page right if(cxyOffset < cxyMax - cxySizePage) { cxyScroll = -cxySizePage; cxyOffset += cxySizePage; } else { cxyScroll = cxyOffset - cxyMax; cxyOffset = cxyMax; } break; case SB_THUMBTRACK: if(IsNoThumbTracking()) break; // else fall through case SB_THUMBPOSITION: { SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; if(pT->GetScrollInfo(nType, &si)) { cxyScroll = cxyOffset - si.nTrackPos; cxyOffset = si.nTrackPos; } } break; case SB_ENDSCROLL: default: bUpdate = false; break; } if(bUpdate && cxyScroll != 0) { pT->SetScrollPos(nType, cxyOffset, TRUE); if(nType == SB_VERT) pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags); else pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags); } } static int CalcLineOrPage(int nVal, int nMax, int nDiv) { if(nVal == 0) { nVal = nMax / nDiv; if(nVal < 1) nVal = 1; } else if(nVal > nMax) { nVal = nMax; } return nVal; } bool AdjustScrollOffset(int& x, int& y) { int xOld = x; int yOld = y; int cxMax = m_sizeAll.cx - m_sizeClient.cx; if(x > cxMax) x = (cxMax >= 0) ? cxMax : 0; else if(x < 0) x = 0; int cyMax = m_sizeAll.cy - m_sizeClient.cy; if(y > cyMax) y = (cyMax >= 0) ? cyMax : 0; else if(y < 0) y = 0; return (x != xOld || y != yOld); } void GetSystemSettings() { #ifndef _WIN32_WCE #ifndef SPI_GETWHEELSCROLLLINES const UINT SPI_GETWHEELSCROLLLINES = 104; #endif // !SPI_GETWHEELSCROLLLINES ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0); #ifndef SPI_GETWHEELSCROLLCHARS const UINT SPI_GETWHEELSCROLLCHARS = 0x006C; #endif // !SPI_GETWHEELSCROLLCHARS ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0); #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) if(m_uMsgMouseWheel != 0) m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL); HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); if(::IsWindow(hWndWheel)) { UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES); if(uMsgScrollLines != 0) m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L); } #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) #endif // !_WIN32_WCE } bool IsScrollingChildren() const { return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0; } bool IsErasingBackground() const { return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0; } bool IsNoThumbTracking() const { return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0; } #if (WINVER >= 0x0500) bool IsSmoothScroll() const { return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0; } #endif // (WINVER >= 0x0500) }; /////////////////////////////////////////////////////////////////////////////// // CScrollWindowImpl - Implements a scrollable window template class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl, public CScrollImpl< T > { public: BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->GetSystemSettings(); RECT rect = { 0 }; GetClientRect(&rect); pT->DoSize(rect.right, rect.bottom); } return bRet; } BEGIN_MSG_MAP(CScrollWindowImpl) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint) #endif // !_WIN32_WCE ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CMapScrollImpl - Provides mapping and scrolling support to any window #ifndef _WIN32_WCE template class CMapScrollImpl : public CScrollImpl< T > { public: int m_nMapMode; RECT m_rectLogAll; SIZE m_sizeLogLine; SIZE m_sizeLogPage; // Constructor CMapScrollImpl() : m_nMapMode(MM_TEXT) { ::SetRectEmpty(&m_rectLogAll); m_sizeLogPage.cx = 0; m_sizeLogPage.cy = 0; m_sizeLogLine.cx = 0; m_sizeLogLine.cy = 0; } // Attributes & Operations // mapping mode operations void SetScrollMapMode(int nMapMode) { ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE); m_nMapMode = nMapMode; } int GetScrollMapMode() const { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); return m_nMapMode; } // offset operations void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); POINT ptOff = { x, y }; // block: convert logical to device units { CWindowDC dc(NULL); dc.SetMapMode(m_nMapMode); dc.LPtoDP(&ptOff); } CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw); } void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) { SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); } void GetScrollOffset(POINT& ptOffset) const { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); ptOffset = m_ptOffset; // block: convert device to logical units { CWindowDC dc(NULL); dc.SetMapMode(m_nMapMode); dc.DPtoLP(&ptOffset); } } // size operations void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true) { ATLASSERT(xMax > xMin && yMax > yMin); ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax); SIZE sizeAll = { 0 }; sizeAll.cx = xMax - xMin + 1; sizeAll.cy = yMax - yMin + 1; // block: convert logical to device units { CWindowDC dc(NULL); dc.SetMapMode(m_nMapMode); dc.LPtoDP(&sizeAll); } CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); SetScrollLine(0, 0); SetScrollPage(0, 0); } void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true) { SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset); } void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) { SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset); } void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) { SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset); } void GetScrollSize(RECT& rcScroll) const { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); rcScroll = m_rectLogAll; } // line operations void SetScrollLine(int cxLine, int cyLine) { ATLASSERT(cxLine >= 0 && cyLine >= 0); ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); m_sizeLogLine.cx = cxLine; m_sizeLogLine.cy = cyLine; SIZE sizeLine = m_sizeLogLine; // block: convert logical to device units { CWindowDC dc(NULL); dc.SetMapMode(m_nMapMode); dc.LPtoDP(&sizeLine); } CScrollImpl< T >::SetScrollLine(sizeLine); } void SetScrollLine(SIZE sizeLine) { SetScrollLine(sizeLine.cx, sizeLine.cy); } void GetScrollLine(SIZE& sizeLine) const { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); sizeLine = m_sizeLogLine; } // page operations void SetScrollPage(int cxPage, int cyPage) { ATLASSERT(cxPage >= 0 && cyPage >= 0); ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); m_sizeLogPage.cx = cxPage; m_sizeLogPage.cy = cyPage; SIZE sizePage = m_sizeLogPage; // block: convert logical to device units { CWindowDC dc(NULL); dc.SetMapMode(m_nMapMode); dc.LPtoDP(&sizePage); } CScrollImpl< T >::SetScrollPage(sizePage); } void SetScrollPage(SIZE sizePage) { SetScrollPage(sizePage.cx, sizePage.cy); } void GetScrollPage(SIZE& sizePage) const { ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); sizePage = m_sizeLogPage; } BEGIN_MSG_MAP(CMapScrollImpl) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); if(wParam != NULL) { CDCHandle dc = (HDC)wParam; int nMapModeSav = dc.GetMapMode(); dc.SetMapMode(m_nMapMode); POINT ptViewportOrg = { 0, 0 }; if(m_nMapMode == MM_TEXT) dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); else dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg); POINT ptWindowOrg = { 0, 0 }; dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg); pT->DoPaint(dc); dc.SetMapMode(nMapModeSav); dc.SetViewportOrg(ptViewportOrg); dc.SetWindowOrg(ptWindowOrg); } else { CPaintDC dc(pT->m_hWnd); dc.SetMapMode(m_nMapMode); if(m_nMapMode == MM_TEXT) dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); else dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy); dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top); pT->DoPaint(dc.m_hDC); } return 0; } }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CMapScrollWindowImpl - Implements scrolling window with mapping #ifndef _WIN32_WCE template class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T > { public: BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->GetSystemSettings(); RECT rect = { 0 }; GetClientRect(&rect); pT->DoSize(rect.right, rect.bottom); } return bRet; } BEGIN_MSG_MAP(CMapScrollWindowImpl) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support #if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) template class CFSBWindowT : public TBase, public CFlatScrollBarImpl > { public: // Constructors CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd) { } CFSBWindowT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } // CWindow overrides that use flat scroll bar API // (only those methods that are used by scroll window classes) int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return FlatSB_SetScrollPos(nBar, nPos, bRedraw); } BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) { ATLASSERT(::IsWindow(m_hWnd)); return FlatSB_GetScrollInfo(nBar, lpScrollInfo); } BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw); } }; typedef CFSBWindowT CFSBWindow; #endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) /////////////////////////////////////////////////////////////////////////////// // CZoomScrollImpl - Provides zooming and scrolling support to any window #ifndef _WIN32_WCE // The zoom modes that can be set with the SetZoomMode method enum { ZOOMMODE_OFF, ZOOMMODE_IN, // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged. ZOOMMODE_OUT // If left mouse button clicked, zoom out on point clicked. }; // Notification to parent that zoom scale changed as a result of user mouse action. #define ZSN_ZOOMCHANGED (NM_FIRST - 50) template class CZoomScrollImpl : public CScrollImpl< T > { public: enum { m_cxyMinZoomRect = 12 }; // min rect size to zoom in on rect. struct _ChildPlacement { HWND hWnd; int x; int y; int cx; int cy; bool operator ==(const _ChildPlacement& cp) const { return (memcmp(this, &cp, sizeof(_ChildPlacement)) == 0); } }; // Data members SIZE m_sizeLogAll; SIZE m_sizeLogLine; SIZE m_sizeLogPage; float m_fZoomScale; float m_fZoomScaleMin; float m_fZoomScaleMax; float m_fZoomDelta; // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click. int m_nZoomMode; RECT m_rcTrack; bool m_bTracking; bool m_bZoomChildren; ATL::CSimpleArray<_ChildPlacement> m_arrChildren; // Constructor CZoomScrollImpl(): m_fZoomScale(1.0f), m_fZoomScaleMin(0.1f), m_fZoomScaleMax(100.0f), m_fZoomDelta(0.5f), m_nZoomMode(ZOOMMODE_OFF), m_bTracking(false), m_bZoomChildren(false) { m_sizeLogAll.cx = 0; m_sizeLogAll.cy = 0; m_sizeLogPage.cx = 0; m_sizeLogPage.cy = 0; m_sizeLogLine.cx = 0; m_sizeLogLine.cy = 0; ::SetRectEmpty(&m_rcTrack); } // Attributes & Operations // size operations void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true) { ATLASSERT(cxLog >= 0 && cyLog >= 0); // Set up the defaults if((cxLog == 0) && (cyLog == 0)) { cxLog = 1; cyLog = 1; } m_sizeLogAll.cx = cxLog; m_sizeLogAll.cy = cyLog; SIZE sizeAll = { 0 }; sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale); sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale); CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); } void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true) { SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset); } void GetScrollSize(SIZE& sizeLog) const { sizeLog = m_sizeLogAll; } // line operations void SetScrollLine(int cxLogLine, int cyLogLine) { ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0); m_sizeLogLine.cx = cxLogLine; m_sizeLogLine.cy = cyLogLine; SIZE sizeLine = { 0 }; sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale); sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale); CScrollImpl< T >::SetScrollLine(sizeLine); } void SetScrollLine(SIZE sizeLogLine) { SetScrollLine(sizeLogLine.cx, sizeLogLine.cy); } void GetScrollLine(SIZE& sizeLogLine) const { sizeLogLine = m_sizeLogLine; } // page operations void SetScrollPage(int cxLogPage, int cyLogPage) { ATLASSERT((cxLogPage >= 0) && (cyLogPage >= 0)); m_sizeLogPage.cx = cxLogPage; m_sizeLogPage.cy = cyLogPage; SIZE sizePage = { 0 }; sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale); sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale); CScrollImpl< T >::SetScrollPage(sizePage); } void SetScrollPage(SIZE sizeLogPage) { SetScrollPage(sizeLogPage.cx, sizeLogPage.cy); } void GetScrollPage(SIZE& sizeLogPage) const { sizeLogPage = m_sizeLogPage; } void SetZoomScale(float fZoomScale) { ATLASSERT(fZoomScale > 0.0f); if(fZoomScale <= 0.0f) return; m_fZoomScale = fZoomScale; if(m_fZoomScale < m_fZoomScaleMin) m_fZoomScale = m_fZoomScaleMin; else if(m_fZoomScale > m_fZoomScaleMax) m_fZoomScale = m_fZoomScaleMax; } float GetZoomScale() const { return m_fZoomScale; } void SetZoomScaleMin(float fZoomScaleMin) { ATLASSERT(fZoomScaleMin > 0.0f); ATLASSERT(fZoomScaleMin <= m_fZoomScaleMax); m_fZoomScaleMin = fZoomScaleMin; } float GetZoomScaleMin() const { return m_fZoomScaleMin; } void SetZoomScaleMax(float fZoomScaleMax) { ATLASSERT(fZoomScaleMax > 0.0f); ATLASSERT(m_fZoomScaleMin <= fZoomScaleMax); m_fZoomScaleMax = fZoomScaleMax; } float GetZoomScaleMax() const { return m_fZoomScaleMax; } void SetZoomDelta(float fZoomDelta) { ATLASSERT(fZoomDelta >= 0.0f); if(fZoomDelta >= 0.0f) m_fZoomDelta = fZoomDelta; } float GetZoomDelta() const { return m_fZoomDelta; } void SetZoomMode(int nZoomMode) { m_nZoomMode = nZoomMode; } int GetZoomMode() const { return m_nZoomMode; } void SetZoomChildren(bool bEnable = true) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); m_bZoomChildren = bEnable; m_arrChildren.RemoveAll(); if(m_bZoomChildren) { for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) { RECT rect = { 0 }; ::GetWindowRect(hWndChild, &rect); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); _ChildPlacement cp = { 0 }; cp.hWnd = hWndChild; cp.x = rect.left; cp.y = rect.top; cp.cx = rect.right - rect.left; cp.cy = rect.bottom - rect.top; m_arrChildren.Add(cp); } } } bool GetZoomChildren() const { return m_bZoomChildren; } void Zoom(int x, int y, float fZoomScale) { if(fZoomScale <= 0.0f) return; if(fZoomScale < m_fZoomScaleMin) fZoomScale = m_fZoomScaleMin; else if(fZoomScale > m_fZoomScaleMax) fZoomScale = m_fZoomScaleMax; T* pT = static_cast(this); POINT pt = { x, y }; if(!pT->PtInDevRect(pt)) return; pT->ViewDPtoLP(&pt); pT->Zoom(fZoomScale, false); pT->CenterOnLogicalPoint(pt); } void Zoom(POINT pt, float fZoomScale) { T* pT = static_cast(this); pT->Zoom(pt.x, pt.y, fZoomScale); } void Zoom(RECT& rc) { T* pT = static_cast(this); RECT rcZoom = rc; pT->NormalizeRect(rcZoom); SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top }; POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 }; if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect) { pT->Zoom(pt, m_fZoomScale + m_fZoomDelta); return; } ATLASSERT((size.cx > 0) && (size.cy > 0)); float fScaleH = (float)(m_sizeClient.cx + 1) / (float)size.cx; float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy; float fZoomScale = __min(fScaleH, fScaleV) * m_fZoomScale; pT->Zoom(pt, fZoomScale); } void Zoom(float fZoomScale, bool bCenter = true) { if(fZoomScale <= 0.0f) return; if(fZoomScale < m_fZoomScaleMin) fZoomScale = m_fZoomScaleMin; else if(fZoomScale > m_fZoomScaleMax) fZoomScale = m_fZoomScaleMax; T* pT = static_cast(this); POINT pt = { 0 }; if(bCenter) { RECT rcClient = { 0 }; ::GetClientRect(pT->m_hWnd, &rcClient); pt.x = rcClient.right / 2; pt.y = rcClient.bottom / 2; pT->ViewDPtoLP(&pt); } // Modify the Viewport extent SIZE sizeAll = { 0 }; sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale); sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale); // Update scroll bars and window CScrollImpl< T >::SetScrollSize(sizeAll); // Zoom all children if needed if(m_bZoomChildren && (m_fZoomScale != fZoomScale)) { for(int i = 0; i < m_arrChildren.GetSize(); i++) { ATLASSERT(::IsWindow(m_arrChildren[i].hWnd)); ::SetWindowPos(m_arrChildren[i].hWnd, NULL, (int)((float)m_arrChildren[i].x * fZoomScale + 0.5f), (int)((float)m_arrChildren[i].y * fZoomScale + 0.5f), (int)((float)m_arrChildren[i].cx * fZoomScale + 0.5f), (int)((float)m_arrChildren[i].cy * fZoomScale + 0.5f), SWP_NOZORDER | SWP_NOACTIVATE); } } // Set new zoom scale m_fZoomScale = fZoomScale; if(bCenter) pT->CenterOnLogicalPoint(pt); } // Helper functions void PrepareDC(CDCHandle dc) { ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); dc.SetMapMode(MM_ANISOTROPIC); dc.SetWindowExt(m_sizeLogAll); dc.SetViewportExt(m_sizeAll); dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); } void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1) { ATLASSERT(lpPoints); T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); CWindowDC dc(pT->m_hWnd); pT->PrepareDC(dc.m_hDC); dc.DPtoLP(lpPoints, nCount); } void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1) { ATLASSERT(lpPoints); T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); CWindowDC dc(pT->m_hWnd); pT->PrepareDC(dc.m_hDC); dc.LPtoDP(lpPoints, nCount); } void ClientToDevice(POINT &pt) { pt.x += m_ptOffset.x; pt.y += m_ptOffset.y; } void DeviceToClient(POINT &pt) { pt.x -= m_ptOffset.x; pt.y -= m_ptOffset.y; } void CenterOnPoint(POINT pt) { T* pT = static_cast(this); RECT rect = { 0 }; pT->GetClientRect(&rect); int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x; if(xOfs < 0) { xOfs = 0; } else { int xMax = __max((int)(m_sizeAll.cx - rect.right), 0); if(xOfs > xMax) xOfs = xMax; } int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y; if(yOfs < 0) { yOfs = 0; } else { int yMax = __max((int)(m_sizeAll.cy - rect.bottom), 0); if(yOfs > yMax) yOfs = yMax; } CScrollImpl< T >::SetScrollOffset(xOfs, yOfs); } void CenterOnLogicalPoint(POINT ptLog) { T* pT = static_cast(this); pT->ViewLPtoDP(&ptLog); pT->DeviceToClient(ptLog); pT->CenterOnPoint(ptLog); } BOOL PtInDevRect(POINT pt) { RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy }; ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y); return ::PtInRect(&rc, pt); } void NormalizeRect(RECT& rc) { if(rc.left > rc.right) { int r = rc.right; rc.right = rc.left; rc.left = r; } if(rc.top > rc.bottom) { int b = rc.bottom; rc.bottom = rc.top; rc.top = b; } } void DrawTrackRect() { T* pT = static_cast(this); const SIZE sizeLines = { 2, 2 }; RECT rc = m_rcTrack; pT->NormalizeRect(rc); if(!::IsRectEmpty(&rc)) { ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2); CWindowDC dc(NULL); dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines); } } void NotifyParentZoomChanged() { T* pT = static_cast(this); int nId = pT->GetDlgCtrlID(); NMHDR nmhdr = { pT->m_hWnd, (UINT_PTR)nId, ZSN_ZOOMCHANGED }; ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr); } BEGIN_MSG_MAP(CZoomScrollImpl) MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); ATLASSERT((m_sizeLogAll.cx >= 0) && (m_sizeLogAll.cy >= 0)); ATLASSERT((m_sizeAll.cx >= 0) && (m_sizeAll.cy >= 0)); if(wParam != NULL) { CDCHandle dc = (HDC)wParam; int nMapModeSav = dc.GetMapMode(); dc.SetMapMode(MM_ANISOTROPIC); SIZE szWindowExt = { 0, 0 }; dc.SetWindowExt(m_sizeLogAll, &szWindowExt); SIZE szViewportExt = { 0, 0 }; dc.SetViewportExt(m_sizeAll, &szViewportExt); POINT ptViewportOrg = { 0, 0 }; dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); pT->DoPaint(dc); dc.SetMapMode(nMapModeSav); dc.SetWindowExt(szWindowExt); dc.SetViewportExt(szViewportExt); dc.SetViewportOrg(ptViewportOrg); } else { CPaintDC dc(pT->m_hWnd); pT->PrepareDC(dc.m_hDC); pT->DoPaint(dc.m_hDC); } return 0; } LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking) { T* pT = static_cast(this); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if(pT->PtInDevRect(pt)) { pT->SetCapture(); m_bTracking = true; ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y); } } bHandled = FALSE; return 0; } LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if(m_bTracking) { T* pT = static_cast(this); POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if(pT->PtInDevRect(pt)) { pT->DrawTrackRect(); m_rcTrack.right = pt.x; m_rcTrack.bottom = pt.y; pT->DrawTrackRect(); } } bHandled = FALSE; return 0; } LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { ::ReleaseCapture(); if(m_nZoomMode == ZOOMMODE_OUT) { T* pT = static_cast(this); pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta); pT->NotifyParentZoomChanged(); } bHandled = FALSE; return 0; } LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_bTracking) { m_bTracking = false; T* pT = static_cast(this); pT->DrawTrackRect(); pT->Zoom(m_rcTrack); pT->NotifyParentZoomChanged(); ::SetRectEmpty(&m_rcTrack); } bHandled = FALSE; return 0; } LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF) { T* pT = static_cast(this); if((HWND)wParam == pT->m_hWnd) { DWORD dwPos = ::GetMessagePos(); POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; pT->ScreenToClient(&pt); if(pT->PtInDevRect(pt)) { ::SetCursor(::LoadCursor(NULL, IDC_CROSS)); return 1; } } } bHandled = FALSE; return 0; } }; /////////////////////////////////////////////////////////////////////////////// // CZoomScrollWindowImpl - Implements scrolling window with zooming template class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > { public: BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->GetSystemSettings(); RECT rect = { 0 }; GetClientRect(&rect); pT->DoSize(rect.right, rect.bottom); } return bRet; } BEGIN_MSG_MAP(CZoomScrollWindowImpl) MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint) MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() }; #endif // !_WIN32_WCE /////////////////////////////////////////////////////////////////////////////// // CScrollContainer template class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits > { public: DECLARE_WND_CLASS_EX(NULL, 0, -1) typedef CScrollWindowImpl< T, TBase, TWinTraits > _baseClass; // Data members ATL::CWindow m_wndClient; bool m_bAutoSizeClient; bool m_bDrawEdgeIfEmpty; // Constructor CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false) { // Set CScrollWindowImpl extended style SetScrollExtendedStyle(SCRL_SCROLLCHILDREN); } // Attributes HWND GetClient() const { return m_wndClient; } HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true) { ATLASSERT(::IsWindow(m_hWnd)); HWND hWndOldClient = m_wndClient; m_wndClient = hWndClient; SetRedraw(FALSE); SetScrollSize(1, 1, FALSE); if(m_wndClient.m_hWnd != NULL) { m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); if(bClientSizeAsMin) { RECT rect = { 0 }; m_wndClient.GetWindowRect(&rect); if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0) SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE); } T* pT = static_cast(this); pT->UpdateLayout(); } SetRedraw(TRUE); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN); return hWndOldClient; } // Message map and handlers BEGIN_MSG_MAP(CScrollContainerImpl) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) CHAIN_MSG_MAP(_baseClass) FORWARD_NOTIFICATIONS() ALT_MSG_MAP(1) CHAIN_MSG_MAP_ALT(_baseClass, 1) END_MSG_MAP() LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(m_wndClient.m_hWnd != NULL) m_wndClient.SetFocus(); return 0; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background needed } // Overrides for CScrollWindowImpl void DoSize(int cx, int cy) { _baseClass::DoSize(cx, cy); T* pT = static_cast(this); pT->UpdateLayout(); } void DoPaint(CDCHandle dc) { if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL) { T* pT = static_cast(this); RECT rect = { 0 }; pT->GetContainerRect(rect); if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL) dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); dc.FillRect(&rect, COLOR_APPWORKSPACE); } } void ScrollToView(POINT pt) { CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt); } void ScrollToView(RECT& rect) { CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect); } void ScrollToView(HWND hWnd) // client window coordinates { T* pT = static_cast(this); pT; // avoid level 4 warning ATLASSERT(::IsWindow(pT->m_hWnd)); ATLASSERT(m_wndClient.IsWindow()); RECT rect = { 0 }; ::GetWindowRect(hWnd, &rect); ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2); ScrollToView(rect); } // Implementation - overrideable methods void UpdateLayout() { ATLASSERT(::IsWindow(m_hWnd)); if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL) { T* pT = static_cast(this); RECT rect = { 0 }; pT->GetContainerRect(rect); m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); } else { Invalidate(); } } void GetContainerRect(RECT& rect) { GetClientRect(&rect); if(rect.right < m_sizeAll.cx) rect.right = m_sizeAll.cx; if(rect.bottom < m_sizeAll.cy) rect.bottom = m_sizeAll.cy; } }; class CScrollContainer : public CScrollContainerImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1) }; }; // namespace WTL #endif // __ATLSCRL_H__ ================================================ FILE: WTL/atlsplit.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLSPLIT_H__ #define __ATLSPLIT_H__ #pragma once #ifndef __ATLAPP_H__ #error atlsplit.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlsplit.h requires atlwin.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CSplitterImpl // CSplitterWindowImpl // CSplitterWindowT - CSplitterWindow, CHorSplitterWindow namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CSplitterImpl - Provides splitter support to any window // Splitter panes constants #define SPLIT_PANE_LEFT 0 #define SPLIT_PANE_RIGHT 1 #define SPLIT_PANE_TOP SPLIT_PANE_LEFT #define SPLIT_PANE_BOTTOM SPLIT_PANE_RIGHT #define SPLIT_PANE_NONE -1 // Splitter extended styles #define SPLIT_PROPORTIONAL 0x00000001 #define SPLIT_NONINTERACTIVE 0x00000002 #define SPLIT_RIGHTALIGNED 0x00000004 #define SPLIT_BOTTOMALIGNED SPLIT_RIGHTALIGNED #define SPLIT_GRADIENTBAR 0x00000008 #define SPLIT_FIXEDBARSIZE 0x00000010 // Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are // mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL. // SPLIT_GRADIENTBAR doesn't work with _ATL_NO_MSIMG template class CSplitterImpl { public: enum { m_nPanesCount = 2, m_nPropMax = 10000, m_cxyStep = 10 }; bool m_bVertical; HWND m_hWndPane[m_nPanesCount]; RECT m_rcSplitter; int m_xySplitterPos; // splitter bar position int m_xySplitterPosNew; // internal - new position while moving HWND m_hWndFocusSave; int m_nDefActivePane; int m_cxySplitBar; // splitter bar width/height HCURSOR m_hCursor; int m_cxyMin; // minimum pane size int m_cxyBarEdge; // splitter bar edge bool m_bFullDrag; int m_cxyDragOffset; // internal int m_nProportionalPos; bool m_bUpdateProportionalPos; DWORD m_dwExtendedStyle; // splitter specific extended styles int m_nSinglePane; // single pane mode int m_xySplitterDefPos; // default position bool m_bProportionalDefPos; // porportinal def pos // Constructor CSplitterImpl(bool bVertical = true) : m_bVertical(bVertical), m_xySplitterPos(-1), m_xySplitterPosNew(-1), m_hWndFocusSave(NULL), m_nDefActivePane(SPLIT_PANE_NONE), m_cxySplitBar(4), m_hCursor(NULL), m_cxyMin(0), m_cxyBarEdge(0), m_bFullDrag(true), m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true), m_dwExtendedStyle(SPLIT_PROPORTIONAL), m_nSinglePane(SPLIT_PANE_NONE), m_xySplitterDefPos(-1), m_bProportionalDefPos(false) { m_hWndPane[SPLIT_PANE_LEFT] = NULL; m_hWndPane[SPLIT_PANE_RIGHT] = NULL; ::SetRectEmpty(&m_rcSplitter); } // Attributes void SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true) { if(lpRect == NULL) { T* pT = static_cast(this); pT->GetClientRect(&m_rcSplitter); } else { m_rcSplitter = *lpRect; } if(IsProportional()) UpdateProportionalPos(); else if(IsRightAligned()) UpdateRightAlignPos(); if(bUpdate) UpdateSplitterLayout(); } void GetSplitterRect(LPRECT lpRect) const { ATLASSERT(lpRect != NULL); *lpRect = m_rcSplitter; } bool SetSplitterPos(int xyPos = -1, bool bUpdate = true) { if(xyPos == -1) // -1 == default position { if(m_bProportionalDefPos) { ATLASSERT((m_xySplitterDefPos >= 0) && (m_xySplitterDefPos <= m_nPropMax)); if(m_bVertical) xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge, m_nPropMax); else xyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge, m_nPropMax); } else if(m_xySplitterDefPos != -1) { xyPos = m_xySplitterDefPos; } else // not set, use middle position { if(m_bVertical) xyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; else xyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; } } // Adjust if out of valid range int cxyMax = 0; if(m_bVertical) cxyMax = m_rcSplitter.right - m_rcSplitter.left; else cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; if(xyPos < m_cxyMin + m_cxyBarEdge) xyPos = m_cxyMin; else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; // Set new position and update if requested bool bRet = (m_xySplitterPos != xyPos); m_xySplitterPos = xyPos; if(m_bUpdateProportionalPos) { if(IsProportional()) StoreProportionalPos(); else if(IsRightAligned()) StoreRightAlignPos(); } else { m_bUpdateProportionalPos = true; } if(bUpdate && bRet) UpdateSplitterLayout(); return bRet; } int GetSplitterPos() const { return m_xySplitterPos; } void SetSplitterPosPct(int nPct, bool bUpdate = true) { ATLASSERT((nPct >= 0) && (nPct <= 100)); m_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100); UpdateProportionalPos(); if(bUpdate) UpdateSplitterLayout(); } int GetSplitterPosPct() const { int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); return ((cxyTotal > 0) && (m_xySplitterPos >= 0)) ? (::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal) / 100) : -1; } bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE) { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE)); if(!((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE))) return false; if(nPane != SPLIT_PANE_NONE) { if(::IsWindowVisible(m_hWndPane[nPane]) == FALSE) ::ShowWindow(m_hWndPane[nPane], SW_SHOW); int nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; ::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE); if(m_nDefActivePane != nPane) m_nDefActivePane = nPane; } else if(m_nSinglePane != SPLIT_PANE_NONE) { int nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT; ::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW); } m_nSinglePane = nPane; UpdateSplitterLayout(); return true; } int GetSinglePaneMode() const { return m_nSinglePane; } DWORD GetSplitterExtendedStyle() const { return m_dwExtendedStyle; } DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); #ifdef _DEBUG if(IsProportional() && IsRightAligned()) ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\n")); #endif // _DEBUG return dwPrevStyle; } void SetSplitterDefaultPos(int xyPos = -1) { m_xySplitterDefPos = xyPos; m_bProportionalDefPos = false; } void SetSplitterDefaultPosPct(int nPct) { ATLASSERT((nPct >= 0) && (nPct <= 100)); m_xySplitterDefPos = ::MulDiv(nPct, m_nPropMax, 100); m_bProportionalDefPos = true; } // Splitter operations void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true) { m_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop; m_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom; ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT])); if(bUpdate) UpdateSplitterLayout(); } bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true) { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) return false; m_hWndPane[nPane] = hWnd; ATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT])); if(bUpdate) UpdateSplitterLayout(); return true; } HWND GetSplitterPane(int nPane) const { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) return NULL; return m_hWndPane[nPane]; } bool SetActivePane(int nPane) { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) return false; if((m_nSinglePane != SPLIT_PANE_NONE) && (nPane != m_nSinglePane)) return false; ::SetFocus(m_hWndPane[nPane]); m_nDefActivePane = nPane; return true; } int GetActivePane() const { int nRet = SPLIT_PANE_NONE; HWND hWndFocus = ::GetFocus(); if(hWndFocus != NULL) { for(int nPane = 0; nPane < m_nPanesCount; nPane++) { if((hWndFocus == m_hWndPane[nPane]) || (::IsChild(m_hWndPane[nPane], hWndFocus) != FALSE)) { nRet = nPane; break; } } } return nRet; } bool ActivateNextPane(bool bNext = true) { int nPane = m_nSinglePane; if(nPane == SPLIT_PANE_NONE) { switch(GetActivePane()) { case SPLIT_PANE_LEFT: nPane = SPLIT_PANE_RIGHT; break; case SPLIT_PANE_RIGHT: nPane = SPLIT_PANE_LEFT; break; default: nPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT; break; } } return SetActivePane(nPane); } bool SetDefaultActivePane(int nPane) { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); if((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT)) return false; m_nDefActivePane = nPane; return true; } bool SetDefaultActivePane(HWND hWnd) { for(int nPane = 0; nPane < m_nPanesCount; nPane++) { if(hWnd == m_hWndPane[nPane]) { m_nDefActivePane = nPane; return true; } } return false; // not found } int GetDefaultActivePane() const { return m_nDefActivePane; } void DrawSplitter(CDCHandle dc) { ATLASSERT(dc.m_hDC != NULL); if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) return; T* pT = static_cast(this); if(m_nSinglePane == SPLIT_PANE_NONE) { pT->DrawSplitterBar(dc); for(int nPane = 0; nPane < m_nPanesCount; nPane++) { if(m_hWndPane[nPane] == NULL) pT->DrawSplitterPane(dc, nPane); } } else { if(m_hWndPane[m_nSinglePane] == NULL) pT->DrawSplitterPane(dc, m_nSinglePane); } } // call to initiate moving splitter bar with keyboard void MoveSplitterBar() { T* pT = static_cast(this); int x = 0; int y = 0; if(m_bVertical) { x = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge; y = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2; } else { x = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2; y = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge; } POINT pt = { x, y }; pT->ClientToScreen(&pt); ::SetCursorPos(pt.x, pt.y); m_xySplitterPosNew = m_xySplitterPos; pT->SetCapture(); m_hWndFocusSave = pT->SetFocus(); ::SetCursor(m_hCursor); if(!m_bFullDrag) DrawGhostBar(); if(m_bVertical) m_cxyDragOffset = x - m_rcSplitter.left - m_xySplitterPos; else m_cxyDragOffset = y - m_rcSplitter.top - m_xySplitterPos; } void SetOrientation(bool bVertical, bool bUpdate = true) { if(m_bVertical != bVertical) { m_bVertical = bVertical; m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS); T* pT = static_cast(this); pT->GetSystemSettings(false); if(m_bVertical) m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.right - m_rcSplitter.left, m_rcSplitter.bottom - m_rcSplitter.top); else m_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.bottom - m_rcSplitter.top, m_rcSplitter.right - m_rcSplitter.left); } if(bUpdate) UpdateSplitterLayout(); } // Overrideables void DrawSplitterBar(CDCHandle dc) { RECT rect = { 0 }; if(GetSplitterBarRect(&rect)) { dc.FillRect(&rect, COLOR_3DFACE); #if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) if((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0) { RECT rect2 = rect; if(m_bVertical) rect2.left = (rect.left + rect.right) / 2 - 1; else rect2.top = (rect.top + rect.bottom) / 2 - 1; dc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), m_bVertical); } #endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420) // draw 3D edge if needed T* pT = static_cast(this); if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) dc.DrawEdge(&rect, EDGE_RAISED, m_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM)); } } // called only if pane is empty void DrawSplitterPane(CDCHandle dc, int nPane) { RECT rect = { 0 }; if(GetSplitterPaneRect(nPane, &rect)) { T* pT = static_cast(this); if((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0) dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); dc.FillRect(&rect, COLOR_APPWORKSPACE); } } // Message map and handlers BEGIN_MSG_MAP(CSplitterImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_PAINT, OnPaint) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) #endif // !_WIN32_WCE if(IsInteractive()) { MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick) MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) } MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) #ifndef _WIN32_WCE MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) #endif // !_WIN32_WCE MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->Init(); bHandled = FALSE; return 1; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); // try setting position if not set if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) pT->SetSplitterPos(); // do painting if(wParam != NULL) { pT->DrawSplitter((HDC)wParam); } else { CPaintDC dc(pT->m_hWnd); pT->DrawSplitter(dc.m_hDC); } return 0; } LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); if(((HWND)wParam == pT->m_hWnd) && (LOWORD(lParam) == HTCLIENT)) { DWORD dwPos = ::GetMessagePos(); POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; pT->ScreenToClient(&ptPos); if(IsOverSplitterBar(ptPos.x, ptPos.y)) return 1; } bHandled = FALSE; return 0; } LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); if(::GetCapture() == pT->m_hWnd) { int xyNewSplitPos = 0; if(m_bVertical) xyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset; else xyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset; if(xyNewSplitPos == -1) // avoid -1, that means default position xyNewSplitPos = -2; if(m_xySplitterPos != xyNewSplitPos) { if(m_bFullDrag) { if(pT->SetSplitterPos(xyNewSplitPos, true)) pT->UpdateWindow(); } else { DrawGhostBar(); pT->SetSplitterPos(xyNewSplitPos, false); DrawGhostBar(); } } } else // not dragging, just set cursor { if(IsOverSplitterBar(xPos, yPos)) ::SetCursor(m_hCursor); bHandled = FALSE; } return 0; } LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); if((::GetCapture() != pT->m_hWnd) && IsOverSplitterBar(xPos, yPos)) { m_xySplitterPosNew = m_xySplitterPos; pT->SetCapture(); m_hWndFocusSave = pT->SetFocus(); ::SetCursor(m_hCursor); if(!m_bFullDrag) DrawGhostBar(); if(m_bVertical) m_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos; else m_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos; } else if((::GetCapture() == pT->m_hWnd) && !IsOverSplitterBar(xPos, yPos)) { ::ReleaseCapture(); } bHandled = FALSE; return 1; } LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); if(::GetCapture() == pT->m_hWnd) { m_xySplitterPosNew = m_xySplitterPos; ::ReleaseCapture(); } bHandled = FALSE; return 1; } LRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->SetSplitterPos(); // default return 0; } LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(!m_bFullDrag) DrawGhostBar(); if((m_xySplitterPosNew != -1) && (!m_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew))) { m_xySplitterPos = m_xySplitterPosNew; m_xySplitterPosNew = -1; UpdateSplitterLayout(); T* pT = static_cast(this); pT->UpdateWindow(); } if(m_hWndFocusSave != NULL) ::SetFocus(m_hWndFocusSave); return 0; } LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); if(::GetCapture() == pT->m_hWnd) { switch(wParam) { case VK_RETURN: m_xySplitterPosNew = m_xySplitterPos; case VK_ESCAPE: ::ReleaseCapture(); break; case VK_LEFT: case VK_RIGHT: if(m_bVertical) { POINT pt = { 0, 0 }; ::GetCursorPos(&pt); int xyPos = m_xySplitterPos + ((wParam == VK_LEFT) ? -pT->m_cxyStep : pT->m_cxyStep); int cxyMax = m_rcSplitter.right - m_rcSplitter.left; if(xyPos < (m_cxyMin + m_cxyBarEdge)) xyPos = m_cxyMin; else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; pt.x += xyPos - m_xySplitterPos; ::SetCursorPos(pt.x, pt.y); } break; case VK_UP: case VK_DOWN: if(!m_bVertical) { POINT pt = { 0, 0 }; ::GetCursorPos(&pt); int xyPos = m_xySplitterPos + ((wParam == VK_UP) ? -pT->m_cxyStep : pT->m_cxyStep); int cxyMax = m_rcSplitter.bottom - m_rcSplitter.top; if(xyPos < (m_cxyMin + m_cxyBarEdge)) xyPos = m_cxyMin; else if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin)) xyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin; pt.y += xyPos - m_xySplitterPos; ::SetCursorPos(pt.x, pt.y); } break; default: break; } } else { bHandled = FALSE; } return 0; } LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled) { T* pT = static_cast(this); if(::GetCapture() != pT->m_hWnd) { if(m_nSinglePane == SPLIT_PANE_NONE) { if((m_nDefActivePane == SPLIT_PANE_LEFT) || (m_nDefActivePane == SPLIT_PANE_RIGHT)) ::SetFocus(m_hWndPane[m_nDefActivePane]); } else { ::SetFocus(m_hWndPane[m_nSinglePane]); } } bHandled = FALSE; return 1; } #ifndef _WIN32_WCE LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); if((lRet == MA_ACTIVATE) || (lRet == MA_ACTIVATEANDEAT)) { DWORD dwPos = ::GetMessagePos(); POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; pT->ScreenToClient(&pt); RECT rcPane = { 0 }; for(int nPane = 0; nPane < m_nPanesCount; nPane++) { if(GetSplitterPaneRect(nPane, &rcPane) && (::PtInRect(&rcPane, pt) != FALSE)) { m_nDefActivePane = nPane; break; } } } return lRet; } #endif // !_WIN32_WCE LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->GetSystemSettings(true); return 0; } // Implementation - internal helpers void Init() { m_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS); T* pT = static_cast(this); pT->GetSystemSettings(false); } void UpdateSplitterLayout() { if((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1)) return; T* pT = static_cast(this); RECT rect = { 0 }; if(m_nSinglePane == SPLIT_PANE_NONE) { if(GetSplitterBarRect(&rect)) pT->InvalidateRect(&rect); for(int nPane = 0; nPane < m_nPanesCount; nPane++) { if(GetSplitterPaneRect(nPane, &rect)) { if(m_hWndPane[nPane] != NULL) ::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); else pT->InvalidateRect(&rect); } } } else { if(GetSplitterPaneRect(m_nSinglePane, &rect)) { if(m_hWndPane[m_nSinglePane] != NULL) ::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); else pT->InvalidateRect(&rect); } } } bool GetSplitterBarRect(LPRECT lpRect) const { ATLASSERT(lpRect != NULL); if((m_nSinglePane != SPLIT_PANE_NONE) || (m_xySplitterPos == -1)) return false; if(m_bVertical) { lpRect->left = m_rcSplitter.left + m_xySplitterPos; lpRect->top = m_rcSplitter.top; lpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; lpRect->bottom = m_rcSplitter.bottom; } else { lpRect->left = m_rcSplitter.left; lpRect->top = m_rcSplitter.top + m_xySplitterPos; lpRect->right = m_rcSplitter.right; lpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; } return true; } bool GetSplitterPaneRect(int nPane, LPRECT lpRect) const { ATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT)); ATLASSERT(lpRect != NULL); bool bRet = true; if(m_nSinglePane != SPLIT_PANE_NONE) { if(nPane == m_nSinglePane) *lpRect = m_rcSplitter; else bRet = false; } else if(nPane == SPLIT_PANE_LEFT) { if(m_bVertical) { lpRect->left = m_rcSplitter.left; lpRect->top = m_rcSplitter.top; lpRect->right = m_rcSplitter.left + m_xySplitterPos; lpRect->bottom = m_rcSplitter.bottom; } else { lpRect->left = m_rcSplitter.left; lpRect->top = m_rcSplitter.top; lpRect->right = m_rcSplitter.right; lpRect->bottom = m_rcSplitter.top + m_xySplitterPos; } } else if(nPane == SPLIT_PANE_RIGHT) { if(m_bVertical) { lpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; lpRect->top = m_rcSplitter.top; lpRect->right = m_rcSplitter.right; lpRect->bottom = m_rcSplitter.bottom; } else { lpRect->left = m_rcSplitter.left; lpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge; lpRect->right = m_rcSplitter.right; lpRect->bottom = m_rcSplitter.bottom; } } else { bRet = false; } return bRet; } bool IsOverSplitterRect(int x, int y) const { // -1 == don't check return ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) && (y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom))); } bool IsOverSplitterBar(int x, int y) const { if(m_nSinglePane != SPLIT_PANE_NONE) return false; if((m_xySplitterPos == -1) || !IsOverSplitterRect(x, y)) return false; int xy = m_bVertical ? x : y; int xyOff = m_bVertical ? m_rcSplitter.left : m_rcSplitter.top; return ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge)); } void DrawGhostBar() { RECT rect = { 0 }; if(GetSplitterBarRect(&rect)) { // convert client to window coordinates T* pT = static_cast(this); RECT rcWnd = { 0 }; pT->GetWindowRect(&rcWnd); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2); ::OffsetRect(&rect, -rcWnd.left, -rcWnd.top); // invert the brush pattern (looks just like frame window sizing) CWindowDC dc(pT->m_hWnd); CBrush brush = CDCHandle::GetHalftoneBrush(); if(brush.m_hBrush != NULL) { CBrushHandle brushOld = dc.SelectBrush(brush); dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT); dc.SelectBrush(brushOld); } } } void GetSystemSettings(bool bUpdate) { if((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0) { #ifndef _WIN32_WCE m_cxySplitBar = ::GetSystemMetrics(m_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME); #else // CE specific m_cxySplitBar = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); #endif // _WIN32_WCE } T* pT = static_cast(this); if((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0) { m_cxyBarEdge = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); m_cxyMin = 0; } else { m_cxyBarEdge = 0; m_cxyMin = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE); } #ifndef _WIN32_WCE ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0); #endif // !_WIN32_WCE if(bUpdate) UpdateSplitterLayout(); } bool IsProportional() const { return ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0); } void StoreProportionalPos() { int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); if(cxyTotal > 0) m_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal); else m_nProportionalPos = 0; ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreProportionalPos - %i\n"), m_nProportionalPos); } void UpdateProportionalPos() { int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); if(cxyTotal > 0) { int xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax); m_bUpdateProportionalPos = false; T* pT = static_cast(this); pT->SetSplitterPos(xyNewPos, false); } } bool IsRightAligned() const { return ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0); } void StoreRightAlignPos() { int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); if(cxyTotal > 0) m_nProportionalPos = cxyTotal - m_xySplitterPos; else m_nProportionalPos = 0; ATLTRACE2(atlTraceUI, 0, _T("CSplitterImpl::StoreRightAlignPos - %i\n"), m_nProportionalPos); } void UpdateRightAlignPos() { int cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge); if(cxyTotal > 0) { m_bUpdateProportionalPos = false; T* pT = static_cast(this); pT->SetSplitterPos(cxyTotal - m_nProportionalPos, false); } } bool IsInteractive() const { return ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0); } }; /////////////////////////////////////////////////////////////////////////////// // CSplitterWindowImpl - Implements a splitter window template class ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T > { public: DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW) CSplitterWindowImpl(bool bVertical = true) : CSplitterImpl< T >(bVertical) { } BOOL SubclassWindow(HWND hWnd) { #if (_MSC_VER >= 1300) BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd); #else // !(_MSC_VER >= 1300) typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; BOOL bRet = _baseClass::SubclassWindow(hWnd); #endif // !(_MSC_VER >= 1300) if(bRet != FALSE) { T* pT = static_cast(this); pT->Init(); SetSplitterRect(); } return bRet; } BEGIN_MSG_MAP(CSplitterWindowImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) CHAIN_MSG_MAP(CSplitterImpl< T >) FORWARD_NOTIFICATIONS() END_MSG_MAP() LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // handled, no background painting needed return 1; } LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam != SIZE_MINIMIZED) SetSplitterRect(); bHandled = FALSE; return 1; } }; /////////////////////////////////////////////////////////////////////////////// // CSplitterWindow/CHorSplitterWindow - Implements splitter windows to be used as is template class CSplitterWindowT : public CSplitterWindowImpl > { public: DECLARE_WND_CLASS_EX(_T("WTL_SplitterWindow"), CS_DBLCLKS, COLOR_WINDOW) CSplitterWindowT() : CSplitterWindowImpl >(t_bVertical) { } }; typedef CSplitterWindowT CSplitterWindow; typedef CSplitterWindowT CHorSplitterWindow; }; // namespace WTL #endif // __ATLSPLIT_H__ ================================================ FILE: WTL/atltheme.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLTHEME_H__ #define __ATLTHEME_H__ #pragma once #ifdef _WIN32_WCE #error atltheme.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atltheme.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atltheme.h requires atlwin.h to be included first #endif #if (_WIN32_WINNT < 0x0501) #error atltheme.h requires _WIN32_WINNT >= 0x0501 #endif // (_WIN32_WINNT < 0x0501) #if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)) #include #else #ifndef TMSCHEMA_H #include #endif #endif #include #pragma comment(lib, "uxtheme.lib") // Note: To create an application that also runs on older versions of Windows, // use delay load of uxtheme.dll and ensure that no calls to the Theme API are // made if theming is not supported. It is enough to check if m_hTheme is NULL. // Example: // if(m_hTheme != NULL) // { // DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL); // DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect); // } // else // { // dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH); // dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); // } // // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, // and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the // project properties. #if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) #pragma comment(lib, "delayimp.lib") #pragma comment(linker, "/delayload:uxtheme.dll") #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) // Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h // is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE // Note: In WinSDK 7.0 (and higher) they are defined with #if (_WIN32_WINNT >= 0x0600), // so you have to compile with _WTL_NEW_UXTHEME defined for _WIN32_WINNT < 0x0600 #ifndef _WTL_NEW_UXTHEME #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) #define _WTL_NEW_UXTHEME #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) #endif // _WTL_NEW_UXTHEME /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CTheme // CThemeImpl // // CBufferedPaint // CBufferedPaintImpl // CBufferedPaintWindowImpl // CBufferedAnimation // CBufferedAnimationImpl // CBufferedAnimationWindowImpl // // Global functions: // AtlDrawThemeClientEdge() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CTheme - wrapper for theme handle class CTheme { public: // Data members HTHEME m_hTheme; static int m_nIsThemingSupported; // Constructor CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme) { IsThemingSupported(); } // Operators and helpers bool IsThemeNull() const { return (m_hTheme == NULL); } CTheme& operator =(HTHEME hTheme) { m_hTheme = hTheme; return *this; } operator HTHEME() const { return m_hTheme; } void Attach(HTHEME hTheme) { m_hTheme = hTheme; } HTHEME Detach() { HTHEME hTheme = m_hTheme; m_hTheme = NULL; return hTheme; } // Theme support helper static bool IsThemingSupported() { if(m_nIsThemingSupported == -1) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n")); ATLASSERT(FALSE); return false; } if(m_nIsThemingSupported == -1) { HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0; if(hThemeDLL != NULL) ::FreeLibrary(hThemeDLL); } lock.Unlock(); } ATLASSERT(m_nIsThemingSupported != -1); return (m_nIsThemingSupported == 1); } // Operations and theme properties HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList) { if(!IsThemingSupported()) return NULL; ATLASSERT(m_hTheme == NULL); m_hTheme = ::OpenThemeData(hWnd, pszClassList); return m_hTheme; } HRESULT CloseThemeData() { HRESULT hRet = S_FALSE; if(m_hTheme != NULL) { hRet = ::CloseThemeData(m_hTheme); if(SUCCEEDED(hRet)) m_hTheme = NULL; } return hRet; } HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect); } // Missing in original uxtheme.h #ifdef DTBG_CLIPRECT HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions); } #endif // DTBG_CLIPRECT HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect); } HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect); } HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect); } HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const { ATLASSERT(m_hTheme != NULL); #ifdef _WTL_NEW_UXTHEME return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize); #else // !_WTL_NEW_UXTHEME // Note: The cast to LPRECT is because uxtheme.h incorrectly uses it instead of LPCRECT return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, (LPRECT)pRect, eSize, pSize); #endif // !_WTL_NEW_UXTHEME } HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect); } HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const { ATLASSERT(m_hTheme != NULL); #ifdef _WTL_NEW_UXTHEME return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric); #else // !_WTL_NEW_UXTHEME // Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric); #endif // !_WTL_NEW_UXTHEME } HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion); } HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const { ATLASSERT(m_hTheme != NULL); return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode); } HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect); } HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex); } BOOL IsThemePartDefined(int nPartID, int nStateID) const { ATLASSERT(m_hTheme != NULL); return ::IsThemePartDefined(m_hTheme, nPartID, nStateID); } BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const { ATLASSERT(m_hTheme != NULL); return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID); } HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor); } HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal); } HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars); } HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal); } HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal); } HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal); } HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const { ATLASSERT(m_hTheme != NULL); return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint); } // deprecated HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const { ATLASSERT(m_hTheme != NULL); #ifdef _WTL_NEW_UXTHEME return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); #else // !_WTL_NEW_UXTHEME // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); #endif // !_WTL_NEW_UXTHEME } HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const { ATLASSERT(m_hTheme != NULL); #ifdef _WTL_NEW_UXTHEME return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); #else // !_WTL_NEW_UXTHEME // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); #endif // !_WTL_NEW_UXTHEME } HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect); } HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins); } HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList); } HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const { ATLASSERT(m_hTheme != NULL); return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin); } HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars); } COLORREF GetThemeSysColor(int nColorID) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysColor(m_hTheme, nColorID); } HBRUSH GetThemeSysColorBrush(int nColorID) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysColorBrush(m_hTheme, nColorID); } int GetThemeSysSize(int nSizeID) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysSize(m_hTheme, nSizeID); } BOOL GetThemeSysBool(int nBoolID) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysBool(m_hTheme, nBoolID); } HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const { ATLASSERT(m_hTheme != NULL); #ifdef _WTL_NEW_UXTHEME return ::GetThemeSysFont(m_hTheme, nFontID, plf); #else // !_WTL_NEW_UXTHEME // Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf); #endif // !_WTL_NEW_UXTHEME } HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars); } HRESULT GetThemeSysInt(int nIntID, int* pnValue) const { ATLASSERT(m_hTheme != NULL); return ::GetThemeSysInt(m_hTheme, nIntID, pnValue); } #ifdef _WTL_NEW_UXTHEME HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags) { if(!IsThemingSupported()) return NULL; ATLASSERT(m_hTheme == NULL); m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags); return m_hTheme; } #if (_WIN32_WINNT >= 0x0600) HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions) { ATLASSERT(m_hTheme != NULL); return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions); } HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration) { ATLASSERT(m_hTheme != NULL); return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration); } #endif // (_WIN32_WINNT >= 0x0600) #endif // _WTL_NEW_UXTHEME #if (_WIN32_WINNT >= 0x0600) HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap) { ATLASSERT(m_hTheme != NULL); return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap); } HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance) { ATLASSERT(m_hTheme != NULL); return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance); } #endif // (_WIN32_WINNT >= 0x0600) #if (_WIN32_WINNT >= 0x0602) HRESULT GetThemeAnimationProperty(int iStoryboardId, int iTargetId, TA_PROPERTY eProperty, VOID* pvProperty, DWORD cbSize, DWORD* pcbSizeOut) { ATLASSERT(m_hTheme != NULL); return ::GetThemeAnimationProperty(m_hTheme, iStoryboardId, iTargetId, eProperty, pvProperty, cbSize, pcbSizeOut); } HRESULT GetThemeAnimationTransform(int iStoryboardId, int iTargetId, DWORD dwTransformIndex, TA_TRANSFORM* pTransform, DWORD cbSize, DWORD* pcbSizeOut) { ATLASSERT(m_hTheme != NULL); return ::GetThemeAnimationTransform(m_hTheme, iStoryboardId, iTargetId, dwTransformIndex, pTransform, cbSize, pcbSizeOut); } HRESULT GetThemeTimingFunction(int iTimingFunctionId, TA_TIMINGFUNCTION* pTimingFunction, DWORD cbSize, DWORD* pcbSizeOut) { ATLASSERT(m_hTheme != NULL); return ::GetThemeTimingFunction(m_hTheme, iTimingFunctionId, pTimingFunction, cbSize, pcbSizeOut); } #endif // (_WIN32_WINNT >= 0x0602) }; __declspec(selectany) int CTheme::m_nIsThemingSupported = -1; /////////////////////////////////////////////////////////////////////////////// // CThemeImpl - theme support implementation // Derive from this class to implement window with theme support. // Example: // class CMyThemeWindow : public CWindowImpl, public CThemeImpl // { // ... // BEGIN_MSG_MAP(CMyThemeWindow) // CHAIN_MSG_MAP(CThemeImpl) // ... // END_MSG_MAP() // ... // }; // // If you set theme class list, the class will automaticaly open/close/reopen theme data. // Helper for drawing theme client edge inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0) { ATLASSERT(hTheme != NULL); ATLASSERT(::IsWindow(hWnd)); CWindowDC dc(hWnd); if(dc.IsNull()) return false; // Get border size int cxBorder = ::GetSystemMetrics(SM_CXBORDER); int cyBorder = ::GetSystemMetrics(SM_CYBORDER); if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder))) cyBorder = cxBorder; RECT rect = { 0 }; ::GetWindowRect(hWnd, &rect); // Remove the client edge from the update region int cxEdge = ::GetSystemMetrics(SM_CXEDGE); int cyEdge = ::GetSystemMetrics(SM_CYEDGE); ::InflateRect(&rect, -cxEdge, -cyEdge); CRgn rgn; rgn.CreateRectRgnIndirect(&rect); if(rgn.IsNull()) return false; if(hRgnUpdate != NULL) rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND); ::OffsetRect(&rect, -rect.left, -rect.top); ::OffsetRect(&rect, cxEdge, cyEdge); dc.ExcludeClipRect(&rect); ::InflateRect(&rect, cxEdge, cyEdge); ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL); // Use background brush too, since theme border might not cover everything if((cxBorder < cxEdge) && (cyBorder < cyEdge)) { if(hBrush == NULL) // need conditional code because types don't match in winuser.h #ifdef _WIN64 hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND); #else hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND)); #endif ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge); dc.FillRect(&rect, hBrush); } ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L); return true; } // Theme extended styles #define THEME_EX_3DCLIENTEDGE 0x00000001 #define THEME_EX_THEMECLIENTEDGE 0x00000002 template class CThemeImpl : public TBase { public: // Data members LPWSTR m_lpstrThemeClassList; DWORD m_dwExtendedStyle; // theme specific extended styles // Constructor & destructor CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0) { } ~CThemeImpl() { delete [] m_lpstrThemeClassList; } // Attributes bool SetThemeClassList(LPCWSTR lpstrThemeClassList) { if(m_lpstrThemeClassList != NULL) { delete [] m_lpstrThemeClassList; m_lpstrThemeClassList = NULL; } if(lpstrThemeClassList == NULL) return true; int cchLen = lstrlenW(lpstrThemeClassList) + 1; ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]); if(m_lpstrThemeClassList == NULL) return false; SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList); return true; } bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const { int cchLen = lstrlenW(m_lpstrThemeClassList) + 1; if(cchListBuffer < cchLen) return false; SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList); return true; } LPCWSTR GetThemeClassList() const { return m_lpstrThemeClassList; } DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) { DWORD dwPrevStyle = m_dwExtendedStyle; if(dwMask == 0) m_dwExtendedStyle = dwExtendedStyle; else m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); return dwPrevStyle; } DWORD GetThemeExtendedStyle() const { return m_dwExtendedStyle; } // Operations HTHEME OpenThemeData() { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); ATLASSERT(m_lpstrThemeClassList != NULL); if(m_lpstrThemeClassList == NULL) return NULL; CloseThemeData(); return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList); } HTHEME OpenThemeData(LPCWSTR pszClassList) { if(!SetThemeClassList(pszClassList)) return NULL; return OpenThemeData(); } HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList); } HTHEME GetWindowTheme() const { if(!IsThemingSupported()) return NULL; const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::GetWindowTheme(pT->m_hWnd); } HRESULT EnableThemeDialogTexture(DWORD dwFlags) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags); } BOOL IsThemeDialogTextureEnabled() const { if(!IsThemingSupported()) return FALSE; const T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::IsThemeDialogTextureEnabled(pT->m_hWnd); } HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); #ifdef _WTL_NEW_UXTHEME return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect); #else return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect); #endif } #if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute); } HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); WTA_OPTIONS opt = { dwAttributes, dwMask }; return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt)); } HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL) { if(!IsThemingSupported()) return S_FALSE; T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect); } #endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) // Message map and handlers // Note: If you handle any of these messages in your derived class, // it is better to put CHAIN_MSG_MAP at the start of your message map. BEGIN_MSG_MAP(CThemeImpl) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) END_MSG_MAP() LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_lpstrThemeClassList != NULL) OpenThemeData(); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { CloseThemeData(); bHandled = FALSE; return 1; } LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { CloseThemeData(); if(m_lpstrThemeClassList != NULL) OpenThemeData(); bHandled = FALSE; return 1; } LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); LRESULT lRet = 0; bHandled = FALSE; if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)) { if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0) { lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam); bHandled = TRUE; } else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0)) { HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL; if(pT->DrawThemeClientEdge(hRgn)) bHandled = TRUE; } } return lRet; } // Drawing helper bool DrawThemeClientEdge(HRGN hRgnUpdate) { T* pT = static_cast(this); return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0); } }; /////////////////////////////////////////////////////////////////////////////// // Buffered Paint and Animation #if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) /////////////////////////////////////////////////////////////////////////////// // CBufferedPaintBase - Buffered Paint support for othe classes class CBufferedPaintBase { public: static int m_nIsBufferedPaintSupported; CBufferedPaintBase() { if(IsBufferedPaintSupported()) ATLVERIFY(SUCCEEDED(::BufferedPaintInit())); } ~CBufferedPaintBase() { if(IsBufferedPaintSupported()) ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit())); } static bool IsBufferedPaintSupported() { if(m_nIsBufferedPaintSupported == -1) { CStaticDataInitCriticalSectionLock lock; if(FAILED(lock.Lock())) { ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n")); ATLASSERT(FALSE); return false; } if(m_nIsBufferedPaintSupported == -1) m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0; lock.Unlock(); } ATLASSERT(m_nIsBufferedPaintSupported != -1); return (m_nIsBufferedPaintSupported == 1); } }; __declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1; /////////////////////////////////////////////////////////////////////////////// // CBufferedPaint - support for buffered paint functions class CBufferedPaint { public: HPAINTBUFFER m_hPaintBuffer; CBufferedPaint() : m_hPaintBuffer(NULL) { } ~CBufferedPaint() { ATLVERIFY(SUCCEEDED(End())); } bool IsNull() const { return (m_hPaintBuffer == NULL); } HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint) { ATLASSERT(m_hPaintBuffer == NULL); m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint); return m_hPaintBuffer; } HRESULT End(BOOL bUpdate = TRUE) { HRESULT hRet = S_FALSE; if(m_hPaintBuffer != NULL) { hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate); m_hPaintBuffer = NULL; } return hRet; } HRESULT GetTargetRect(LPRECT pRect) const { ATLASSERT(m_hPaintBuffer != NULL); return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect); } HDC GetTargetDC() const { ATLASSERT(m_hPaintBuffer != NULL); return ::GetBufferedPaintTargetDC(m_hPaintBuffer); } HDC GetPaintDC() const { ATLASSERT(m_hPaintBuffer != NULL); return ::GetBufferedPaintDC(m_hPaintBuffer); } HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const { ATLASSERT(m_hPaintBuffer != NULL); return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow); } HRESULT Clear(const RECT* pRect = NULL) { ATLASSERT(m_hPaintBuffer != NULL); return ::BufferedPaintClear(m_hPaintBuffer, pRect); } HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL) { ATLASSERT(m_hPaintBuffer != NULL); return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha); } HRESULT MakeOpaque(const RECT* pRect = NULL) { ATLASSERT(m_hPaintBuffer != NULL); return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255); } }; /////////////////////////////////////////////////////////////////////////////// // CBufferedPaintImpl - provides buffered paint for any window template class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase { public: CBufferedPaint m_BufferedPaint; BP_BUFFERFORMAT m_dwFormat; BP_PAINTPARAMS m_PaintParams; CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB) { memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); } // Message map and handlers BEGIN_MSG_MAP(CBufferedPaintImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) END_MSG_MAP() LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background needed } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if(wParam != NULL) { RECT rect = { 0 }; pT->GetClientRect(&rect); pT->DoPaint((HDC)wParam, rect); } else { CPaintDC dc(pT->m_hWnd); pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint); } return 0; } // Overrideables void DoBufferedPaint(CDCHandle dc, RECT& rect) { HDC hDCPaint = NULL; if(IsBufferedPaintSupported()) m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); T* pT = static_cast(this); if(hDCPaint != NULL) pT->DoPaint(hDCPaint, rect); else pT->DoPaint(dc.m_hDC, rect); if(IsBufferedPaintSupported()) m_BufferedPaint.End(); } void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/) { // must be implemented in a derived class ATLASSERT(FALSE); } }; /////////////////////////////////////////////////////////////////////////////// // CBufferedPaintWindowImpl - implements a window that uses buffered paint template class ATL_NO_VTABLE CBufferedPaintWindowImpl : public ATL::CWindowImpl, public CBufferedPaintImpl< T > { public: BEGIN_MSG_MAP(CBufferedPaintWindowImpl) CHAIN_MSG_MAP(CBufferedPaintImpl< T >) END_MSG_MAP() }; /////////////////////////////////////////////////////////////////////////////// // CBufferedAnimation - support for buffered animation class CBufferedAnimation { public: HANIMATIONBUFFER m_hAnimationBuffer; CBufferedAnimation() : m_hAnimationBuffer(NULL) { } ~CBufferedAnimation() { ATLVERIFY(SUCCEEDED(End())); } bool IsNull() const { return (m_hAnimationBuffer == NULL); } HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo) { ATLASSERT(m_hAnimationBuffer == NULL); m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); return m_hAnimationBuffer; } HRESULT End(BOOL bUpdate = TRUE) { HRESULT hRet = S_FALSE; if(m_hAnimationBuffer != NULL) { hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate); m_hAnimationBuffer = NULL; } return hRet; } static bool IsRendering(HWND hWnd, HDC hDC) { return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE); } static HRESULT StopAllAnimations(HWND hWnd) { return ::BufferedPaintStopAllAnimations(hWnd); } }; /////////////////////////////////////////////////////////////////////////////// // CBufferedAnimationImpl - provides buffered animation support for any window // Note: You can either use m_State and m_NewState to store the state information // for the animation change, or map your state to those data members. DoPaint() // should only rely on the state information that is passed to it. template class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase { public: BP_BUFFERFORMAT m_dwFormat; BP_PAINTPARAMS m_PaintParams; BP_ANIMATIONPARAMS m_AnimationParams; TState m_State; TState m_NewState; CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB) { memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS)); m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS); m_AnimationParams.style = BPAS_LINEAR; m_AnimationParams.dwDuration = 500; T* pT = static_cast(this); pT->SetState(InitialState); pT->SetNewState(InitialState); } DWORD GetDuration() const { return m_AnimationParams.dwDuration; } void SetDuration(DWORD dwDuration) { m_AnimationParams.dwDuration = dwDuration; } void DoAnimation(TState NewState, const RECT* pRect = NULL) { T* pT = static_cast(this); pT->SetNewState(NewState); pT->InvalidateRect(pRect, FALSE); pT->UpdateWindow(); pT->SetState(NewState); } // Message map and handlers BEGIN_MSG_MAP(CBufferedAnimationImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) END_MSG_MAP() LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no background needed } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if(wParam != NULL) { RECT rect = { 0 }; pT->GetClientRect(&rect); pT->DoPaint((HDC)wParam, rect, m_NewState); } else { CPaintDC dc(pT->m_hWnd); pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint); } return 0; } // Overrideables void SetState(TState State) { m_State = State; } void SetNewState(TState State) { m_NewState = State; } bool AreStatesEqual() const { return (m_State == m_NewState); } void DoAnimationPaint(CDCHandle dc, RECT& rect) { T* pT = static_cast(this); if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc)) return; DWORD dwDurationSave = m_AnimationParams.dwDuration; if(pT->AreStatesEqual()) m_AnimationParams.dwDuration = 0; HDC hdcFrom = NULL, hdcTo = NULL; CBufferedAnimation ba; if(IsBufferedPaintSupported()) ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo); if(!ba.IsNull()) { if(hdcFrom != NULL) pT->DoPaint(hdcFrom, rect, m_State); if (hdcTo != NULL) pT->DoPaint(hdcTo, rect, m_NewState); } else { pT->DoPaint(dc.m_hDC, rect, m_NewState); } m_AnimationParams.dwDuration = dwDurationSave; } void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/) { // must be implemented in a derived class ATLASSERT(FALSE); } }; /////////////////////////////////////////////////////////////////////////////// // CBufferedAnimationWindowImpl - implements a window that uses buffered animation template class ATL_NO_VTABLE CBufferedAnimationWindowImpl : public ATL::CWindowImpl, public CBufferedAnimationImpl< T, TState > { public: CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState) { } typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation; BEGIN_MSG_MAP(CBufferedAnimationWindowImpl) CHAIN_MSG_MAP(_baseBufferedAnimation) END_MSG_MAP() }; #endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600) }; // namespace WTL #endif // __ATLTHEME_H__ ================================================ FILE: WTL/atluser.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLUSER_H__ #define __ATLUSER_H__ #pragma once #ifndef __ATLAPP_H__ #error atluser.h requires atlapp.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CMenuItemInfo // CMenuT // CAcceleratorT // CIconT // CCursorT // CResource // // Global functions: // AtlMessageBox() // // AtlLoadAccelerators() // AtlLoadMenu() // AtlLoadBitmap() // AtlLoadSysBitmap() // AtlLoadCursor() // AtlLoadSysCursor() // AtlLoadIcon() // AtlLoadSysIcon() // AtlLoadBitmapImage() // AtlLoadCursorImage() // AtlLoadIconImage() // AtlLoadSysBitmapImage() // AtlLoadSysCursorImage() // AtlLoadSysIconImage() // AtlLoadString() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // AtlMessageBox - accepts both memory and resource based strings inline int AtlMessageBox(HWND hWndOwner, ATL::_U_STRINGorID message, ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uType = MB_OK | MB_ICONINFORMATION) { ATLASSERT(hWndOwner == NULL || ::IsWindow(hWndOwner)); LPTSTR lpstrMessage = NULL; if(IS_INTRESOURCE(message.m_lpstr)) { for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrMessage = new TCHAR[nLen]); if(lpstrMessage == NULL) { ATLASSERT(FALSE); return 0; } int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(message.m_lpstr), lpstrMessage, nLen); if(nRes < nLen - 1) break; delete [] lpstrMessage; lpstrMessage = NULL; } message.m_lpstr = lpstrMessage; } LPTSTR lpstrTitle = NULL; if(IS_INTRESOURCE(title.m_lpstr) && LOWORD(title.m_lpstr) != 0) { for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrTitle = new TCHAR[nLen]); if(lpstrTitle == NULL) { ATLASSERT(FALSE); return 0; } int nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(title.m_lpstr), lpstrTitle, nLen); if(nRes < nLen - 1) break; delete [] lpstrTitle; lpstrTitle = NULL; } title.m_lpstr = lpstrTitle; } int nRet = ::MessageBox(hWndOwner, message.m_lpstr, title.m_lpstr, uType); delete [] lpstrMessage; delete [] lpstrTitle; return nRet; } /////////////////////////////////////////////////////////////////////////////// // CMenu #if (WINVER >= 0x0500) #ifndef MII_SIZEOF_STRUCT #define MII_SIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) #endif #define MENUITEMINFO_SIZE_VERSION_400A MII_SIZEOF_STRUCT(MENUITEMINFOA, cch) #define MENUITEMINFO_SIZE_VERSION_400W MII_SIZEOF_STRUCT(MENUITEMINFOW, cch) #ifdef UNICODE #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400W #else #define MENUITEMINFO_SIZE_VERSION_400 MENUITEMINFO_SIZE_VERSION_400A #endif // !UNICODE #endif // (WINVER >= 0x0500) class CMenuItemInfo : public MENUITEMINFO { public: CMenuItemInfo() { memset(this, 0, sizeof(MENUITEMINFO)); cbSize = sizeof(MENUITEMINFO); #if (WINVER >= 0x0500) // adjust struct size if running on older version of Windows if(AtlIsOldWindows()) { ATLASSERT(cbSize > MENUITEMINFO_SIZE_VERSION_400); // must be cbSize = MENUITEMINFO_SIZE_VERSION_400; } #endif // (WINVER >= 0x0500) } }; // forward declarations template class CMenuT; typedef CMenuT CMenuHandle; typedef CMenuT CMenu; template class CMenuT { public: // Data members HMENU m_hMenu; // Constructor/destructor/operators CMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu) { } ~CMenuT() { if(t_bManaged && m_hMenu != NULL) DestroyMenu(); } CMenuT& operator =(HMENU hMenu) { Attach(hMenu); return *this; } void Attach(HMENU hMenuNew) { ATLASSERT(::IsMenu(hMenuNew)); if(t_bManaged && m_hMenu != NULL && m_hMenu != hMenuNew) ::DestroyMenu(m_hMenu); m_hMenu = hMenuNew; } HMENU Detach() { HMENU hMenu = m_hMenu; m_hMenu = NULL; return hMenu; } operator HMENU() const { return m_hMenu; } bool IsNull() const { return (m_hMenu == NULL); } BOOL IsMenu() const { return ::IsMenu(m_hMenu); } // Create/destroy methods BOOL CreateMenu() { ATLASSERT(m_hMenu == NULL); m_hMenu = ::CreateMenu(); return (m_hMenu != NULL) ? TRUE : FALSE; } BOOL CreatePopupMenu() { ATLASSERT(m_hMenu == NULL); m_hMenu = ::CreatePopupMenu(); return (m_hMenu != NULL) ? TRUE : FALSE; } BOOL LoadMenu(ATL::_U_STRINGorID menu) { ATLASSERT(m_hMenu == NULL); m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); return (m_hMenu != NULL) ? TRUE : FALSE; } #ifndef _WIN32_WCE BOOL LoadMenuIndirect(const void* lpMenuTemplate) { ATLASSERT(m_hMenu == NULL); m_hMenu = ::LoadMenuIndirect(lpMenuTemplate); return (m_hMenu != NULL) ? TRUE : FALSE; } #endif // !_WIN32_WCE BOOL DestroyMenu() { if (m_hMenu == NULL) return FALSE; BOOL bRet = ::DestroyMenu(m_hMenu); if(bRet) m_hMenu = NULL; return bRet; } // Menu Operations BOOL DeleteMenu(UINT nPosition, UINT nFlags) { ATLASSERT(::IsMenu(m_hMenu)); return ::DeleteMenu(m_hMenu, nPosition, nFlags); } BOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = NULL) { ATLASSERT(::IsMenu(m_hMenu)); #ifndef _WIN32_WCE #if (WINVER >= 0x0500) x = _FixTrackMenuPopupX(x, y); #endif // !(WINVER >= 0x0500) return ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect); #else // CE specific lpRect; return ::TrackPopupMenuEx(m_hMenu, nFlags, x, y, hWnd, NULL); #endif // _WIN32_WCE } BOOL TrackPopupMenuEx(UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm = NULL) { ATLASSERT(::IsMenu(m_hMenu)); #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) x = _FixTrackMenuPopupX(x, y); #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) return ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm); } #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) // helper that fixes popup menu X position when it's off-screen static int _FixTrackMenuPopupX(int x, int y) { POINT pt = { x, y }; HMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); if(hMonitor == NULL) { HMONITOR hMonitorNear = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); if(hMonitorNear != NULL) { MONITORINFO mi = { sizeof(MONITORINFO) }; if(::GetMonitorInfo(hMonitorNear, &mi) != FALSE) { if(x < mi.rcWork.left) x = mi.rcWork.left; else if(x > mi.rcWork.right) x = mi.rcWork.right; } } } return x; } BOOL GetMenuInfo(LPMENUINFO lpMenuInfo) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuInfo(m_hMenu, lpMenuInfo); } BOOL SetMenuInfo(LPCMENUINFO lpMenuInfo) { ATLASSERT(::IsMenu(m_hMenu)); return ::SetMenuInfo(m_hMenu, lpMenuInfo); } #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) // Menu Item Operations BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) { ATLASSERT(::IsMenu(m_hMenu)); return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem); } BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::AppendMenu(m_hMenu, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); } #ifndef _WIN32_WCE BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); return ::AppendMenu(m_hMenu, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); } BOOL AppendMenu(UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::AppendMenu(m_hMenu, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); } #endif // !_WIN32_WCE UINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck) { ATLASSERT(::IsMenu(m_hMenu)); return (UINT)::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck); } UINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable) { ATLASSERT(::IsMenu(m_hMenu)); return ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable); } #ifndef _WIN32_WCE BOOL HiliteMenuItem(HWND hWnd, UINT uIDHiliteItem, UINT uHilite) { ATLASSERT(::IsMenu(m_hMenu)); return ::HiliteMenuItem(hWnd, m_hMenu, uIDHiliteItem, uHilite); } int GetMenuItemCount() const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuItemCount(m_hMenu); } UINT GetMenuItemID(int nPos) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuItemID(m_hMenu, nPos); } UINT GetMenuState(UINT nID, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuState(m_hMenu, nID, nFlags); } int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); } int GetMenuStringLen(UINT nIDItem, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); } #ifndef _ATL_NO_COM BOOL GetMenuString(UINT nIDItem, BSTR& bstrText, UINT nFlags) const { USES_CONVERSION; ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(bstrText == NULL); int nLen = GetMenuStringLen(nIDItem, nFlags); if(nLen == 0) { bstrText = ::SysAllocString(OLESTR("")); return (bstrText != NULL) ? TRUE : FALSE; } nLen++; // increment to include terminating NULL char CTempBuffer buff; LPTSTR lpszText = buff.Allocate(nLen); if(lpszText == NULL) return FALSE; if(!GetMenuString(nIDItem, lpszText, nLen, nFlags)) return FALSE; bstrText = ::SysAllocString(T2OLE(lpszText)); return (bstrText != NULL) ? TRUE : FALSE; } #endif // !_ATL_NO_COM #elif (_ATL_VER >= 0x0800) int GetMenuItemCount() const { ATLASSERT(::IsMenu(m_hMenu)); return ATL::GetMenuItemCount(m_hMenu); } UINT GetMenuItemID(int nPos) const { ATLASSERT(::IsMenu(m_hMenu)); return ATL::GetMenuItemID(m_hMenu, nPos); } UINT GetMenuState(UINT nID, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ATL::GetMenuState(m_hMenu, nID, nFlags); } int GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ATL::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags); } int GetMenuStringLen(UINT nIDItem, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); return ATL::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags); } #endif // (_ATL_VER >= 0x0800) #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) int GetMenuString(UINT nIDItem, _CSTRING_NS::CString& strText, UINT nFlags) const { ATLASSERT(::IsMenu(m_hMenu)); int nLen = GetMenuStringLen(nIDItem, nFlags); if(nLen == 0) return 0; nLen++; // increment to include terminating NULL char LPTSTR lpstr = strText.GetBufferSetLength(nLen); if(lpstr == NULL) return 0; int nRet = GetMenuString(nIDItem, lpstr, nLen, nFlags); strText.ReleaseBuffer(); return nRet; } #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) CMenuHandle GetSubMenu(int nPos) const { ATLASSERT(::IsMenu(m_hMenu)); return CMenuHandle(::GetSubMenu(m_hMenu, nPos)); } BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) { ATLASSERT(::IsMenu(m_hMenu)); return ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); } BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); } #ifndef _WIN32_WCE BOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); return ::InsertMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); } BOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::InsertMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); } BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) { ATLASSERT(::IsMenu(m_hMenu)); return ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem); } BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem); } BOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); return ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp); } BOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp) { ATLASSERT(::IsMenu(m_hMenu)); ATLASSERT(::IsMenu(hSubMenu)); return ::ModifyMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp); } #endif // !_WIN32_WCE BOOL RemoveMenu(UINT nPosition, UINT nFlags) { ATLASSERT(::IsMenu(m_hMenu)); return ::RemoveMenu(m_hMenu, nPosition, nFlags); } #ifndef _WIN32_WCE BOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, HBITMAP hBmpUnchecked, HBITMAP hBmpChecked) { ATLASSERT(::IsMenu(m_hMenu)); return ::SetMenuItemBitmaps(m_hMenu, nPosition, nFlags, hBmpUnchecked, hBmpChecked); } #endif // !_WIN32_WCE BOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags) { ATLASSERT(::IsMenu(m_hMenu)); return ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags); } BOOL GetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) const { ATLASSERT(::IsMenu(m_hMenu)); return (BOOL)::GetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); } BOOL SetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) { ATLASSERT(::IsMenu(m_hMenu)); return (BOOL)::SetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii); } #ifndef _WIN32_WCE BOOL InsertMenuItem(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) { ATLASSERT(::IsMenu(m_hMenu)); return (BOOL)::InsertMenuItem(m_hMenu, uItem, bByPosition, lpmii); } UINT GetMenuDefaultItem(BOOL bByPosition = FALSE, UINT uFlags = 0U) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuDefaultItem(m_hMenu, (UINT)bByPosition, uFlags); } BOOL SetMenuDefaultItem(UINT uItem = (UINT)-1, BOOL bByPosition = FALSE) { ATLASSERT(::IsMenu(m_hMenu)); return ::SetMenuDefaultItem(m_hMenu, uItem, (UINT)bByPosition); } BOOL GetMenuItemRect(HWND hWnd, UINT uItem, LPRECT lprcItem) const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuItemRect(hWnd, m_hMenu, uItem, lprcItem); } int MenuItemFromPoint(HWND hWnd, POINT point) const { ATLASSERT(::IsMenu(m_hMenu)); return ::MenuItemFromPoint(hWnd, m_hMenu, point); } // Context Help Functions BOOL SetMenuContextHelpId(DWORD dwContextHelpId) { ATLASSERT(::IsMenu(m_hMenu)); return ::SetMenuContextHelpId(m_hMenu, dwContextHelpId); } DWORD GetMenuContextHelpId() const { ATLASSERT(::IsMenu(m_hMenu)); return ::GetMenuContextHelpId(m_hMenu); } #endif // !_WIN32_WCE }; /////////////////////////////////////////////////////////////////////////////// // CAccelerator template class CAcceleratorT { public: HACCEL m_hAccel; // Constructor/destructor/operators CAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel) { } ~CAcceleratorT() { if(t_bManaged && m_hAccel != NULL) ::DestroyAcceleratorTable(m_hAccel); } CAcceleratorT& operator =(HACCEL hAccel) { Attach(hAccel); return *this; } void Attach(HACCEL hAccel) { if(t_bManaged && m_hAccel != NULL) ::DestroyAcceleratorTable(m_hAccel); m_hAccel = hAccel; } HACCEL Detach() { HACCEL hAccel = m_hAccel; m_hAccel = NULL; return hAccel; } operator HACCEL() const { return m_hAccel; } bool IsNull() const { return m_hAccel == NULL; } // Create/destroy methods HACCEL LoadAccelerators(ATL::_U_STRINGorID accel) { ATLASSERT(m_hAccel == NULL); m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), accel.m_lpstr); return m_hAccel; } HACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries) { ATLASSERT(m_hAccel == NULL); ATLASSERT(pAccel != NULL); m_hAccel = ::CreateAcceleratorTable(pAccel, cEntries); return m_hAccel; } void DestroyObject() { if(m_hAccel != NULL) { ::DestroyAcceleratorTable(m_hAccel); m_hAccel = NULL; } } // Operations #ifndef _WIN32_WCE int CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries) { ATLASSERT(m_hAccel != NULL); ATLASSERT(lpAccelDst != NULL); return ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries); } int GetEntriesCount() const { ATLASSERT(m_hAccel != NULL); return ::CopyAcceleratorTable(m_hAccel, NULL, 0); } #endif // !_WIN32_WCE BOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg) { ATLASSERT(m_hAccel != NULL); ATLASSERT(::IsWindow(hWnd)); ATLASSERT(pMsg != NULL); return ::TranslateAccelerator(hWnd, m_hAccel, pMsg); } }; typedef CAcceleratorT CAcceleratorHandle; typedef CAcceleratorT CAccelerator; /////////////////////////////////////////////////////////////////////////////// // CIcon template class CIconT { public: HICON m_hIcon; // Constructor/destructor/operators CIconT(HICON hIcon = NULL) : m_hIcon(hIcon) { } ~CIconT() { if(t_bManaged && m_hIcon != NULL) ::DestroyIcon(m_hIcon); } CIconT& operator =(HICON hIcon) { Attach(hIcon); return *this; } void Attach(HICON hIcon) { if(t_bManaged && m_hIcon != NULL) ::DestroyIcon(m_hIcon); m_hIcon = hIcon; } HICON Detach() { HICON hIcon = m_hIcon; m_hIcon = NULL; return hIcon; } operator HICON() const { return m_hIcon; } bool IsNull() const { return m_hIcon == NULL; } // Create/destroy methods HICON LoadIcon(ATL::_U_STRINGorID icon) { ATLASSERT(m_hIcon == NULL); m_hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); return m_hIcon; } HICON LoadIcon(ATL::_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0) { ATLASSERT(m_hIcon == NULL); m_hIcon = (HICON) ::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); return m_hIcon; } #ifndef _WIN32_WCE HICON LoadOEMIcon(LPCTSTR lpstrIconName) { ATLASSERT(m_hIcon == NULL); ATLASSERT(IsOEMIcon(lpstrIconName)); m_hIcon = ::LoadIcon(NULL, lpstrIconName); return m_hIcon; } HICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDbits, CONST BYTE *lpbXORbits) { ATLASSERT(m_hIcon == NULL); ATLASSERT(lpbANDbits != NULL); ATLASSERT(lpbXORbits != NULL); m_hIcon = ::CreateIcon(ModuleHelper::GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits); return m_hIcon; } HICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) { ATLASSERT(m_hIcon == NULL); ATLASSERT(pBits != NULL); m_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion); return m_hIcon; } HICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) { ATLASSERT(m_hIcon == NULL); ATLASSERT(pbBits != NULL); ATLASSERT(cbBits > 0); m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags); return m_hIcon; } #endif // !_WIN32_WCE HICON CreateIconIndirect(PICONINFO pIconInfo) { ATLASSERT(m_hIcon == NULL); ATLASSERT(pIconInfo != NULL); m_hIcon = ::CreateIconIndirect(pIconInfo); return m_hIcon; } #ifndef _WIN32_WCE HICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex) { ATLASSERT(m_hIcon == NULL); ATLASSERT(lpszExeFileName != NULL); m_hIcon = ::ExtractIcon(ModuleHelper::GetModuleInstance(), lpszExeFileName, nIconIndex); return m_hIcon; } HICON ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon) { ATLASSERT(m_hIcon == NULL); ATLASSERT(lpIconPath != NULL); ATLASSERT(lpiIcon != NULL); m_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon); return m_hIcon; } #endif // !_WIN32_WCE BOOL DestroyIcon() { ATLASSERT(m_hIcon != NULL); BOOL bRet = ::DestroyIcon(m_hIcon); if(bRet != FALSE) m_hIcon = NULL; return bRet; } // Operations #ifndef _WIN32_WCE HICON CopyIcon() { ATLASSERT(m_hIcon != NULL); return ::CopyIcon(m_hIcon); } HICON DuplicateIcon() { ATLASSERT(m_hIcon != NULL); return ::DuplicateIcon(NULL, m_hIcon); } #endif // !_WIN32_WCE BOOL DrawIcon(HDC hDC, int x, int y) { ATLASSERT(m_hIcon != NULL); #ifndef _WIN32_WCE return ::DrawIcon(hDC, x, y, m_hIcon); #else // CE specific return ::DrawIconEx(hDC, x, y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); #endif // _WIN32_WCE } BOOL DrawIcon(HDC hDC, POINT pt) { ATLASSERT(m_hIcon != NULL); #ifndef _WIN32_WCE return ::DrawIcon(hDC, pt.x, pt.y, m_hIcon); #else // CE specific return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL); #endif // _WIN32_WCE } BOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hIcon != NULL); return ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } BOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hIcon != NULL); return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } #ifndef _WIN32_WCE BOOL GetIconInfo(PICONINFO pIconInfo) const { ATLASSERT(m_hIcon != NULL); ATLASSERT(pIconInfo != NULL); return ::GetIconInfo(m_hIcon, pIconInfo); } #if (_WIN32_WINNT >= 0x0600) BOOL GetIconInfoEx(PICONINFOEX pIconInfo) const { ATLASSERT(m_hIcon != NULL); ATLASSERT(pIconInfo != NULL); return ::GetIconInfoEx(m_hIcon, pIconInfo); } #endif // (_WIN32_WINNT >= 0x0600) #if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) HRESULT LoadIconMetric(ATL::_U_STRINGorID icon, int lims) { ATLASSERT(m_hIcon == NULL); USES_CONVERSION; return ::LoadIconMetric(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), lims, &m_hIcon); } HRESULT LoadIconWithScaleDown(ATL::_U_STRINGorID icon, int cx, int cy) { ATLASSERT(m_hIcon == NULL); USES_CONVERSION; return ::LoadIconWithScaleDown(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), cx, cy, &m_hIcon); } HRESULT LoadOEMIconMetric(LPCTSTR lpstrIconName, int lims) { ATLASSERT(m_hIcon == NULL); ATLASSERT(IsOEMIcon(lpstrIconName)); return ::LoadIconMetric(NULL, (LPCWSTR)lpstrIconName, lims, &m_hIcon); } HRESULT LoadOEMIconWithScaleDown(LPCTSTR lpstrIconName, int cx, int cy) { ATLASSERT(m_hIcon == NULL); ATLASSERT(IsOEMIcon(lpstrIconName)); USES_CONVERSION; return ::LoadIconWithScaleDown(NULL, (LPCWSTR)lpstrIconName, cx, cy, &m_hIcon); } #endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) #endif // !_WIN32_WCE // Helper #ifndef _WIN32_WCE static bool IsOEMIcon(LPCTSTR lpstrIconName) { #if (WINVER >= 0x0600) return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO || lpstrIconName == IDI_SHIELD); #else // !(WINVER >= 0x0600) return (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION || lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO); #endif // !(WINVER >= 0x0600) } #endif // !_WIN32_WCE }; typedef CIconT CIconHandle; typedef CIconT CIcon; /////////////////////////////////////////////////////////////////////////////// // CCursor // protect template member from a winuser.h macro #ifdef CopyCursor #undef CopyCursor #endif template class CCursorT { public: HCURSOR m_hCursor; // Constructor/destructor/operators CCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor) { } ~CCursorT() { if(t_bManaged && m_hCursor != NULL) DestroyCursor(); } CCursorT& operator =(HCURSOR hCursor) { Attach(hCursor); return *this; } void Attach(HCURSOR hCursor) { if(t_bManaged && m_hCursor != NULL) DestroyCursor(); m_hCursor = hCursor; } HCURSOR Detach() { HCURSOR hCursor = m_hCursor; m_hCursor = NULL; return hCursor; } operator HCURSOR() const { return m_hCursor; } bool IsNull() const { return m_hCursor == NULL; } // Create/destroy methods HCURSOR LoadCursor(ATL::_U_STRINGorID cursor) { ATLASSERT(m_hCursor == NULL); m_hCursor = ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); return m_hCursor; } HCURSOR LoadSysCursor(LPCTSTR lpstrCursorName) { ATLASSERT(m_hCursor == NULL); #if (WINVER >= 0x0500) ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP || lpstrCursorName == IDC_HAND); #else // !(WINVER >= 0x0500) ATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT || lpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE || lpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW || lpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL || lpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP); #endif // !(WINVER >= 0x0500) m_hCursor = ::LoadCursor(NULL, lpstrCursorName); return m_hCursor; } // deprecated HCURSOR LoadOEMCursor(LPCTSTR lpstrCursorName) { return LoadSysCursor(lpstrCursorName); } HCURSOR LoadCursor(ATL::_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0) { ATLASSERT(m_hCursor == NULL); m_hCursor = (HCURSOR) ::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); return m_hCursor; } #ifndef _WIN32_WCE HCURSOR LoadCursorFromFile(LPCTSTR pstrFilename) { ATLASSERT(m_hCursor == NULL); ATLASSERT(pstrFilename != NULL); m_hCursor = ::LoadCursorFromFile(pstrFilename); return m_hCursor; } #endif // !_WIN32_WCE #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) HCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane) { ATLASSERT(m_hCursor == NULL); m_hCursor = ::CreateCursor(ModuleHelper::GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane); return m_hCursor; } #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) #ifndef _WIN32_WCE HCURSOR CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) { ATLASSERT(m_hCursor == NULL); ATLASSERT(pBits != NULL); m_hCursor = (HCURSOR)::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion); return m_hCursor; } HCURSOR CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) { ATLASSERT(m_hCursor == NULL); ATLASSERT(pbBits != NULL); ATLASSERT(cbBits > 0); m_hCursor = (HCURSOR)::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags); return m_hCursor; } #endif // !_WIN32_WCE BOOL DestroyCursor() { ATLASSERT(m_hCursor != NULL); #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) BOOL bRet = ::DestroyCursor(m_hCursor); if(bRet != FALSE) m_hCursor = NULL; return bRet; #else // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) ATLTRACE2(atlTraceUI, 0, _T("Warning: This version of Windows CE does not have ::DestroyCursor()\n")); return FALSE; #endif // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))) } // Operations #ifndef _WIN32_WCE HCURSOR CopyCursor() { ATLASSERT(m_hCursor != NULL); return (HCURSOR)::CopyIcon((HICON)m_hCursor); } #endif // !_WIN32_WCE #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) BOOL GetCursorInfo(LPCURSORINFO pCursorInfo) { ATLASSERT(m_hCursor != NULL); ATLASSERT(pCursorInfo != NULL); return ::GetCursorInfo(pCursorInfo); } #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) }; typedef CCursorT CCursorHandle; typedef CCursorT CCursor; /////////////////////////////////////////////////////////////////////////////// // CResource - Wraps a generic Windows resource. // Use it with custom resource types other than the // standard RT_CURSOR, RT_BITMAP, etc. class CResource { public: HGLOBAL m_hGlobal; HRSRC m_hResource; // Constructor/destructor CResource() : m_hGlobal(NULL), m_hResource(NULL) { } ~CResource() { Release(); } // Load methods bool Load(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID) { ATLASSERT(m_hResource == NULL); ATLASSERT(m_hGlobal == NULL); m_hResource = ::FindResource(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr); if(m_hResource == NULL) return false; m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); if(m_hGlobal == NULL) { m_hResource = NULL; return false; } return true; } #ifndef _WIN32_WCE bool LoadEx(ATL::_U_STRINGorID ID, ATL::_U_STRINGorID Type, WORD wLanguage) { ATLASSERT(m_hResource == NULL); ATLASSERT(m_hGlobal == NULL); m_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), Type.m_lpstr, ID.m_lpstr, wLanguage); if(m_hResource == NULL) return false; m_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource); if(m_hGlobal == NULL) { m_hResource = NULL; return false; } return true; } #endif // !_WIN32_WCE // Misc. operations DWORD GetSize() const { ATLASSERT(m_hResource != NULL); return ::SizeofResource(ModuleHelper::GetResourceInstance(), m_hResource); } LPVOID Lock() { ATLASSERT(m_hResource != NULL); ATLASSERT(m_hGlobal != NULL); LPVOID pVoid = ::LockResource(m_hGlobal); ATLASSERT(pVoid != NULL); return pVoid; } void Release() { if(m_hGlobal != NULL) { FreeResource(m_hGlobal); m_hGlobal = NULL; m_hResource = NULL; } } }; /////////////////////////////////////////////////////////////////////////////// // Toolbar resource descriptor struct _AtlToolBarData { WORD wVersion; WORD wWidth; WORD wHeight; WORD wItemCount; WORD* items() { return (WORD*)(this+1); } }; /////////////////////////////////////////////////////////////////////////////// // Global functions for loading resources inline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table) { return ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_lpstr); } inline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu) { return ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr); } inline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap) { return ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr); } #ifdef OEMRESOURCE inline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap) { #ifdef _DEBUG WORD wID = LOWORD(bitmap.m_lpstr); ATLASSERT(wID >= 32734 && wID <= 32767); #endif // _DEBUG return ::LoadBitmap(NULL, bitmap.m_lpstr); } #endif // OEMRESOURCE inline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor) { return ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr); } inline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName) { #if (WINVER >= 0x0500) ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP || lpCursorName == IDC_HAND); #else // !(WINVER >= 0x0500) ATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT || lpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE || lpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW || lpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL || lpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP); #endif // !(WINVER >= 0x0500) return ::LoadCursor(NULL, lpCursorName); } inline HICON AtlLoadIcon(ATL::_U_STRINGorID icon) { return ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr); } #ifndef _WIN32_WCE inline HICON AtlLoadSysIcon(LPCTSTR lpIconName) { #if (WINVER >= 0x0600) ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO || lpIconName == IDI_SHIELD); #else // !(WINVER >= 0x0600) ATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION || lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO); #endif // !(WINVER >= 0x0600) return ::LoadIcon(NULL, lpIconName); } #endif // !_WIN32_WCE inline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR) { return (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad); } inline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) { return (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); } inline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) { return (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); } #ifdef OEMRESOURCE inline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR) { ATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767); ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file return (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad); } #endif // OEMRESOURCE inline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) { #ifdef _DEBUG WORD wID = LOWORD(cursor.m_lpstr); ATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651)); ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file #endif // _DEBUG return (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); } inline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0) { #ifdef _DEBUG WORD wID = LOWORD(icon.m_lpstr); ATLASSERT(wID >= 32512 && wID <= 32517); ATLASSERT((fuLoad & LR_LOADFROMFILE) == 0); // this one doesn't load from a file #endif // _DEBUG return (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); } #if (_ATL_VER < 0x0700) inline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax) { return ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpBuffer, nBufferMax); } #else using ATL::AtlLoadString; #endif // (_ATL_VER < 0x0700) #ifdef _WIN32_WCE // CE only direct access to the resource inline LPCTSTR AtlLoadString(UINT uID) { LPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), uID, NULL, 0); #ifdef DEBUG // Check for null-termination if(s != NULL) // Note: RC -n compiles null-terminated resource strings ATLASSERT(s[*((WORD*)s -1) - 1] == L'\0'); #endif return s; } #endif // _WIN32_WCE inline bool AtlLoadString(UINT uID, BSTR& bstrText) { USES_CONVERSION; ATLASSERT(bstrText == NULL); LPTSTR lpstrText = NULL; int nRes = 0; for(int nLen = 256; ; nLen *= 2) { ATLTRY(lpstrText = new TCHAR[nLen]); if(lpstrText == NULL) break; nRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpstrText, nLen); if(nRes < nLen - 1) break; delete [] lpstrText; lpstrText = NULL; } if(lpstrText != NULL) { if(nRes != 0) bstrText = ::SysAllocString(T2OLE(lpstrText)); delete [] lpstrText; } return (bstrText != NULL) ? true : false; } }; // namespace WTL #endif // __ATLUSER_H__ ================================================ FILE: WTL/atlwince.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLWINCE_H__ #define __ATLWINCE_H__ #pragma once #ifndef __ATLAPP_H__ #error atlwince.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlwince.h requires atlwin.h to be included first #endif #ifndef _WIN32_WCE #error atlwince.h compiles under Windows CE only #endif #if (_WIN32_WCE < 300) #error atlwince.h requires Windows CE 3.0 or higher. #endif #if defined(WIN32_PLATFORM_WFSP) && _MSC_VER < 1400 // EVC compiling SmartPhone code #if (WIN32_PLATFORM_WFSP < 200) #error atlwince.h requires Smartphone 2003 or higher #endif #endif // WIN32_PLATFORM_WFSP #if defined(WIN32_PLATFORM_PSPC) && _MSC_VER < 1400 // EVC compiling Pocket PC code #if (WIN32_PLATFORM_PSPC < 310) #error atlwince.h requires Pocket PC 2002 or higher #endif #endif // WIN32_PLATFORM_PSPC #if !defined(_AYGSHELL_H_) && !defined(__AYGSHELL_H__) #error atlwince.h requires aygshell.h to be included first #else #if defined(WIN32_PLATFORM_WFSP) && !defined(_TPCSHELL_H_) #error SmartPhone dialog classes require tpcshell.h to be included first #endif #endif #if (_MSC_VER >= 1400) // VS2005 #include #define _WTL_CE_DRA #endif // (_MSC_VER >= 1400) #if !defined(_WTL_CE_NO_DIALOGS) && !defined(__ATLFRAME_H__) #error Orientation aware dialog classes require atlframe.h to be included first #endif #if !defined(_WTL_CE_NO_APPWINDOW) && !defined(__ATLFRAME_H__) #error Application window class require atlframe.h to be included first #endif #if !defined(_WTL_CE_NO_ZOOMSCROLL) && !defined(__ATLSCRL_H__) #error ZoomScroll implementation requires atlscrl.h to be included first #endif #if !defined(_WTL_CE_NO_ZOOMSCROLL) #if !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) #error ZoomScroll requires _WTL_NO_WTYPES not to be defined and either atlmisc.h or atltypes.h to be included first #endif // !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES))) #endif // !defined(_WTL_CE_NO_ZOOMSCROLL) #if !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) #define _WTL_CE_NO_CONTROLS #endif // !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC) #ifndef _WTL_CE_NO_CONTROLS #ifndef __ATLCTRLS_H__ #error The PPC/SmartPhone controls classes require atlctrls.h to be included first #endif #include #pragma comment(lib, "htmlview.lib") #include #pragma comment(lib, "voicectl.lib") #ifdef WIN32_PLATFORM_PSPC #include #pragma comment(lib, "richink.lib") #include #pragma comment(lib, "inkx.lib") #include #pragma comment(lib, "doclist.lib") #endif #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CStdDialogBase : Standard PPC/SmartPhone dialog base class // CStdDialogImplBase - Base implementation of standard dialog // CStdDialogImpl : Standard dialog implementation // CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog // CStdAxDialogImpl : Standard AxDialog implementation // CStdSimpleDialog : Standard simple dialog // CStdDialogResizeImplBase - Base implementation of orientation resizing standard dialog // CStdDialogResizeImpl : Orientation resizing standard dialog implementation // CStdAxDialogResizeImpl - implementation of orientation resizing standard AxDialog // CStdSimpleDialogResizeImpl : Standard resizing simple dialog implementation // CStdOrientedDialogBase - Oriented PPC standard dialog base class // CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation // CStdOrientedDialogImpl : Oriented PPC standard dialog implementation // CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation // CStdSimpleOrientedDialog : Standard simple orientable dialog // // CAppInfoBase : Helper for application state save/restore to registry // CAppInfoT : CAppInfoBase constructed from a CAppWindow // CAppWindowBase : Base class for PPC/SmartPhone well-behaved application window or dialog // CAppWindow : PPC/SmartPhone well-behaved application window class // CAppDialog : PPC/SmartPhone well-behaved application dialog class // CAppStdDialogImplBase - Base implementation of standard application dialogs // CAppStdDialogImpl : Implementation of standard application dialog // CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog // CAppStdAxDialogImpl - Implementation of standard application AxDialog // CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog // CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog // CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog // // CFullScreenFrame : Full screen frame class // // CZoomScrollImpl : WinCE zooming implementation // // CBottomTabViewImpl - CBottomTabView // CHtmlCtrlT - CHtmlCtrl // CRichInkCtrlT - CRichInkCtrl // CInkXCtrlT - CInkXCtrl // CVoiceRecorderCtrlT - CVoiceRecorderCtrl // CDocListCtrlT - CDocListCtrl // CCapEditT - CCapEdit // CTTStaticT - CTTStatic // CTTButtonT - CTTButton // // CSpinCtrlT - CSpinCtrl : SmartPhone specific UpDown control // CSpinned : SmartPhone association of control and Spin // CSpinListBox : SmartPhone spinned ListBox control // CExpandListBox : SmartPhone expandable ListBox control // CExpandEdit : SmartPhone expandable Edit control // CExpandCapEdit : SmartPhone expandable CapEdit control // // Global functions: // AtlCreateMenuBar() // AtlCreateEmptyMenuBar() // AtlIsEditFocus() // AtlActivateBackKey() namespace WTL { /////////////////////////////////////////////////////////////////////////////// // MenuBar creation functions for property sheets and dialogs // Frame windows use CreateSimpleCEMenuBar inline HWND AtlCreateMenuBar(SHMENUBARINFO& mbi) { ATLASSERT(::IsWindow(mbi.hwndParent)); ATLVERIFY(::SHCreateMenuBar(&mbi) != FALSE); return mbi.hwndMB; }; inline HWND AtlCreateMenuBar(HWND hWnd, UINT nToolBarId = ATL_IDW_TOOLBAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0, COLORREF clrBk = 0) { SHMENUBARINFO mbi = { sizeof(mbi), hWnd, dwFlags, nToolBarId, ModuleHelper::GetResourceInstance(), nBmpId, cBmpImages, 0, clrBk }; return AtlCreateMenuBar(mbi); } inline HWND AtlCreateEmptyMenuBar(HWND hWnd, bool bSip = true) { SHMENUBARINFO embi = { sizeof(SHMENUBARINFO), hWnd, SHCMBF_EMPTYBAR }; if (!bSip) embi.dwFlags |= SHCMBF_HIDESIPBUTTON; return AtlCreateMenuBar(embi); } /////////////////////////////////////////////////////////////////////////////// // Helper functions for SmartPhone back key handling inline bool AtlIsEditFocus() { ATL::CWindow wCtrl = GetFocus(); if (wCtrl.IsWindow()) { TCHAR szClassName[8] = {0}; ATLVERIFY(::GetClassName(wCtrl.m_hWnd, szClassName, 8)); return !_tcscmp(szClassName, _T("Edit")) || !_tcscmp(szClassName, WC_CAPEDIT); } return false; } #if defined WIN32_PLATFORM_WFSP inline void AtlActivateBackKey(HWND hMenuBar) { ATLASSERT(::IsWindow(hMenuBar)); ::SendMessage(hMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK, MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); } #endif // WIN32_PLATFORM_WFSP // --- Standard PPC/SmartPhone dialogs --- #ifndef _WTL_CE_NO_DIALOGS /////////////////////////////////////////////////////////////////////////////// // CStdDialogBase - base class for standard PPC/SmartPhone dialogs #define WTL_STD_SHIDIF SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN #define WTL_SP_SHIDIF SHIDIF_SIZEDLGFULLSCREEN // Title setting macros #define WTL_DLG_TITLEHEIGHT(iHeight) static const int GetTitleHeight(){return iHeight;} #define WTL_DLG_NOTITLE WTL_DLG_TITLEHEIGHT(0) /////////////////////////////////////////////////////////////////////////////// // CStdDialogBase - Base class for standard PPC/SmartPhone dialog template class CStdDialogBase { public: #ifdef WIN32_PLATFORM_PSPC // Pocket PC only Dialog title handling const int nTitleHeight; CStdDialogBase() : nTitleHeight(T::GetTitleHeight()) { } // Overloads BOOL GetClientRect(LPRECT lpRect) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); BOOL bRes = ::GetClientRect(pT->m_hWnd, lpRect); if (nTitleHeight) lpRect->top += nTitleHeight + 1; return bRes; } BOOL SetWindowText(LPCTSTR lpszString) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); BOOL bRes = ::SetWindowText(pT->m_hWnd, lpszString); if (nTitleHeight != 0) pT->DoPaintTitle(); return bRes; } // Overrideables static const int GetTitleHeight() { #ifdef _WTL_CE_DRA return DRA::SCALEY(24); #else // !_WTL_CE_DRA CWindowDC dc(NULL); return dc.GetDeviceCaps(LOGPIXELSY) >> 2; // LOGPIXELSY * 24 / 96, #endif // !_WTL_CE_DRA } // Title painting bool DoPaintTitle() { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); TCHAR sTitle[48] = { 0 }; // Preparation CPaintDC dc(pT->m_hWnd); CFont fontTitle = AtlCreateBoldFont(); CFontHandle fontOld = dc.SelectFont(fontTitle); dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); int nLen = pT->GetWindowText(sTitle, 48); int nWidth = dc.GetDeviceCaps(HORZRES); // Display title text RECT rTitle = { 0, 0, nWidth, nTitleHeight }; dc.FillRect(&rTitle, COLOR_3DHIGHLIGHT); #ifdef _WTL_CE_DRA rTitle.left = DRA::SCALEX(8); #else // !_WTL_CE_DRA rTitle.left = nTitleHeight / 3; // 8 == 24 / 3 #endif // !_WTL_CE_DRA dc.DrawText(sTitle, nLen, &rTitle, DT_VCENTER | DT_SINGLELINE); dc.SelectFont(fontOld); // Draw bottom line, 2 pixels thick if HI_RES_AWARE CPenHandle penOld = dc.SelectStockPen(BLACK_PEN); POINT line[4] = {{0, nTitleHeight}, {nWidth, nTitleHeight}, {0, nTitleHeight - 1}, {nWidth, nTitleHeight - 1}}; #ifdef _WTL_CE_DRA int nSeg = DRA::SCALEY(1); #else // !_WTL_CE_DRA int nSeg = nTitleHeight / 24; #endif // !_WTL_CE_DRA dc.Polyline(line, nSeg <= 2 ? nSeg * 2 : 4); dc.SelectPen(penOld); return false; } // Title preparation: move the dialog controls down to make room for title void DialogTitleInit() { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); while (wCtl.IsWindow()) { RECT rCtl = { 0 }; wCtl.GetWindowRect(&rCtl); ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rCtl, 2); ::OffsetRect(&rCtl, 0, nTitleHeight); wCtl.MoveWindow(&rCtl, FALSE); wCtl = wCtl.GetWindow(GW_HWNDNEXT); } } // SIP management void DoSipInfo() { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); SIPINFO si = {sizeof(SIPINFO)}; SipGetInfo(&si); if ((si.fdwFlags & SIPF_ON) ^ SIPF_ON) si.rcVisibleDesktop.bottom = si.rcSipRect.bottom; pT->MoveWindow(&si.rcVisibleDesktop, FALSE); } // Title painting handler LRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); return bHandled = nTitleHeight ? pT->DoPaintTitle() : FALSE; } // SIP handler LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); if (wParam == SPI_SETSIPINFO) { pT->DoSipInfo(); return TRUE; } return bHandled = FALSE; } #elif defined WIN32_PLATFORM_WFSP // SmartPhone VK_TBACK key standard management LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); const UINT uModif = (UINT)LOWORD(lParam); const UINT uVirtKey = (UINT)HIWORD(lParam); if(uVirtKey == VK_TBACK) if (AtlIsEditFocus()) ::SHSendBackToFocusWindow(uMsg, wParam, lParam); else if (uModif & MOD_KEYUP) pT->StdCloseDialog(IDCANCEL); return 1; } // SmartPhone MenuBar and VK_TBACK key initialization void StdSPInit() { T* pT = static_cast(this); HWND hMenuBar = ::SHFindMenuBar(pT->m_hWnd); if (!hMenuBar && (t_shidiFlags & SHIDIF_DONEBUTTON)) hMenuBar = CreateMenuBar(ATL_IDM_MENU_DONE); if(hMenuBar != NULL) AtlActivateBackKey(hMenuBar); } void SetStaticBold() { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); CFontHandle fontBold = AtlCreateBoldFont(pT->GetFont()); ATL::CWindow wCtl = pT->GetWindow(GW_CHILD); while (wCtl.IsWindow()) { if ((short int)wCtl.GetDlgCtrlID() == IDC_STATIC) wCtl.SetFont(fontBold); wCtl = wCtl.GetWindow(GW_HWNDNEXT); } } #endif // WIN32_PLATFORM_WFSP // Platform dependant initialization void StdPlatformInit() { T* pT = static_cast(this); #ifdef WIN32_PLATFORM_PSPC // Pocket PC title initialization if (nTitleHeight != 0) pT->DialogTitleInit(); #elif defined(WIN32_PLATFORM_WFSP) pT->StdSPInit(); SetStaticBold(); #endif // WIN32_PLATFORM_WFSP } // Menu bar creation HWND CreateMenuBar(UINT uiMB = T::IDD, int nBmpImages = 0) { T* pT = static_cast(this); return AtlCreateMenuBar(pT->m_hWnd, uiMB, 0, nBmpImages ? uiMB : 0, nBmpImages); } // Dialog closing void StdCloseDialog(WORD wID) { T* pT = static_cast(this); if (t_bModal) ::EndDialog(pT->m_hWnd, wID); else pT->DestroyWindow(); } // Shell dialog layout initialization void StdShidInit() { T* pT = static_cast(this); SHINITDLGINFO shidi = { SHIDIM_FLAGS, pT->m_hWnd, t_shidiFlags }; ::SHInitDialog(&shidi); } // IDC_INFOSTATIC background setting LRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (::GetDlgCtrlID((HWND)lParam) == IDC_INFOSTATIC) { ::SetBkMode((HDC)wParam, TRANSPARENT); return (LRESULT)::GetSysColorBrush(COLOR_INFOBK); } return bHandled = FALSE; } // Menu dialog ending LRESULT OnMenuClose(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->StdCloseDialog((WORD)(wID - ID_MENU_OK + IDOK)); return 0; } // Standard dialog ending: may be used with any command LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->StdCloseDialog(wID); return 0; } }; /////////////////////////////////////////////////////////////////////////////// // CStdDialogImplBase - Base implementation of standard PPC/SmartPhone dialog template > class ATL_NO_VTABLE CStdDialogImplBase : public TBase, public CStdDialogBase { public: #ifdef WIN32_PLATFORM_PSPC BOOL GetClientRect(LPRECT lpRect) { return CStdDialogBase::GetClientRect(lpRect); } BOOL SetWindowText(LPCTSTR lpszString) { return CStdDialogBase::SetWindowText(lpszString); } #endif BEGIN_MSG_MAP(CStdDialogImplBase) #ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) #elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) #endif MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(t_bModal == pT->m_bModal); pT->StdPlatformInit(); pT->StdShidInit(); return bHandled = FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CStdDialogImpl - implementation of standard PPC/SmartPhone dialog template class ATL_NO_VTABLE CStdDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal> {}; /////////////////////////////////////////////////////////////////////////////// // CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog #if defined __ATLDLGS_H__ template class ATL_NO_VTABLE CStdIndirectDialogImpl : public CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > { public: typedef CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl > _baseClass; typedef CStdDialogImpl _baseStd; void CheckStyle() { // Mobile devices don't support DLGTEMPLATEEX ATLASSERT(!m_Template.IsTemplateEx()); // Standard dialogs need only DS_CENTER DWORD &dwStyle = m_Template.GetTemplatePtr()->style; if (dwStyle & DS_CENTER) if(t_bModal) { ATLASSERT((dwStyle & WS_CHILD) != WS_CHILD); dwStyle |= WS_POPUP; } else { if((dwStyle & WS_CHILD) != WS_CHILD) dwStyle |= WS_POPUP; } } INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL) { ATLASSERT(t_bModal); if (!m_Template.IsValid()) CreateTemplate(); CheckStyle(); return _baseClass::DoModal(hWndParent, dwInitParam); } HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL) { ATLASSERT(!t_bModal); if (!m_Template.IsValid()) CreateTemplate(); CheckStyle(); return _baseClass::Create(hWndParent, dwInitParam); } BEGIN_MSG_MAP(CStdIndirectDialogImpl) CHAIN_MSG_MAP(_baseStd) END_MSG_MAP() }; #endif // defined __ATLDLGS_H__ #ifndef _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdAxDialogImpl - implementation of standard PPC/SmartPhone AxDialog template class ATL_NO_VTABLE CStdAxDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl< T > > {}; #endif // _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdSimpleDialog - standard PPC/SmartPhone simple dialog with SHIDIF_xxx flags template class CStdSimpleDialog : public ATL::CSimpleDialog, public CStdDialogBase, t_shidiFlags> { public: typedef CStdDialogBase, t_shidiFlags> baseClass; #ifdef WIN32_PLATFORM_PSPC BOOL GetClientRect(LPRECT lpRect) { return baseClass::GetClientRect(lpRect); } BOOL SetWindowText(LPCTSTR lpszString) { return baseClass::SetWindowText(lpszString); } #endif BEGIN_MSG_MAP(CStdSimpleDialog) #ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) #elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) #endif MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { StdPlatformInit(); StdShidInit(); return bHandled = FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CStdDialogResizeImplBase - Base implementation of orientation resizing standard PPC/SmartPhone dialog template > class ATL_NO_VTABLE CStdDialogResizeImplBase : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, public CDialogResize { public: // Note: BEGIN_DLGRESIZE_MAP is required in the derived class. BEGIN_MSG_MAP(CStdResizeDialogImplBase) #ifdef WIN32_PLATFORM_PSPC // Pocket PC title MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) #elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) #endif MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) CHAIN_MSG_MAP(CDialogResize< T >) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(t_bModal == pT->m_bModal); pT->StdPlatformInit(); pT->DlgResize_Init(FALSE); pT->StdShidInit(); return bHandled = FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CStdDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone dialog template class ATL_NO_VTABLE CStdDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal> {}; #ifndef _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdAxDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone AxDialog template class ATL_NO_VTABLE CStdAxDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > {}; #endif // _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdSimpleDialogResizeImpl - implementation of standard resizing simple dialog with SHIDIF_xxx flags // Usage: // class CMyDlg : public CStdSimpleDialogResize // { // public: // BEGIN_DLGRESIZE_MAP(CMyDlg) // ... // END_DLGRESIZE_MAP() // }; template class ATL_NO_VTABLE CStdSimpleDialogResizeImpl : public CStdSimpleDialog, public CDialogResize< T > { public: typedef CStdSimpleDialog::baseClass baseClass; BEGIN_MSG_MAP(CStdSimpleDialogResizeImpl) #ifdef WIN32_PLATFORM_PSPC // Pocket PC title MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) #elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) #endif MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) CHAIN_MSG_MAP(CDialogResize< T >) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->StdPlatformInit(); pT->DlgResize_Init(FALSE); pT->StdShidInit(); return bHandled = FALSE; } }; #if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) /////////////////////////////////////////////////////////////////////////////// // CStdOrientedDialogBase - Oriented PPC standard dialog base class template class CStdOrientedDialogBase { public: // Operation BOOL SetOrientation(DRA::DisplayMode mode) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); ATLASSERT(mode == DRA::GetDisplayMode()); // Derived dialog must enumerate TWO dialog templates with the same control ids and types ie: // enum { IDD = IDD_MYDLG, IDD_LANDSCAPE = IDD_MYDLG_L }; UINT iResource = (mode == DRA::Landscape)? T::IDD_LANDSCAPE : T::IDD; BOOL bRes = DRA::RelayoutDialog(ModuleHelper::GetResourceInstance(), pT->m_hWnd, MAKEINTRESOURCE(iResource)); pT->OnOrientation(mode); return bRes; } // Override void OnOrientation(DRA::DisplayMode /*mode*/) {} // Message handlers LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); if (wParam == SETTINGCHANGE_RESET) { pT->SetOrientation(DRA::GetDisplayMode()); pT->StdPlatformInit(); pT->StdShidInit(); } else if (wParam == SPI_SETSIPINFO) { pT->DoSipInfo(); return TRUE; } return bHandled = FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation template > class ATL_NO_VTABLE CStdOrientedDialogImplBase : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>, public CStdOrientedDialogBase { public: BEGIN_MSG_MAP(CStdOrientedDialogImpl) MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_SETTINGCHANGE, CStdOrientedDialogBase::OnSettingChange) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); #ifdef _DEBUG ATLASSERT(t_bModal == pT->m_bModal); #endif if (DRA::GetDisplayMode() == DRA::Landscape) pT->SetOrientation(DRA::Landscape); pT->StdPlatformInit(); pT->StdShidInit(); return bHandled = FALSE; } }; /////////////////////////////////////////////////////////////////////////////// // CStdOrientedDialogImpl - Oriented PPC standard dialog implementation template class ATL_NO_VTABLE CStdOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal> {}; #ifndef _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation template class ATL_NO_VTABLE CStdAxOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl > {}; #endif // _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CStdSimpleOrientedDialog - Standard simple orientable dialog template class CStdSimpleOrientedDialog : public CStdSimpleDialog, public CStdOrientedDialogBase > { public: typedef CStdSimpleDialog::baseClass baseClass; typedef CStdOrientedDialogBase > baseOriented; enum {IDD = t_wDlgTemplateID, IDD_LANDSCAPE = t_wDlgLandscapeID}; BEGIN_MSG_MAP(CStdSimpleDialog) MESSAGE_HANDLER(WM_PAINT, OnPaintTitle) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic) MESSAGE_HANDLER(WM_SETTINGCHANGE, baseOriented::OnSettingChange) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd) COMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose) END_MSG_MAP() LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if (DRA::GetDisplayMode() == DRA::Landscape) SetOrientation(DRA::Landscape); StdPlatformInit(); StdShidInit(); return bHandled = FALSE; } }; #endif // _WTL_CE_DRA #endif // _WTL_CE_NO_DIALOGS // --- PPC/SmartPhone application window and helpers --- #ifndef _WTL_CE_NO_APPWINDOW /////////////////////////////////////////////////////////////////////////////// // CAppInfoBase - Helper for application state save/restore to registry class CAppInfoBase { public: CRegKeyEx m_Key; CAppInfoBase(ATL::_U_STRINGorID sAppKey) { m_Key.Create(HKEY_CURRENT_USER, sAppKey.m_lpstr); ATLASSERT(m_Key.m_hKey); } template LONG Save(V& val, ATL::_U_STRINGorID sName) { return m_Key.SetBinaryValue(sName.m_lpstr, &val, sizeof(V)); } template LONG Save(int nb, V& val0, ATL::_U_STRINGorID sName) { return m_Key.SetBinaryValue(sName.m_lpstr, &val0, nb * sizeof(V)); } template LONG Restore(V& val, ATL::_U_STRINGorID sName) { ULONG bufSize = sizeof(V); return m_Key.QueryBinaryValue(sName.m_lpstr, &val, &bufSize); } template LONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName) { ULONG bufSize = nb * sizeof(V); return m_Key.QueryBinaryValue(sName.m_lpstr, &val0, &bufSize); } #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) LONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) { return m_Key.SetStringValue(sName.m_lpstr, sval); } LONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName) { DWORD size = MAX_PATH; LONG res = m_Key.QueryStringValue(sName.m_lpstr, sval.GetBuffer(size), &size); sval.ReleaseBuffer(); return res; } #else #pragma message("Warning: CAppInfoBase compiles without CString support. Do not use CString in Save or Restore.") #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__) LONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName) { return m_Key.SetStringValue(sName.m_lpstr, sval); } LONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength) { return m_Key.QueryStringValue(sName.m_lpstr, sval, plength); } LONG Delete(ATL::_U_STRINGorID sName) { return m_Key.DeleteValue(sName.m_lpstr); } }; /////////////////////////////////////////////////////////////////////////////// // CAppInfoT - CAppInfoBase constructed from a class with T::GetAppKey() // Macro for declaring AppKey #define DECLARE_APPKEY(uAppKey) \ static LPCTSTR GetAppKey() \ { \ static LPCTSTR sAppKey = ATL::_U_STRINGorID(uAppKey).m_lpstr; \ return sAppKey; \ } template class CAppInfoT : public CAppInfoBase { public: CAppInfoT() : CAppInfoBase(T::GetAppKey()){} }; /////////////////////////////////////////////////////////////////////////////// // CAppWindowBase - Base class for PPC/SmartPhone "well-behaved" application window or dialog // Macros for declaring frame WNDCLASS and AppKey #define DECLARE_APP_FRAME_CLASS(WndClassName, uCommonResourceID, uAppKey) \ DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ DECLARE_APPKEY(uAppKey) #define DECLARE_APP_FRAME_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd, uAppKey) \ DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ DECLARE_APPKEY(uAppKey) template class CAppWindowBase { public: typedef class CAppInfoT< T > CAppInfo; #ifndef WIN32_PLATFORM_WFSP SHACTIVATEINFO m_sai; // NoOp on SmartPhones #endif // WIN32_PLATFORM_WFSP bool m_bHibernate; CAppWindowBase< T >() : m_bHibernate(false) { #ifndef WIN32_PLATFORM_WFSP SHACTIVATEINFO sai = { sizeof(SHACTIVATEINFO) }; m_sai = sai; #endif // WIN32_PLATFORM_WFSP }; // Same as WTL 7.1 AppWizard generated ActivatePreviousInstance + SendMessage WM_COPYDATA static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine, bool bDialog) { // requires T does DECLARE_APP_FRAME_CLASS, DECLARE_APP_FRAME_CLASS_EX or DECLARE_APP_DLG_CLASS CFrameWndClassInfo& classInfo = T::GetWndClassInfo(); ATLVERIFY(::LoadString(hInstance, classInfo.m_uCommonResourceID, classInfo.m_szAutoName, sizeof(classInfo.m_szAutoName)/sizeof(classInfo.m_szAutoName[0])) != 0); classInfo.m_wc.lpszClassName = classInfo.m_szAutoName; const TCHAR* pszClass = classInfo.m_wc.lpszClassName; if(NULL == pszClass || '\0' == *pszClass) { return E_FAIL; } const DWORD dRetryInterval = 100; const int iMaxRetries = 25; for(int i = 0; i < iMaxRetries; ++i) { HANDLE hMutex = CreateMutex(NULL, FALSE, pszClass); DWORD dw = GetLastError(); if(NULL == hMutex) { HRESULT hr; switch(dw) { case ERROR_INVALID_HANDLE: // A non-mutext object with this name already exists. hr = E_INVALIDARG; break; default: // This should never happen... hr = E_FAIL; } return hr; } // If the mutex already exists, then there should be another instance running if(dw == ERROR_ALREADY_EXISTS) { CloseHandle(hMutex); HWND hwnd = NULL; if (bDialog) hwnd = FindWindow(NULL, pszClass); else hwnd = FindWindow(pszClass, NULL); if(hwnd == NULL) { Sleep(dRetryInterval); continue; } else { // Transmit our params to previous instance if (lpstrCmdLine && *lpstrCmdLine) { COPYDATASTRUCT cd = { NULL, sizeof(TCHAR) * (wcslen(lpstrCmdLine) + 1), (PVOID)lpstrCmdLine }; ::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cd); } // Set the previous instance as the foreground window if(0 != SetForegroundWindow(reinterpret_cast(reinterpret_cast(hwnd) | 0x1))) return S_FALSE; } } else { return S_OK; } } return S_OK; } // Operations overriden in derived class bool AppHibernate(bool /*bHibernate*/) { return false; } bool AppNewInstance(LPCTSTR /*lpstrCmdLine*/) { return false; } void AppSave() { } #ifdef WIN32_PLATFORM_WFSP void AppBackKey() { ::SHNavigateBack(); } #endif // Message map and handlers BEGIN_MSG_MAP(CAppWindowBase) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) #ifdef WIN32_PLATFORM_WFSP MESSAGE_HANDLER(WM_HOTKEY, OnHotKey) #else MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) #endif // WIN32_PLATFORM_WFSP MESSAGE_HANDLER(WM_HIBERNATE, OnHibernate) MESSAGE_HANDLER(WM_COPYDATA, OnNewInstance) MESSAGE_HANDLER(WM_CLOSE, OnClose) END_MSG_MAP() LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); if (m_bHibernate) m_bHibernate = pT->AppHibernate(false); #ifndef WIN32_PLATFORM_WFSP ::SHHandleWMActivate(pT->m_hWnd, wParam, lParam, &m_sai, 0); #else wParam; lParam; #endif // WIN32_PLATFORM_WFSP return bHandled = FALSE; } #ifdef WIN32_PLATFORM_WFSP // SmartPhone VK_TBACK key standard management LRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); const UINT uModif = (UINT)LOWORD(lParam); const UINT uVirtKey = (UINT)HIWORD(lParam); if(uVirtKey == VK_TBACK) if (AtlIsEditFocus()) ::SHSendBackToFocusWindow(uMsg, wParam, lParam); else if (uModif & MOD_KEYUP) pT->AppBackKey(); return 1; } #else // !WIN32_PLATFORM_WFSP // PPC SIP handling LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); bHandled = FALSE; return ::SHHandleWMSettingChange(pT->m_hWnd, wParam, lParam, &m_sai); } #endif // !WIN32_PLATFORM_WFSP LRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); return m_bHibernate = pT->AppHibernate(true); } LRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { T* pT = static_cast(this); PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam; return pT->AppNewInstance((LPCTSTR)pcds->lpData); } LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); pT->AppSave(); bHandled = FALSE; return 1; } }; /////////////////////////////////////////////////////////////////////////////// // CAppWindow - PPC/SmartPhone "well-behaved" application window class template class CAppWindow : public CAppWindowBase< T > { public: // Same as WTL 7.1 AppWizard generated Run + lpstrCmdLine in CreateEx static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) { CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); T wndMain; if(wndMain.CreateEx(NULL, NULL, 0, 0, lpstrCmdLine) == NULL) { ATLTRACE2(atlTraceUI, 0, _T("Main window creation failed!\n")); return 0; } wndMain.ShowWindow(nCmdShow); int nRet = theLoop.Run(); _Module.RemoveMessageLoop(); return nRet; } static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) { return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, false); } }; #ifndef _WTL_CE_NO_DIALOGS /////////////////////////////////////////////////////////////////////////////// // CAppDialog - PPC/SmartPhone "well-behaved" dialog application class // Macro for declaring dialog WNDCLASS and AppKey #define DECLARE_APP_DLG_CLASS(WndClassName, uCommonResourceID, uAppKey) \ static WTL::CFrameWndClassInfo& GetWndClassInfo() \ { \ static WTL::CFrameWndClassInfo wc = \ { \ { 0, (WNDPROC)StartDialogProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ }; \ DECLARE_APPKEY(uAppKey) template class CAppDialog : public CAppWindowBase< T > { public: static int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL) { CMessageLoop theLoop; _Module.AddMessageLoop(&theLoop); T dlgMain; if(dlgMain.Create(NULL, (LPARAM)lpstrCmdLine) == NULL) { ATLTRACE2(atlTraceUI, 0, _T("Main dialog creation failed!\n")); return 0; } dlgMain.ShowWindow(nCmdShow); int nRet = theLoop.Run(); _Module.RemoveMessageLoop(); return nRet; } static HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR lpstrCmdLine) { return CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, true); }; }; // PPC/SmartPhone standard application dialogs #ifdef WIN32_PLATFORM_WFSP #define WTL_APP_SHIDIF WTL_SP_SHIDIF #else #define WTL_APP_SHIDIF WTL_STD_SHIDIF #endif /////////////////////////////////////////////////////////////////////////////// // CAppStdDialogImplBase - Base implementation of standard application dialogs template class ATL_NO_VTABLE CAppStdDialogImplBase : public TImplBase, public CAppDialog< T > { public: WTL_DLG_NOTITLE; void StdCloseDialog(int nVal) { T* pT = static_cast(this); if (nVal != IDCANCEL) pT->AppSave(); if (t_bModal == false) { pT->DestroyWindow(); ::PostQuitMessage(nVal); } else ::EndDialog(pT->m_hWnd, nVal); } BEGIN_MSG_MAP(CAppStdDialogImplBase) MESSAGE_HANDLER(WM_CLOSE, OnSystemClose) CHAIN_MSG_MAP(TImplBase) CHAIN_MSG_MAP(CAppDialog< T >) END_MSG_MAP() LRESULT OnSystemClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); pT->StdCloseDialog(IDCANCEL); return 0; } }; /////////////////////////////////////////////////////////////////////////////// // CAppStdDialogImpl - Implementation of standard application dialog template class ATL_NO_VTABLE CAppStdDialogImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; /////////////////////////////////////////////////////////////////////////////// // CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog template class ATL_NO_VTABLE CAppStdDialogResizeImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; #ifndef _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CAppStdAxDialogImpl - Implementation of standard application AxDialog template class ATL_NO_VTABLE CAppStdAxDialogImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; /////////////////////////////////////////////////////////////////////////////// // CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog template class ATL_NO_VTABLE CAppStdAxDialogResizeImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; #endif // _ATL_NO_HOSTING #if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) /////////////////////////////////////////////////////////////////////////////// // CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog template class ATL_NO_VTABLE CAppStdOrientedDialogImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; #ifndef _ATL_NO_HOSTING /////////////////////////////////////////////////////////////////////////////// // CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog template class ATL_NO_VTABLE CAppStdAxOrientedDialogImpl : public CAppStdDialogImplBase, t_shidiFlags, t_bModal> {}; #endif // _ATL_NO_HOSTING #endif // defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC) #endif // _WTL_CE_NO_DIALOGS #endif // _WTL_CE_NO_APPWINDOW // --- Full screen support --- #ifndef _WTL_CE_NO_FULLSCREEN /////////////////////////////////////////////////////////////////////////////// // CFullScreenFrame - full screen frame implementation template class CFullScreenFrame { public: bool m_bFullScreen; CFullScreenFrame() : m_bFullScreen(false) { } // Operation void SetFullScreen(bool bFull) { m_bFullScreen = bFull; ShowTaskBar(!bFull, false); ShowMenuBar(!bFull); } // Manage TaskBar for modal dialogs and property sheets template int FSDoModal(D& dlg) { T* pT = static_cast(this); pT; // avoid level 4 warning ATLASSERT(pT->IsWindow()); if (m_bFullScreen) // Show taskbar if hidden ShowTaskBar(true, false); int iRet = dlg.DoModal(); if (m_bFullScreen) // Hide taskbar if restored ShowTaskBar(false); return iRet; } // Implementation void ShowMenuBar(bool bShow) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); ATL::CWindow MenuBar = pT->m_hWndCECommandBar; ATLASSERT(MenuBar.IsWindow()); MenuBar.ShowWindow(bShow ? SW_SHOWNORMAL : SW_HIDE); pT->SizeToMenuBar(); } void ShowTaskBar(bool bShow, bool bRepaint = true) { T* pT = static_cast(this); ATLASSERT(pT->IsWindow()); RECT rect = { 0 }; SystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, FALSE); if (!bShow) rect.top = 0; #ifdef WIN32_PLATFORM_PSPC // Pocket PC code UINT uShow = t_bHasSip ? SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON : SHFS_SHOWTASKBAR | SHFS_HIDESIPBUTTON; SHFullScreen(pT->m_hWnd, bShow ? uShow : SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON); #elif _WIN32_WCE > 0x500 // Smartphone 2005 code SHFullScreen(pT->m_hWnd, bShow ? SHFS_SHOWTASKBAR : SHFS_HIDETASKBAR); #else // Smartphone 2003 HWND hTaskBar = FindWindow(_T("tray"), NULL); ATLASSERT(::IsWindow(hTaskBar)); ::ShowWindow(hTaskBar, bShow ? SW_SHOW : SW_HIDE); #endif // WIN32_PLATFORM_PSPC pT->MoveWindow(&rect, bRepaint); } // Message map and handler BEGIN_MSG_MAP(CFullScreenFrame) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) END_MSG_MAP() LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { #ifndef SETTINGCHANGE_RESET // not defined for PPC 2002 #define SETTINGCHANGE_RESET SPI_SETWORKAREA #endif if (m_bFullScreen && (wParam == SETTINGCHANGE_RESET)) SetFullScreen(m_bFullScreen); return bHandled = FALSE; } LRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if (m_bFullScreen) { ShowTaskBar(!wParam); ShowMenuBar(!wParam); } return bHandled = FALSE; } }; #endif // _WTL_CE_NO_FULLSCREEN // --- WinCE zoom support --- #ifndef _WTL_CE_NO_ZOOMSCROLL /////////////////////////////////////////////////////////////////////////////// // CZoomScrollImpl - WinCE zooming implementation on top of CScrollImpl template class CZoomScrollImpl: public CScrollImpl< T > { public: // Data members _WTYPES_NS::CSize m_sizeTrue; double m_fzoom; // Creation CZoomScrollImpl() : m_sizeTrue(0), m_fzoom(1.) { } // Zoom operations and access void SetZoomScrollSize(_WTYPES_NS::CSize sizeTrue, double fzoom = 1., BOOL bRedraw = TRUE) { ATLASSERT(fzoom > 0.); m_sizeTrue = sizeTrue; m_fzoom = fzoom; CScrollImpl< T >::SetScrollSize(sizeTrue / fzoom, bRedraw); } void SetZoomScrollSize(int cx, int cy, double fzoom=1., BOOL bRedraw = TRUE) { SetZoomScrollSize(_WTYPES_NS::CSize(cx, cy), fzoom, bRedraw); } void SetZoom(double fzoom, BOOL bRedraw = TRUE) { _WTYPES_NS::CPoint ptCenter = WndtoTrue(m_sizeClient / 2); _WTYPES_NS::CSize sizePage = GetScrollPage(); _WTYPES_NS::CSize sizeLine = GetScrollLine(); SetZoomScrollSize(GetScrollSize(), fzoom, bRedraw); SetScrollLine(sizeLine); SetScrollPage(sizePage); _WTYPES_NS::CPoint ptOffset = ptCenter - (m_sizeClient / 2) * fzoom; SetScrollOffset(ptOffset, bRedraw); } double GetZoom() { return m_fzoom; } // CScrollImpl overrides void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) { CScrollImpl< T >::SetScrollOffset((int)(x / m_fzoom), (int)(y / m_fzoom), bRedraw); } void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) { SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); } void GetScrollOffset(POINT& ptOffset) { ptOffset.x = (LONG)(m_ptOffset.x * m_fzoom); ptOffset.y = (LONG)(m_ptOffset.y * m_fzoom); } void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE) { SetZoomScrollSize(cx, cy, GetZoom(), bRedraw); } void SetScrollSize(SIZE sizeTrue, BOOL bRedraw = TRUE) { SetZoomScrollSize(sizeTrue, GetZoom(), bRedraw); } void GetScrollSize(SIZE& sizeTrue) const { sizeTrue = m_sizeTrue; } void SetScrollPage(int cxPage, int cyPage) { SetScrollPage(_WTYPES_NS::CSize(cxPage, cyPage)); } void SetScrollPage(SIZE sizePage) { CScrollImpl< T >::SetScrollPage(sizePage / m_fzoom); } void GetScrollPage(SIZE& sizePage) const { sizePage = m_sizePage * m_fzoom; } void SetScrollLine(int cxLine, int cyLine) { SetScrollLine(_WTYPES_NS::CSize(cxLine, cyLine)); } void SetScrollLine(SIZE sizeLine) { CScrollImpl< T >::SetScrollLine(sizeLine / m_fzoom); } void GetScrollLine(SIZE& sizeLine) const { sizeLine = m_sizeLine * m_fzoom; } // Data access complements _WTYPES_NS::CSize GetScrollSize() { return m_sizeTrue; } _WTYPES_NS::CSize GetScrollPage() { return m_sizePage * m_fzoom; } _WTYPES_NS::CSize GetScrollLine() { return m_sizeLine * m_fzoom; } _WTYPES_NS::CPoint GetScrollOffset() { return (_WTYPES_NS::CSize)m_ptOffset * m_fzoom; } // Helper coordinate functions _WTYPES_NS::CPoint WndtoTrue(CPoint ptW) { return (_WTYPES_NS::CSize)ptW * GetZoom() + GetScrollOffset(); } void WndtoTrue(LPPOINT aptW, int nPts) // in place coord transformation { for (int i = 0 ; i < nPts ; i++) aptW[i] = WndtoTrue(aptW[i]); } void WndtoTrue(LPRECT prectW) // in place coord transformation { WndtoTrue((LPPOINT)prectW, 2); } _WTYPES_NS::CPoint TruetoWnd(CPoint ptT) { return (ptT - GetScrollOffset()) / GetZoom(); } void TruetoWnd(LPPOINT aptT, int nPts) // in place coord transformation { for (int i = 0 ; i < nPts ; i++) aptT[i] = TruetoWnd(aptT[i]); } void TruetoWnd(LPRECT prectT) // in place coord transformation { TruetoWnd((LPPOINT)prectT, 2); } // Drawing operations : assume adequate setting of data members BOOL Draw(HBITMAP hbm, HDC hdestDC, DWORD dwROP = SRCCOPY) { CDC memDC = CreateCompatibleDC(hdestDC); CBitmapHandle bmpOld = memDC.SelectBitmap(hbm); BOOL bRes = Draw(memDC, hdestDC, dwROP); memDC.SelectBitmap(bmpOld); return bRes; } BOOL Draw(HDC hsourceDC, HDC hdestDC, DWORD dwROP = SRCCOPY) { CDCHandle destDC = hdestDC; destDC.SetViewportOrg(0,0); _WTYPES_NS::CPoint ptOffset = GetScrollOffset(); _WTYPES_NS::CSize sizeZClient = m_sizeClient * GetZoom(); return destDC.StretchBlt(0, 0, m_sizeClient.cx, m_sizeClient.cy, hsourceDC, ptOffset.x, ptOffset.y, sizeZClient.cx, sizeZClient.cy, dwROP); } #ifdef _IMAGING_H BOOL Draw(IImage* pIImage, HDC hdestDC) { CDCHandle destDC = hdestDC; destDC.SetViewportOrg(0,0); return SUCCEEDED(pIImage->Draw(destDC, _WTYPES_NS::CRect(-_WTYPES_NS::CPoint(m_ptOffset), m_sizeAll), NULL)); } #endif // Message map and handlers BEGIN_MSG_MAP(CZoomScrollImpl< T >) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) CHAIN_MSG_MAP(CScrollImpl< T >) END_MSG_MAP() LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); ATLASSERT(::IsWindow(pT->m_hWnd)); if ((GetScrollExtendedStyle() & SCRL_ERASEBACKGROUND)) { _WTYPES_NS::CRect rect; pT->GetClientRect(rect); _WTYPES_NS::CSize sizeClient=rect.Size(); if (m_sizeAll.cx < sizeClient.cx || m_sizeAll.cy < sizeClient.cy) { CDCHandle hdc = (HDC)wParam; HBRUSH hbr = GetSysColorBrush((int)T::GetWndClassInfo().m_wc.hbrBackground - 1); if (m_sizeAll.cx < sizeClient.cx) { _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(m_sizeAll.cx, 0), sizeClient); hdc.FillRect(rectBG, hbr); } if (m_sizeAll.cy < sizeClient.cy) { _WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(0, m_sizeAll.cy), sizeClient); hdc.FillRect(rectBG, hbr); } } } else { bHandled = FALSE; } return 1; } }; #endif // _WTL_CE_NO_ZOOMSCROLL #ifndef _WTL_CE_NO_CONTROLS // --- PPC bottom TabView control --- #if defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) /////////////////////////////////////////////////////////////////////////////// // CBottomTabViewImpl template class ATL_NO_VTABLE CBottomTabViewImpl : public CTabViewImpl { public: DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) // Implementation overrideables bool CreateTabControl() { m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | TCS_BOTTOM, 0, m_nTabID); ATLASSERT(m_tab.m_hWnd != NULL); if(m_tab.m_hWnd == NULL) return false; m_tab.SendMessage(CCM_SETVERSION, COMCTL32_VERSION); m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); T* pT = static_cast(this); m_cyTabHeight = pT->CalcTabHeight(); return true; } int CalcTabHeight() { int nCount = m_tab.GetItemCount(); TCITEMEXTRA tcix = { 0 }; tcix.tciheader.mask = TCIF_TEXT; tcix.tciheader.pszText = _T("NS"); int nIndex = m_tab.InsertItem(nCount, tcix); RECT rect = { 0 }; SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0); RECT rcWnd = rect; m_tab.AdjustRect(FALSE, &rect); rcWnd.top = rect.bottom; ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); m_tab.DeleteItem(nIndex); return rcWnd.bottom - rcWnd.top; } void UpdateLayout() { RECT rect = { 0 }; GetClientRect(&rect); if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) m_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER /*| SWP_SHOWWINDOW*/); if(m_nActivePage != -1) ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - m_cyTabHeight, SWP_NOZORDER); } }; class CBottomTabView : public CBottomTabViewImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_BottomTabView"), 0, COLOR_APPWORKSPACE) }; #endif // defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC) // --- PPC/SmartPhone controls --- //////////////////////////////////////////////////////////////////////////////// // These are wrapper classes for the Pocket PC 2002/2003 and SmartPhone 2003 controls // To implement a window based on a control, use following: // Example: Implementing a window based on a Html control // // class CMyHtml : CWindowImpl // { // public: // BEGIN_MSG_MAP(CMyHtml) // // put your message handler entries here // END_MSG_MAP() // }; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // CHtmlCtrl template class CHtmlCtrlT : public TBase { public: // Constructors CHtmlCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CHtmlCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call InitHTMLControl(hInstance) ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_HTML; } #if (_WIN32_WCE >= 400) void AddStyle(LPCWSTR pszStyle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ADDSTYLE, 0, (LPARAM)pszStyle); } #endif // (_WIN32_WCE >= 400) void AddText(BOOL bPlainText, LPCSTR pszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)bPlainText, (LPARAM)pszText); } void AddHTML(LPCSTR pszHTML) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)FALSE, (LPARAM)pszHTML); } void AddText(BOOL bPlainText, LPCWSTR pszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)bPlainText, (LPARAM)pszText); } void AddHTML(LPCWSTR pszHTML) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)FALSE, (LPARAM)pszHTML); } void Anchor(LPCSTR pszAnchor) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ANCHOR, 0, (LPARAM)pszAnchor); } void Anchor(LPCWSTR pszAnchor) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ANCHORW, 0, (LPARAM)pszAnchor); } #if (_WIN32_WCE >= 420) void GetBrowserDispatch(IDispatch** ppDispatch) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(ppDispatch); ATLASSERT(*ppDispatch==NULL); ::SendMessage(m_hWnd, DTM_BROWSERDISPATCH, 0, (LPARAM)ppDispatch); } void GetDocumentDispatch(IDispatch** ppDispatch) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(ppDispatch); ATLASSERT(*ppDispatch==NULL); ::SendMessage(m_hWnd, DTM_DOCUMENTDISPATCH , 0, (LPARAM)ppDispatch); } #endif // (_WIN32_WCE >= 420) void Clear() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_CLEAR, 0, 0L); } void EnableClearType(BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ENABLECLEARTYPE, 0, (LPARAM)bEnable); } void EnableContextMenu(BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ENABLECONTEXTMENU, 0, (LPARAM)bEnable); } void EnableScripting(BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ENABLESCRIPTING, 0, (LPARAM)bEnable); } void EnableShrink(BOOL bEnable = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ENABLESHRINK, 0, (LPARAM)bEnable); } void EndOfSource() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ENDOFSOURCE, 0, 0L); } void ImageFail(DWORD dwCookie) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_IMAGEFAIL, 0, (LPARAM)dwCookie); } int GetLayoutHeight() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DTM_LAYOUTHEIGHT, 0, 0L); } int GetLayoutWidth() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DTM_LAYOUTWIDTH, 0, 0L); } void Navigate(LPCTSTR pstrURL, UINT uFlags = 0) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrURL); ::SendMessage(m_hWnd, DTM_NAVIGATE, (WPARAM)uFlags, (LPARAM)pstrURL); } void SelectAll() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_SELECTALL, 0, 0L); } void SetImage(INLINEIMAGEINFO* pImageInfo) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pImageInfo); ::SendMessage(m_hWnd, DTM_SETIMAGE, 0, (LPARAM)pImageInfo); } void ZoomLevel(int iLevel) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_ZOOMLEVEL, 0, (LPARAM)iLevel); } #if (_WIN32_WCE >= 400) void Stop() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DTM_STOP, 0, 0L); } #endif // (_WIN32_WCE >= 400) void GetScriptDispatch(IDispatch** ppDispatch) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(ppDispatch); ATLASSERT(*ppDispatch==NULL); ::SendMessage(m_hWnd, DTM_SCRIPTDISPATCH, 0, (LPARAM)ppDispatch); } }; typedef CHtmlCtrlT CHtmlCtrl; #ifdef WIN32_PLATFORM_PSPC /////////////////////////////////////////////////////////////////////////////// // CRichInkCtrl template class CRichInkCtrlT : public TBase { public: // Constructors CRichInkCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CRichInkCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call InitRichInkDLL() ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_RICHINK; } BOOL CanPaste(UINT uFormat = 0) const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, (WPARAM)uFormat, 0L); } BOOL CanRedo() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L); } BOOL CanUndo() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L); } void ClearAll(BOOL bRepaint = TRUE) const { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_CLEARALL, (WPARAM)bRepaint, 0L); } BOOL GetModify() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L); } UINT GetPageStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETPAGESTYLE, 0, 0L); } UINT GetPenMode() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETPENMODE, 0, 0L); } UINT GetViewStyle() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETVIEW, 0, 0L); } UINT GetWrapMode() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETWRAPMODE, 0, 0L); } UINT GetZoomPercent() const { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_GETZOOMPERCENT, 0, 0L); } void InsertLinks(LPWSTR lpString, int cchLength = -1) { ATLASSERT(::IsWindow(m_hWnd)); if(cchLength == -1) cchLength = lstrlen(lpString); ::SendMessage(m_hWnd, EM_INSERTLINKS, (WPARAM)cchLength, (LPARAM)lpString); } void RedoEvent() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_REDOEVENT, 0, 0L); } UINT SetInkLayer(UINT uLayer) { ATLASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, EM_SETINKLAYER, (WPARAM)uLayer, 0L); } void SetPageStyle(UINT uStyle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETPAGESTYLE, (WPARAM)uStyle, 0L); } void SetPenMode(UINT uMode) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETPENMODE, (WPARAM)uMode, 0L); } void SetViewStyle(UINT uStyle) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETVIEW, (WPARAM)uStyle, 0L); } void SetViewAttributes(VIEWATTRIBUTES* pAttribs) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pAttribs); ::SendMessage(m_hWnd, EM_SETVIEWATTRIBUTES, 0, (LPARAM)pAttribs); } void SetWrapMode(UINT uMode) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETWRAPMODE, (WPARAM)uMode, 0L); } void SetZoomPercent(UINT uPercent) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETZOOMPERCENT, (WPARAM)uPercent, 0L); } LONG StreamIn(UINT uFormat, EDITSTREAM& es) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_STREAMIN, (WPARAM)uFormat, (LPARAM)&es); } LONG StreamOut(UINT uFormat, EDITSTREAM& es) { ATLASSERT(::IsWindow(m_hWnd)); return (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, (WPARAM)uFormat, (LPARAM)&es); } void UndoEvent() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_UNDOEVENT, 0, 0L); } void Undo() { UndoEvent(); } // Standard EM_xxx messages DWORD GetSel() const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); return (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L); } void GetSel(int& nStartChar, int& nEndChar) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); ::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar); } void SetSel(int nStartChar, int nEndChar) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); ::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar); } void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetViewStyle() != VT_DRAWINGVIEW); ::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM)bCanUndo, (LPARAM)lpszNewText); } void SetModify(BOOL bModified = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, EM_SETMODIFY, (WPARAM)bModified, 0L); } int GetTextLength() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L); } // Clipboard operations void Clear() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CLEAR, 0, 0L); } void Copy() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_COPY, 0, 0L); } void Cut() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_CUT, 0, 0L); } void Paste() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, WM_PASTE, 0, 0L); } }; typedef CRichInkCtrlT CRichInkCtrl; /////////////////////////////////////////////////////////////////////////////// // CInkXCtrl template class CInkXCtrlT : public TBase { public: // Constructors CInkXCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CInkXCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call InitInkX() ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_INKX; } static UINT GetHotRecordingMessage() { return ::RegisterWindowMessage(szHotRecording); } void ClearAll() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IM_CLEARALL, 0, 0L); } int GetData(BYTE* lpBuffer, INT cbBuffer) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpBuffer); return (int)::SendMessage(m_hWnd, IM_GETDATA, (WPARAM)cbBuffer, (LPARAM)lpBuffer); } int GetDataLen() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, IM_GETDATALEN, 0, 0L); } CRichInkCtrl GetRichInk() const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, IM_GETRICHINK, 0, 0L); } BOOL IsRecording() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, IM_RECORDING, 0, 0L); } void ReInit() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IM_REINIT, 0, 0L); } void SetData(const BYTE* lpInkData, INT cbInkData) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(lpInkData); ::SendMessage(m_hWnd, IM_SETDATA, (WPARAM)cbInkData, (LPARAM)lpInkData); } void VoicePlay() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IM_VOICE_PLAY, 0, 0L); } BOOL IsVoicePlaying() const { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, IM_VOICE_PLAYING, 0, 0L); } BOOL VoiceRecord() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, IM_VOICE_RECORD, 0, 0L); } void VoiceStop() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IM_VOICE_STOP, 0, 0L); } void ShowVoiceBar(BOOL bShow = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, IM_VOICEBAR, (WPARAM)bShow, 0L); } }; typedef CInkXCtrlT CInkXCtrl; #endif // WIN32_PLATFORM_PSPC /////////////////////////////////////////////////////////////////////////////// // CVoiceRecorderCtrl template class CVoiceRecorderCtrlT : public TBase { public: // Constructors CVoiceRecorderCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CVoiceRecorderCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, const POINT pt, LPTSTR pstrFileName, UINT nID, DWORD dwStyle = 0) { ATLASSERT(pstrFileName != NULL); CM_VOICE_RECORDER cmvr = { 0 }; cmvr.cb = sizeof(CM_VOICE_RECORDER); cmvr.dwStyle = dwStyle; cmvr.xPos = pt.x; cmvr.yPos = pt.y; cmvr.hwndParent = hWndParent; cmvr.id = nID; cmvr.lpszRecordFileName = pstrFileName; m_hWnd = VoiceRecorder_Create(&cmvr); return m_hWnd; } HWND Create(LPCM_VOICE_RECORDER pAttribs) { ATLASSERT(pAttribs); m_hWnd = VoiceRecorder_Create(pAttribs); return m_hWnd; } // Attributes void Record() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, VRM_RECORD, 0, 0L); } void Play() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, VRM_PLAY, 0, 0L); } void Stop() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, VRM_STOP, 0, 0L); } void Cancel() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, VRM_CANCEL, 0, 0L); } void Done() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, VRM_OK, 0, 0L); } }; typedef CVoiceRecorderCtrlT CVoiceRecorderCtrl; #ifdef WIN32_PLATFORM_PSPC /////////////////////////////////////////////////////////////////////////////// // CDocListCtrl template class CDocListCtrlT : public TBase { public: // Attributes DOCLISTCREATE m_dlc; TCHAR m_szPath[MAX_PATH]; // Constructors CDocListCtrlT(HWND hWnd = NULL) : TBase(hWnd) { } CDocListCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, WORD wId, LPCTSTR pszFolder = NULL, LPCTSTR pstrFilter = NULL, WORD wFilterIndex = 0, DWORD dwFlags = DLF_SHOWEXTENSION) { ATLASSERT(pstrFilter != NULL); // It seems to need a filter badly!! ::ZeroMemory(&m_dlc, sizeof(DOCLISTCREATE)); ::ZeroMemory(m_szPath, sizeof(m_szPath)); if(pszFolder != NULL) SecureHelper::strncpy_x(m_szPath, MAX_PATH, pszFolder, MAX_PATH - 1); m_dlc.dwStructSize = sizeof(DOCLISTCREATE); m_dlc.hwndParent = hWndParent; m_dlc.pszFolder = m_szPath; m_dlc.pstrFilter = pstrFilter; m_dlc.wFilterIndex = wFilterIndex; m_dlc.wId = wId; m_dlc.dwFlags = dwFlags; m_hWnd = DocList_Create(&m_dlc); return m_hWnd; } HWND Create(DOCLISTCREATE* pDlc) { m_dlc = *pDlc; m_hWnd = DocList_Create(&m_dlc); return m_hWnd; } // Attributes void DeleteSel() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_DELETESEL, 0, 0L); } void DisableUpdates() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_DISABLEUPDATES, 0, 0L); } void EnableUpdates() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_ENABLEUPDATES, 0, 0L); } int GetFilterIndex() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_GETFILTERINDEX, 0, 0L); } int GetItemCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_GETITEMCOUNT, 0, 0L); } int GetNextItem(int iIndex, DWORD dwRelation = LVNI_ALL) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)dwRelation); } int GetFirstItem(DWORD dwRelation = LVNI_ALL) const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)-1, (LPARAM)dwRelation); } BOOL GetNextWave(int* pIndex) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pIndex); return (BOOL)::SendMessage(m_hWnd, DLM_GETNEXTWAVE, 0, (LPARAM)pIndex); } BOOL GetPrevWave(int* pIndex) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pIndex); return (BOOL)::SendMessage(m_hWnd, DLM_GETPREVWAVE, 0, (LPARAM)pIndex); } int GetSelCount() const { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_GETSELCOUNT, 0, 0L); } BOOL GetSelPathName(LPTSTR pstrPath, int cchMax) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrPath); return (BOOL)::SendMessage(m_hWnd, DLM_GETSELPATHNAME, (WPARAM)cchMax, (LPARAM)pstrPath); } void ReceiveIR(LPCTSTR pstrPath) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrPath); ::SendMessage(m_hWnd, DLM_RECEIVEIR, 0, (LPARAM)pstrPath); } void Refresh() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_REFRESH, 0, 0L); } BOOL RenameMoveSelectedItems() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DLM_RENAMEMOVE, 0, 0L); } int SelectAll() { ATLASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, DLM_SELECTALL, 0, 0L); } HRESULT SelectItem(LPCTSTR pstrPath, BOOL bVisible = TRUE) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrPath); return (HRESULT)::SendMessage(m_hWnd, DLM_SELECTITEM, (WPARAM)bVisible, (LPARAM)pstrPath); } void SendEMail(LPCTSTR pstrAttachment) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_SENDEMAIL, 0, (LPARAM)pstrAttachment); } void SendIR(LPCTSTR pstrPath) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_SENDIR, 0, (LPARAM)pstrPath); } HRESULT SetFilterIndex(int iIndex) { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, DLM_SETFILTERINDEX, (WPARAM)iIndex, 0L); } void SetFolder(LPCTSTR pstrPath) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrPath); ::SendMessage(m_hWnd, DLM_SETFOLDER, 0, (LPARAM)pstrPath); } BOOL SetItemState(int iIndex, const LVITEM* pItem) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pItem); return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)pItem); } BOOL SetItemState(int iIndex, UINT uState, UINT uMask) { ATLASSERT(::IsWindow(m_hWnd)); LVITEM lvi = { 0 }; lvi.stateMask = uMask; lvi.state = uState; return (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)&lvi); } void SetOneItem(int iIndex, LPCVOID pPA) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_SETONEITEM, (WPARAM)iIndex, (LPARAM)pPA); } void SetSelect(int iIndex) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DLM_SETSELECT, (WPARAM)iIndex, 0L); } void SetSelPathName(LPCTSTR pstrPath) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrPath); ::SendMessage(m_hWnd, DLM_SETSELPATHNAME, 0, (LPARAM)pstrPath); } BOOL SetSortOrder() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DLM_SETSORTORDER, 0, 0L); } HRESULT Update() { ATLASSERT(::IsWindow(m_hWnd)); return (HRESULT)::SendMessage(m_hWnd, DLM_UPDATE, 0, 0L); } BOOL ValidateFolder() { ATLASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, DLM_VALIDATEFOLDER, 0, 0L); } // Functions BOOL GetFirstSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) { ATLASSERT(::IsWindow(m_hWnd)); return DocList_GetFirstSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); } BOOL GetNextSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath) { ATLASSERT(::IsWindow(m_hWnd)); return DocList_GetNextSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath); } }; typedef CDocListCtrlT CDocListCtrl; #endif // WIN32_PLATFORM_PSPC /////////////////////////////////////////////////////////////////////////////// // CCapEdit template class CCapEditT : public TBase { public: // Constructors CCapEditT(HWND hWnd = NULL) : TBase(hWnd) { } CCapEditT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = /*TBase*/CWindow::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_CAPEDIT; } }; typedef CCapEditT CCapEdit; /////////////////////////////////////////////////////////////////////////////// // CTTStatic #ifndef WIN32_PLATFORM_WFSP // Tooltips not supported on SmartPhone template class CTTStaticT : public TBase { public: // Constructors CTTStaticT(HWND hWnd = NULL) : TBase(hWnd) { } CTTStaticT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_TSTATIC; } // Operations BOOL SetToolTipText(LPCTSTR pstrTipText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrTipText); ATLASSERT(lstrlen(pstrTipText) <= 253); CTempBuffer buff; int cchLen = lstrlen(pstrTipText) + 3; LPTSTR pstr = buff.Allocate(cchLen); if(pstr == NULL) return FALSE; SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); SecureHelper::strcat_x(pstr, cchLen, pstrTipText); return SetWindowText(pstr); } }; typedef CTTStaticT CTTStatic; /////////////////////////////////////////////////////////////////////////////// // CTTButton template class CTTButtonT : public TBase { public: // Constructors CTTButtonT(HWND hWnd = NULL) : TBase(hWnd) { } CTTButtonT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { HWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam); ATLASSERT(hWnd != NULL); // Did you remember to call SHInitExtraControls() ?? return hWnd; } // Attributes static LPCTSTR GetWndClassName() { return WC_TBUTTON; } // Operations BOOL SetToolTipText(LPCTSTR pstrTipText) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(pstrTipText); ATLASSERT(lstrlen(pstrTipText) <= 253); CTempBuffer buff; int cchLen = lstrlen(pstrTipText) + 3; LPTSTR pstr = buff.Allocate(cchLen); if(pstr == NULL) return FALSE; SecureHelper::strcpy_x(pstr, cchLen, _T("~~")); SecureHelper::strcat_x(pstr, cchLen, pstrTipText); return SetWindowText(pstr); } }; typedef CTTButtonT CTTButton; #endif // !WIN32_PLATFORM_WFSP // --- SmartPhone specific controls --- #ifdef WIN32_PLATFORM_WFSP /////////////////////////////////////////////////////////////////////////////// // CSpinCtrlT - CSpinCtrl : SmartPhone adapted UpDown control template class CSpinCtrlT : public CUpDownCtrlT< TBase > { public: // Constructors CSpinCtrlT(HWND hWnd = NULL) : CUpDownCtrlT< TBase >(hWnd) { } CSpinCtrlT< TBase >& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } HWND Create(HWND hWndParent, HWND hBuddy, DWORD dwStyle, int nID, LPCTSTR szExpandedName = NULL) { ATLASSERT(::IsWindow(hWndParent)); CUpDownCtrlT< TBase >::Create(hWndParent, NULL, szExpandedName, dwStyle, 0, nID, NULL); ATLASSERT(m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? if (hBuddy != NULL) { ATLASSERT(::IsWindow(hBuddy)); SetBuddy(hBuddy); } return m_hWnd; } }; typedef CSpinCtrlT CSpinCtrl; /////////////////////////////////////////////////////////////////////////////// // CSpinned - SmartPhone association of control and Spin template class CSpinned : public TBase { public: CSpinCtrl m_SpinCtrl; DWORD m_dwSpinnedStyle; // Constructors CSpinned(HWND hWnd = NULL) : TBase(hWnd) { m_dwSpinnedStyle = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE; if (t_bExpandOnly == true) m_dwSpinnedStyle |= UDS_NOSCROLL; else m_dwSpinnedStyle |= UDS_HORZ | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_WRAP; if (hWnd != NULL) AttachOrCreateSpinCtrl(); } CSpinned& operator =(HWND hWnd) { Attach(hWnd); return *this; } void Attach(HWND hWnd) { ATLASSERT(!IsWindow()); TBase* pT = static_cast(this); pT->m_hWnd = hWnd; if (hWnd != NULL) AttachOrCreateSpinCtrl(); } HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szExpandedName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL) { TBase* pT = static_cast(this); TBase::Create(hWndParent, rect, NULL, dwStyle, dwExStyle, MenuOrID, lpCreateParam); ATLASSERT(pT->m_hWnd != NULL); m_SpinCtrl.Create(hWndParent, pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + (int)MenuOrID.m_hMenu, szExpandedName); ATLASSERT(m_SpinCtrl.m_hWnd != NULL); // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)? return pT->m_hWnd; } // Attributes CSpinCtrl& GetSpinCtrl() { return m_SpinCtrl; } // Implementation // Attach our existing SpinCtrl or create one bool AttachOrCreateSpinCtrl() { TBase* pT = static_cast(this); HWND hSpin = ::GetDlgItem(pT->GetParent(), ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); if (hSpin != NULL) { m_SpinCtrl.Attach(hSpin); #ifdef DEBUG TCHAR sClassName[16] = { 0 }; ::GetClassName(hSpin, sClassName, 16); ATLASSERT(!_tcscmp(sClassName, UPDOWN_CLASS)); ATLASSERT(m_SpinCtrl.GetBuddy().m_hWnd == pT->m_hWnd); #endif // DEBUG } else { m_SpinCtrl.Create(pT->GetParent(), pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + pT->GetDlgCtrlID()); } return m_SpinCtrl.m_hWnd != NULL; } }; /////////////////////////////////////////////////////////////////////////////// // CSpinListBox - SmartPhone spinned ListBox control // CExpandListBox - SmartPhone expandable ListBox control // CExpandEdit - SmartPhone expandable Edit control // CExpandCapEdit - SmartPhone expandable CapEdit control typedef CSpinned CSpinListBox; typedef CSpinned CExpandListBox; typedef CSpinned CExpandEdit; typedef CSpinned CExpandCapEdit; #endif // WIN32_PLATFORM_WFSP #endif // _WTL_CE_NO_CONTROLS }; // namespace WTL #endif // __ATLWINCE_H__ ================================================ FILE: WTL/atlwinx.h ================================================ // Windows Template Library - WTL version 9.10 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLWINX_H__ #define __ATLWINX_H__ #pragma once #ifndef __ATLAPP_H__ #error atlwinx.h requires atlapp.h to be included first #endif #if (_ATL_VER >= 0x0700) #include #endif // (_ATL_VER >= 0x0700) /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // _U_RECT // _U_MENUorID // _U_STRINGorID /////////////////////////////////////////////////////////////////////////////// // Command Chaining Macros #define CHAIN_COMMANDS(theChainClass) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP(theChainClass) #define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) #define CHAIN_COMMANDS_MEMBER(theChainMember) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_MEMBER(theChainMember) #define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) /////////////////////////////////////////////////////////////////////////////// // Macros for parent message map to selectively reflect control messages // NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot // (and overridden in 2 cases - CContainedWindowT and CAxHostWindow) // Since we can't modify ATL, we'll provide the needed additions // in a separate function (that is not a member of CWindowImplRoot) namespace WTL { inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled, UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL) { if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg)) { // The notification message doesn't match the filter. bHandled = FALSE; return 1; } HWND hWndChild = NULL; UINT_PTR idFrom = 0; switch(uMsg) { case WM_COMMAND: if(lParam != NULL) // not from a menu { hWndChild = (HWND)lParam; idFrom = (UINT_PTR)LOWORD(wParam); } break; case WM_NOTIFY: hWndChild = ((LPNMHDR)lParam)->hwndFrom; idFrom = ((LPNMHDR)lParam)->idFrom; break; #ifndef _WIN32_WCE case WM_PARENTNOTIFY: switch(LOWORD(wParam)) { case WM_CREATE: case WM_DESTROY: hWndChild = (HWND)lParam; idFrom = (UINT_PTR)HIWORD(wParam); break; default: hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam)); idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); break; } break; #endif // !_WIN32_WCE case WM_DRAWITEM: if(wParam) // not from a menu { hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_MEASUREITEM: if(wParam) // not from a menu { hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID); idFrom = (UINT_PTR)wParam; } break; case WM_COMPAREITEM: if(wParam) // not from a menu { hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_DELETEITEM: if(wParam) // not from a menu { hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_VKEYTOITEM: case WM_CHARTOITEM: case WM_HSCROLL: case WM_VSCROLL: hWndChild = (HWND)lParam; idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); break; case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORMSGBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: hWndChild = (HWND)lParam; idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); break; default: break; } if((hWndChild == NULL) || ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild))) { // Either hWndChild isn't valid, or // hWndChild doesn't match the filter. bHandled = FALSE; return 1; } if((idFromFilter != 0) && (idFromFilter != idFrom)) { // The dialog control id doesn't match the filter. bHandled = FALSE; return 1; } ATLASSERT(::IsWindow(hWndChild)); LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam); if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) { // Try to prevent problems with WM_CTLCOLOR* messages when // the message wasn't really handled bHandled = FALSE; } return lResult; } }; // namespace WTL // Try to prevent problems with WM_CTLCOLOR* messages when // the message wasn't really handled #define REFLECT_NOTIFICATIONS_EX() \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \ bHandled = FALSE; \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND(id, code) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_ID(id) \ if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_CODE(code) \ if(uMsg == WM_COMMAND && code == HIWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_RANGE(idFirst, idLast) \ if(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \ if(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY(id, cd) \ if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_ID(id) \ if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_CODE(cd) \ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_RANGE(idFirst, idLast) \ if(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \ if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ bHandled = TRUE; \ lResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // Reflected message handler macros for message maps (for ATL 3.0) #if (_ATL_VER < 0x0700) #define REFLECTED_COMMAND_HANDLER(id, code, func) \ if(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_COMMAND_ID_HANDLER(id, func) \ if(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_COMMAND_CODE_HANDLER(code, func) \ if(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \ if(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \ if(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \ { \ bHandled = TRUE; \ lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_NOTIFY_HANDLER(id, cd, func) \ if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \ { \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_NOTIFY_ID_HANDLER(id, func) \ if(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \ { \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \ { \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \ if(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \ if(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \ { \ bHandled = TRUE; \ lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #endif // (_ATL_VER < 0x0700) /////////////////////////////////////////////////////////////////////////////// // Dual argument helper classes (for ATL 3.0) #if (_ATL_VER < 0x0700) namespace ATL { class _U_RECT { public: _U_RECT(LPRECT lpRect) : m_lpRect(lpRect) { } _U_RECT(RECT& rc) : m_lpRect(&rc) { } LPRECT m_lpRect; }; class _U_MENUorID { public: _U_MENUorID(HMENU hMenu) : m_hMenu(hMenu) { } _U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID)) { } HMENU m_hMenu; }; class _U_STRINGorID { public: _U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString) { } _U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID)) { } LPCTSTR m_lpstr; }; }; // namespace ATL #endif // (_ATL_VER < 0x0700) namespace WTL { /////////////////////////////////////////////////////////////////////////////// // Forward notifications support for message maps (for ATL 3.0) #if (_ATL_VER < 0x0700) // forward notifications support #define FORWARD_NOTIFICATIONS() \ { \ bHandled = TRUE; \ lResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } static LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LRESULT lResult = 0; switch(uMsg) { case WM_COMMAND: case WM_NOTIFY: #ifndef _WIN32_WCE case WM_PARENTNOTIFY: #endif // !_WIN32_WCE case WM_DRAWITEM: case WM_MEASUREITEM: case WM_COMPAREITEM: case WM_DELETEITEM: case WM_VKEYTOITEM: case WM_CHARTOITEM: case WM_HSCROLL: case WM_VSCROLL: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORMSGBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: lResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam); break; default: bHandled = FALSE; break; } return lResult; } #endif // (_ATL_VER < 0x0700) }; // namespace WTL #endif // __ATLWINX_H__ ================================================ FILE: bin/upx-4.1.0-win32/COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: bin/upx-4.1.0-win32/LICENSE ================================================ -----BEGIN PGP SIGNED MESSAGE----- ooooo ooo ooooooooo. ooooooo ooooo `888' `8' `888 `Y88. `8888 d8' 888 8 888 .d88' Y888..8P 888 8 888ooo88P' `8888' 888 8 888 .8PY888. `88. .8' 888 d8' `888b `YbodP' o888o o888o o88888o The Ultimate Packer for eXecutables Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar http://wildsau.idv.uni-linz.ac.at/mfx/upx.html http://www.nexus.hu/upx http://upx.tsx.org PLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN TO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION. ABSTRACT ======== UPX and UCL are copyrighted software distributed under the terms of the GNU General Public License (hereinafter the "GPL"). The stub which is imbedded in each UPX compressed program is part of UPX and UCL, and contains code that is under our copyright. The terms of the GNU General Public License still apply as compressing a program is a special form of linking with our stub. As a special exception we grant the free usage of UPX for all executables, including commercial programs. See below for details and restrictions. COPYRIGHT ========= UPX and UCL are copyrighted software. All rights remain with the authors. UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer UPX is Copyright (C) 1996-2000 Laszlo Molnar UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer GNU GENERAL PUBLIC LICENSE ========================== UPX and the UCL library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. UPX and UCL are distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. SPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES ============================================ The stub which is imbedded in each UPX compressed program is part of UPX and UCL, and contains code that is under our copyright. The terms of the GNU General Public License still apply as compressing a program is a special form of linking with our stub. Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special permission to freely use and distribute all UPX compressed programs (including commercial ones), subject to the following restrictions: 1. You must compress your program with a completely unmodified UPX version; either with our precompiled version, or (at your option) with a self compiled version of the unmodified UPX sources as distributed by us. 2. This also implies that the UPX stub must be completely unmodfied, i.e. the stub imbedded in your compressed program must be byte-identical to the stub that is produced by the official unmodified UPX version. 3. The decompressor and any other code from the stub must exclusively get used by the unmodified UPX stub for decompressing your program at program startup. No portion of the stub may get read, copied, called or otherwise get used or accessed by your program. ANNOTATIONS =========== - You can use a modified UPX version or modified UPX stub only for programs that are compatible with the GNU General Public License. - We grant you special permission to freely use and distribute all UPX compressed programs. But any modification of the UPX stub (such as, but not limited to, removing our copyright string or making your program non-decompressible) will immediately revoke your right to use and distribute a UPX compressed program. - UPX is not a software protection tool; by requiring that you use the unmodified UPX version for your proprietary programs we make sure that any user can decompress your program. This protects both you and your users as nobody can hide malicious code - any program that cannot be decompressed is highly suspicious by definition. - You can integrate all or part of UPX and UCL into projects that are compatible with the GNU GPL, but obviously you cannot grant any special exceptions beyond the GPL for our code in your project. - We want to actively support manufacturers of virus scanners and similar security software. Please contact us if you would like to incorporate parts of UPX or UCL into such a product. Markus F.X.J. Oberhumer Laszlo Molnar markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu Linz, Austria, 25 Feb 2000 -----BEGIN PGP SIGNATURE----- Version: 2.6.3ia Charset: noconv iQCVAwUBOLaLS210fyLu8beJAQFYVAP/ShzENWKLTvedLCjZbDcwaBEHfUVcrGMI wE7frMkbWT2zmkdv9hW90WmjMhOBu7yhUplvN8BKOtLiolEnZmLCYu8AGCwr5wBf dfLoClxnzfTtgQv5axF1awp4RwCUH3hf4cDrOVqmAsWXKPHtm4hx96jF6L4oHhjx OO03+ojZdO8= =CS52 -----END PGP SIGNATURE----- ================================================ FILE: bin/upx-4.1.0-win32/NEWS ================================================ ================================================================== User visible changes for UPX ================================================================== Changes in 4.1.0 (08 Aug 2023): * ELF: handle shared libraries with more than 2 PT_LOAD segments * bug fixes - see https://github.com/upx/upx/milestone/11 Changes in 4.0.2 (30 Jan 2023): * bug fixes - see https://github.com/upx/upx/milestone/9 Changes in 4.0.1 (16 Nov 2022): * bug fixes - see https://github.com/upx/upx/milestone/8 Changes in 4.0.0 (28 Oct 2022): * Switch to semantic versioning * SECURITY NOTES: emphasize the security context in the docs * Support easy building from source code with CMake * Support easy rebuilding the stubs from source with Podman/Docker * Add integrated doctest C++ testing framework * Add support for EFI files (PE x86; Kornel Pal) * win32/pe and win64/pe: set correct SizeOfHeaders in the PE header * bug fixes - see https://github.com/upx/upx/milestone/6 * bug fixes - see https://github.com/upx/upx/milestone/7 Changes in 3.96 (23 Jan 2020): * bug fixes - see https://github.com/upx/upx/milestone/5 Changes in 3.95 (26 Aug 2018): * Flag --android-shlib to work around bad design in Android * Flag --force-pie when ET_DYN main program is not marked as DF_1_PIE * Better compatibility with varying layout of address space on Linux * Support for 4 PT_LOAD layout in ELF generated by binutils-2.31 * bug fixes, particularly better diagnosis of malformed input * bug fixes - see https://github.com/upx/upx/milestone/4 Changes in 3.94 (12 May 2017): * Add support for arm64-linux (aka "aarch64"). * Add support for --lzma compression on 64-bit PowerPC (Thierry Fauck). * For Mach, "upx -d" will unpack a prefix of the file (and warn). * Various improvements to the ELF formats. * bug fixes - see https://github.com/upx/upx/milestone/3 Changes in 3.93 (29 Jan 2017): * Fixed some win32/pe and win64/pe regressions introduced in 3.92 * bug fixes - see https://github.com/upx/upx/milestone/2 Changes in 3.92 (11 Dec 2016): * INFO: UPX has moved to GitHub - the new home page is https://upx.github.io * IMPORTANT: all PE formats: internal changes: reunited the diverged source files - please report all regressions into the bug tracker and try UPX 3.91 in case of problems. * Support Apple MacOS 10.12 "Sierra", including more-robust de-compression. * Explicitly diagnose Go-language bad PT_LOAD; recommend hemfix.c. https://sourceforge.net/p/upx/bugs/195/ https://github.com/pwaller/goupx * Fix CERT-FI Case 829767 UPX command line tools segfaults. Received by UPX Team on 2015-May-08; originally reported by Codenomicon to NCSC-FI on 2015-01-08. The vulnerabilities were discovered by Joonas Kuorilehto and Antti Häyrynen from Codenomicon. * bug fixes - see https://github.com/upx/upx/milestone/1 Changes in 3.91 (30 Sep 2013): * Added experimental support for Windows 64-bit PE files, based on work by Stefan Widmann. Please use for testing only! * bug fixes ================================================================== Changes in 3.09 (18 Feb 2013): * New option --preserve-build-id for GNU ELF. * Allow for code signing and LC_UUID on Mac OS X executables. * Allow non-contiguous LC_SEGMENTs and 0==.vmsize for Mach-O. * Allow zero-filled final page in PackUnix::canUnpack(). * bug fixes Changes in 3.08 (12 Dec 2011): * Fix allocation in runtime stub for darwin.macho-entry (i386 and amd64). * Compress shared library on ELF i386 only [ld.so threatens even this case]. * Attempt to support ELF on QNX 6.3.0 for armel (experimental). * Better diagnostic when ELF -fPIC is needed. * PT_NOTE improvements for BSD. * Preserve more ELF .e_flags on ARM. * Minor code improvements for ELF stubs. * Defend against another flavor of corrupt PE header. * bug fixes Changes in 3.07 (08 Sep 2010): * win32/pe: fixed relocation handling for files with *no* TLS callbacks [severe bug introduced in 3.06] Changes in 3.06 (04 Sep 2010): * win32/pe: TLS callback support contributed by Stefan Widmann. Thanks! * bug fixes Changes in 3.05 (27 Apr 2010): * i386-linux and amd64-linux support shared libraries (DT_INIT must exist, all info needed by runtime loader must be first in .text, etc.) * Linux /proc/self/exe now is preserved by default, by leaving behind one page. New compress-time option --unmap-all-pages is available. * Withdraw support for shared libraries on Darwin (Apple Mac OS X) because upx does not understand enough about .dylib. * bug fixes Changes in 3.04 (27 Sep 2009): * new format Mach/AMD64 supports 64-bit programs on Apple Macintosh. * new formats Dylib/i386 and Dylib/ppc32 support shared libraries [such as browser plugins] on Darwin (Apple Macintosh). An existing -init function (LC_ROUTINES command) is required. * new format vmlinuz/armel for Debian NSLU2 (etc.) linux kernel * bvmlinuz boot protocol 2.08 for 386 Linux kernel * Extended ABI version 4 for armel-eabi ARM Linux ELF * bug fixes Changes in 3.03 (27 Apr 2008): * implement cache flushing for PowerPC (esp. model 440) * fix cache flushing on MIPS (>3 MiB compressed, or with holes) * fix MIPS big-endian * bug fixes Changes in 3.02 (16 Dec 2007): * fix unmapping on arm-linux.elf * fix error checking in mmap for i386-linux.elf [triggered by -fPIE] * bug fixes Changes in 3.01 (31 Jul 2007): * new options --no-mode, --no-owner and --no-time to disable preservation of mode (file permissions), file ownership and timestamps. * dos/exe: fixed an incorrect error message caused by a bug in relocation handling * new format linux/mipsel supports ELF on [32-bit] R3000 * fix argv[0] on PowerPC with --lzma * bug fixes Changes in 3.00 (27 Apr 2007): * watcom/le & tmt/adam: fixed a problem when using certain filters Changes in 2.93 beta (08 Mar 2007): * new formats Mach/i386 and Mach/fat support Mac OS X i686 and Universal binaries [i686 and PowerPC only] * dos/exe: LZMA is now also supported for 16-bit dos/exe. Please note that you have to explicitly use '--lzma' even for '--ultra-brute' here because runtime decompression is about 30 times slower than NRV - which is really noticeable on old machines. * dos/exe: fixed a rarely occurring bug in relocation handling * win32/pe & arm/pe: better icon compression handling Changes in 2.92 beta (23 Jan 2007): * new option '--ultra-brute' which tries even more variants * slightly improved compression ratio for some files when using '--brute' or '--ultra-brute' * bug fixes Changes in 2.91 beta (29 Nov 2006): * assorted bug fixes * wince/arm: fix "missing" icon & version info resource problem for WinCE 5 * win32/pe & arm/pe: added option --compress-icons=3 to compress all icons Changes in 2.90 beta (08 Oct 2006): * LZMA algorithm support for most of the 32-bit and 64-bit file formats; use new option '--lzma' to enable * new format: BSD/elf386 supporting FreeBSD, NetBSD and OpenBSD via auto-detection of PT_NOTE or EI_OSABI * arm/pe: all the NRV compression methods are now supported (only NRV2D is missing in thumb mode) * linux/elf386, linux/ElfAMD: remember /proc/self/exe in environment * major source code changes: the runtime decompression stubs are now built from internal ELF objects ================================================================== Changes in 2.03 (07 Nov 2006): * bvmlinuz/386: fix for kernels not at 0x100000; also allow x86_64 * linux/elf386: work around Linux kernel bug (0-length .bss needs PF_W) Changes in 2.02 (13 Aug 2006): * linux/386: work around Linux kernel bug (".bss" requires PF_W) * linux/ppc32, mach/ppc32: compressed programs now work on a 405 CPU * vmlinuz/386: fixed zlib uncompression problem on DOS Changes in 2.01 (06 Jun 2006): * arm/pe: better DLL support * dos/exe: device driver support added * linux/386: Fix --force-execve for PaX, grSecurity, and strict SELinux. /tmp must support execve(); therefore /tmp cannot be mounted 'noexec'. * win32/pe & arm/pe: added new option '--keep-resource=' for excluding selected resources from compression Changes in 2.00 (27 Apr 2006): * linux/386: the stub now prints an error message if some strict SELinux mode does prevent runtime decompression and execution (for a fully SELinux-compatible but otherwise inferior compression format you can use the '--force-execve' option) * linux/386: worked around a problem where certain Linux kernels clobber the %ebx register during a syscall * win32/pe: disable filters for files with broken PE headers Changes in 1.96 beta (13 Apr 2006): * arm/pe: added filter support * win32/pe: removed an unnecessary check so that Delphi 2006 and Digital Mars C++ programs finally are supported Changes in 1.95 beta (09 Apr 2006): * arm/pe: added DLL support * arm/pe: added thumb mode stub support * arm/pe: added unpacking support * win32/pe: really worked around R6002 runtime errors Changes in 1.94 beta (11 Mar 2006): * new format: added support for wince/arm (ARM executables running on WinCE) * new format: added support for linux elf/amd64 * new format: added support for linux elf/ppc32 * new format: added support for mach/ppc32 (Apple Mac OS X) * win32/pe: hopefully working "load config" support * win32/pe: R6002 runtime errors worked around * win32/pe: the stub now clears the dirty stack Changes in 1.93 beta (07 Feb 2005): * vmlinuz/386: fixes to support more kernels Changes in 1.92 beta (20 Jul 2004): * win32/pe: added option '--strip-loadconf' to strip the SEH load config section [NOTE: this option is obsolete since UPX 1.94] * win32/pe: try to detect .NET (win32/net) files [not yet supported by UPX] * vmlinux/386: new format that directly supports building Linux kernels * source code: now compiles cleanly under Win64 Changes in 1.91 beta (30 Jun 2004): * djgpp2/coff: added support for recent binutils versions * linux/elf386, linux/sh386: lots of improvements * vmlinuz/386: added support for recent kernels * watcom/le: don't crash on files without relocations * win32/pe: stricter checks of some PE values * option '--brute' now implies '--crp-ms=999999'. * source code: much improved portability using ACC, the Automatic Compiler Configuration * source code: compile fixes for strict ISO C++ compilers * source code: compile fixes for Win64 * re-synced with upx 1.25 branch Changes in 1.90 beta (11 Nov 2002): * implemented several new options for finer compression control: '--all-methods', '--all-filters' and '--brute' * ps1/exe: new format - UPX now supports PlayStation One programs * linux/386: added the option '--force-execve' * vmlinuz/386: better kernel detection and sanity checks * re-synced with upx 1.24 branch * documentation updates Changes in 1.11 beta (20 Dec 2000): * vmlinuz/386: new format - UPX now supports bootable linux kernels * linux/elf386: added the new ELF direct-to-memory executable format - no more temp files are needed for decompression! * linux/sh386: added the new shell direct-to-memory executable format - no more temp files are needed for decompression! * reduced overall memory requirements during packing * quite a number of internal source code rearrangements ================================================================== Changes in 1.25 (29 Jun 2004) * INFO: http://upx.sourceforge.net is the new UPX home page * watcom/le: don't crash on files without relocations * win32/pe: stricter checks of some PE values * source code: much improved portability using ACC, the Automatic Compiler Configuration * source code: compile fixes for strict ISO C++ compilers * source code: compile fixes for Win64 Changes in 1.24 (07 Nov 2002) * djgpp2/coff: stricter check of the COFF header to work around a problem with certain binutils versions Changes in 1.23 (05 Sep 2002) * atari/tos: fixed an unpacking problem where a buffer was too small (introduced in 1.22) * linux/386: don't give up too early if a single block turns out to be incompressible * documentation: added some quick tips how to achieve the best compression ratio for the final release of your application * fixed a rare situation where the exit code was not set correctly Changes in 1.22 (27 Jun 2002) * atari/tos: the stub now flushes the CPU cache to avoid problems on 68030+ machines * source code: additional compiler support for Borland C++, Digital Mars C++ and Watcom C++ Changes in 1.21 (01 Jun 2002) * New option '--crp-ms=' for slightly better compression at the cost of higher memory requirements during compression. Try 'upx --best --crp-ms=100000'. See the docs for more info. * source code: portability fixes * source code: compile fixes for g++ 3.0 and g++ 3.1 Changes in 1.20 (23 May 2001) * slightly faster compression * work around a gcc problem in the latest djgpp2 distribution * watcom/le: fixed detection of already compressed files * win32/pe: do not compress RT_MANIFEST resource types * win32/pe: improved the error message for empty resource sections * [NOTE: the jump from 1.08 to 1.20 is to avoid confusion with our unstable development releases 1.1x and 1.9x] Changes in 1.08 (30 Apr 2001) * new native port to atari/tos * win32/pe: shortened the identstring * source code: portability fixes - UPX now builds cleanly under m68k CPUs Changes in 1.07 (20 Feb 2001) * win32/pe: corrected the TLS callback check * win32/pe: really fixed that rare bug in relocation handling * win32/pe: experimental support for SizeOfHeaders > 0x1000 * win32/pe: check for superfluous data between sections * win32/pe: compressing screensavers (.scr) should finally work Changes in 1.06 (27 Jan 2001) * win32/pe: the check for TLS callbacks introduced in 1.05 was too strict - disabled for now * dos/com: decreased the decompressor stack size a little bit Changes in 1.05 (24 Jan 2001) * win32/pe: refuse to compress programs with TLS callbacks * win32/pe: stub changes to avoid slowdowns with some virus monitors * win32/pe: reverted the relocation handling changes in 1.04 * linux/386: dont try to compress Linux kernel images (have a look at the unstable UPX 1.1x beta versions for that) Changes in 1.04 (19 Dec 2000) * dos/exe: fixed an internal error when using '--no-reloc' * win32/pe: fixed a rare bug in the relocation handling code * some tunings for the default compression level Changes in 1.03 (30 Nov 2000) * linked with a new version of the NRV compression library: - improved compression ratio a little bit - overall significantly faster compression - much faster when using high compression levels like '-9' or '--best' - much faster with large files * atari/tos: added support for FreeMiNT * the 32-bit DOS version now uses the new CWSDSTUB extender Changes in 1.02 (13 Sep 2000) * watcom/le: fixed a problem with the Causeway extender * win32/pe: don't automatically strip relocs if they seem needed * support multiple backup generations when using '-k' * updated the console screen driver Changes in 1.01 (09 Apr 2000) * win32/pe: fixed an uncompression problem in DLLs with empty fixup sections * win32/pe: fixed another rare uncompression problem - a field in the PE header was set incorrectly Changes in 1.00 (26 Mar 2000) * documentation updates * watcom/le: do not duplicate the non-resident name table * win32/pe: fixed an import handling problem: sometimes too much data could be deleted from a file -> the uncompressed file would not work anymore Changes in 0.99.3 (07 Mar 2000) * win32/pe: fixed a rare problem in the stub string handling part Changes in 0.99.2 (02 Mar 2000) * dos/exe: fixed a typo causing an internal error (introduced in 0.99.1) Changes in 0.99.1 (29 Feb 2000) * win32/pe: fixed some object alignments which were causing problems when loading compressed DLLs under Windows NT/2000 Changes in 0.99 (25 Feb 2000) * FULL SOURCE CODE RELEASED UNDER THE TERMS OF THE GNU GPL * win32/pe: changed default to '--strip-relocs=1' * dos/com and dos/sys: fixed a bad decompressor problem * linux/386: the counter for the progress indicator was off by one ================================================================== Changes in 0.94 (06 Dec 1999) * win32/pe: the stub now calls ExitProcess in case of import errors * under DOS and Windows, the environment variable UPX now accepts a '#' as replacement for '=' because of a COMMAND.COM limitation Changes in 0.93 (22 Nov 1999) * win32/pe: fixed --strip-relocs problem with uncompression * win32/pe: fixed a bug which could produce a broken decompressor stub * linux/386: yet another FreeBSD compatibility fix Changes in 0.92 (14 Nov 1999) * win32/pe: really fixed that one line (see below) Changes in 0.91 (13 Nov 1999) * win32/pe: an important one-line fix for the newly introduced problems * dos/com and dos/sys: fixed an internal error * dos/exe: correctly restore cs when uncompressing Changes in 0.90 (10 Nov 1999) * all formats: '--overlay=copy' now is the default overlay mode * improved compression ratio for most files * win32/pe: uncompression is finally supported * win32/pe: never compress REGISTRY resources * win32/pe: headersize was not set in PE header * win32/pe: resource handling is rewritten * win32/pe: the last :-) TLS problem is fixed * win32/pe: somewhat less memory is required during compression * linux/386: fixed compression of scripts which was broken since 0.71 * linux/386: more FreeBSD compatibility issues * changed option: '-i' now prints some more details during compression (not finished yet) Changes in 0.84 (04 Oct 1999) * dos/exe: fixed a rare problem where the decompressor could crash * some other minor fixes Changes in 0.83 (17 Sep 1999) * dos/exe: fixed minimal memory requirement problem for some files * win32/pe: fixed a bug which caused a crash in some compressed files * linux/386: various improvements in the stub; also, for the sake of FreeBSD users, the stub is now branded as Linux/ELF Changes in 0.82 (16 Aug 1999) * dos/exe: fixed a decompressor bug which could cause crash on some files * linux/386: section headers are now stripped from the stub so that 'strip' won't ruin a compressed file any longer * wc/le: support for stack not in the last object disabled again * win32/pe: removed some unneeded data Changes in 0.81 (04 Aug 1999) * win32/pe: fixed an important bug in import handling * dos/com: fixed an internal error that could happen with very small files Changes in 0.80 (03 Aug 1999) * you can set some default options in the environment var 'UPX' * dos/com: the decompressor stub now checks for enough free memory * dos/exe: decompressor rewritten, some bugs are fixed * dos/exe: new option '--no-reloc': no relocation data is put into the DOS header * tmt/adam: added support for more stubs, detect already packed files * tmt/adam: new option '--copy-overlay' * wc/le: reduced memory requirement during uncompression * wc/le: support files which do not contain their stack in the last object * wc/le: fixed a bug which could cause a crash, improved relocation handling * wc/le: new option '--copy-overlay' * win32/pe: '--compress-icons=2' is now the default * win32/pe: even better TLS support * win32/pe: versioninfo works on NT * win32/pe: import by ordinal from kernel32.dll works * win32/pe: other import improvements: importing a nonexistent DLL results in a usual Windows message, importing a nonexistent function results in program exit (instead of crash ;-) * win32/pe: new option: '--compress-resources=0' * win32/pe: reduced memory requirement during uncompression, some files might even require LESS memory when they're compressed * win32/pe: TYPELIBs should work now * win32/pe: improved relocation handling, 16-bit relocations should work * win32/pe: new option '--strip-relocs' (only if you know what you are doing) * win32/pe: new option '--copy-overlay' * important internal changes: now the stubs are built at runtime Changes in 0.72 (12 May 1999) * tmt/adam: fixed a serious problem in the decompressor stub; all compressed tmt files should be recompressed * win32/pe: fixed the 'shared sections not supported' warning: read-only shared sections are fine * win32/pe: never compress TYPELIB resources * win32/pe: compressed files are hopefully less suspicious to heuristic virus scanners now * linux/386: minor decompressor stub updates, nicer progress bar Changes in 0.71 (19 Apr 1999) * dos/exe: added option '--no-overlay' * linux/386: various improvements in the stub, most notably the overhead for an extra cleanup process has been removed * win32/pe: added support for export forwarders * win32/pe: added support for DLLs without entry point or imports * win32/pe: yet another .bss fix * win32/pe: new option '--compress-icons=2': compress all icons which are not in the first icon directory * win32/pe: rearranged stub to avoid false alerts from some virus scanners Changes in 0.70 (30 Mar 1999) * added support for linux/386 executables * improved compression ratio quite a bit * added new compression level '--best' to squeeze out even some more bytes * win32/pe: TLS support is much better now * win32/pe: --compress-icons=0 should now work as well * the usual minor fixes for win32/pe Changes in 0.62 (16 Mar 1999) * win32/pe: --compress-icons and --compress-exports are on now by default * win32/pe: --compress-icons should really work now * win32/pe: fixed a problem with embedded .bss sections Changes in 0.61 (08 Mar 1999) * atari/tos: fixed a problem where the bss segment could become too small Changes in 0.60 (06 Mar 1999) * win32/pe: fixed file corruption when the size of the export data is invalid * win32/pe: fixed a problem with empty resource data * win32/pe: compressed file alignment set to minimum value * win32/pe: made all compressed sections writable * fixed some other win32/pe bugs * fixed an address optimization problem for some not Watcom LE files * fixed a bug which could make UPX hang when an exe header contained an illegal value * added some compression flags for the win32/pe format * added support for Atari ST/TT executables (atari/tos) * improved compression ratio * improved compression speed Changes in 0.51 (14 Jan 1999) * fixed a small bug in the PE header that would prevent some compressed win32/pe executables from running under Windows NT and WINE Changes in 0.50 (03 Jan 1999) * added support for PE format executables (win32/pe & rtm32/pe) * added support for TMT executables (tmt/adam) * fixed a dos/sys bug that affected OpenDOS Changes in 0.40 (05 Oct 1998) * improved compression ratio * fixed a small but fatal bug in dos/sys introduced in 0.30 * fixed a rare bug in dos/exe * worked around a bug in djgpp's strip 2.8 * djgpp2/coff: Allegro packfile support should work now * added dos/exeh compression method (works on 386+) Changes in 0.30 (27 Jul 1998) * fixed a serious bug in the 32-bit compressors - please don't use djgpp2/coff and watcom/le compressed files from previous versions, some of them are possibly damaged ! * the 16-bit uncompressors are a little bit shorter & faster * fixed progress indicator for VESA and SVGA text modes Changes in 0.20 (05 Jul 1998) * second public beta release * too many changes to list here Changes in 0.05 (26 May 1998) * first public beta release * based on experience gained from our previous packers DJP (djgpp2/coff, 1996), lzop (1996) and mfxpak (atari/tos, 1990) ================================================ FILE: bin/upx-4.1.0-win32/README ================================================ ooooo ooo ooooooooo. ooooooo ooooo `888' `8' `888 `Y88. `8888 d8' 888 8 888 .d88' Y888..8P 888 8 888ooo88P' `8888' 888 8 888 .8PY888. `88. .8' 888 d8' `888b `YbodP' o888o o888o o88888o The Ultimate Packer for eXecutables Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser https://upx.github.io WELCOME ======= Welcome to UPX ! UPX is a free, secure, portable, extendable, high-performance executable packer for several executable formats. INTRODUCTION ============ UPX is an advanced executable file compressor. UPX will typically reduce the file size of programs and DLLs by around 50%-70%, thus reducing disk space, network load times, download times and other distribution and storage costs. Programs and libraries compressed by UPX are completely self-contained and run exactly as before, with no runtime or memory penalty for most of the supported formats. UPX supports a number of different executable formats, including Windows programs and DLLs, macOS apps and Linux executables. UPX is free software distributed under the term of the GNU General Public License. Full source code is available. UPX may be distributed and used freely, even with commercial applications. See the UPX License Agreements for details. SECURITY CONTEXT ================ IMPORTANT NOTE: UPX inherits the security context of any files it handles. This means that packing, unpacking, or even testing or listing a file requires the same security considerations as actually executing the file. Use UPX on trusted files only! SHORT DOCUMENTATION =================== 'upx program.exe' will compress a program or DLL. For best compression results try 'upx --best program.exe' or 'upx --brute program.exe'. Please see the file UPX.DOC for the full documentation. The files NEWS and BUGS also contain various tidbits of information. THE FUTURE ========== - Stay up-to-date with ongoing OS and executable format changes - RISC-V 64 for Linux - ARM64 for Windows (help wanted) - We will *NOT* add any sort of protection and/or encryption. This only gives people a false feeling of security because all "protectors" can be broken by definition. - Fix all remaining bugs - please report any issues https://github.com/upx/upx/issues COPYRIGHT ========= Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2023 Laszlo Molnar Copyright (C) 2000-2023 John F. Reiser UPX is distributed with full source code under the terms of the GNU General Public License v2+; either under the pure GPLv2+ (see the file COPYING), or (at your option) under the GPLv+2 with special exceptions and restrictions granting the free usage for all binaries including commercial programs (see the file LICENSE). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the UPX License Agreements along with this program; see the files COPYING and LICENSE. If not, visit the UPX home page. Share and enjoy, Markus & Laszlo & John Markus F.X.J. Oberhumer Laszlo Molnar John F. Reiser [ The term UPX is a shorthand for the Ultimate Packer for eXecutables and holds no connection with potential owners of registered trademarks or other rights. ] ================================================ FILE: bin/upx-4.1.0-win32/THANKS.txt ================================================ ooooo ooo ooooooooo. ooooooo ooooo `888' `8' `888 `Y88. `8888 d8' 888 8 888 .d88' Y888..8P 888 8 888ooo88P' `8888' 888 8 888 .8PY888. `88. .8' 888 d8' `888b `YbodP' o888o o888o o88888o The Ultimate Packer for eXecutables Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser https://upx.github.io .___.. . | |_ _.._ ;_/ __ | [ )(_][ )| \_) -------------------- UPX would not be what it is today without the invaluable help of everybody who was kind enough to spend time testing it, using it in applications and reporting bugs. The following people made especially gracious contributions of their time and energy in helping to track down bugs, add new features, and generally assist in the UPX maintainership process: Adam Ierymenko for severals ideas for the Linux version Andi Kleen and Jamie Lokier for the /proc/self/fd/X and other Linux suggestions Andreas Muegge for the Win32 GUI Atli Mar Gudmundsson for several comments on the win32/pe stub Charles W. Sandmann for the idea with the stubless decompressor in djgpp2/coff Ice for debugging the PE headersize problem down Joergen Ibsen and d'b for the relocation & address optimization ideas John S. Fine for the new version of the dos/exe decompressor Kornel Pal for the EFI support Lukundoo for beta testing Michael Devore for initial dos/exe device driver support Oleg V. Volkov for various FreeBSD specific information The Owl & G-RoM for the --compress-icons fix Ralph Roth for reporting several bugs Salvador Eduardo Tropea for beta testing Stefan Widmann for the win32/pe TLS callback support The WINE project (https://www.winehq.com/) for lots of useful information found in their PE loader sources Natascha ================================================ FILE: bin/upx-4.1.0-win32/upx-doc.html ================================================ upx - compress or expand executable files

NAME

upx - compress or expand executable files

SYNOPSIS

upx [ command ] [ options ] filename...

ABSTRACT

                 The Ultimate Packer for eXecutables
Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser
                        https://upx.github.io

UPX is a portable, extendable, high-performance executable packer for several different executable formats. It achieves an excellent compression ratio and offers *very* fast decompression. Your executables suffer no memory overhead or other drawbacks for most of the formats supported, because of in-place decompression.

DISCLAIMER

UPX comes with ABSOLUTELY NO WARRANTY; for details see the file COPYING.

Please report all problems or suggestions to the authors. Thanks.

SECURITY CONTEXT

IMPORTANT NOTE: UPX inherits the security context of any files it handles.

This means that packing, unpacking, or even testing or listing a file requires the same security considerations as actually executing the file.

Use UPX on trusted files only!

DESCRIPTION

UPX is a versatile executable packer with the following features:

- secure: as UPX is documented Open Source since many years any relevant
    Security/Antivirus software is able to peek inside UPX compressed
    apps to verify them

- excellent compression ratio: typically compresses better than Zip,
    use UPX to decrease the size of your distribution !

- very fast decompression: more than 500 MB/sec on any reasonably modern
    machine

- no memory overhead for your compressed executables for most of the
    supported formats because of in-place decompression

- safe: you can list, test and unpack your executables.
    Also, a checksum of both the compressed and uncompressed file is
    maintained internally.

- universal: UPX can pack a number of executable formats, including
    Windows programs and DLLs, macOS apps and Linux executables

- portable: UPX is written in portable endian-neutral C++

- extendable: because of the class layout it's very easy to support
    new executable formats or add new compression algorithms

- free: UPX is distributed with full source code under the GNU General
    Public License v2+, with special exceptions granting the free usage
    for commercial programs

You probably understand now why we call UPX the "ultimate" executable packer.

COMMANDS

Compress

This is the default operation, eg. upx yourfile.exe will compress the file specified on the command line.

Decompress

All UPX supported file formats can be unpacked using the -d switch, eg. upx -d yourfile.exe will uncompress the file you've just compressed.

Test

The -t command tests the integrity of the compressed and uncompressed data, eg. upx -t yourfile.exe check whether your file can be safely decompressed. Note, that this command doesn't check the whole file, only the part that will be uncompressed during program execution. This means that you should not use this command instead of a virus checker.

List

The -l command prints out some information about the compressed files specified on the command line as parameters, eg upx -l yourfile.exe shows the compressed / uncompressed size and the compression ratio of yourfile.exe.

OPTIONS

-q: be quiet, suppress warnings

-q -q (or -qq): be very quiet, suppress errors

-q -q -q (or -qqq): produce no output at all

--help: prints the help

--version: print the version of UPX

--exact: when compressing, require to be able to get a byte-identical file after decompression with option -d. [NOTE: this is work in progress and is not supported for all formats yet. If you do care, as a workaround you can compress and then decompress your program a first time - any further compress-decompress steps should then yield byte-identical results as compared to the first decompressed version.]

-k: keep backup files

-o file: write output to file

[ ...more docs need to be written... - type `upx --help' for now ]

COMPRESSION LEVELS & TUNING

UPX offers ten different compression levels from -1 to -9, and --best. The default compression level is -8 for files smaller than 512 KiB, and -7 otherwise.

  • Compression levels 1, 2 and 3 are pretty fast.

  • Compression levels 4, 5 and 6 achieve a good time/ratio performance.

  • Compression levels 7, 8 and 9 favor compression ratio over speed.

  • Compression level --best may take a long time.

Note that compression level --best can be somewhat slow for large files, but you definitely should use it when releasing a final version of your program.

Quick info for achieving the best compression ratio:

  • Try upx --brute --no-lzma myfile.exe or even upx --ultra-brute --no-lzma myfile.exe.

  • The option --lzma enables LZMA compression, which compresses better but is *significantly slower* at decompression. You probably do not want to use it for large files.

    (Note that --lzma is automatically enabled by --all-methods and --brute, use --no-lzma to override.)

  • Try if --overlay=strip works.

  • For win32/pe programs there's --strip-relocs=0. See notes below.

OVERLAY HANDLING OPTIONS

Info: An "overlay" means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections).

UPX handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn't work with others, depending on how an application actually accesses this overlaid data.

--overlay=copy    Copy any extra data attached to the file. [DEFAULT]

--overlay=strip   Strip any overlay from the program instead of
                  copying it. Be warned, this may make the compressed
                  program crash or otherwise unusable.

--overlay=skip    Refuse to compress any program which has an overlay.

ENVIRONMENT VARIABLE

The environment variable UPX can hold a set of default options for UPX. These options are interpreted first and can be overwritten by explicit command line parameters. For example:

for DOS/Windows:   set UPX=-9 --compress-icons#0
for sh/ksh/zsh:    UPX="-9 --compress-icons=0"; export UPX
for csh/tcsh:      setenv UPX "-9 --compress-icons=0"

Under DOS/Windows you must use '#' instead of '=' when setting the environment variable because of a COMMAND.COM limitation.

Not all of the options are valid in the environment variable - UPX will tell you.

You can explicitly use the --no-env option to ignore the environment variable.

NOTES FOR THE SUPPORTED EXECUTABLE FORMATS

NOTES FOR ATARI/TOS

This is the executable format used by the Atari ST/TT, a Motorola 68000 based personal computer which was popular in the late '80s. Support of this format is only because of nostalgic feelings of one of the authors and serves no practical purpose :-). See https://freemint.github.io for more info.

Packed programs will be byte-identical to the original after uncompression. All debug information will be stripped, though.

Extra options available for this executable format:

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

NOTES FOR BVMLINUZ/I386

Same as vmlinuz/i386.

NOTES FOR DOS/COM

Obviously UPX won't work with executables that want to read data from themselves (like some commandline utilities that ship with Win95/98/ME).

Compressed programs only work on a 286+.

Packed programs will be byte-identical to the original after uncompression.

Maximum uncompressed size: ~65100 bytes.

Extra options available for this executable format:

--8086              Create an executable that works on any 8086 CPU.

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--all-filters       Compress the program several times, using all
                    available preprocessing filters. This may improve
                    the compression ratio in some cases, but usually
                    the default filter gives the best results anyway.

NOTES FOR DOS/EXE

dos/exe stands for all "normal" 16-bit DOS executables.

Obviously UPX won't work with executables that want to read data from themselves (like some command line utilities that ship with Win95/98/ME).

Compressed programs only work on a 286+.

Extra options available for this executable format:

--8086              Create an executable that works on any 8086 CPU.

--no-reloc          Use no relocation records in the exe header.

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

NOTES FOR DOS/SYS

Compressed programs only work on a 286+.

Packed programs will be byte-identical to the original after uncompression.

Maximum uncompressed size: ~65350 bytes.

Extra options available for this executable format:

--8086              Create an executable that works on any 8086 CPU.

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--all-filters       Compress the program several times, using all
                    available preprocessing filters. This may improve
                    the compression ratio in some cases, but usually
                    the default filter gives the best results anyway.

NOTES FOR DJGPP2/COFF

First of all, it is recommended to use UPX *instead* of strip. strip has the very bad habit of replacing your stub with its own (outdated) version. Additionally UPX corrects a bug/feature in strip v2.8.x: it will fix the 4 KiB alignment of the stub.

UPX includes the full functionality of stubify. This means it will automatically stubify your COFF files. Use the option --coff to disable this functionality (see below).

UPX automatically handles Allegro packfiles.

The DLM format (a rather exotic shared library extension) is not supported.

Packed programs will be byte-identical to the original after uncompression. All debug information and trailing garbage will be stripped, though.

Extra options available for this executable format:

--coff              Produce COFF output instead of EXE. By default
                    UPX keeps your current stub.

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--all-filters       Compress the program several times, using all
                    available preprocessing filters. This may improve
                    the compression ratio in some cases, but usually
                    the default filter gives the best results anyway.

NOTES FOR LINUX [general]

Introduction

Linux/386 support in UPX consists of 3 different executable formats,
one optimized for ELF executables ("linux/elf386"), one optimized
for shell scripts ("linux/sh386"), and one generic format
("linux/386").

We will start with a general discussion first, but please
also read the relevant docs for each of the individual formats.

Also, there is special support for bootable kernels - see the
description of the vmlinuz/386 format.

General user's overview

Running a compressed executable program trades less space on a
``permanent'' storage medium (such as a hard disk, floppy disk,
CD-ROM, flash memory, EPROM, etc.) for more space in one or more
``temporary'' storage media (such as RAM, swap space, /tmp, etc.).
Running a compressed executable also requires some additional CPU
cycles to generate the compressed executable in the first place,
and to decompress it at each invocation.

How much space is traded?  It depends on the executable, but many
programs save 30% to 50% of permanent disk space.  How much CPU
overhead is there?  Again, it depends on the executable, but
decompression speed generally is at least many megabytes per second,
and frequently is limited by the speed of the underlying disk
or network I/O.

Depending on the statistics of usage and access, and the relative
speeds of CPU, RAM, swap space, /tmp, and file system storage, then
invoking and running a compressed executable can be faster than
directly running the corresponding uncompressed program.
The operating system might perform fewer expensive I/O operations
to invoke the compressed program.  Paging to or from swap space
or /tmp might be faster than paging from the general file system.
``Medium-sized'' programs which access about 1/3 to 1/2 of their
stored program bytes can do particularly well with compression.
Small programs tend not to benefit as much because the absolute
savings is less.  Big programs tend not to benefit proportionally
because each invocation may use only a small fraction of the program,
yet UPX decompresses the entire program before invoking it.
But in environments where disk or flash memory storage is limited,
then compression may win anyway.

Currently, executables compressed by UPX do not share RAM at runtime
in the way that executables mapped from a file system do.  As a
result, if the same program is run simultaneously by more than one
process, then using the compressed version will require more RAM and/or
swap space.  So, shell programs (bash, csh, etc.)  and ``make''
might not be good candidates for compression.

UPX recognizes three executable formats for Linux: Linux/elf386,
Linux/sh386, and Linux/386.  Linux/386 is the most generic format;
it accommodates any file that can be executed.  At runtime, the UPX
decompression stub re-creates in /tmp a copy of the original file,
and then the copy is (re-)executed with the same arguments.
ELF binary executables prefer the Linux/elf386 format by default,
because UPX decompresses them directly into RAM, uses only one
exec, does not use space in /tmp, and does not use /proc.
Shell scripts where the underlying shell accepts a ``-c'' argument
can use the Linux/sh386 format.  UPX decompresses the shell script
into low memory, then maps the shell and passes the entire text of the
script as an argument with a leading ``-c''.

General benefits:

- UPX can compress all executables, be it AOUT, ELF, libc4, libc5,
  libc6, Shell/Perl/Python/... scripts, standalone Java .class
  binaries, or whatever...
  All scripts and programs will work just as before.

- Compressed programs are completely self-contained. No need for
  any external program.

- UPX keeps your original program untouched. This means that
  after decompression you will have a byte-identical version,
  and you can use UPX as a file compressor just like gzip.
  [ Note that UPX maintains a checksum of the file internally,
    so it is indeed a reliable alternative. ]

- As the stub only uses syscalls and isn't linked against libc it
  should run under any Linux configuration that can run ELF
  binaries.

- For the same reason compressed executables should run under
  FreeBSD and other systems which can run Linux binaries.
  [ Please send feedback on this topic ]

General drawbacks:

- It is not advisable to compress programs which usually have many
  instances running (like `sh' or `make') because the common segments of
  compressed programs won't be shared any longer between different
  processes.

- `ldd' and `size' won't show anything useful because all they
  see is the statically linked stub.  Since version 0.82 the section
  headers are stripped from the UPX stub and `size' doesn't even
  recognize the file format.  The file patches/patch-elfcode.h has a
  patch to fix this bug in `size' and other programs which use GNU BFD.

General notes:

- As UPX leaves your original program untouched it is advantageous
  to strip it before compression.

- If you compress a script you will lose platform independence -
  this could be a problem if you are using NFS mounted disks.

- Compression of suid, guid and sticky-bit programs is rejected
  because of possible security implications.

- For the same reason there is no sense in making any compressed
  program suid.

- Obviously UPX won't work with executables that want to read data
  from themselves. E.g., this might be a problem for Perl scripts
  which access their __DATA__ lines.

- In case of internal errors the stub will abort with exitcode 127.
  Typical reasons for this to happen are that the program has somehow
  been modified after compression.
  Running `strace -o strace.log compressed_file' will tell you more.

NOTES FOR LINUX/ELF386

Please read the general Linux description first.

The linux/elf386 format decompresses directly into RAM, uses only one exec, does not use space in /tmp, and does not use /proc.

Linux/elf386 is automatically selected for Linux ELF executables.

Packed programs will be byte-identical to the original after uncompression.

How it works:

For ELF executables, UPX decompresses directly to memory, simulating
the mapping that the operating system kernel uses during exec(),
including the PT_INTERP program interpreter (if any).
The brk() is set by a special PT_LOAD segment in the compressed
executable itself.  UPX then wipes the stack clean except for
arguments, environment variables, and Elf_auxv entries (this is
required by bugs in the startup code of /lib/ld-linux.so as of
May 2000), and transfers control to the program interpreter or
the e_entry address of the original executable.

The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.

Specific drawbacks:

- For linux/elf386 and linux/sh386 formats, you will be relying on
  RAM and swap space to hold all of the decompressed program during
  the lifetime of the process.  If you already use most of your swap
  space, then you may run out.  A system that is "out of memory"
  can become fragile.  Many programs do not react gracefully when
  malloc() returns 0.  With newer Linux kernels, the kernel
  may decide to kill some processes to regain memory, and you
  may not like the kernel's choice of which to kill.  Running
  /usr/bin/top is one way to check on the usage of swap space.

Extra options available for this executable format:

(none)

NOTES FOR LINUX/SH386

Please read the general Linux description first.

Shell scripts where the underling shell accepts a ``-c'' argument can use the Linux/sh386 format. UPX decompresses the shell script into low memory, then maps the shell and passes the entire text of the script as an argument with a leading ``-c''. It does not use space in /tmp, and does not use /proc.

Linux/sh386 is automatically selected for shell scripts that use a known shell.

Packed programs will be byte-identical to the original after uncompression.

How it works:

For shell script executables (files beginning with "#!/" or "#! /")
where the shell is known to accept "-c <command>", UPX decompresses
the file into low memory, then maps the shell (and its PT_INTERP),
and passes control to the shell with the entire decompressed file
as the argument after "-c".  Known shells are sh, ash, bash, bsh, csh,
ksh, tcsh, pdksh.  Restriction: UPX cannot use this method
for shell scripts which use the one optional string argument after
the shell name in the script (example: "#! /bin/sh option3\n".)

The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.

Specific drawbacks:

- For linux/elf386 and linux/sh386 formats, you will be relying on
  RAM and swap space to hold all of the decompressed program during
  the lifetime of the process.  If you already use most of your swap
  space, then you may run out.  A system that is "out of memory"
  can become fragile.  Many programs do not react gracefully when
  malloc() returns 0.  With newer Linux kernels, the kernel
  may decide to kill some processes to regain memory, and you
  may not like the kernel's choice of which to kill.  Running
  /usr/bin/top is one way to check on the usage of swap space.

Extra options available for this executable format:

(none)

NOTES FOR LINUX/386

Please read the general Linux description first.

The generic linux/386 format decompresses to /tmp and needs /proc file system support. It starts the decompressed program via the execve() syscall.

Linux/386 is only selected if the specialized linux/elf386 and linux/sh386 won't recognize a file.

Packed programs will be byte-identical to the original after uncompression.

How it works:

For files which are not ELF and not a script for a known "-c" shell,
UPX uses kernel execve(), which first requires decompressing to a
temporary file in the file system.  Interestingly -
because of the good memory management of the Linux kernel - this
often does not introduce a noticeable delay, and in fact there
will be no disk access at all if you have enough free memory as
the entire process takes places within the file system buffers.

A compressed executable consists of the UPX stub and an overlay
which contains the original program in a compressed form.

The UPX stub is a statically linked ELF executable and does
the following at program startup:

  1) decompress the overlay to a temporary location in /tmp
  2) open the temporary file for reading
  3) try to delete the temporary file and start (execve)
     the uncompressed program in /tmp using /proc/<pid>/fd/X as
     attained by step 2)
  4) if that fails, fork off a subprocess to clean up and
     start the program in /tmp in the meantime

The UPX stub is about 1700 bytes long, partly written in assembler
and only uses kernel syscalls. It is not linked against any libc.

Specific drawbacks:

- You need additional free disk space for the uncompressed program
  in your /tmp directory. This program is deleted immediately after
  decompression, but you still need it for the full execution time
  of the program.

- You must have /proc file system support as the stub wants to open
  /proc/<pid>/exe and needs /proc/<pid>/fd/X. This also means that you
  cannot compress programs that are used during the boot sequence
  before /proc is mounted.

- Utilities like `top' will display numerical values in the process
  name field. This is because Linux computes the process name from
  the first argument of the last execve syscall (which is typically
  something like /proc/<pid>/fd/3).

- Because of temporary decompression to disk the decompression speed
  is not as fast as with the other executable formats. Still, I can see
  no noticeable delay when starting programs like my ~3 MiB emacs (which
  is less than 1 MiB when compressed :-).

Extra options available for this executable format:

--force-execve      Force the use of the generic linux/386 "execve"
                    format, i.e. do not try the linux/elf386 and
                    linux/sh386 formats.

NOTES FOR PS1/EXE

This is the executable format used by the Sony PlayStation (PSone), a MIPS R3000 based gaming console which is popular since the late '90s. Support of this format is very similar to the Atari one, because of nostalgic feelings of one of the authors.

Packed programs will be byte-identical to the original after uncompression, until further notice.

Maximum uncompressed size: ~1.89 / ~7.60 MiB.

Notes:

- UPX creates as default a suitable executable for CD-Mastering
  and console transfer. For a CD-Master main executable you could also try
  the special option "--boot-only" as described below.
  It has been reported that upx packed executables are fully compatible with
  the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in
  Sony PlayStation (PSone) emulation mode.

- Normally the packed files use the same memory areas like the uncompressed
  versions, so they will not override other memory areas while unpacking.
  If this isn't possible UPX will abort showing a 'packed data overlap'
  error. With the "--force" option UPX will relocate the loading address
  for the packed file, but this isn't a real problem if it is a single or
  the main executable.

Extra options available for this executable format:

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--8-bit             Uses 8 bit size compression [default: 32 bit]

--8mib-ram          PSone has 8 MiB ram available [default: 2 MiB]

--boot-only         This format is for main exes and CD-Mastering only !
                    It may slightly improve the compression ratio,
                    decompression routines are faster than default ones.
                    But it cannot be used for console transfer !

--no-align          This option disables CD mode 2 data sector format
                    alignment. May slightly improves the compression ratio,
                    but the compressed executable will not boot from a CD.
                    Use it for console transfer only !

NOTES FOR RTM32/PE and ARM/PE

Same as win32/pe.

NOTES FOR TMT/ADAM

This format is used by the TMT Pascal compiler - see http://www.tmt.com/ .

Extra options available for this executable format:

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--all-filters       Compress the program several times, using all
                    available preprocessing filters. This may improve
                    the compression ratio in some cases, but usually
                    the default filter gives the best results anyway.

NOTES FOR VMLINUZ/386

The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed bootable Linux kernel image ("vmlinuz", "zImage", "bzImage"), gzip-decompress it and re-compress it with the UPX compression method.

vmlinuz/386 is completely unrelated to the other Linux executable formats, and it does not share any of their drawbacks.

Notes:

- Be sure that "vmlinuz/386" or "bvmlinuz/386" is displayed
during compression - otherwise a wrong executable format
may have been used, and the kernel won't boot.

Benefits:

- Better compression (but note that the kernel was already compressed,
so the improvement is not as large as with other formats).
Still, the bytes saved may be essential for special needs like
boot disks.

   For example, this is what I get for my 2.2.16 kernel:
      1589708  vmlinux
       641073  bzImage        [original]
       560755  bzImage.upx    [compressed by "upx -9"]

- Much faster decompression at kernel boot time (but kernel
  decompression speed is not really an issue these days).

Drawbacks:

(none)

Extra options available for this executable format:

--all-methods       Compress the program several times, using all
                    available compression methods. This may improve
                    the compression ratio in some cases, but usually
                    the default method gives the best results anyway.

--all-filters       Compress the program several times, using all
                    available preprocessing filters. This may improve
                    the compression ratio in some cases, but usually
                    the default filter gives the best results anyway.

NOTES FOR WATCOM/LE

UPX has been successfully tested with the following extenders: DOS4G, DOS4GW, PMODE/W, DOS32a, CauseWay. The WDOS/X extender is partly supported (for details see the file bugs BUGS).

DLLs and the LX format are not supported.

Extra options available for this executable format:

--le                Produce an unbound LE output instead of
                    keeping the current stub.

NOTES FOR WIN32/PE

The PE support in UPX is quite stable now, but probably there are still some incompatibilities with some files.

Because of the way UPX (and other packers for this format) works, you can see increased memory usage of your compressed files because the whole program is loaded into memory at startup. If you start several instances of huge compressed programs you're wasting memory because the common segments of the program won't get shared across the instances. On the other hand if you're compressing only smaller programs, or running only one instance of larger programs, then this penalty is smaller, but it's still there.

If you're running executables from network, then compressed programs will load faster, and require less bandwidth during execution.

DLLs are supported. But UPX compressed DLLs can not share common data and code when they got used by multiple applications. So compressing msvcrt.dll is a waste of memory, but compressing the dll plugins of a particular application may be a better idea.

Screensavers are supported, with the restriction that the filename must end with ".scr" (as screensavers are handled slightly different than normal exe files).

UPX compressed PE files have some minor memory overhead (usually in the 10 - 30 KiB range) which can be seen by specifying the "-i" command line switch during compression.

Extra options available for this executable format:

--compress-exports=0 Don't compress the export section.
                     Use this if you plan to run the compressed
                     program under Wine.
--compress-exports=1 Compress the export section. [DEFAULT]
                     Compression of the export section can improve the
                     compression ratio quite a bit but may not work
                     with all programs (like winword.exe).
                     UPX never compresses the export section of a DLL
                     regardless of this option.

 --compress-icons=0  Don't compress any icons.
 --compress-icons=1  Compress all but the first icon.
 --compress-icons=2  Compress all icons which are not in the
                     first icon directory. [DEFAULT]
 --compress-icons=3  Compress all icons.

 --compress-resources=0  Don't compress any resources at all.

 --keep-resource=list Don't compress resources specified by the list.
                     The members of the list are separated by commas.
                     A list member has the following format: I<type[/name]>.
                     I<Type> is the type of the resource. Standard types
                     must be specified as decimal numbers, user types can be
                     specified by decimal IDs or strings. I<Name> is the
                     identifier of the resource. It can be a decimal number
                     or a string. For example:

                     --keep-resource=2/MYBITMAP,5,6/12345

                     UPX won't compress the named bitmap resource "MYBITMAP",
                     it leaves every dialog (5) resource uncompressed, and
                     it won't touch the string table resource with identifier
                     12345.

 --force             Force compression even when there is an
                     unexpected value in a header field.
                     Use with care.

 --strip-relocs=0    Don't strip relocation records.
 --strip-relocs=1    Strip relocation records. [DEFAULT]
                     This option only works on executables with base
                     address greater or equal to 0x400000. Usually the
                     compressed files becomes smaller, but some files
                     may become larger. Note that the resulting file will
                     not work under Windows 3.x (Win32s).
                     UPX never strips relocations from a DLL
                     regardless of this option.

 --all-methods       Compress the program several times, using all
                     available compression methods. This may improve
                     the compression ratio in some cases, but usually
                     the default method gives the best results anyway.

 --all-filters       Compress the program several times, using all
                     available preprocessing filters. This may improve
                     the compression ratio in some cases, but usually
                     the default filter gives the best results anyway.

DIAGNOSTICS

Exit status is normally 0; if an error occurs, exit status is 1. If a warning occurs, exit status is 2.

UPX's diagnostics are intended to be self-explanatory.

BUGS

Please report all bugs immediately to the authors.

AUTHORS

Markus F.X.J. Oberhumer <markus@oberhumer.com>
http://www.oberhumer.com

Laszlo Molnar <ezerotven+github@gmail.com>

John F. Reiser <jreiser@BitWagon.com>

Jens Medoch <jssg@users.sourceforge.net>

COPYRIGHT

Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer

Copyright (C) 1996-2023 Laszlo Molnar

Copyright (C) 2000-2023 John F. Reiser

Copyright (C) 2002-2023 Jens Medoch

UPX is distributed with full source code under the terms of the GNU General Public License v2+; either under the pure GPLv2+ (see the file COPYING), or (at your option) under the GPLv+2 with special exceptions and restrictions granting the free usage for all binaries including commercial programs (see the file LICENSE).

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

You should have received a copy of the UPX License Agreements along with this program; see the files COPYING and LICENSE. If not, visit the UPX home page.

================================================ FILE: bin/upx-4.1.0-win32/upx-doc.txt ================================================ NAME upx - compress or expand executable files SYNOPSIS upx [ *command* ] [ *options* ] *filename*... ABSTRACT The Ultimate Packer for eXecutables Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser https://upx.github.io UPX is a portable, extendable, high-performance executable packer for several different executable formats. It achieves an excellent compression ratio and offers **very** fast decompression. Your executables suffer no memory overhead or other drawbacks for most of the formats supported, because of in-place decompression. DISCLAIMER UPX comes with ABSOLUTELY NO WARRANTY; for details see the file COPYING. Please report all problems or suggestions to the authors. Thanks. SECURITY CONTEXT IMPORTANT NOTE: UPX inherits the security context of any files it handles. This means that packing, unpacking, or even testing or listing a file requires the same security considerations as actually executing the file. Use UPX on trusted files only! DESCRIPTION UPX is a versatile executable packer with the following features: - secure: as UPX is documented Open Source since many years any relevant Security/Antivirus software is able to peek inside UPX compressed apps to verify them - excellent compression ratio: typically compresses better than Zip, use UPX to decrease the size of your distribution ! - very fast decompression: more than 500 MB/sec on any reasonably modern machine - no memory overhead for your compressed executables for most of the supported formats because of in-place decompression - safe: you can list, test and unpack your executables. Also, a checksum of both the compressed and uncompressed file is maintained internally. - universal: UPX can pack a number of executable formats, including Windows programs and DLLs, macOS apps and Linux executables - portable: UPX is written in portable endian-neutral C++ - extendable: because of the class layout it's very easy to support new executable formats or add new compression algorithms - free: UPX is distributed with full source code under the GNU General Public License v2+, with special exceptions granting the free usage for commercial programs You probably understand now why we call UPX the "*ultimate*" executable packer. COMMANDS Compress This is the default operation, eg. upx yourfile.exe will compress the file specified on the command line. Decompress All UPX supported file formats can be unpacked using the -d switch, eg. upx -d yourfile.exe will uncompress the file you've just compressed. Test The -t command tests the integrity of the compressed and uncompressed data, eg. upx -t yourfile.exe check whether your file can be safely decompressed. Note, that this command doesn't check the whole file, only the part that will be uncompressed during program execution. This means that you should not use this command instead of a virus checker. List The -l command prints out some information about the compressed files specified on the command line as parameters, eg upx -l yourfile.exe shows the compressed / uncompressed size and the compression ratio of *yourfile.exe*. OPTIONS -q: be quiet, suppress warnings -q -q (or -qq): be very quiet, suppress errors -q -q -q (or -qqq): produce no output at all --help: prints the help --version: print the version of UPX --exact: when compressing, require to be able to get a byte-identical file after decompression with option -d. [NOTE: this is work in progress and is not supported for all formats yet. If you do care, as a workaround you can compress and then decompress your program a first time - any further compress-decompress steps should then yield byte-identical results as compared to the first decompressed version.] -k: keep backup files -o file: write output to file [ ...more docs need to be written... - type `upx --help' for now ] COMPRESSION LEVELS & TUNING UPX offers ten different compression levels from -1 to -9, and --best. The default compression level is -8 for files smaller than 512 KiB, and -7 otherwise. * Compression levels 1, 2 and 3 are pretty fast. * Compression levels 4, 5 and 6 achieve a good time/ratio performance. * Compression levels 7, 8 and 9 favor compression ratio over speed. * Compression level --best may take a long time. Note that compression level --best can be somewhat slow for large files, but you definitely should use it when releasing a final version of your program. Quick info for achieving the best compression ratio: * Try upx --brute --no-lzma myfile.exe or even upx --ultra-brute --no-lzma myfile.exe. * The option --lzma enables LZMA compression, which compresses better but is *significantly slower* at decompression. You probably do not want to use it for large files. (Note that --lzma is automatically enabled by --all-methods and --brute, use --no-lzma to override.) * Try if --overlay=strip works. * For win32/pe programs there's --strip-relocs=0. See notes below. OVERLAY HANDLING OPTIONS Info: An "overlay" means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections). UPX handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn't work with others, depending on how an application actually accesses this overlaid data. --overlay=copy Copy any extra data attached to the file. [DEFAULT] --overlay=strip Strip any overlay from the program instead of copying it. Be warned, this may make the compressed program crash or otherwise unusable. --overlay=skip Refuse to compress any program which has an overlay. ENVIRONMENT VARIABLE The environment variable UPX can hold a set of default options for UPX. These options are interpreted first and can be overwritten by explicit command line parameters. For example: for DOS/Windows: set UPX=-9 --compress-icons#0 for sh/ksh/zsh: UPX="-9 --compress-icons=0"; export UPX for csh/tcsh: setenv UPX "-9 --compress-icons=0" Under DOS/Windows you must use '#' instead of '=' when setting the environment variable because of a COMMAND.COM limitation. Not all of the options are valid in the environment variable - UPX will tell you. You can explicitly use the --no-env option to ignore the environment variable. NOTES FOR THE SUPPORTED EXECUTABLE FORMATS NOTES FOR ATARI/TOS This is the executable format used by the Atari ST/TT, a Motorola 68000 based personal computer which was popular in the late '80s. Support of this format is only because of nostalgic feelings of one of the authors and serves no practical purpose :-). See https://freemint.github.io for more info. Packed programs will be byte-identical to the original after uncompression. All debug information will be stripped, though. Extra options available for this executable format: --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. NOTES FOR BVMLINUZ/I386 Same as vmlinuz/i386. NOTES FOR DOS/COM Obviously UPX won't work with executables that want to read data from themselves (like some commandline utilities that ship with Win95/98/ME). Compressed programs only work on a 286+. Packed programs will be byte-identical to the original after uncompression. Maximum uncompressed size: ~65100 bytes. Extra options available for this executable format: --8086 Create an executable that works on any 8086 CPU. --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. NOTES FOR DOS/EXE dos/exe stands for all "normal" 16-bit DOS executables. Obviously UPX won't work with executables that want to read data from themselves (like some command line utilities that ship with Win95/98/ME). Compressed programs only work on a 286+. Extra options available for this executable format: --8086 Create an executable that works on any 8086 CPU. --no-reloc Use no relocation records in the exe header. --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. NOTES FOR DOS/SYS Compressed programs only work on a 286+. Packed programs will be byte-identical to the original after uncompression. Maximum uncompressed size: ~65350 bytes. Extra options available for this executable format: --8086 Create an executable that works on any 8086 CPU. --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. NOTES FOR DJGPP2/COFF First of all, it is recommended to use UPX *instead* of strip. strip has the very bad habit of replacing your stub with its own (outdated) version. Additionally UPX corrects a bug/feature in strip v2.8.x: it will fix the 4 KiB alignment of the stub. UPX includes the full functionality of stubify. This means it will automatically stubify your COFF files. Use the option --coff to disable this functionality (see below). UPX automatically handles Allegro packfiles. The DLM format (a rather exotic shared library extension) is not supported. Packed programs will be byte-identical to the original after uncompression. All debug information and trailing garbage will be stripped, though. Extra options available for this executable format: --coff Produce COFF output instead of EXE. By default UPX keeps your current stub. --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. NOTES FOR LINUX [general] Introduction Linux/386 support in UPX consists of 3 different executable formats, one optimized for ELF executables ("linux/elf386"), one optimized for shell scripts ("linux/sh386"), and one generic format ("linux/386"). We will start with a general discussion first, but please also read the relevant docs for each of the individual formats. Also, there is special support for bootable kernels - see the description of the vmlinuz/386 format. General user's overview Running a compressed executable program trades less space on a ``permanent'' storage medium (such as a hard disk, floppy disk, CD-ROM, flash memory, EPROM, etc.) for more space in one or more ``temporary'' storage media (such as RAM, swap space, /tmp, etc.). Running a compressed executable also requires some additional CPU cycles to generate the compressed executable in the first place, and to decompress it at each invocation. How much space is traded? It depends on the executable, but many programs save 30% to 50% of permanent disk space. How much CPU overhead is there? Again, it depends on the executable, but decompression speed generally is at least many megabytes per second, and frequently is limited by the speed of the underlying disk or network I/O. Depending on the statistics of usage and access, and the relative speeds of CPU, RAM, swap space, /tmp, and file system storage, then invoking and running a compressed executable can be faster than directly running the corresponding uncompressed program. The operating system might perform fewer expensive I/O operations to invoke the compressed program. Paging to or from swap space or /tmp might be faster than paging from the general file system. ``Medium-sized'' programs which access about 1/3 to 1/2 of their stored program bytes can do particularly well with compression. Small programs tend not to benefit as much because the absolute savings is less. Big programs tend not to benefit proportionally because each invocation may use only a small fraction of the program, yet UPX decompresses the entire program before invoking it. But in environments where disk or flash memory storage is limited, then compression may win anyway. Currently, executables compressed by UPX do not share RAM at runtime in the way that executables mapped from a file system do. As a result, if the same program is run simultaneously by more than one process, then using the compressed version will require more RAM and/or swap space. So, shell programs (bash, csh, etc.) and ``make'' might not be good candidates for compression. UPX recognizes three executable formats for Linux: Linux/elf386, Linux/sh386, and Linux/386. Linux/386 is the most generic format; it accommodates any file that can be executed. At runtime, the UPX decompression stub re-creates in /tmp a copy of the original file, and then the copy is (re-)executed with the same arguments. ELF binary executables prefer the Linux/elf386 format by default, because UPX decompresses them directly into RAM, uses only one exec, does not use space in /tmp, and does not use /proc. Shell scripts where the underlying shell accepts a ``-c'' argument can use the Linux/sh386 format. UPX decompresses the shell script into low memory, then maps the shell and passes the entire text of the script as an argument with a leading ``-c''. General benefits: - UPX can compress all executables, be it AOUT, ELF, libc4, libc5, libc6, Shell/Perl/Python/... scripts, standalone Java .class binaries, or whatever... All scripts and programs will work just as before. - Compressed programs are completely self-contained. No need for any external program. - UPX keeps your original program untouched. This means that after decompression you will have a byte-identical version, and you can use UPX as a file compressor just like gzip. [ Note that UPX maintains a checksum of the file internally, so it is indeed a reliable alternative. ] - As the stub only uses syscalls and isn't linked against libc it should run under any Linux configuration that can run ELF binaries. - For the same reason compressed executables should run under FreeBSD and other systems which can run Linux binaries. [ Please send feedback on this topic ] General drawbacks: - It is not advisable to compress programs which usually have many instances running (like `sh' or `make') because the common segments of compressed programs won't be shared any longer between different processes. - `ldd' and `size' won't show anything useful because all they see is the statically linked stub. Since version 0.82 the section headers are stripped from the UPX stub and `size' doesn't even recognize the file format. The file patches/patch-elfcode.h has a patch to fix this bug in `size' and other programs which use GNU BFD. General notes: - As UPX leaves your original program untouched it is advantageous to strip it before compression. - If you compress a script you will lose platform independence - this could be a problem if you are using NFS mounted disks. - Compression of suid, guid and sticky-bit programs is rejected because of possible security implications. - For the same reason there is no sense in making any compressed program suid. - Obviously UPX won't work with executables that want to read data from themselves. E.g., this might be a problem for Perl scripts which access their __DATA__ lines. - In case of internal errors the stub will abort with exitcode 127. Typical reasons for this to happen are that the program has somehow been modified after compression. Running `strace -o strace.log compressed_file' will tell you more. NOTES FOR LINUX/ELF386 Please read the general Linux description first. The linux/elf386 format decompresses directly into RAM, uses only one exec, does not use space in /tmp, and does not use /proc. Linux/elf386 is automatically selected for Linux ELF executables. Packed programs will be byte-identical to the original after uncompression. How it works: For ELF executables, UPX decompresses directly to memory, simulating the mapping that the operating system kernel uses during exec(), including the PT_INTERP program interpreter (if any). The brk() is set by a special PT_LOAD segment in the compressed executable itself. UPX then wipes the stack clean except for arguments, environment variables, and Elf_auxv entries (this is required by bugs in the startup code of /lib/ld-linux.so as of May 2000), and transfers control to the program interpreter or the e_entry address of the original executable. The UPX stub is about 1700 bytes long, partly written in assembler and only uses kernel syscalls. It is not linked against any libc. Specific drawbacks: - For linux/elf386 and linux/sh386 formats, you will be relying on RAM and swap space to hold all of the decompressed program during the lifetime of the process. If you already use most of your swap space, then you may run out. A system that is "out of memory" can become fragile. Many programs do not react gracefully when malloc() returns 0. With newer Linux kernels, the kernel may decide to kill some processes to regain memory, and you may not like the kernel's choice of which to kill. Running /usr/bin/top is one way to check on the usage of swap space. Extra options available for this executable format: (none) NOTES FOR LINUX/SH386 Please read the general Linux description first. Shell scripts where the underling shell accepts a ``-c'' argument can use the Linux/sh386 format. UPX decompresses the shell script into low memory, then maps the shell and passes the entire text of the script as an argument with a leading ``-c''. It does not use space in /tmp, and does not use /proc. Linux/sh386 is automatically selected for shell scripts that use a known shell. Packed programs will be byte-identical to the original after uncompression. How it works: For shell script executables (files beginning with "#!/" or "#! /") where the shell is known to accept "-c ", UPX decompresses the file into low memory, then maps the shell (and its PT_INTERP), and passes control to the shell with the entire decompressed file as the argument after "-c". Known shells are sh, ash, bash, bsh, csh, ksh, tcsh, pdksh. Restriction: UPX cannot use this method for shell scripts which use the one optional string argument after the shell name in the script (example: "#! /bin/sh option3\n".) The UPX stub is about 1700 bytes long, partly written in assembler and only uses kernel syscalls. It is not linked against any libc. Specific drawbacks: - For linux/elf386 and linux/sh386 formats, you will be relying on RAM and swap space to hold all of the decompressed program during the lifetime of the process. If you already use most of your swap space, then you may run out. A system that is "out of memory" can become fragile. Many programs do not react gracefully when malloc() returns 0. With newer Linux kernels, the kernel may decide to kill some processes to regain memory, and you may not like the kernel's choice of which to kill. Running /usr/bin/top is one way to check on the usage of swap space. Extra options available for this executable format: (none) NOTES FOR LINUX/386 Please read the general Linux description first. The generic linux/386 format decompresses to /tmp and needs /proc file system support. It starts the decompressed program via the execve() syscall. Linux/386 is only selected if the specialized linux/elf386 and linux/sh386 won't recognize a file. Packed programs will be byte-identical to the original after uncompression. How it works: For files which are not ELF and not a script for a known "-c" shell, UPX uses kernel execve(), which first requires decompressing to a temporary file in the file system. Interestingly - because of the good memory management of the Linux kernel - this often does not introduce a noticeable delay, and in fact there will be no disk access at all if you have enough free memory as the entire process takes places within the file system buffers. A compressed executable consists of the UPX stub and an overlay which contains the original program in a compressed form. The UPX stub is a statically linked ELF executable and does the following at program startup: 1) decompress the overlay to a temporary location in /tmp 2) open the temporary file for reading 3) try to delete the temporary file and start (execve) the uncompressed program in /tmp using /proc//fd/X as attained by step 2) 4) if that fails, fork off a subprocess to clean up and start the program in /tmp in the meantime The UPX stub is about 1700 bytes long, partly written in assembler and only uses kernel syscalls. It is not linked against any libc. Specific drawbacks: - You need additional free disk space for the uncompressed program in your /tmp directory. This program is deleted immediately after decompression, but you still need it for the full execution time of the program. - You must have /proc file system support as the stub wants to open /proc//exe and needs /proc//fd/X. This also means that you cannot compress programs that are used during the boot sequence before /proc is mounted. - Utilities like `top' will display numerical values in the process name field. This is because Linux computes the process name from the first argument of the last execve syscall (which is typically something like /proc//fd/3). - Because of temporary decompression to disk the decompression speed is not as fast as with the other executable formats. Still, I can see no noticeable delay when starting programs like my ~3 MiB emacs (which is less than 1 MiB when compressed :-). Extra options available for this executable format: --force-execve Force the use of the generic linux/386 "execve" format, i.e. do not try the linux/elf386 and linux/sh386 formats. NOTES FOR PS1/EXE This is the executable format used by the Sony PlayStation (PSone), a MIPS R3000 based gaming console which is popular since the late '90s. Support of this format is very similar to the Atari one, because of nostalgic feelings of one of the authors. Packed programs will be byte-identical to the original after uncompression, until further notice. Maximum uncompressed size: ~1.89 / ~7.60 MiB. Notes: - UPX creates as default a suitable executable for CD-Mastering and console transfer. For a CD-Master main executable you could also try the special option "--boot-only" as described below. It has been reported that upx packed executables are fully compatible with the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in Sony PlayStation (PSone) emulation mode. - Normally the packed files use the same memory areas like the uncompressed versions, so they will not override other memory areas while unpacking. If this isn't possible UPX will abort showing a 'packed data overlap' error. With the "--force" option UPX will relocate the loading address for the packed file, but this isn't a real problem if it is a single or the main executable. Extra options available for this executable format: --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --8-bit Uses 8 bit size compression [default: 32 bit] --8mib-ram PSone has 8 MiB ram available [default: 2 MiB] --boot-only This format is for main exes and CD-Mastering only ! It may slightly improve the compression ratio, decompression routines are faster than default ones. But it cannot be used for console transfer ! --no-align This option disables CD mode 2 data sector format alignment. May slightly improves the compression ratio, but the compressed executable will not boot from a CD. Use it for console transfer only ! NOTES FOR RTM32/PE and ARM/PE Same as win32/pe. NOTES FOR TMT/ADAM This format is used by the TMT Pascal compiler - see http://www.tmt.com/ . Extra options available for this executable format: --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. NOTES FOR VMLINUZ/386 The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed bootable Linux kernel image ("vmlinuz", "zImage", "bzImage"), gzip-decompress it and re-compress it with the UPX compression method. vmlinuz/386 is completely unrelated to the other Linux executable formats, and it does not share any of their drawbacks. Notes: - Be sure that "vmlinuz/386" or "bvmlinuz/386" is displayed during compression - otherwise a wrong executable format may have been used, and the kernel won't boot. Benefits: - Better compression (but note that the kernel was already compressed, so the improvement is not as large as with other formats). Still, the bytes saved may be essential for special needs like boot disks. For example, this is what I get for my 2.2.16 kernel: 1589708 vmlinux 641073 bzImage [original] 560755 bzImage.upx [compressed by "upx -9"] - Much faster decompression at kernel boot time (but kernel decompression speed is not really an issue these days). Drawbacks: (none) Extra options available for this executable format: --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. NOTES FOR WATCOM/LE UPX has been successfully tested with the following extenders: DOS4G, DOS4GW, PMODE/W, DOS32a, CauseWay. The WDOS/X extender is partly supported (for details see the file bugs BUGS). DLLs and the LX format are not supported. Extra options available for this executable format: --le Produce an unbound LE output instead of keeping the current stub. NOTES FOR WIN32/PE The PE support in UPX is quite stable now, but probably there are still some incompatibilities with some files. Because of the way UPX (and other packers for this format) works, you can see increased memory usage of your compressed files because the whole program is loaded into memory at startup. If you start several instances of huge compressed programs you're wasting memory because the common segments of the program won't get shared across the instances. On the other hand if you're compressing only smaller programs, or running only one instance of larger programs, then this penalty is smaller, but it's still there. If you're running executables from network, then compressed programs will load faster, and require less bandwidth during execution. DLLs are supported. But UPX compressed DLLs can not share common data and code when they got used by multiple applications. So compressing msvcrt.dll is a waste of memory, but compressing the dll plugins of a particular application may be a better idea. Screensavers are supported, with the restriction that the filename must end with ".scr" (as screensavers are handled slightly different than normal exe files). UPX compressed PE files have some minor memory overhead (usually in the 10 - 30 KiB range) which can be seen by specifying the "-i" command line switch during compression. Extra options available for this executable format: --compress-exports=0 Don't compress the export section. Use this if you plan to run the compressed program under Wine. --compress-exports=1 Compress the export section. [DEFAULT] Compression of the export section can improve the compression ratio quite a bit but may not work with all programs (like winword.exe). UPX never compresses the export section of a DLL regardless of this option. --compress-icons=0 Don't compress any icons. --compress-icons=1 Compress all but the first icon. --compress-icons=2 Compress all icons which are not in the first icon directory. [DEFAULT] --compress-icons=3 Compress all icons. --compress-resources=0 Don't compress any resources at all. --keep-resource=list Don't compress resources specified by the list. The members of the list are separated by commas. A list member has the following format: I. I is the type of the resource. Standard types must be specified as decimal numbers, user types can be specified by decimal IDs or strings. I is the identifier of the resource. It can be a decimal number or a string. For example: --keep-resource=2/MYBITMAP,5,6/12345 UPX won't compress the named bitmap resource "MYBITMAP", it leaves every dialog (5) resource uncompressed, and it won't touch the string table resource with identifier 12345. --force Force compression even when there is an unexpected value in a header field. Use with care. --strip-relocs=0 Don't strip relocation records. --strip-relocs=1 Strip relocation records. [DEFAULT] This option only works on executables with base address greater or equal to 0x400000. Usually the compressed files becomes smaller, but some files may become larger. Note that the resulting file will not work under Windows 3.x (Win32s). UPX never strips relocations from a DLL regardless of this option. --all-methods Compress the program several times, using all available compression methods. This may improve the compression ratio in some cases, but usually the default method gives the best results anyway. --all-filters Compress the program several times, using all available preprocessing filters. This may improve the compression ratio in some cases, but usually the default filter gives the best results anyway. DIAGNOSTICS Exit status is normally 0; if an error occurs, exit status is 1. If a warning occurs, exit status is 2. UPX's diagnostics are intended to be self-explanatory. BUGS Please report all bugs immediately to the authors. AUTHORS Markus F.X.J. Oberhumer http://www.oberhumer.com Laszlo Molnar John F. Reiser Jens Medoch COPYRIGHT Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2023 Laszlo Molnar Copyright (C) 2000-2023 John F. Reiser Copyright (C) 2002-2023 Jens Medoch UPX is distributed with full source code under the terms of the GNU General Public License v2+; either under the pure GPLv2+ (see the file COPYING), or (at your option) under the GPLv+2 with special exceptions and restrictions granting the free usage for all binaries including commercial programs (see the file LICENSE). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the UPX License Agreements along with this program; see the files COPYING and LICENSE. If not, visit the UPX home page. ================================================ FILE: bin/upx-4.1.0-win32/upx.1 ================================================ .\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "UPX 1" .TH UPX 1 "2023-08-08" "upx 4.1.0" " " .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" upx \- compress or expand executable files .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBupx\fR [\ \fIcommand\fR\ ] [\ \fIoptions\fR\ ] \fIfilename\fR... .SH "ABSTRACT" .IX Header "ABSTRACT" .Vb 3 \& The Ultimate Packer for eXecutables \& Copyright (c) 1996\-2023 Markus Oberhumer, Laszlo Molnar & John Reiser \& https://upx.github.io .Ve .PP \&\fB\s-1UPX\s0\fR is a portable, extendable, high-performance executable packer for several different executable formats. It achieves an excellent compression ratio and offers \fI*very*\fR fast decompression. Your executables suffer no memory overhead or other drawbacks for most of the formats supported, because of in-place decompression. .SH "DISCLAIMER" .IX Header "DISCLAIMER" \&\fB\s-1UPX\s0\fR comes with \s-1ABSOLUTELY NO WARRANTY\s0; for details see the file \s-1COPYING.\s0 .PP Please report all problems or suggestions to the authors. Thanks. .SH "SECURITY CONTEXT" .IX Header "SECURITY CONTEXT" \&\s-1IMPORTANT NOTE:\s0 \fB\s-1UPX\s0\fR inherits the security context of any files it handles. .PP This means that packing, unpacking, or even testing or listing a file requires the same security considerations as actually executing the file. .PP Use \fB\s-1UPX\s0\fR on trusted files only! .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fB\s-1UPX\s0\fR is a versatile executable packer with the following features: .PP .Vb 3 \& \- secure: as UPX is documented Open Source since many years any relevant \& Security/Antivirus software is able to peek inside UPX compressed \& apps to verify them \& \& \- excellent compression ratio: typically compresses better than Zip, \& use UPX to decrease the size of your distribution ! \& \& \- very fast decompression: more than 500 MB/sec on any reasonably modern \& machine \& \& \- no memory overhead for your compressed executables for most of the \& supported formats because of in\-place decompression \& \& \- safe: you can list, test and unpack your executables. \& Also, a checksum of both the compressed and uncompressed file is \& maintained internally. \& \& \- universal: UPX can pack a number of executable formats, including \& Windows programs and DLLs, macOS apps and Linux executables \& \& \- portable: UPX is written in portable endian\-neutral C++ \& \& \- extendable: because of the class layout it\*(Aqs very easy to support \& new executable formats or add new compression algorithms \& \& \- free: UPX is distributed with full source code under the GNU General \& Public License v2+, with special exceptions granting the free usage \& for commercial programs .Ve .PP You probably understand now why we call \fB\s-1UPX\s0\fR the "\fIultimate\fR" executable packer. .SH "COMMANDS" .IX Header "COMMANDS" .SS "Compress" .IX Subsection "Compress" This is the default operation, eg. \fBupx yourfile.exe\fR will compress the file specified on the command line. .SS "Decompress" .IX Subsection "Decompress" All \fB\s-1UPX\s0\fR supported file formats can be unpacked using the \fB\-d\fR switch, eg. \&\fBupx \-d yourfile.exe\fR will uncompress the file you've just compressed. .SS "Test" .IX Subsection "Test" The \fB\-t\fR command tests the integrity of the compressed and uncompressed data, eg. \fBupx \-t yourfile.exe\fR check whether your file can be safely decompressed. Note, that this command doesn't check the whole file, only the part that will be uncompressed during program execution. This means that you should not use this command instead of a virus checker. .SS "List" .IX Subsection "List" The \fB\-l\fR command prints out some information about the compressed files specified on the command line as parameters, eg \fBupx \-l yourfile.exe\fR shows the compressed / uncompressed size and the compression ratio of \&\fIyourfile.exe\fR. .SH "OPTIONS" .IX Header "OPTIONS" \&\fB\-q\fR: be quiet, suppress warnings .PP \&\fB\-q \-q\fR (or \fB\-qq\fR): be very quiet, suppress errors .PP \&\fB\-q \-q \-q\fR (or \fB\-qqq\fR): produce no output at all .PP \&\fB\-\-help\fR: prints the help .PP \&\fB\-\-version\fR: print the version of \fB\s-1UPX\s0\fR .PP \&\fB\-\-exact\fR: when compressing, require to be able to get a byte-identical file after decompression with option \fB\-d\fR. [\s-1NOTE:\s0 this is work in progress and is not supported for all formats yet. If you do care, as a workaround you can compress and then decompress your program a first time \- any further compress-decompress steps should then yield byte-identical results as compared to the first decompressed version.] .PP \&\fB\-k\fR: keep backup files .PP \&\fB\-o file\fR: write output to file .PP [ ...more docs need to be written... \- type `\fBupx \-\-help\fR' for now ] .SH "COMPRESSION LEVELS & TUNING" .IX Header "COMPRESSION LEVELS & TUNING" \&\fB\s-1UPX\s0\fR offers ten different compression levels from \fB\-1\fR to \fB\-9\fR, and \fB\-\-best\fR. The default compression level is \fB\-8\fR for files smaller than 512 KiB, and \fB\-7\fR otherwise. .IP "\(bu" 4 Compression levels 1, 2 and 3 are pretty fast. .IP "\(bu" 4 Compression levels 4, 5 and 6 achieve a good time/ratio performance. .IP "\(bu" 4 Compression levels 7, 8 and 9 favor compression ratio over speed. .IP "\(bu" 4 Compression level \fB\-\-best\fR may take a long time. .PP Note that compression level \fB\-\-best\fR can be somewhat slow for large files, but you definitely should use it when releasing a final version of your program. .PP Quick info for achieving the best compression ratio: .IP "\(bu" 4 Try \fBupx \-\-brute \-\-no\-lzma myfile.exe\fR or even \&\fBupx \-\-ultra\-brute \-\-no\-lzma myfile.exe\fR. .IP "\(bu" 4 The option \fB\-\-lzma\fR enables \s-1LZMA\s0 compression, which compresses better but is *significantly slower* at decompression. You probably do not want to use it for large files. .Sp (Note that \fB\-\-lzma\fR is automatically enabled by \fB\-\-all\-methods\fR and \&\fB\-\-brute\fR, use \fB\-\-no\-lzma\fR to override.) .IP "\(bu" 4 Try if \fB\-\-overlay=strip\fR works. .IP "\(bu" 4 For win32/pe programs there's \fB\-\-strip\-relocs=0\fR. See notes below. .SH "OVERLAY HANDLING OPTIONS" .IX Header "OVERLAY HANDLING OPTIONS" Info: An \*(L"overlay\*(R" means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections). .PP \&\fB\s-1UPX\s0\fR handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn't work with others, depending on how an application actually accesses this overlaid data. .PP .Vb 1 \& \-\-overlay=copy Copy any extra data attached to the file. [DEFAULT] \& \& \-\-overlay=strip Strip any overlay from the program instead of \& copying it. Be warned, this may make the compressed \& program crash or otherwise unusable. \& \& \-\-overlay=skip Refuse to compress any program which has an overlay. .Ve .SH "ENVIRONMENT VARIABLE" .IX Header "ENVIRONMENT VARIABLE" The environment variable \fB\s-1UPX\s0\fR can hold a set of default options for \fB\s-1UPX\s0\fR. These options are interpreted first and can be overwritten by explicit command line parameters. For example: .PP .Vb 3 \& for DOS/Windows: set UPX=\-9 \-\-compress\-icons#0 \& for sh/ksh/zsh: UPX="\-9 \-\-compress\-icons=0"; export UPX \& for csh/tcsh: setenv UPX "\-9 \-\-compress\-icons=0" .Ve .PP Under DOS/Windows you must use '#' instead of '=' when setting the environment variable because of a \s-1COMMAND.COM\s0 limitation. .PP Not all of the options are valid in the environment variable \- \&\fB\s-1UPX\s0\fR will tell you. .PP You can explicitly use the \fB\-\-no\-env\fR option to ignore the environment variable. .SH "NOTES FOR THE SUPPORTED EXECUTABLE FORMATS" .IX Header "NOTES FOR THE SUPPORTED EXECUTABLE FORMATS" .SS "\s-1NOTES FOR ATARI/TOS\s0" .IX Subsection "NOTES FOR ATARI/TOS" This is the executable format used by the Atari \s-1ST/TT,\s0 a Motorola 68000 based personal computer which was popular in the late '80s. Support of this format is only because of nostalgic feelings of one of the authors and serves no practical purpose :\-). See https://freemint.github.io for more info. .PP Packed programs will be byte-identical to the original after uncompression. All debug information will be stripped, though. .PP Extra options available for this executable format: .PP .Vb 4 \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. .Ve .SS "\s-1NOTES FOR BVMLINUZ/I386\s0" .IX Subsection "NOTES FOR BVMLINUZ/I386" Same as vmlinuz/i386. .SS "\s-1NOTES FOR DOS/COM\s0" .IX Subsection "NOTES FOR DOS/COM" Obviously \fB\s-1UPX\s0\fR won't work with executables that want to read data from themselves (like some commandline utilities that ship with Win95/98/ME). .PP Compressed programs only work on a 286+. .PP Packed programs will be byte-identical to the original after uncompression. .PP Maximum uncompressed size: ~65100 bytes. .PP Extra options available for this executable format: .PP .Vb 1 \& \-\-8086 Create an executable that works on any 8086 CPU. \& \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SS "\s-1NOTES FOR DOS/EXE\s0" .IX Subsection "NOTES FOR DOS/EXE" dos/exe stands for all \*(L"normal\*(R" 16\-bit \s-1DOS\s0 executables. .PP Obviously \fB\s-1UPX\s0\fR won't work with executables that want to read data from themselves (like some command line utilities that ship with Win95/98/ME). .PP Compressed programs only work on a 286+. .PP Extra options available for this executable format: .PP .Vb 1 \& \-\-8086 Create an executable that works on any 8086 CPU. \& \& \-\-no\-reloc Use no relocation records in the exe header. \& \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. .Ve .SS "\s-1NOTES FOR DOS/SYS\s0" .IX Subsection "NOTES FOR DOS/SYS" Compressed programs only work on a 286+. .PP Packed programs will be byte-identical to the original after uncompression. .PP Maximum uncompressed size: ~65350 bytes. .PP Extra options available for this executable format: .PP .Vb 1 \& \-\-8086 Create an executable that works on any 8086 CPU. \& \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SS "\s-1NOTES FOR DJGPP2/COFF\s0" .IX Subsection "NOTES FOR DJGPP2/COFF" First of all, it is recommended to use \fB\s-1UPX\s0\fR *instead* of \fBstrip\fR. strip has the very bad habit of replacing your stub with its own (outdated) version. Additionally \fB\s-1UPX\s0\fR corrects a bug/feature in strip v2.8.x: it will fix the 4 KiB alignment of the stub. .PP \&\fB\s-1UPX\s0\fR includes the full functionality of stubify. This means it will automatically stubify your \s-1COFF\s0 files. Use the option \fB\-\-coff\fR to disable this functionality (see below). .PP \&\fB\s-1UPX\s0\fR automatically handles Allegro packfiles. .PP The \s-1DLM\s0 format (a rather exotic shared library extension) is not supported. .PP Packed programs will be byte-identical to the original after uncompression. All debug information and trailing garbage will be stripped, though. .PP Extra options available for this executable format: .PP .Vb 2 \& \-\-coff Produce COFF output instead of EXE. By default \& UPX keeps your current stub. \& \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SS "\s-1NOTES FOR LINUX\s0 [general]" .IX Subsection "NOTES FOR LINUX [general]" Introduction .PP .Vb 4 \& Linux/386 support in UPX consists of 3 different executable formats, \& one optimized for ELF executables ("linux/elf386"), one optimized \& for shell scripts ("linux/sh386"), and one generic format \& ("linux/386"). \& \& We will start with a general discussion first, but please \& also read the relevant docs for each of the individual formats. \& \& Also, there is special support for bootable kernels \- see the \& description of the vmlinuz/386 format. .Ve .PP General user's overview .PP .Vb 7 \& Running a compressed executable program trades less space on a \& \`\`permanent\*(Aq\*(Aq storage medium (such as a hard disk, floppy disk, \& CD\-ROM, flash memory, EPROM, etc.) for more space in one or more \& \`\`temporary\*(Aq\*(Aq storage media (such as RAM, swap space, /tmp, etc.). \& Running a compressed executable also requires some additional CPU \& cycles to generate the compressed executable in the first place, \& and to decompress it at each invocation. \& \& How much space is traded? It depends on the executable, but many \& programs save 30% to 50% of permanent disk space. How much CPU \& overhead is there? Again, it depends on the executable, but \& decompression speed generally is at least many megabytes per second, \& and frequently is limited by the speed of the underlying disk \& or network I/O. \& \& Depending on the statistics of usage and access, and the relative \& speeds of CPU, RAM, swap space, /tmp, and file system storage, then \& invoking and running a compressed executable can be faster than \& directly running the corresponding uncompressed program. \& The operating system might perform fewer expensive I/O operations \& to invoke the compressed program. Paging to or from swap space \& or /tmp might be faster than paging from the general file system. \& \`\`Medium\-sized\*(Aq\*(Aq programs which access about 1/3 to 1/2 of their \& stored program bytes can do particularly well with compression. \& Small programs tend not to benefit as much because the absolute \& savings is less. Big programs tend not to benefit proportionally \& because each invocation may use only a small fraction of the program, \& yet UPX decompresses the entire program before invoking it. \& But in environments where disk or flash memory storage is limited, \& then compression may win anyway. \& \& Currently, executables compressed by UPX do not share RAM at runtime \& in the way that executables mapped from a file system do. As a \& result, if the same program is run simultaneously by more than one \& process, then using the compressed version will require more RAM and/or \& swap space. So, shell programs (bash, csh, etc.) and \`\`make\*(Aq\*(Aq \& might not be good candidates for compression. \& \& UPX recognizes three executable formats for Linux: Linux/elf386, \& Linux/sh386, and Linux/386. Linux/386 is the most generic format; \& it accommodates any file that can be executed. At runtime, the UPX \& decompression stub re\-creates in /tmp a copy of the original file, \& and then the copy is (re\-)executed with the same arguments. \& ELF binary executables prefer the Linux/elf386 format by default, \& because UPX decompresses them directly into RAM, uses only one \& exec, does not use space in /tmp, and does not use /proc. \& Shell scripts where the underlying shell accepts a \`\`\-c\*(Aq\*(Aq argument \& can use the Linux/sh386 format. UPX decompresses the shell script \& into low memory, then maps the shell and passes the entire text of the \& script as an argument with a leading \`\`\-c\*(Aq\*(Aq. .Ve .PP General benefits: .PP .Vb 4 \& \- UPX can compress all executables, be it AOUT, ELF, libc4, libc5, \& libc6, Shell/Perl/Python/... scripts, standalone Java .class \& binaries, or whatever... \& All scripts and programs will work just as before. \& \& \- Compressed programs are completely self\-contained. No need for \& any external program. \& \& \- UPX keeps your original program untouched. This means that \& after decompression you will have a byte\-identical version, \& and you can use UPX as a file compressor just like gzip. \& [ Note that UPX maintains a checksum of the file internally, \& so it is indeed a reliable alternative. ] \& \& \- As the stub only uses syscalls and isn\*(Aqt linked against libc it \& should run under any Linux configuration that can run ELF \& binaries. \& \& \- For the same reason compressed executables should run under \& FreeBSD and other systems which can run Linux binaries. \& [ Please send feedback on this topic ] .Ve .PP General drawbacks: .PP .Vb 4 \& \- It is not advisable to compress programs which usually have many \& instances running (like \`sh\*(Aq or \`make\*(Aq) because the common segments of \& compressed programs won\*(Aqt be shared any longer between different \& processes. \& \& \- \`ldd\*(Aq and \`size\*(Aq won\*(Aqt show anything useful because all they \& see is the statically linked stub. Since version 0.82 the section \& headers are stripped from the UPX stub and \`size\*(Aq doesn\*(Aqt even \& recognize the file format. The file patches/patch\-elfcode.h has a \& patch to fix this bug in \`size\*(Aq and other programs which use GNU BFD. .Ve .PP General notes: .PP .Vb 2 \& \- As UPX leaves your original program untouched it is advantageous \& to strip it before compression. \& \& \- If you compress a script you will lose platform independence \- \& this could be a problem if you are using NFS mounted disks. \& \& \- Compression of suid, guid and sticky\-bit programs is rejected \& because of possible security implications. \& \& \- For the same reason there is no sense in making any compressed \& program suid. \& \& \- Obviously UPX won\*(Aqt work with executables that want to read data \& from themselves. E.g., this might be a problem for Perl scripts \& which access their _\|_DATA_\|_ lines. \& \& \- In case of internal errors the stub will abort with exitcode 127. \& Typical reasons for this to happen are that the program has somehow \& been modified after compression. \& Running \`strace \-o strace.log compressed_file\*(Aq will tell you more. .Ve .SS "\s-1NOTES FOR LINUX/ELF386\s0" .IX Subsection "NOTES FOR LINUX/ELF386" Please read the general Linux description first. .PP The linux/elf386 format decompresses directly into \s-1RAM,\s0 uses only one exec, does not use space in /tmp, and does not use /proc. .PP Linux/elf386 is automatically selected for Linux \s-1ELF\s0 executables. .PP Packed programs will be byte-identical to the original after uncompression. .PP How it works: .PP .Vb 9 \& For ELF executables, UPX decompresses directly to memory, simulating \& the mapping that the operating system kernel uses during exec(), \& including the PT_INTERP program interpreter (if any). \& The brk() is set by a special PT_LOAD segment in the compressed \& executable itself. UPX then wipes the stack clean except for \& arguments, environment variables, and Elf_auxv entries (this is \& required by bugs in the startup code of /lib/ld\-linux.so as of \& May 2000), and transfers control to the program interpreter or \& the e_entry address of the original executable. \& \& The UPX stub is about 1700 bytes long, partly written in assembler \& and only uses kernel syscalls. It is not linked against any libc. .Ve .PP Specific drawbacks: .PP .Vb 9 \& \- For linux/elf386 and linux/sh386 formats, you will be relying on \& RAM and swap space to hold all of the decompressed program during \& the lifetime of the process. If you already use most of your swap \& space, then you may run out. A system that is "out of memory" \& can become fragile. Many programs do not react gracefully when \& malloc() returns 0. With newer Linux kernels, the kernel \& may decide to kill some processes to regain memory, and you \& may not like the kernel\*(Aqs choice of which to kill. Running \& /usr/bin/top is one way to check on the usage of swap space. .Ve .PP Extra options available for this executable format: .PP .Vb 1 \& (none) .Ve .SS "\s-1NOTES FOR LINUX/SH386\s0" .IX Subsection "NOTES FOR LINUX/SH386" Please read the general Linux description first. .PP Shell scripts where the underling shell accepts a ``\-c'' argument can use the Linux/sh386 format. \fB\s-1UPX\s0\fR decompresses the shell script into low memory, then maps the shell and passes the entire text of the script as an argument with a leading ``\-c''. It does not use space in /tmp, and does not use /proc. .PP Linux/sh386 is automatically selected for shell scripts that use a known shell. .PP Packed programs will be byte-identical to the original after uncompression. .PP How it works: .PP .Vb 8 \& For shell script executables (files beginning with "#!/" or "#! /") \& where the shell is known to accept "\-c ", UPX decompresses \& the file into low memory, then maps the shell (and its PT_INTERP), \& and passes control to the shell with the entire decompressed file \& as the argument after "\-c". Known shells are sh, ash, bash, bsh, csh, \& ksh, tcsh, pdksh. Restriction: UPX cannot use this method \& for shell scripts which use the one optional string argument after \& the shell name in the script (example: "#! /bin/sh option3\en".) \& \& The UPX stub is about 1700 bytes long, partly written in assembler \& and only uses kernel syscalls. It is not linked against any libc. .Ve .PP Specific drawbacks: .PP .Vb 9 \& \- For linux/elf386 and linux/sh386 formats, you will be relying on \& RAM and swap space to hold all of the decompressed program during \& the lifetime of the process. If you already use most of your swap \& space, then you may run out. A system that is "out of memory" \& can become fragile. Many programs do not react gracefully when \& malloc() returns 0. With newer Linux kernels, the kernel \& may decide to kill some processes to regain memory, and you \& may not like the kernel\*(Aqs choice of which to kill. Running \& /usr/bin/top is one way to check on the usage of swap space. .Ve .PP Extra options available for this executable format: .PP .Vb 1 \& (none) .Ve .SS "\s-1NOTES FOR LINUX/386\s0" .IX Subsection "NOTES FOR LINUX/386" Please read the general Linux description first. .PP The generic linux/386 format decompresses to /tmp and needs /proc file system support. It starts the decompressed program via the \fBexecve()\fR syscall. .PP Linux/386 is only selected if the specialized linux/elf386 and linux/sh386 won't recognize a file. .PP Packed programs will be byte-identical to the original after uncompression. .PP How it works: .PP .Vb 7 \& For files which are not ELF and not a script for a known "\-c" shell, \& UPX uses kernel execve(), which first requires decompressing to a \& temporary file in the file system. Interestingly \- \& because of the good memory management of the Linux kernel \- this \& often does not introduce a noticeable delay, and in fact there \& will be no disk access at all if you have enough free memory as \& the entire process takes places within the file system buffers. \& \& A compressed executable consists of the UPX stub and an overlay \& which contains the original program in a compressed form. \& \& The UPX stub is a statically linked ELF executable and does \& the following at program startup: \& \& 1) decompress the overlay to a temporary location in /tmp \& 2) open the temporary file for reading \& 3) try to delete the temporary file and start (execve) \& the uncompressed program in /tmp using /proc//fd/X as \& attained by step 2) \& 4) if that fails, fork off a subprocess to clean up and \& start the program in /tmp in the meantime \& \& The UPX stub is about 1700 bytes long, partly written in assembler \& and only uses kernel syscalls. It is not linked against any libc. .Ve .PP Specific drawbacks: .PP .Vb 4 \& \- You need additional free disk space for the uncompressed program \& in your /tmp directory. This program is deleted immediately after \& decompression, but you still need it for the full execution time \& of the program. \& \& \- You must have /proc file system support as the stub wants to open \& /proc//exe and needs /proc//fd/X. This also means that you \& cannot compress programs that are used during the boot sequence \& before /proc is mounted. \& \& \- Utilities like \`top\*(Aq will display numerical values in the process \& name field. This is because Linux computes the process name from \& the first argument of the last execve syscall (which is typically \& something like /proc//fd/3). \& \& \- Because of temporary decompression to disk the decompression speed \& is not as fast as with the other executable formats. Still, I can see \& no noticeable delay when starting programs like my ~3 MiB emacs (which \& is less than 1 MiB when compressed :\-). .Ve .PP Extra options available for this executable format: .PP .Vb 3 \& \-\-force\-execve Force the use of the generic linux/386 "execve" \& format, i.e. do not try the linux/elf386 and \& linux/sh386 formats. .Ve .SS "\s-1NOTES FOR PS1/EXE\s0" .IX Subsection "NOTES FOR PS1/EXE" This is the executable format used by the Sony PlayStation (PSone), a \s-1MIPS R3000\s0 based gaming console which is popular since the late '90s. Support of this format is very similar to the Atari one, because of nostalgic feelings of one of the authors. .PP Packed programs will be byte-identical to the original after uncompression, until further notice. .PP Maximum uncompressed size: ~1.89 / ~7.60 MiB. .PP Notes: .PP .Vb 6 \& \- UPX creates as default a suitable executable for CD\-Mastering \& and console transfer. For a CD\-Master main executable you could also try \& the special option "\-\-boot\-only" as described below. \& It has been reported that upx packed executables are fully compatible with \& the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in \& Sony PlayStation (PSone) emulation mode. \& \& \- Normally the packed files use the same memory areas like the uncompressed \& versions, so they will not override other memory areas while unpacking. \& If this isn\*(Aqt possible UPX will abort showing a \*(Aqpacked data overlap\*(Aq \& error. With the "\-\-force" option UPX will relocate the loading address \& for the packed file, but this isn\*(Aqt a real problem if it is a single or \& the main executable. .Ve .PP Extra options available for this executable format: .PP .Vb 4 \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-8\-bit Uses 8 bit size compression [default: 32 bit] \& \& \-\-8mib\-ram PSone has 8 MiB ram available [default: 2 MiB] \& \& \-\-boot\-only This format is for main exes and CD\-Mastering only ! \& It may slightly improve the compression ratio, \& decompression routines are faster than default ones. \& But it cannot be used for console transfer ! \& \& \-\-no\-align This option disables CD mode 2 data sector format \& alignment. May slightly improves the compression ratio, \& but the compressed executable will not boot from a CD. \& Use it for console transfer only ! .Ve .SS "\s-1NOTES FOR RTM32/PE\s0 and \s-1ARM/PE\s0" .IX Subsection "NOTES FOR RTM32/PE and ARM/PE" Same as win32/pe. .SS "\s-1NOTES FOR TMT/ADAM\s0" .IX Subsection "NOTES FOR TMT/ADAM" This format is used by the \s-1TMT\s0 Pascal compiler \- see http://www.tmt.com/ . .PP Extra options available for this executable format: .PP .Vb 4 \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SS "\s-1NOTES FOR VMLINUZ/386\s0" .IX Subsection "NOTES FOR VMLINUZ/386" The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed bootable Linux kernel image (\*(L"vmlinuz\*(R", \*(L"zImage\*(R", \*(L"bzImage\*(R"), gzip-decompress it and re-compress it with the \fB\s-1UPX\s0\fR compression method. .PP vmlinuz/386 is completely unrelated to the other Linux executable formats, and it does not share any of their drawbacks. .PP Notes: .PP .Vb 3 \& \- Be sure that "vmlinuz/386" or "bvmlinuz/386" is displayed \& during compression \- otherwise a wrong executable format \& may have been used, and the kernel won\*(Aqt boot. .Ve .PP Benefits: .PP .Vb 4 \& \- Better compression (but note that the kernel was already compressed, \& so the improvement is not as large as with other formats). \& Still, the bytes saved may be essential for special needs like \& boot disks. \& \& For example, this is what I get for my 2.2.16 kernel: \& 1589708 vmlinux \& 641073 bzImage [original] \& 560755 bzImage.upx [compressed by "upx \-9"] \& \& \- Much faster decompression at kernel boot time (but kernel \& decompression speed is not really an issue these days). .Ve .PP Drawbacks: .PP .Vb 1 \& (none) .Ve .PP Extra options available for this executable format: .PP .Vb 4 \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SS "\s-1NOTES FOR WATCOM/LE\s0" .IX Subsection "NOTES FOR WATCOM/LE" \&\fB\s-1UPX\s0\fR has been successfully tested with the following extenders: \s-1DOS4G, DOS4GW, PMODE/W,\s0 DOS32a, CauseWay. The \s-1WDOS/X\s0 extender is partly supported (for details see the file bugs \s-1BUGS\s0). .PP DLLs and the \s-1LX\s0 format are not supported. .PP Extra options available for this executable format: .PP .Vb 2 \& \-\-le Produce an unbound LE output instead of \& keeping the current stub. .Ve .SS "\s-1NOTES FOR WIN32/PE\s0" .IX Subsection "NOTES FOR WIN32/PE" The \s-1PE\s0 support in \fB\s-1UPX\s0\fR is quite stable now, but probably there are still some incompatibilities with some files. .PP Because of the way \fB\s-1UPX\s0\fR (and other packers for this format) works, you can see increased memory usage of your compressed files because the whole program is loaded into memory at startup. If you start several instances of huge compressed programs you're wasting memory because the common segments of the program won't get shared across the instances. On the other hand if you're compressing only smaller programs, or running only one instance of larger programs, then this penalty is smaller, but it's still there. .PP If you're running executables from network, then compressed programs will load faster, and require less bandwidth during execution. .PP DLLs are supported. But \s-1UPX\s0 compressed DLLs can not share common data and code when they got used by multiple applications. So compressing msvcrt.dll is a waste of memory, but compressing the dll plugins of a particular application may be a better idea. .PP Screensavers are supported, with the restriction that the filename must end with \*(L".scr\*(R" (as screensavers are handled slightly different than normal exe files). .PP \&\s-1UPX\s0 compressed \s-1PE\s0 files have some minor memory overhead (usually in the 10 \- 30 KiB range) which can be seen by specifying the \*(L"\-i\*(R" command line switch during compression. .PP Extra options available for this executable format: .PP .Vb 9 \& \-\-compress\-exports=0 Don\*(Aqt compress the export section. \& Use this if you plan to run the compressed \& program under Wine. \& \-\-compress\-exports=1 Compress the export section. [DEFAULT] \& Compression of the export section can improve the \& compression ratio quite a bit but may not work \& with all programs (like winword.exe). \& UPX never compresses the export section of a DLL \& regardless of this option. \& \& \-\-compress\-icons=0 Don\*(Aqt compress any icons. \& \-\-compress\-icons=1 Compress all but the first icon. \& \-\-compress\-icons=2 Compress all icons which are not in the \& first icon directory. [DEFAULT] \& \-\-compress\-icons=3 Compress all icons. \& \& \-\-compress\-resources=0 Don\*(Aqt compress any resources at all. \& \& \-\-keep\-resource=list Don\*(Aqt compress resources specified by the list. \& The members of the list are separated by commas. \& A list member has the following format: I. \& I is the type of the resource. Standard types \& must be specified as decimal numbers, user types can be \& specified by decimal IDs or strings. I is the \& identifier of the resource. It can be a decimal number \& or a string. For example: \& \& \-\-keep\-resource=2/MYBITMAP,5,6/12345 \& \& UPX won\*(Aqt compress the named bitmap resource "MYBITMAP", \& it leaves every dialog (5) resource uncompressed, and \& it won\*(Aqt touch the string table resource with identifier \& 12345. \& \& \-\-force Force compression even when there is an \& unexpected value in a header field. \& Use with care. \& \& \-\-strip\-relocs=0 Don\*(Aqt strip relocation records. \& \-\-strip\-relocs=1 Strip relocation records. [DEFAULT] \& This option only works on executables with base \& address greater or equal to 0x400000. Usually the \& compressed files becomes smaller, but some files \& may become larger. Note that the resulting file will \& not work under Windows 3.x (Win32s). \& UPX never strips relocations from a DLL \& regardless of this option. \& \& \-\-all\-methods Compress the program several times, using all \& available compression methods. This may improve \& the compression ratio in some cases, but usually \& the default method gives the best results anyway. \& \& \-\-all\-filters Compress the program several times, using all \& available preprocessing filters. This may improve \& the compression ratio in some cases, but usually \& the default filter gives the best results anyway. .Ve .SH "DIAGNOSTICS" .IX Header "DIAGNOSTICS" Exit status is normally 0; if an error occurs, exit status is 1. If a warning occurs, exit status is 2. .PP \&\fB\s-1UPX\s0\fR's diagnostics are intended to be self-explanatory. .SH "BUGS" .IX Header "BUGS" Please report all bugs immediately to the authors. .SH "AUTHORS" .IX Header "AUTHORS" .Vb 2 \& Markus F.X.J. Oberhumer \& http://www.oberhumer.com \& \& Laszlo Molnar \& \& John F. Reiser \& \& Jens Medoch .Ve .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (C) 1996\-2023 Markus Franz Xaver Johannes Oberhumer .PP Copyright (C) 1996\-2023 Laszlo Molnar .PP Copyright (C) 2000\-2023 John F. Reiser .PP Copyright (C) 2002\-2023 Jens Medoch .PP \&\fB\s-1UPX\s0\fR is distributed with full source code under the terms of the \&\s-1GNU\s0 General Public License v2+; either under the pure GPLv2+ (see the file \s-1COPYING\s0), or (at your option) under the GPLv+2 with special exceptions and restrictions granting the free usage for all binaries including commercial programs (see the file \s-1LICENSE\s0). .PP This program is distributed in the hope that it will be useful, but \s-1WITHOUT ANY WARRANTY\s0; without even the implied warranty of \&\s-1MERCHANTABILITY\s0 or \s-1FITNESS FOR A PARTICULAR PURPOSE.\s0 .PP You should have received a copy of the \s-1UPX\s0 License Agreements along with this program; see the files \s-1COPYING\s0 and \s-1LICENSE.\s0 If not, visit the \s-1UPX\s0 home page. ================================================ FILE: common/jsoncpp/json/autolink.h ================================================ #ifndef JSON_AUTOLINK_H_INCLUDED # define JSON_AUTOLINK_H_INCLUDED # include "config.h" # ifdef JSON_IN_CPPTL # include # endif # if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) # define CPPTL_AUTOLINK_NAME "json" # undef CPPTL_AUTOLINK_DLL # ifdef JSON_DLL # define CPPTL_AUTOLINK_DLL # endif # include "autolink.h" # endif #endif // JSON_AUTOLINK_H_INCLUDED ================================================ FILE: common/jsoncpp/json/config.h ================================================ #ifndef JSON_CONFIG_H_INCLUDED # define JSON_CONFIG_H_INCLUDED /// If defined, indicates that json library is embedded in CppTL library. //# define JSON_IN_CPPTL 1 /// If defined, indicates that json may leverage CppTL library //# define JSON_USE_CPPTL 1 /// If defined, indicates that cpptl vector based map should be used instead of std::map /// as Value container. //# define JSON_USE_CPPTL_SMALLMAP 1 /// If defined, indicates that Json specific container should be used /// (hash table & simple deque container with customizable allocator). /// THIS FEATURE IS STILL EXPERIMENTAL! //# define JSON_VALUE_USE_INTERNAL_MAP 1 /// Force usage of standard new/malloc based allocator instead of memory pool based allocator. /// The memory pools allocator used optimization (initializing Value and ValueInternalLink /// as if it was a POD) that may cause some validation tool to report errors. /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 /// If defined, indicates that Json use exception to report invalid type manipulation /// instead of C assert macro. # define JSON_USE_EXCEPTION 1 # ifdef JSON_IN_CPPTL # include # ifndef JSON_USE_CPPTL # define JSON_USE_CPPTL 1 # endif # endif # ifdef JSON_IN_CPPTL # define JSON_API CPPTL_API # elif defined(JSON_DLL_BUILD) # define JSON_API __declspec(dllexport) # elif defined(JSON_DLL) # define JSON_API __declspec(dllimport) # else # define JSON_API # endif #endif // JSON_CONFIG_H_INCLUDED ================================================ FILE: common/jsoncpp/json/features.h ================================================ #ifndef CPPTL_JSON_FEATURES_H_INCLUDED # define CPPTL_JSON_FEATURES_H_INCLUDED # include "forwards.h" namespace Json { /** \brief Configuration passed to reader and writer. * This configuration object can be used to force the Reader or Writer * to behave in a standard conforming way. */ class JSON_API Features { public: /** \brief A configuration that allows all features and assumes all strings are UTF-8. * - C & C++ comments are allowed * - Root object can be any JSON value * - Assumes Value strings are encoded in UTF-8 */ static Features all(); /** \brief A configuration that is strictly compatible with the JSON specification. * - Comments are forbidden. * - Root object must be either an array or an object value. * - Assumes Value strings are encoded in UTF-8 */ static Features strictMode(); /** \brief Initialize the configuration like JsonConfig::allFeatures; */ Features(); /// \c true if comments are allowed. Default: \c true. bool allowComments_; /// \c true if root must be either an array or an object value. Default: \c false. bool strictRoot_; }; } // namespace Json #endif // CPPTL_JSON_FEATURES_H_INCLUDED ================================================ FILE: common/jsoncpp/json/forwards.h ================================================ #ifndef JSON_FORWARDS_H_INCLUDED # define JSON_FORWARDS_H_INCLUDED # include "config.h" namespace Json { // writer.h class FastWriter; class StyledWriter; // reader.h class Reader; // features.h class Features; // value.h typedef int Int; typedef unsigned int UInt; class StaticString; class Path; class PathArgument; class Value; class ValueIteratorBase; class ValueIterator; class ValueConstIterator; #ifdef JSON_VALUE_USE_INTERNAL_MAP class ValueAllocator; class ValueMapAllocator; class ValueInternalLink; class ValueInternalArray; class ValueInternalMap; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP } // namespace Json #endif // JSON_FORWARDS_H_INCLUDED ================================================ FILE: common/jsoncpp/json/json.h ================================================ #ifndef JSON_JSON_H_INCLUDED # define JSON_JSON_H_INCLUDED # include "autolink.h" # include "value.h" # include "reader.h" # include "writer.h" # include "features.h" #endif // JSON_JSON_H_INCLUDED ================================================ FILE: common/jsoncpp/json/reader.h ================================================ #ifndef CPPTL_JSON_READER_H_INCLUDED # define CPPTL_JSON_READER_H_INCLUDED # include "features.h" # include "value.h" # include # include # include # include namespace Json { /** \brief Unserialize a JSON document into a Value. * */ class JSON_API Reader { public: typedef char Char; typedef const Char *Location; /** \brief Constructs a Reader allowing all features * for parsing. */ Reader(); /** \brief Constructs a Reader allowing the specified feature set * for parsing. */ Reader( const Features &features ); /** \brief Read a Value from a JSON document. * \param document UTF-8 encoded string containing the document to read. * \param root [out] Contains the root value of the document if it was * successfully parsed. * \param collectComments \c true to collect comment and allow writing them back during * serialization, \c false to discard comments. * This parameter is ignored if Features::allowComments_ * is \c false. * \return \c true if the document was successfully parsed, \c false if an error occurred. */ bool parse( const std::string &document, Value &root, bool collectComments = true ); /** \brief Read a Value from a JSON document. * \param document UTF-8 encoded string containing the document to read. * \param root [out] Contains the root value of the document if it was * successfully parsed. * \param collectComments \c true to collect comment and allow writing them back during * serialization, \c false to discard comments. * This parameter is ignored if Features::allowComments_ * is \c false. * \return \c true if the document was successfully parsed, \c false if an error occurred. */ bool parse( const char *beginDoc, const char *endDoc, Value &root, bool collectComments = true ); /// \brief Parse from input stream. /// \see Json::operator>>(std::istream&, Json::Value&). bool parse( std::istream &is, Value &root, bool collectComments = true ); /** \brief Returns a user friendly string that list errors in the parsed document. * \return Formatted error message with the list of errors with their location in * the parsed document. An empty string is returned if no error occurred * during parsing. */ std::string getFormatedErrorMessages() const; private: enum TokenType { tokenEndOfStream = 0, tokenObjectBegin, tokenObjectEnd, tokenArrayBegin, tokenArrayEnd, tokenString, tokenNumber, tokenTrue, tokenFalse, tokenNull, tokenArraySeparator, tokenMemberSeparator, tokenComment, tokenError }; class Token { public: TokenType type_; Location start_; Location end_; }; class ErrorInfo { public: Token token_; std::string message_; Location extra_; }; typedef std::deque Errors; bool expectToken( TokenType type, Token &token, const char *message ); bool readToken( Token &token ); void skipSpaces(); bool match( Location pattern, int patternLength ); bool readComment(); bool readCStyleComment(); bool readCppStyleComment(); bool readString(); void readNumber(); bool readValue(); bool readObject( Token &token ); bool readArray( Token &token ); bool decodeNumber( Token &token ); bool decodeString( Token &token ); bool decodeString( Token &token, std::string &decoded ); bool decodeDouble( Token &token ); bool decodeUnicodeCodePoint( Token &token, Location ¤t, Location end, unsigned int &unicode ); bool decodeUnicodeEscapeSequence( Token &token, Location ¤t, Location end, unsigned int &unicode ); bool addError( const std::string &message, Token &token, Location extra = 0 ); bool recoverFromError( TokenType skipUntilToken ); bool addErrorAndRecover( const std::string &message, Token &token, TokenType skipUntilToken ); void skipUntilSpace(); Value ¤tValue(); Char getNextChar(); void getLocationLineAndColumn( Location location, int &line, int &column ) const; std::string getLocationLineAndColumn( Location location ) const; void addComment( Location begin, Location end, CommentPlacement placement ); void skipCommentTokens( Token &token ); typedef std::stack Nodes; Nodes nodes_; Errors errors_; std::string document_; Location begin_; Location end_; Location current_; Location lastValueEnd_; Value *lastValue_; std::string commentsBefore_; Features features_; bool collectComments_; }; /** \brief Read from 'sin' into 'root'. Always keep comments from the input JSON. This can be used to read a file into a particular sub-object. For example: \code Json::Value root; cin >> root["dir"]["file"]; cout << root; \endcode Result: \verbatim { "dir": { "file": { // The input stream JSON would be nested here. } } } \endverbatim \throw std::exception on parse error. \see Json::operator<<() */ std::istream& operator>>( std::istream&, Value& ); } // namespace Json #endif // CPPTL_JSON_READER_H_INCLUDED ================================================ FILE: common/jsoncpp/json/value.h ================================================ #ifndef CPPTL_JSON_H_INCLUDED # define CPPTL_JSON_H_INCLUDED # include "forwards.h" # include # include # ifndef JSON_USE_CPPTL_SMALLMAP # include # else # include # endif # ifdef JSON_USE_CPPTL # include # endif /** \brief JSON (JavaScript Object Notation). */ namespace Json { /** \brief Type of the value held by a Value object. */ enum ValueType { nullValue = 0, ///< 'null' value intValue, ///< signed integer value uintValue, ///< unsigned integer value realValue, ///< double value stringValue, ///< UTF-8 string value booleanValue, ///< bool value arrayValue, ///< array value (ordered list) objectValue ///< object value (collection of name/value pairs). }; enum CommentPlacement { commentBefore = 0, ///< a comment placed on the line before a value commentAfterOnSameLine, ///< a comment just after a value on the same line commentAfter, ///< a comment on the line after a value (only make sense for root value) numberOfCommentPlacement }; //# ifdef JSON_USE_CPPTL // typedef CppTL::AnyEnumerator EnumMemberNames; // typedef CppTL::AnyEnumerator EnumValues; //# endif /** \brief Lightweight wrapper to tag static string. * * Value constructor and objectValue member assignement takes advantage of the * StaticString and avoid the cost of string duplication when storing the * string or the member name. * * Example of usage: * \code * Json::Value aValue( StaticString("some text") ); * Json::Value object; * static const StaticString code("code"); * object[code] = 1234; * \endcode */ class JSON_API StaticString { public: explicit StaticString( const char *czstring ) : str_( czstring ) { } operator const char *() const { return str_; } const char *c_str() const { return str_; } private: const char *str_; }; /** \brief Represents a JSON value. * * This class is a discriminated union wrapper that can represents a: * - signed integer [range: Value::minInt - Value::maxInt] * - unsigned integer (range: 0 - Value::maxUInt) * - double * - UTF-8 string * - boolean * - 'null' * - an ordered list of Value * - collection of name/value pairs (javascript object) * * The type of the held value is represented by a #ValueType and * can be obtained using type(). * * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. * Non const methods will automatically create the a #nullValue element * if it does not exist. * The sequence of an #arrayValue will be automatically resize and initialized * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. * * The get() methods can be used to obtanis default value in the case the required element * does not exist. * * It is possible to iterate over the list of a #objectValue values using * the getMemberNames() method. */ class JSON_API Value { friend class ValueIteratorBase; # ifdef JSON_VALUE_USE_INTERNAL_MAP friend class ValueInternalLink; friend class ValueInternalMap; # endif public: typedef std::vector Members; typedef ValueIterator iterator; typedef ValueConstIterator const_iterator; typedef Json::UInt UInt; typedef Json::Int Int; typedef UInt ArrayIndex; static const Value null; static const Int minInt; static const Int maxInt; static const UInt maxUInt; private: #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION # ifndef JSON_VALUE_USE_INTERNAL_MAP class CZString { public: enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy }; CZString( int index ); CZString( const char *cstr, DuplicationPolicy allocate ); CZString( const CZString &other ); ~CZString(); CZString &operator =( const CZString &other ); bool operator<( const CZString &other ) const; bool operator==( const CZString &other ) const; int index() const; const char *c_str() const; bool isStaticString() const; private: void swap( CZString &other ); const char *cstr_; int index_; }; public: # ifndef JSON_USE_CPPTL_SMALLMAP typedef std::map ObjectValues; # else typedef CppTL::SmallMap ObjectValues; # endif // ifndef JSON_USE_CPPTL_SMALLMAP # endif // ifndef JSON_VALUE_USE_INTERNAL_MAP #endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION public: /** \brief Create a default Value of the given type. This is a very useful constructor. To create an empty array, pass arrayValue. To create an empty object, pass objectValue. Another Value can then be set to this one by assignment. This is useful since clear() and resize() will not alter types. Examples: \code Json::Value null_value; // null Json::Value arr_value(Json::arrayValue); // [] Json::Value obj_value(Json::objectValue); // {} \endcode */ Value( ValueType type = nullValue ); Value( Int value ); Value( UInt value ); Value( double value ); Value( const char *value ); Value( const char *beginValue, const char *endValue ); /** \brief Constructs a value from a static string. * Like other value string constructor but do not duplicate the string for * internal storage. The given string must remain alive after the call to this * constructor. * Example of usage: * \code * Json::Value aValue( StaticString("some text") ); * \endcode */ Value( const StaticString &value ); Value( const std::string &value ); # ifdef JSON_USE_CPPTL Value( const CppTL::ConstString &value ); # endif Value( bool value ); Value( const Value &other ); ~Value(); Value &operator=( const Value &other ); /// Swap values. /// \note Currently, comments are intentionally not swapped, for /// both logic and efficiency. void swap( Value &other ); ValueType type() const; bool operator <( const Value &other ) const; bool operator <=( const Value &other ) const; bool operator >=( const Value &other ) const; bool operator >( const Value &other ) const; bool operator ==( const Value &other ) const; bool operator !=( const Value &other ) const; int compare( const Value &other ); const char *asCString() const; std::string asString() const; # ifdef JSON_USE_CPPTL CppTL::ConstString asConstString() const; # endif Int asInt() const; UInt asUInt() const; double asDouble() const; bool asBool() const; bool isNull() const; bool isBool() const; bool isInt() const; bool isUInt() const; bool isIntegral() const; bool isDouble() const; bool isNumeric() const; bool isString() const; bool isArray() const; bool isObject() const; bool isConvertibleTo( ValueType other ) const; /// Number of values in array or object UInt size() const; /// \brief Return true if empty array, empty object, or null; /// otherwise, false. bool empty() const; /// Return isNull() bool operator!() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue /// \post type() is unchanged void clear(); /// Resize the array to size elements. /// New elements are initialized to null. /// May only be called on nullValue or arrayValue. /// \pre type() is arrayValue or nullValue /// \post type() is arrayValue void resize( UInt size ); /// Access an array element (zero based index ). /// If the array contains less than index element, then null value are inserted /// in the array so that its size is index+1. /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) Value &operator[]( UInt index ); /// Access an array element (zero based index ) /// (You may need to say 'value[0u]' to get your compiler to distinguish /// this from the operator[] which takes a string.) const Value &operator[]( UInt index ) const; /// If the array contains at least index+1 elements, returns the element value, /// otherwise returns defaultValue. Value get( UInt index, const Value &defaultValue ) const; /// Return true if index < size(). bool isValidIndex( UInt index ) const; /// \brief Append value to array at the end. /// /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value &append( const Value &value ); /// Access an object value by name, create a null member if it does not exist. Value &operator[]( const char *key ); /// Access an object value by name, returns null if there is no member with that name. const Value &operator[]( const char *key ) const; /// Access an object value by name, create a null member if it does not exist. Value &operator[]( const std::string &key ); /// Access an object value by name, returns null if there is no member with that name. const Value &operator[]( const std::string &key ) const; /** \brief Access an object value by name, create a null member if it does not exist. * If the object as no entry for that name, then the member name used to store * the new entry is not duplicated. * Example of use: * \code * Json::Value object; * static const StaticString code("code"); * object[code] = 1234; * \endcode */ Value &operator[]( const StaticString &key ); # ifdef JSON_USE_CPPTL /// Access an object value by name, create a null member if it does not exist. Value &operator[]( const CppTL::ConstString &key ); /// Access an object value by name, returns null if there is no member with that name. const Value &operator[]( const CppTL::ConstString &key ) const; # endif /// Return the member named key if it exist, defaultValue otherwise. Value get( const char *key, const Value &defaultValue ) const; /// Return the member named key if it exist, defaultValue otherwise. Value get( const std::string &key, const Value &defaultValue ) const; # ifdef JSON_USE_CPPTL /// Return the member named key if it exist, defaultValue otherwise. Value get( const CppTL::ConstString &key, const Value &defaultValue ) const; # endif /// \brief Remove and return the named member. /// /// Do nothing if it did not exist. /// \return the removed Value, or null. /// \pre type() is objectValue or nullValue /// \post type() is unchanged Value removeMember( const char* key ); /// Same as removeMember(const char*) Value removeMember( const std::string &key ); /// Return true if the object has a member named key. bool isMember( const char *key ) const; /// Return true if the object has a member named key. bool isMember( const std::string &key ) const; # ifdef JSON_USE_CPPTL /// Return true if the object has a member named key. bool isMember( const CppTL::ConstString &key ) const; # endif /// \brief Return a list of the member names. /// /// If null, return an empty list. /// \pre type() is objectValue or nullValue /// \post if type() was nullValue, it remains nullValue Members getMemberNames() const; //# ifdef JSON_USE_CPPTL // EnumMemberNames enumMemberNames() const; // EnumValues enumValues() const; //# endif /// Comments must be //... or /* ... */ void setComment( const char *comment, CommentPlacement placement ); /// Comments must be //... or /* ... */ void setComment( const std::string &comment, CommentPlacement placement ); bool hasComment( CommentPlacement placement ) const; /// Include delimiters and embedded newlines. std::string getComment( CommentPlacement placement ) const; std::string toStyledString() const; const_iterator begin() const; const_iterator end() const; iterator begin(); iterator end(); void SetSrcString(const std::string &strSrc) { strSrc_ = strSrc; } std::string GetSrcString() { return strSrc_; } private: Value &resolveReference( const char *key, bool isStatic ); # ifdef JSON_VALUE_USE_INTERNAL_MAP inline bool isItemAvailable() const { return itemIsUsed_ == 0; } inline void setItemUsed( bool isUsed = true ) { itemIsUsed_ = isUsed ? 1 : 0; } inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; } inline void setMemberNameIsStatic( bool isStatic ) { memberNameIsStatic_ = isStatic ? 1 : 0; } # endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP private: struct CommentInfo { CommentInfo(); ~CommentInfo(); void setComment( const char *text ); char *comment_; }; //struct MemberNamesTransform //{ // typedef const char *result_type; // const char *operator()( const CZString &name ) const // { // return name.c_str(); // } //}; union ValueHolder { Int int_; UInt uint_; double real_; bool bool_; char *string_; # ifdef JSON_VALUE_USE_INTERNAL_MAP ValueInternalArray *array_; ValueInternalMap *map_; #else ObjectValues *map_; # endif } value_; ValueType type_ : 8; int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. # ifdef JSON_VALUE_USE_INTERNAL_MAP unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container. int memberNameIsStatic_ : 1; // used by the ValueInternalMap container. # endif CommentInfo *comments_; std::string strSrc_; }; /** \brief Experimental and untested: represents an element of the "path" to access a node. */ class PathArgument { public: friend class Path; PathArgument(); PathArgument( UInt index ); PathArgument( const char *key ); PathArgument( const std::string &key ); private: enum Kind { kindNone = 0, kindIndex, kindKey }; std::string key_; UInt index_; Kind kind_; }; /** \brief Experimental and untested: represents a "path" to access a node. * * Syntax: * - "." => root node * - ".[n]" => elements at index 'n' of root node (an array value) * - ".name" => member named 'name' of root node (an object value) * - ".name1.name2.name3" * - ".[0][1][2].name1[3]" * - ".%" => member name is provided as parameter * - ".[%]" => index is provied as parameter */ class Path { public: Path( const std::string &path, const PathArgument &a1 = PathArgument(), const PathArgument &a2 = PathArgument(), const PathArgument &a3 = PathArgument(), const PathArgument &a4 = PathArgument(), const PathArgument &a5 = PathArgument() ); const Value &resolve( const Value &root ) const; Value resolve( const Value &root, const Value &defaultValue ) const; /// Creates the "path" to access the specified node and returns a reference on the node. Value &make( Value &root ) const; private: typedef std::vector InArgs; typedef std::vector Args; void makePath( const std::string &path, const InArgs &in ); void addPathInArg( const std::string &path, const InArgs &in, InArgs::const_iterator &itInArg, PathArgument::Kind kind ); void invalidPath( const std::string &path, int location ); Args args_; }; /** \brief Experimental do not use: Allocator to customize member name and string value memory management done by Value. * * - makeMemberName() and releaseMemberName() are called to respectively duplicate and * free an Json::objectValue member name. * - duplicateStringValue() and releaseStringValue() are called similarly to * duplicate and free a Json::stringValue value. */ class ValueAllocator { public: enum { unknown = (unsigned)-1 }; virtual ~ValueAllocator(); virtual char *makeMemberName( const char *memberName ) = 0; virtual void releaseMemberName( char *memberName ) = 0; virtual char *duplicateStringValue( const char *value, unsigned int length = unknown ) = 0; virtual void releaseStringValue( char *value ) = 0; }; #ifdef JSON_VALUE_USE_INTERNAL_MAP /** \brief Allocator to customize Value internal map. * Below is an example of a simple implementation (default implementation actually * use memory pool for speed). * \code class DefaultValueMapAllocator : public ValueMapAllocator { public: // overridden from ValueMapAllocator virtual ValueInternalMap *newMap() { return new ValueInternalMap(); } virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) { return new ValueInternalMap( other ); } virtual void destructMap( ValueInternalMap *map ) { delete map; } virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) { return new ValueInternalLink[size]; } virtual void releaseMapBuckets( ValueInternalLink *links ) { delete [] links; } virtual ValueInternalLink *allocateMapLink() { return new ValueInternalLink(); } virtual void releaseMapLink( ValueInternalLink *link ) { delete link; } }; * \endcode */ class JSON_API ValueMapAllocator { public: virtual ~ValueMapAllocator(); virtual ValueInternalMap *newMap() = 0; virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0; virtual void destructMap( ValueInternalMap *map ) = 0; virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0; virtual void releaseMapBuckets( ValueInternalLink *links ) = 0; virtual ValueInternalLink *allocateMapLink() = 0; virtual void releaseMapLink( ValueInternalLink *link ) = 0; }; /** \brief ValueInternalMap hash-map bucket chain link (for internal use only). * \internal previous_ & next_ allows for bidirectional traversal. */ class JSON_API ValueInternalLink { public: enum { itemPerLink = 6 }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture. enum InternalFlags { flagAvailable = 0, flagUsed = 1 }; ValueInternalLink(); ~ValueInternalLink(); Value items_[itemPerLink]; char *keys_[itemPerLink]; ValueInternalLink *previous_; ValueInternalLink *next_; }; /** \brief A linked page based hash-table implementation used internally by Value. * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked * list in each bucket to handle collision. There is an addional twist in that * each node of the collision linked list is a page containing a fixed amount of * value. This provides a better compromise between memory usage and speed. * * Each bucket is made up of a chained list of ValueInternalLink. The last * link of a given bucket can be found in the 'previous_' field of the following bucket. * The last link of the last bucket is stored in tailLink_ as it has no following bucket. * Only the last link of a bucket may contains 'available' item. The last link always * contains at least one element unless is it the bucket one very first link. */ class JSON_API ValueInternalMap { friend class ValueIteratorBase; friend class Value; public: typedef unsigned int HashKey; typedef unsigned int BucketIndex; # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION struct IteratorState { IteratorState() : map_(0) , link_(0) , itemIndex_(0) , bucketIndex_(0) { } ValueInternalMap *map_; ValueInternalLink *link_; BucketIndex itemIndex_; BucketIndex bucketIndex_; }; # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ValueInternalMap(); ValueInternalMap( const ValueInternalMap &other ); ValueInternalMap &operator =( const ValueInternalMap &other ); ~ValueInternalMap(); void swap( ValueInternalMap &other ); BucketIndex size() const; void clear(); bool reserveDelta( BucketIndex growth ); bool reserve( BucketIndex newItemCount ); const Value *find( const char *key ) const; Value *find( const char *key ); Value &resolveReference( const char *key, bool isStatic ); void remove( const char *key ); void doActualRemove( ValueInternalLink *link, BucketIndex index, BucketIndex bucketIndex ); ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex ); Value &setNewItem( const char *key, bool isStatic, ValueInternalLink *link, BucketIndex index ); Value &unsafeAdd( const char *key, bool isStatic, HashKey hashedKey ); HashKey hash( const char *key ) const; int compare( const ValueInternalMap &other ) const; private: void makeBeginIterator( IteratorState &it ) const; void makeEndIterator( IteratorState &it ) const; static bool equals( const IteratorState &x, const IteratorState &other ); static void increment( IteratorState &iterator ); static void incrementBucket( IteratorState &iterator ); static void decrement( IteratorState &iterator ); static const char *key( const IteratorState &iterator ); static const char *key( const IteratorState &iterator, bool &isStatic ); static Value &value( const IteratorState &iterator ); static int distance( const IteratorState &x, const IteratorState &y ); private: ValueInternalLink *buckets_; ValueInternalLink *tailLink_; BucketIndex bucketsSize_; BucketIndex itemCount_; }; /** \brief A simplified deque implementation used internally by Value. * \internal * It is based on a list of fixed "page", each page contains a fixed number of items. * Instead of using a linked-list, a array of pointer is used for fast item look-up. * Look-up for an element is as follow: * - compute page index: pageIndex = itemIndex / itemsPerPage * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage] * * Insertion is amortized constant time (only the array containing the index of pointers * need to be reallocated when items are appended). */ class JSON_API ValueInternalArray { friend class Value; friend class ValueIteratorBase; public: enum { itemsPerPage = 8 }; // should be a power of 2 for fast divide and modulo. typedef Value::ArrayIndex ArrayIndex; typedef unsigned int PageIndex; # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION struct IteratorState // Must be a POD { IteratorState() : array_(0) , currentPageIndex_(0) , currentItemIndex_(0) { } ValueInternalArray *array_; Value **currentPageIndex_; unsigned int currentItemIndex_; }; # endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION ValueInternalArray(); ValueInternalArray( const ValueInternalArray &other ); ValueInternalArray &operator =( const ValueInternalArray &other ); ~ValueInternalArray(); void swap( ValueInternalArray &other ); void clear(); void resize( ArrayIndex newSize ); Value &resolveReference( ArrayIndex index ); Value *find( ArrayIndex index ) const; ArrayIndex size() const; int compare( const ValueInternalArray &other ) const; private: static bool equals( const IteratorState &x, const IteratorState &other ); static void increment( IteratorState &iterator ); static void decrement( IteratorState &iterator ); static Value &dereference( const IteratorState &iterator ); static Value &unsafeDereference( const IteratorState &iterator ); static int distance( const IteratorState &x, const IteratorState &y ); static ArrayIndex indexOf( const IteratorState &iterator ); void makeBeginIterator( IteratorState &it ) const; void makeEndIterator( IteratorState &it ) const; void makeIterator( IteratorState &it, ArrayIndex index ) const; void makeIndexValid( ArrayIndex index ); Value **pages_; ArrayIndex size_; PageIndex pageCount_; }; /** \brief Experimental: do not use. Allocator to customize Value internal array. * Below is an example of a simple implementation (actual implementation use * memory pool). \code class DefaultValueArrayAllocator : public ValueArrayAllocator { public: // overridden from ValueArrayAllocator virtual ~DefaultValueArrayAllocator() { } virtual ValueInternalArray *newArray() { return new ValueInternalArray(); } virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) { return new ValueInternalArray( other ); } virtual void destruct( ValueInternalArray *array ) { delete array; } virtual void reallocateArrayPageIndex( Value **&indexes, ValueInternalArray::PageIndex &indexCount, ValueInternalArray::PageIndex minNewIndexCount ) { ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; if ( minNewIndexCount > newIndexCount ) newIndexCount = minNewIndexCount; void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); if ( !newIndexes ) throw std::bad_alloc(); indexCount = newIndexCount; indexes = static_cast( newIndexes ); } virtual void releaseArrayPageIndex( Value **indexes, ValueInternalArray::PageIndex indexCount ) { if ( indexes ) free( indexes ); } virtual Value *allocateArrayPage() { return static_cast( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); } virtual void releaseArrayPage( Value *value ) { if ( value ) free( value ); } }; \endcode */ class JSON_API ValueArrayAllocator { public: virtual ~ValueArrayAllocator(); virtual ValueInternalArray *newArray() = 0; virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0; virtual void destructArray( ValueInternalArray *array ) = 0; /** \brief Reallocate array page index. * Reallocates an array of pointer on each page. * \param indexes [input] pointer on the current index. May be \c NULL. * [output] pointer on the new index of at least * \a minNewIndexCount pages. * \param indexCount [input] current number of pages in the index. * [output] number of page the reallocated index can handle. * \b MUST be >= \a minNewIndexCount. * \param minNewIndexCount Minimum number of page the new index must be able to * handle. */ virtual void reallocateArrayPageIndex( Value **&indexes, ValueInternalArray::PageIndex &indexCount, ValueInternalArray::PageIndex minNewIndexCount ) = 0; virtual void releaseArrayPageIndex( Value **indexes, ValueInternalArray::PageIndex indexCount ) = 0; virtual Value *allocateArrayPage() = 0; virtual void releaseArrayPage( Value *value ) = 0; }; #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP /** \brief base class for Value iterators. * */ class ValueIteratorBase { public: typedef unsigned int size_t; typedef int difference_type; typedef ValueIteratorBase SelfType; ValueIteratorBase(); #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueIteratorBase( const Value::ObjectValues::iterator ¤t ); #else ValueIteratorBase( const ValueInternalArray::IteratorState &state ); ValueIteratorBase( const ValueInternalMap::IteratorState &state ); #endif bool operator ==( const SelfType &other ) const { return isEqual( other ); } bool operator !=( const SelfType &other ) const { return !isEqual( other ); } difference_type operator -( const SelfType &other ) const { return computeDistance( other ); } /// Return either the index or the member name of the referenced value as a Value. Value key() const; /// Return the index of the referenced Value. -1 if it is not an arrayValue. UInt index() const; /// Return the member name of the referenced Value. "" if it is not an objectValue. const char *memberName() const; protected: Value &deref() const; void increment(); void decrement(); difference_type computeDistance( const SelfType &other ) const; bool isEqual( const SelfType &other ) const; void copy( const SelfType &other ); private: #ifndef JSON_VALUE_USE_INTERNAL_MAP Value::ObjectValues::iterator current_; // Indicates that iterator is for a null value. bool isNull_; #else union { ValueInternalArray::IteratorState array_; ValueInternalMap::IteratorState map_; } iterator_; bool isArray_; #endif }; /** \brief const iterator for object and array value. * */ class ValueConstIterator : public ValueIteratorBase { friend class Value; public: typedef unsigned int size_t; typedef int difference_type; typedef const Value &reference; typedef const Value *pointer; typedef ValueConstIterator SelfType; ValueConstIterator(); private: /*! \internal Use by Value to create an iterator. */ #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueConstIterator( const Value::ObjectValues::iterator ¤t ); #else ValueConstIterator( const ValueInternalArray::IteratorState &state ); ValueConstIterator( const ValueInternalMap::IteratorState &state ); #endif public: SelfType &operator =( const ValueIteratorBase &other ); SelfType operator++( int ) { SelfType temp( *this ); ++*this; return temp; } SelfType operator--( int ) { SelfType temp( *this ); --*this; return temp; } SelfType &operator--() { decrement(); return *this; } SelfType &operator++() { increment(); return *this; } reference operator *() const { return deref(); } }; /** \brief Iterator for object and array value. */ class ValueIterator : public ValueIteratorBase { friend class Value; public: typedef unsigned int size_t; typedef int difference_type; typedef Value &reference; typedef Value *pointer; typedef ValueIterator SelfType; ValueIterator(); ValueIterator( const ValueConstIterator &other ); ValueIterator( const ValueIterator &other ); private: /*! \internal Use by Value to create an iterator. */ #ifndef JSON_VALUE_USE_INTERNAL_MAP explicit ValueIterator( const Value::ObjectValues::iterator ¤t ); #else ValueIterator( const ValueInternalArray::IteratorState &state ); ValueIterator( const ValueInternalMap::IteratorState &state ); #endif public: SelfType &operator =( const SelfType &other ); SelfType operator++( int ) { SelfType temp( *this ); ++*this; return temp; } SelfType operator--( int ) { SelfType temp( *this ); --*this; return temp; } SelfType &operator--() { decrement(); return *this; } SelfType &operator++() { increment(); return *this; } reference operator *() const { return deref(); } }; } // namespace Json #endif // CPPTL_JSON_H_INCLUDED ================================================ FILE: common/jsoncpp/json/writer.h ================================================ #ifndef JSON_WRITER_H_INCLUDED # define JSON_WRITER_H_INCLUDED # include "value.h" # include # include # include namespace Json { class Value; /** \brief Abstract class for writers. */ class JSON_API Writer { public: virtual ~Writer(); virtual std::string write( const Value &root ) = 0; }; /** \brief Outputs a Value in JSON format without formatting (not human friendly). * * The JSON document is written in a single line. It is not intended for 'human' consumption, * but may be usefull to support feature such as RPC where bandwith is limited. * \sa Reader, Value */ class JSON_API FastWriter : public Writer { public: FastWriter(); virtual ~FastWriter(){} void enableYAMLCompatibility(); public: // overridden from Writer virtual std::string write( const Value &root ); private: void writeValue( const Value &value ); std::string document_; bool yamlCompatiblityEnabled_; }; /** \brief Writes a Value in JSON format in a human friendly way. * * The rules for line break and indent are as follow: * - Object value: * - if empty then print {} without indent and line break * - if not empty the print '{', line break & indent, print one value per line * and then unindent and line break and print '}'. * - Array value: * - if empty then print [] without indent and line break * - if the array contains no object value, empty array or some other value types, * and all the values fit on one lines, then print the array on a single line. * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * * If the Value have comments then they are outputed according to their #CommentPlacement. * * \sa Reader, Value, Value::setComment() */ class JSON_API StyledWriter: public Writer { public: StyledWriter(); virtual ~StyledWriter(){} public: // overridden from Writer /** \brief Serialize a Value in JSON format. * \param root Value to serialize. * \return String containing the JSON document that represents the root value. */ virtual std::string write( const Value &root ); private: void writeValue( const Value &value ); void writeArrayValue( const Value &value ); bool isMultineArray( const Value &value ); void pushValue( const std::string &value ); void writeIndent(); void writeWithIndent( const std::string &value ); void indent(); void unindent(); void writeCommentBeforeValue( const Value &root ); void writeCommentAfterValueOnSameLine( const Value &root ); bool hasCommentForValue( const Value &value ); static std::string normalizeEOL( const std::string &text ); typedef std::vector ChildValues; ChildValues childValues_; std::string document_; std::string indentString_; int rightMargin_; int indentSize_; bool addChildValues_; }; /** \brief Writes a Value in JSON format in a human friendly way, to a stream rather than to a string. * * The rules for line break and indent are as follow: * - Object value: * - if empty then print {} without indent and line break * - if not empty the print '{', line break & indent, print one value per line * and then unindent and line break and print '}'. * - Array value: * - if empty then print [] without indent and line break * - if the array contains no object value, empty array or some other value types, * and all the values fit on one lines, then print the array on a single line. * - otherwise, it the values do not fit on one line, or the array contains * object or non empty array, then print one value per line. * * If the Value have comments then they are outputed according to their #CommentPlacement. * * \param indentation Each level will be indented by this amount extra. * \sa Reader, Value, Value::setComment() */ class JSON_API StyledStreamWriter { public: StyledStreamWriter( std::string indentation="\t" ); ~StyledStreamWriter(){} public: /** \brief Serialize a Value in JSON format. * \param out Stream to write to. (Can be ostringstream, e.g.) * \param root Value to serialize. * \note There is no point in deriving from Writer, since write() should not return a value. */ void write( std::ostream &out, const Value &root ); private: void writeValue( const Value &value ); void writeArrayValue( const Value &value ); bool isMultineArray( const Value &value ); void pushValue( const std::string &value ); void writeIndent(); void writeWithIndent( const std::string &value ); void indent(); void unindent(); void writeCommentBeforeValue( const Value &root ); void writeCommentAfterValueOnSameLine( const Value &root ); bool hasCommentForValue( const Value &value ); static std::string normalizeEOL( const std::string &text ); typedef std::vector ChildValues; ChildValues childValues_; std::ostream* document_; std::string indentString_; int rightMargin_; std::string indentation_; bool addChildValues_; }; std::string JSON_API valueToString( Int value ); std::string JSON_API valueToString( UInt value ); std::string JSON_API valueToString( double value ); std::string JSON_API valueToString( bool value ); std::string JSON_API valueToQuotedString( const char *value ); /// \brief Output using the StyledStreamWriter. /// \see Json::operator>>() std::ostream& operator<<( std::ostream&, const Value &root ); } // namespace Json #endif // JSON_WRITER_H_INCLUDED ================================================ FILE: common/jsoncpp/json_batchallocator.h ================================================ #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED #define JSONCPP_BATCHALLOCATOR_H_INCLUDED #include #include #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION namespace Json { /* Fast memory allocator. * * This memory allocator allocates memory for a batch of object (specified by * the page size, the number of object in each page). * * It does not allow the destruction of a single object. All the allocated objects * can be destroyed at once. The memory can be either released or reused for future * allocation. * * The in-place new operator must be used to construct the object using the pointer * returned by allocate. */ template class BatchAllocator { public: typedef AllocatedType Type; BatchAllocator( unsigned int objectsPerPage = 255 ) : freeHead_( 0 ) , objectsPerPage_( objectsPerPage ) { // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. assert( objectsPerPage >= 16 ); batches_ = allocateBatch( 0 ); // allocated a dummy page currentBatch_ = batches_; } ~BatchAllocator() { for ( BatchInfo *batch = batches_; batch; ) { BatchInfo *nextBatch = batch->next_; free( batch ); batch = nextBatch; } } /// allocate space for an array of objectPerAllocation object. /// @warning it is the responsability of the caller to call objects constructors. AllocatedType *allocate() { if ( freeHead_ ) // returns node from free list. { AllocatedType *object = freeHead_; freeHead_ = *(AllocatedType **)object; return object; } if ( currentBatch_->used_ == currentBatch_->end_ ) { currentBatch_ = currentBatch_->next_; while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) currentBatch_ = currentBatch_->next_; if ( !currentBatch_ ) // no free batch found, allocate a new one { currentBatch_ = allocateBatch( objectsPerPage_ ); currentBatch_->next_ = batches_; // insert at the head of the list batches_ = currentBatch_; } } AllocatedType *allocated = currentBatch_->used_; currentBatch_->used_ += objectPerAllocation; return allocated; } /// Release the object. /// @warning it is the responsability of the caller to actually destruct the object. void release( AllocatedType *object ) { assert( object != 0 ); *(AllocatedType **)object = freeHead_; freeHead_ = object; } private: struct BatchInfo { BatchInfo *next_; AllocatedType *used_; AllocatedType *end_; AllocatedType buffer_[objectPerAllocation]; }; // disabled copy constructor and assignement operator. BatchAllocator( const BatchAllocator & ); void operator =( const BatchAllocator &); static BatchInfo *allocateBatch( unsigned int objectsPerPage ) { const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; BatchInfo *batch = static_cast( malloc( mallocSize ) ); batch->next_ = 0; batch->used_ = batch->buffer_; batch->end_ = batch->buffer_ + objectsPerPage; return batch; } BatchInfo *batches_; BatchInfo *currentBatch_; /// Head of a single linked list within the allocated space of freeed object AllocatedType *freeHead_; unsigned int objectsPerPage_; }; } // namespace Json #endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED ================================================ FILE: common/jsoncpp/json_valueiterator.inl ================================================ // included by json_value.cpp // everything is within Json namespace // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIteratorBase // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIteratorBase::ValueIteratorBase() #ifndef JSON_VALUE_USE_INTERNAL_MAP : current_() , isNull_( true ) { } #else : isArray_( true ) , isNull_( true ) { iterator_.array_ = ValueInternalArray::IteratorState(); } #endif #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) : current_( current ) , isNull_( false ) { } #else ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) : isArray_( true ) { iterator_.array_ = state; } ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) : isArray_( false ) { iterator_.map_ = state; } #endif Value & ValueIteratorBase::deref() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP return current_->second; #else if ( isArray_ ) return ValueInternalArray::dereference( iterator_.array_ ); return ValueInternalMap::value( iterator_.map_ ); #endif } void ValueIteratorBase::increment() { #ifndef JSON_VALUE_USE_INTERNAL_MAP ++current_; #else if ( isArray_ ) ValueInternalArray::increment( iterator_.array_ ); ValueInternalMap::increment( iterator_.map_ ); #endif } void ValueIteratorBase::decrement() { #ifndef JSON_VALUE_USE_INTERNAL_MAP --current_; #else if ( isArray_ ) ValueInternalArray::decrement( iterator_.array_ ); ValueInternalMap::decrement( iterator_.map_ ); #endif } ValueIteratorBase::difference_type ValueIteratorBase::computeDistance( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP # ifdef JSON_USE_CPPTL_SMALLMAP return current_ - other.current_; # else // Iterator for null value are initialized using the default // constructor, which initialize current_ to the default // std::map::iterator. As begin() and end() are two instance // of the default std::map::iterator, they can not be compared. // To allow this, we handle this comparison specifically. if ( isNull_ && other.isNull_ ) { return 0; } // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, // which is the one used by default). // Using a portable hand-made version for non random iterator instead: // return difference_type( std::distance( current_, other.current_ ) ); difference_type myDistance = 0; for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) { ++myDistance; } return myDistance; # endif #else if ( isArray_ ) return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); #endif } bool ValueIteratorBase::isEqual( const SelfType &other ) const { #ifndef JSON_VALUE_USE_INTERNAL_MAP if ( isNull_ ) { return other.isNull_; } return current_ == other.current_; #else if ( isArray_ ) return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); #endif } void ValueIteratorBase::copy( const SelfType &other ) { #ifndef JSON_VALUE_USE_INTERNAL_MAP current_ = other.current_; #else if ( isArray_ ) iterator_.array_ = other.iterator_.array_; iterator_.map_ = other.iterator_.map_; #endif } Value ValueIteratorBase::key() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( czstring.c_str() ) { if ( czstring.isStaticString() ) return Value( StaticString( czstring.c_str() ) ); return Value( czstring.c_str() ); } return Value( czstring.index() ); #else if ( isArray_ ) return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); bool isStatic; const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); if ( isStatic ) return Value( StaticString( memberName ) ); return Value( memberName ); #endif } UInt ValueIteratorBase::index() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const Value::CZString czstring = (*current_).first; if ( !czstring.c_str() ) return czstring.index(); return Value::UInt( -1 ); #else if ( isArray_ ) return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); return Value::UInt( -1 ); #endif } const char * ValueIteratorBase::memberName() const { #ifndef JSON_VALUE_USE_INTERNAL_MAP const char *name = (*current_).first.c_str(); return name ? name : ""; #else if ( !isArray_ ) return ValueInternalMap::key( iterator_.map_ ); return ""; #endif } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueConstIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueConstIterator::ValueConstIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueConstIterator & ValueConstIterator::operator =( const ValueIteratorBase &other ) { copy( other ); return *this; } // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class ValueIterator // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// ValueIterator::ValueIterator() { } #ifndef JSON_VALUE_USE_INTERNAL_MAP ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) : ValueIteratorBase( current ) { } #else ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) : ValueIteratorBase( state ) { } ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) : ValueIteratorBase( state ) { } #endif ValueIterator::ValueIterator( const ValueConstIterator &other ) : ValueIteratorBase( other ) { } ValueIterator::ValueIterator( const ValueIterator &other ) : ValueIteratorBase( other ) { } ValueIterator & ValueIterator::operator =( const SelfType &other ) { copy( other ); return *this; } ================================================ FILE: common/jsoncpp/reader.cpp ================================================ #include #include #include #include #include #include #include "json/value.h" #include "json/reader.h" #if _MSC_VER >= 1400 // VC++ 8.0 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. #endif namespace Json { // Implementation of class Features // //////////////////////////////// Features::Features() : allowComments_( true ) , strictRoot_( false ) { } Features Features::all() { return Features(); } Features Features::strictMode() { Features features; features.allowComments_ = false; features.strictRoot_ = true; return features; } // Implementation of class Reader // //////////////////////////////// static inline bool in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) { return c == c1 || c == c2 || c == c3 || c == c4; } static inline bool in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) { return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; } static bool containsNewLine( Reader::Location begin, Reader::Location end ) { for ( ;begin < end; ++begin ) if ( *begin == '\n' || *begin == '\r' ) return true; return false; } static std::string codePointToUTF8(unsigned int cp) { std::string result; // based on description from http://en.wikipedia.org/wiki/UTF-8 if (cp <= 0x7f) { result.resize(1); result[0] = static_cast(cp); } else if (cp <= 0x7FF) { result.resize(2); result[1] = static_cast(0x80 | (0x3f & cp)); result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); } else if (cp <= 0xFFFF) { result.resize(3); result[2] = static_cast(0x80 | (0x3f & cp)); result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); } else if (cp <= 0x10FFFF) { result.resize(4); result[3] = static_cast(0x80 | (0x3f & cp)); result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); } return result; } // Class Reader // ////////////////////////////////////////////////////////////////// Reader::Reader() : features_( Features::all() ) { } Reader::Reader( const Features &features ) : features_( features ) { } bool Reader::parse( const std::string &document, Value &root, bool collectComments ) { document_ = document; const char *begin = document_.c_str(); const char *end = begin + document_.length(); return parse( begin, end, root, collectComments ); } bool Reader::parse( std::istream& sin, Value &root, bool collectComments ) { //std::istream_iterator begin(sin); //std::istream_iterator end; // Those would allow streamed input from a file, if parse() were a // template function. // Since std::string is reference-counted, this at least does not // create an extra copy. std::string doc; std::getline(sin, doc, (char)EOF); return parse( doc, root, collectComments ); } bool Reader::parse( const char *beginDoc, const char *endDoc, Value &root, bool collectComments ) { if ( !features_.allowComments_ ) { collectComments = false; } begin_ = beginDoc; end_ = endDoc; collectComments_ = collectComments; current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; commentsBefore_ = ""; errors_.clear(); while ( !nodes_.empty() ) nodes_.pop(); nodes_.push( &root ); bool successful = readValue(); Token token; skipCommentTokens( token ); if ( collectComments_ && !commentsBefore_.empty() ) root.setComment( commentsBefore_, commentAfter ); if ( features_.strictRoot_ ) { if ( !root.isArray() && !root.isObject() ) { // Set error location to start of doc, ideally should be first token found in doc token.type_ = tokenError; token.start_ = beginDoc; token.end_ = endDoc; addError( "A valid JSON document must be either an array or an object value.", token ); return false; } } return successful; } bool Reader::readValue() { Token token; skipCommentTokens( token ); bool successful = true; if ( collectComments_ && !commentsBefore_.empty() ) { currentValue().setComment( commentsBefore_, commentBefore ); commentsBefore_ = ""; } switch ( token.type_ ) { case tokenObjectBegin: successful = readObject( token ); break; case tokenArrayBegin: successful = readArray( token ); break; case tokenNumber: successful = decodeNumber( token ); break; case tokenString: successful = decodeString( token ); break; case tokenTrue: currentValue() = true; break; case tokenFalse: currentValue() = false; break; case tokenNull: currentValue() = Value(); break; default: return addError( "Syntax error: value, object or array expected.", token ); } if ( collectComments_ ) { lastValueEnd_ = current_; lastValue_ = ¤tValue(); } return successful; } void Reader::skipCommentTokens( Token &token ) { if ( features_.allowComments_ ) { do { readToken( token ); } while ( token.type_ == tokenComment ); } else { readToken( token ); } } bool Reader::expectToken( TokenType type, Token &token, const char *message ) { readToken( token ); if ( token.type_ != type ) return addError( message, token ); return true; } bool Reader::readToken( Token &token ) { skipSpaces(); token.start_ = current_; Char c = getNextChar(); bool ok = true; switch ( c ) { case '{': token.type_ = tokenObjectBegin; break; case '}': token.type_ = tokenObjectEnd; break; case '[': token.type_ = tokenArrayBegin; break; case ']': token.type_ = tokenArrayEnd; break; case '"': token.type_ = tokenString; ok = readString(); break; case '/': token.type_ = tokenComment; ok = readComment(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': token.type_ = tokenNumber; readNumber(); break; case 't': token.type_ = tokenTrue; ok = match( "rue", 3 ); break; case 'f': token.type_ = tokenFalse; ok = match( "alse", 4 ); break; case 'n': token.type_ = tokenNull; ok = match( "ull", 3 ); break; case ',': token.type_ = tokenArraySeparator; break; case ':': token.type_ = tokenMemberSeparator; break; case 0: token.type_ = tokenEndOfStream; break; default: ok = false; break; } if ( !ok ) token.type_ = tokenError; token.end_ = current_; return true; } void Reader::skipSpaces() { while ( current_ != end_ ) { Char c = *current_; if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) ++current_; else break; } } bool Reader::match( Location pattern, int patternLength ) { if ( end_ - current_ < patternLength ) return false; int index = patternLength; while ( index-- ) if ( current_[index] != pattern[index] ) return false; current_ += patternLength; return true; } bool Reader::readComment() { Location commentBegin = current_ - 1; Char c = getNextChar(); bool successful = false; if ( c == '*' ) successful = readCStyleComment(); else if ( c == '/' ) successful = readCppStyleComment(); if ( !successful ) return false; if ( collectComments_ ) { CommentPlacement placement = commentBefore; if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) { if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) placement = commentAfterOnSameLine; } addComment( commentBegin, current_, placement ); } return true; } void Reader::addComment( Location begin, Location end, CommentPlacement placement ) { assert( collectComments_ ); if ( placement == commentAfterOnSameLine ) { assert( lastValue_ != 0 ); lastValue_->setComment( std::string( begin, end ), placement ); } else { if ( !commentsBefore_.empty() ) commentsBefore_ += "\n"; commentsBefore_ += std::string( begin, end ); } } bool Reader::readCStyleComment() { while ( current_ != end_ ) { Char c = getNextChar(); if ( c == '*' && *current_ == '/' ) break; } return getNextChar() == '/'; } bool Reader::readCppStyleComment() { while ( current_ != end_ ) { Char c = getNextChar(); if ( c == '\r' || c == '\n' ) break; } return true; } void Reader::readNumber() { while ( current_ != end_ ) { if ( !(*current_ >= '0' && *current_ <= '9') && !in( *current_, '.', 'e', 'E', '+', '-' ) ) break; ++current_; } } bool Reader::readString() { Char c = 0; while ( current_ != end_ ) { c = getNextChar(); if ( c == '\\' ) getNextChar(); else if ( c == '"' ) break; } return c == '"'; } bool Reader::readObject( Token &tokenStart ) { Token tokenName; std::string name; currentValue() = Value( objectValue ); while ( readToken( tokenName ) ) { bool initialTokenOk = true; while ( tokenName.type_ == tokenComment && initialTokenOk ) initialTokenOk = readToken( tokenName ); if ( !initialTokenOk ) break; if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object return true; if ( tokenName.type_ != tokenString ) break; name = ""; if ( !decodeString( tokenName, name ) ) return recoverFromError( tokenObjectEnd ); Token colon; if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) { return addErrorAndRecover( "Missing ':' after object member name", colon, tokenObjectEnd ); } Value &value = currentValue()[ name ]; nodes_.push( &value ); bool ok = readValue(); nodes_.pop(); if ( !ok ) // error already set return recoverFromError( tokenObjectEnd ); Token comma; if ( !readToken( comma ) || ( comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment ) ) { return addErrorAndRecover( "Missing ',' or '}' in object declaration", comma, tokenObjectEnd ); } bool finalizeTokenOk = true; while ( comma.type_ == tokenComment && finalizeTokenOk ) finalizeTokenOk = readToken( comma ); if ( comma.type_ == tokenObjectEnd ) return true; } return addErrorAndRecover( "Missing '}' or object member name", tokenName, tokenObjectEnd ); } bool Reader::readArray( Token &tokenStart ) { currentValue() = Value( arrayValue ); skipSpaces(); if ( *current_ == ']' ) // empty array { Token endArray; readToken( endArray ); return true; } Value &arrValue = currentValue(); Location locStart = current_; int index = 0; while ( true ) { Value &value = currentValue()[ index++ ]; nodes_.push( &value ); bool ok = readValue(); nodes_.pop(); if ( !ok ) // error already set return recoverFromError( tokenArrayEnd ); Token token; // Accept Comment after last item in the array. ok = readToken( token ); while ( token.type_ == tokenComment && ok ) { ok = readToken( token ); } bool badTokenType = ( token.type_ == tokenArraySeparator && token.type_ == tokenArrayEnd ); if ( !ok || badTokenType ) { return addErrorAndRecover( "Missing ',' or ']' in array declaration", token, tokenArrayEnd ); } if ( token.type_ == tokenArrayEnd ) break; } Location locEnd = current_; std::string strSrc(locStart,locEnd - locStart); strSrc = "["+strSrc; arrValue.SetSrcString(strSrc); return true; } bool Reader::decodeNumber( Token &token ) { bool isDouble = false; for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) { isDouble = isDouble || in( *inspect, '.', 'e', 'E', '+' ) || ( *inspect == '-' && inspect != token.start_ ); } if ( isDouble ) return decodeDouble( token ); Location current = token.start_; bool isNegative = *current == '-'; if ( isNegative ) ++current; Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) : Value::maxUInt) / 10; Value::UInt value = 0; while ( current < token.end_ ) { Char c = *current++; if ( c < '0' || c > '9' ) return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); if ( value >= threshold ) return decodeDouble( token ); value = value * 10 + Value::UInt(c - '0'); } if ( isNegative ) currentValue() = -Value::Int( value ); else if ( value <= Value::UInt(Value::maxInt) ) currentValue() = Value::Int( value ); else currentValue() = value; return true; } bool Reader::decodeDouble( Token &token ) { double value = 0; const int bufferSize = 32; int count; int length = int(token.end_ - token.start_); if ( length <= bufferSize ) { Char buffer[bufferSize]; memcpy( buffer, token.start_, length ); buffer[length] = 0; count = sscanf( buffer, "%lf", &value ); } else { std::string buffer( token.start_, token.end_ ); count = sscanf( buffer.c_str(), "%lf", &value ); } if ( count != 1 ) return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); currentValue() = value; return true; } bool Reader::decodeString( Token &token ) { std::string decoded; if ( !decodeString( token, decoded ) ) return false; currentValue() = decoded; return true; } bool Reader::decodeString( Token &token, std::string &decoded ) { decoded.reserve( token.end_ - token.start_ - 2 ); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while ( current != end ) { Char c = *current++; if ( c == '"' ) break; else if ( c == '\\' ) { if ( current == end ) return addError( "Empty escape sequence in string", token, current ); Char escape = *current++; switch ( escape ) { case '"': decoded += '"'; break; case '/': decoded += '/'; break; case '\\': decoded += '\\'; break; case 'b': decoded += '\b'; break; case 'f': decoded += '\f'; break; case 'n': decoded += '\n'; break; case 'r': decoded += '\r'; break; case 't': decoded += '\t'; break; case 'u': { unsigned int unicode; if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) return false; decoded += codePointToUTF8(unicode); } break; default: return addError( "Bad escape sequence in string", token, current ); } } else { decoded += c; } } return true; } bool Reader::decodeUnicodeCodePoint( Token &token, Location ¤t, Location end, unsigned int &unicode ) { if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) return false; if (unicode >= 0xD800 && unicode <= 0xDBFF) { // surrogate pairs if (end - current < 6) return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); unsigned int surrogatePair; if (*(current++) == '\\' && *(current++)== 'u') { if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) { unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); } else return false; } else return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); } return true; } bool Reader::decodeUnicodeEscapeSequence( Token &token, Location ¤t, Location end, unsigned int &unicode ) { if ( end - current < 4 ) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); unicode = 0; for ( int index =0; index < 4; ++index ) { Char c = *current++; unicode *= 16; if ( c >= '0' && c <= '9' ) unicode += c - '0'; else if ( c >= 'a' && c <= 'f' ) unicode += c - 'a' + 10; else if ( c >= 'A' && c <= 'F' ) unicode += c - 'A' + 10; else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); } return true; } bool Reader::addError( const std::string &message, Token &token, Location extra ) { ErrorInfo info; info.token_ = token; info.message_ = message; info.extra_ = extra; errors_.push_back( info ); return false; } bool Reader::recoverFromError( TokenType skipUntilToken ) { int errorCount = int(errors_.size()); Token skip; while ( true ) { if ( !readToken(skip) ) errors_.resize( errorCount ); // discard errors caused by recovery if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) break; } errors_.resize( errorCount ); return false; } bool Reader::addErrorAndRecover( const std::string &message, Token &token, TokenType skipUntilToken ) { addError( message, token ); return recoverFromError( skipUntilToken ); } Value & Reader::currentValue() { return *(nodes_.top()); } Reader::Char Reader::getNextChar() { if ( current_ == end_ ) return 0; return *current_++; } void Reader::getLocationLineAndColumn( Location location, int &line, int &column ) const { Location current = begin_; Location lastLineStart = current; line = 0; while ( current < location && current != end_ ) { Char c = *current++; if ( c == '\r' ) { if ( *current == '\n' ) ++current; lastLineStart = current; ++line; } else if ( c == '\n' ) { lastLineStart = current; ++line; } } // column & line start at 1 column = int(location - lastLineStart) + 1; ++line; } std::string Reader::getLocationLineAndColumn( Location location ) const { int line, column; getLocationLineAndColumn( location, line, column ); char buffer[18+16+16+1]; sprintf( buffer, "Line %d, Column %d", line, column ); return buffer; } std::string Reader::getFormatedErrorMessages() const { std::string formattedMessage; for ( Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError ) { const ErrorInfo &error = *itError; formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; formattedMessage += " " + error.message_ + "\n"; if ( error.extra_ ) formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; } return formattedMessage; } std::istream& operator>>( std::istream &sin, Value &root ) { Json::Reader reader; bool ok = reader.parse(sin, root, true); //JSON_ASSERT( ok ); if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); return sin; } } // namespace Json ================================================ FILE: common/jsoncpp/value.cpp ================================================ #include #include #include #include #include #ifdef JSON_USE_CPPTL # include #endif #include // size_t #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR # include "json_batchallocator.h" #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR #include "json/value.h" #include "json/writer.h" #define JSON_ASSERT_UNREACHABLE assert( false ) #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); namespace Json { const Value Value::null; const Int Value::minInt = Int( ~(UInt(-1)/2) ); const Int Value::maxInt = Int( UInt(-1)/2 ); const UInt Value::maxUInt = UInt(-1); ValueAllocator::~ValueAllocator() { } class DefaultValueAllocator : public ValueAllocator { public: virtual ~DefaultValueAllocator() { } virtual char *makeMemberName( const char *memberName ) { return duplicateStringValue( memberName ); } virtual void releaseMemberName( char *memberName ) { releaseStringValue( memberName ); } virtual char *duplicateStringValue( const char *value, unsigned int length = unknown ) { if ( length == unknown ) length = (unsigned int)strlen(value); char *newString = static_cast( malloc( length + 1 ) ); memcpy( newString, value, length ); newString[length] = 0; return newString; } virtual void releaseStringValue( char *value ) { if ( value ) free( value ); } }; static ValueAllocator *&valueAllocator() { static DefaultValueAllocator defaultAllocator; static ValueAllocator *valueAllocator = &defaultAllocator; return valueAllocator; } static struct DummyValueAllocatorInitializer { DummyValueAllocatorInitializer() { valueAllocator(); // ensure valueAllocator() statics are initialized before main(). } } dummyValueAllocatorInitializer; #ifdef JSON_VALUE_USE_INTERNAL_MAP # include "json_internalarray.inl" # include "json_internalmap.inl" #endif // JSON_VALUE_USE_INTERNAL_MAP # include "json_valueiterator.inl" Value::CommentInfo::CommentInfo() : comment_( 0 ) { } Value::CommentInfo::~CommentInfo() { if ( comment_ ) valueAllocator()->releaseStringValue( comment_ ); } void Value::CommentInfo::setComment( const char *text ) { if ( comment_ ) valueAllocator()->releaseStringValue( comment_ ); JSON_ASSERT( text ); JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); // It seems that /**/ style comments are acceptable as well. comment_ = valueAllocator()->duplicateStringValue( text ); } # ifndef JSON_VALUE_USE_INTERNAL_MAP // Notes: index_ indicates if the string was allocated when // a string is stored. Value::CZString::CZString( int index ) : cstr_( 0 ) , index_( index ) { } Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr ) , index_( allocate ) { } Value::CZString::CZString( const CZString &other ) : cstr_( other.index_ != noDuplication && other.cstr_ != 0 ? valueAllocator()->makeMemberName( other.cstr_ ) : other.cstr_ ) , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) : other.index_ ) { } Value::CZString::~CZString() { if ( cstr_ && index_ == duplicate ) valueAllocator()->releaseMemberName( const_cast( cstr_ ) ); } void Value::CZString::swap( CZString &other ) { std::swap( cstr_, other.cstr_ ); std::swap( index_, other.index_ ); } Value::CZString & Value::CZString::operator =( const CZString &other ) { CZString temp( other ); swap( temp ); return *this; } bool Value::CZString::operator<( const CZString &other ) const { if ( cstr_ ) return strcmp( cstr_, other.cstr_ ) < 0; return index_ < other.index_; } bool Value::CZString::operator==( const CZString &other ) const { if ( cstr_ ) return strcmp( cstr_, other.cstr_ ) == 0; return index_ == other.index_; } int Value::CZString::index() const { return index_; } const char * Value::CZString::c_str() const { return cstr_; } bool Value::CZString::isStaticString() const { return index_ == noDuplication; } #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // class Value::Value // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// /*! \internal Default constructor initialization must be equivalent to: * memset( this, 0, sizeof(Value) ) * This optimization is used in ValueInternalMap fast allocator. */ Value::Value( ValueType type ) : type_( type ) , allocated_( 0 ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { switch ( type ) { case nullValue: break; case intValue: case uintValue: value_.int_ = 0; break; case realValue: value_.real_ = 0.0; break; case stringValue: value_.string_ = 0; break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_ = new ObjectValues(); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArray(); break; case objectValue: value_.map_ = mapAllocator()->newMap(); break; #endif case booleanValue: value_.bool_ = false; break; default: JSON_ASSERT_UNREACHABLE; } } Value::Value( Int value ) : type_( intValue ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.int_ = value; } Value::Value( UInt value ) : type_( uintValue ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.uint_ = value; } Value::Value( double value ) : type_( realValue ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.real_ = value; } Value::Value( const char *value ) : type_( stringValue ) , allocated_( true ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = valueAllocator()->duplicateStringValue( value ); } Value::Value( const char *beginValue, const char *endValue ) : type_( stringValue ) , allocated_( true ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = valueAllocator()->duplicateStringValue( beginValue, UInt(endValue - beginValue) ); } Value::Value( const std::string &value ) : type_( stringValue ) , allocated_( true ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), (unsigned int)value.length() ); } Value::Value( const StaticString &value ) : type_( stringValue ) , allocated_( false ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = const_cast( value.c_str() ); } # ifdef JSON_USE_CPPTL Value::Value( const CppTL::ConstString &value ) : type_( stringValue ) , allocated_( true ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); } # endif Value::Value( bool value ) : type_( booleanValue ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { value_.bool_ = value; } Value::Value( const Value &other ) : type_( other.type_ ) , comments_( 0 ) # ifdef JSON_VALUE_USE_INTERNAL_MAP , itemIsUsed_( 0 ) #endif { switch ( type_ ) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: value_ = other.value_; break; case stringValue: if ( other.value_.string_ ) { value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); allocated_ = true; } else value_.string_ = 0; break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: strSrc_ = other.strSrc_; case objectValue: value_.map_ = new ObjectValues( *other.value_.map_ ); break; #else case arrayValue: value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); break; case objectValue: value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); break; #endif default: JSON_ASSERT_UNREACHABLE; } if ( other.comments_ ) { comments_ = new CommentInfo[numberOfCommentPlacement]; for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) { const CommentInfo &otherComment = other.comments_[comment]; if ( otherComment.comment_ ) comments_[comment].setComment( otherComment.comment_ ); } } } Value::~Value() { switch ( type_ ) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: break; case stringValue: if ( allocated_ ) valueAllocator()->releaseStringValue( value_.string_ ); break; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: delete value_.map_; break; #else case arrayValue: arrayAllocator()->destructArray( value_.array_ ); break; case objectValue: mapAllocator()->destructMap( value_.map_ ); break; #endif default: JSON_ASSERT_UNREACHABLE; } if ( comments_ ) delete[] comments_; } Value & Value::operator=( const Value &other ) { Value temp( other ); swap( temp ); return *this; } void Value::swap( Value &other ) { ValueType temp = type_; type_ = other.type_; other.type_ = temp; std::swap( value_, other.value_ ); int temp2 = allocated_; allocated_ = other.allocated_; other.allocated_ = temp2; std::string strTemp = strSrc_; strSrc_ = other.strSrc_; other.strSrc_ = strTemp; } ValueType Value::type() const { return type_; } int Value::compare( const Value &other ) { /* int typeDelta = other.type_ - type_; switch ( type_ ) { case nullValue: return other.type_ == type_; case intValue: if ( other.type_.isNumeric() case uintValue: case realValue: case booleanValue: break; case stringValue, break; case arrayValue: delete value_.array_; break; case objectValue: delete value_.map_; default: JSON_ASSERT_UNREACHABLE; } */ return 0; // unreachable } bool Value::operator <( const Value &other ) const { int typeDelta = type_ - other.type_; if ( typeDelta ) return typeDelta < 0 ? true : false; switch ( type_ ) { case nullValue: return false; case intValue: return value_.int_ < other.value_.int_; case uintValue: return value_.uint_ < other.value_.uint_; case realValue: return value_.real_ < other.value_.real_; case booleanValue: return value_.bool_ < other.value_.bool_; case stringValue: return ( value_.string_ == 0 && other.value_.string_ ) || ( other.value_.string_ && value_.string_ && strcmp( value_.string_, other.value_.string_ ) < 0 ); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: { int delta = int( value_.map_->size() - other.value_.map_->size() ); if ( delta ) return delta < 0; return (*value_.map_) < (*other.value_.map_); } #else case arrayValue: return value_.array_->compare( *(other.value_.array_) ) < 0; case objectValue: return value_.map_->compare( *(other.value_.map_) ) < 0; #endif default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable } bool Value::operator <=( const Value &other ) const { return !(other > *this); } bool Value::operator >=( const Value &other ) const { return !(*this < other); } bool Value::operator >( const Value &other ) const { return other < *this; } bool Value::operator ==( const Value &other ) const { //if ( type_ != other.type_ ) // GCC 2.95.3 says: // attempt to take address of bit-field structure member `Json::Value::type_' // Beats me, but a temp solves the problem. int temp = other.type_; if ( type_ != temp ) return false; switch ( type_ ) { case nullValue: return true; case intValue: return value_.int_ == other.value_.int_; case uintValue: return value_.uint_ == other.value_.uint_; case realValue: return value_.real_ == other.value_.real_; case booleanValue: return value_.bool_ == other.value_.bool_; case stringValue: return ( value_.string_ == other.value_.string_ ) || ( other.value_.string_ && value_.string_ && strcmp( value_.string_, other.value_.string_ ) == 0 ); #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: return value_.map_->size() == other.value_.map_->size() && (*value_.map_) == (*other.value_.map_); #else case arrayValue: return value_.array_->compare( *(other.value_.array_) ) == 0; case objectValue: return value_.map_->compare( *(other.value_.map_) ) == 0; #endif default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable } bool Value::operator !=( const Value &other ) const { return !( *this == other ); } const char * Value::asCString() const { JSON_ASSERT( type_ == stringValue ); return value_.string_; } std::string Value::asString() const { switch ( type_ ) { case nullValue: return ""; case stringValue: return value_.string_ ? value_.string_ : ""; case booleanValue: return value_.bool_ ? "true" : "false"; case intValue: case uintValue: case realValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); default: JSON_ASSERT_UNREACHABLE; } return ""; // unreachable } # ifdef JSON_USE_CPPTL CppTL::ConstString Value::asConstString() const { return CppTL::ConstString( asString().c_str() ); } # endif Value::Int Value::asInt() const { switch ( type_ ) { case nullValue: return 0; case intValue: return value_.int_; case uintValue: JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); return value_.uint_; case realValue: JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); return Int( value_.real_ ); case booleanValue: return value_.bool_ ? 1 : 0; case stringValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } Value::UInt Value::asUInt() const { switch ( type_ ) { case nullValue: return 0; case intValue: JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); return value_.int_; case uintValue: return value_.uint_; case realValue: JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); return UInt( value_.real_ ); case booleanValue: return value_.bool_ ? 1 : 0; case stringValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } double Value::asDouble() const { switch ( type_ ) { case nullValue: return 0.0; case intValue: return value_.int_; case uintValue: return value_.uint_; case realValue: return value_.real_; case booleanValue: return value_.bool_ ? 1.0 : 0.0; case stringValue: case arrayValue: case objectValue: JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } bool Value::asBool() const { switch ( type_ ) { case nullValue: return false; case intValue: case uintValue: return value_.int_ != 0; case realValue: return value_.real_ != 0.0; case booleanValue: return value_.bool_; case stringValue: return value_.string_ && value_.string_[0] != 0; case arrayValue: case objectValue: return value_.map_->size() != 0; default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable; } bool Value::isConvertibleTo( ValueType other ) const { switch ( type_ ) { case nullValue: return true; case intValue: return ( other == nullValue && value_.int_ == 0 ) || other == intValue || ( other == uintValue && value_.int_ >= 0 ) || other == realValue || other == stringValue || other == booleanValue; case uintValue: return ( other == nullValue && value_.uint_ == 0 ) || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) || other == uintValue || other == realValue || other == stringValue || other == booleanValue; case realValue: return ( other == nullValue && value_.real_ == 0.0 ) || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) || other == realValue || other == stringValue || other == booleanValue; case booleanValue: return ( other == nullValue && value_.bool_ == false ) || other == intValue || other == uintValue || other == realValue || other == stringValue || other == booleanValue; case stringValue: return other == stringValue || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); case arrayValue: return other == arrayValue || ( other == nullValue && value_.map_->size() == 0 ); case objectValue: return other == objectValue || ( other == nullValue && value_.map_->size() == 0 ); default: JSON_ASSERT_UNREACHABLE; } return false; // unreachable; } /// Number of values in array or object Value::UInt Value::size() const { switch ( type_ ) { case nullValue: case intValue: case uintValue: case realValue: case booleanValue: case stringValue: return 0; #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: // size of the array is highest index + 1 if ( !value_.map_->empty() ) { ObjectValues::const_iterator itLast = value_.map_->end(); --itLast; return (*itLast).first.index()+1; } return 0; case objectValue: return Int( value_.map_->size() ); #else case arrayValue: return Int( value_.array_->size() ); case objectValue: return Int( value_.map_->size() ); #endif default: JSON_ASSERT_UNREACHABLE; } return 0; // unreachable; } bool Value::empty() const { if ( isNull() || isArray() || isObject() ) return size() == 0u; else return false; } bool Value::operator!() const { return isNull(); } void Value::clear() { JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); switch ( type_ ) { #ifndef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: case objectValue: value_.map_->clear(); break; #else case arrayValue: value_.array_->clear(); break; case objectValue: value_.map_->clear(); break; #endif default: break; } } void Value::resize( UInt newSize ) { JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); if ( type_ == nullValue ) *this = Value( arrayValue ); #ifndef JSON_VALUE_USE_INTERNAL_MAP UInt oldSize = size(); if ( newSize == 0 ) clear(); else if ( newSize > oldSize ) (*this)[ newSize - 1 ]; else { for ( UInt index = newSize; index < oldSize; ++index ) value_.map_->erase( index ); assert( size() == newSize ); } #else value_.array_->resize( newSize ); #endif } Value & Value::operator[]( UInt index ) { JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); if ( type_ == nullValue ) *this = Value( arrayValue ); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key( index ); ObjectValues::iterator it = value_.map_->lower_bound( key ); if ( it != value_.map_->end() && (*it).first == key ) return (*it).second; ObjectValues::value_type defaultValue( key, null ); it = value_.map_->insert( it, defaultValue ); return (*it).second; #else return value_.array_->resolveReference( index ); #endif } const Value & Value::operator[]( UInt index ) const { JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); if ( type_ == nullValue ) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString key( index ); ObjectValues::const_iterator it = value_.map_->find( key ); if ( it == value_.map_->end() ) return null; return (*it).second; #else Value *value = value_.array_->find( index ); return value ? *value : null; #endif } Value & Value::operator[]( const char *key ) { return resolveReference( key, false ); } Value & Value::resolveReference( const char *key, bool isStatic ) { JSON_ASSERT( type_ == nullValue || type_ == objectValue ); if ( type_ == nullValue ) *this = Value( objectValue ); #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy ); ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); if ( it != value_.map_->end() && (*it).first == actualKey ) return (*it).second; ObjectValues::value_type defaultValue( actualKey, null ); it = value_.map_->insert( it, defaultValue ); Value &value = (*it).second; return value; #else return value_.map_->resolveReference( key, isStatic ); #endif } Value Value::get( UInt index, const Value &defaultValue ) const { const Value *value = &((*this)[index]); return value == &null ? defaultValue : *value; } bool Value::isValidIndex( UInt index ) const { return index < size(); } const Value & Value::operator[]( const char *key ) const { JSON_ASSERT( type_ == nullValue || type_ == objectValue ); if ( type_ == nullValue ) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, CZString::noDuplication ); ObjectValues::const_iterator it = value_.map_->find( actualKey ); if ( it == value_.map_->end() ) return null; return (*it).second; #else const Value *value = value_.map_->find( key ); return value ? *value : null; #endif } Value & Value::operator[]( const std::string &key ) { return (*this)[ key.c_str() ]; } const Value & Value::operator[]( const std::string &key ) const { return (*this)[ key.c_str() ]; } Value & Value::operator[]( const StaticString &key ) { return resolveReference( key, true ); } # ifdef JSON_USE_CPPTL Value & Value::operator[]( const CppTL::ConstString &key ) { return (*this)[ key.c_str() ]; } const Value & Value::operator[]( const CppTL::ConstString &key ) const { return (*this)[ key.c_str() ]; } # endif Value & Value::append( const Value &value ) { return (*this)[size()] = value; } Value Value::get( const char *key, const Value &defaultValue ) const { const Value *value = &((*this)[key]); return value == &null ? defaultValue : *value; } Value Value::get( const std::string &key, const Value &defaultValue ) const { return get( key.c_str(), defaultValue ); } Value Value::removeMember( const char* key ) { JSON_ASSERT( type_ == nullValue || type_ == objectValue ); if ( type_ == nullValue ) return null; #ifndef JSON_VALUE_USE_INTERNAL_MAP CZString actualKey( key, CZString::noDuplication ); ObjectValues::iterator it = value_.map_->find( actualKey ); if ( it == value_.map_->end() ) return null; Value old(it->second); value_.map_->erase(it); return old; #else Value *value = value_.map_->find( key ); if (value){ Value old(*value); value_.map_.remove( key ); return old; } else { return null; } #endif } Value Value::removeMember( const std::string &key ) { return removeMember( key.c_str() ); } # ifdef JSON_USE_CPPTL Value Value::get( const CppTL::ConstString &key, const Value &defaultValue ) const { return get( key.c_str(), defaultValue ); } # endif bool Value::isMember( const char *key ) const { const Value *value = &((*this)[key]); return value != &null; } bool Value::isMember( const std::string &key ) const { return isMember( key.c_str() ); } # ifdef JSON_USE_CPPTL bool Value::isMember( const CppTL::ConstString &key ) const { return isMember( key.c_str() ); } #endif Value::Members Value::getMemberNames() const { JSON_ASSERT( type_ == nullValue || type_ == objectValue ); if ( type_ == nullValue ) return Value::Members(); Members members; members.reserve( value_.map_->size() ); #ifndef JSON_VALUE_USE_INTERNAL_MAP ObjectValues::const_iterator it = value_.map_->begin(); ObjectValues::const_iterator itEnd = value_.map_->end(); for ( ; it != itEnd; ++it ) members.push_back( std::string( (*it).first.c_str() ) ); #else ValueInternalMap::IteratorState it; ValueInternalMap::IteratorState itEnd; value_.map_->makeBeginIterator( it ); value_.map_->makeEndIterator( itEnd ); for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) members.push_back( std::string( ValueInternalMap::key( it ) ) ); #endif return members; } // //# ifdef JSON_USE_CPPTL //EnumMemberNames //Value::enumMemberNames() const //{ // if ( type_ == objectValue ) // { // return CppTL::Enum::any( CppTL::Enum::transform( // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), // MemberNamesTransform() ) ); // } // return EnumMemberNames(); //} // // //EnumValues //Value::enumValues() const //{ // if ( type_ == objectValue || type_ == arrayValue ) // return CppTL::Enum::anyValues( *(value_.map_), // CppTL::Type() ); // return EnumValues(); //} // //# endif bool Value::isNull() const { return type_ == nullValue; } bool Value::isBool() const { return type_ == booleanValue; } bool Value::isInt() const { return type_ == intValue; } bool Value::isUInt() const { return type_ == uintValue; } bool Value::isIntegral() const { return type_ == intValue || type_ == uintValue || type_ == booleanValue; } bool Value::isDouble() const { return type_ == realValue; } bool Value::isNumeric() const { return isIntegral() || isDouble(); } bool Value::isString() const { return type_ == stringValue; } bool Value::isArray() const { return type_ == nullValue || type_ == arrayValue; } bool Value::isObject() const { return type_ == nullValue || type_ == objectValue; } void Value::setComment( const char *comment, CommentPlacement placement ) { if ( !comments_ ) comments_ = new CommentInfo[numberOfCommentPlacement]; comments_[placement].setComment( comment ); } void Value::setComment( const std::string &comment, CommentPlacement placement ) { setComment( comment.c_str(), placement ); } bool Value::hasComment( CommentPlacement placement ) const { return comments_ != 0 && comments_[placement].comment_ != 0; } std::string Value::getComment( CommentPlacement placement ) const { if ( hasComment(placement) ) return comments_[placement].comment_; return ""; } std::string Value::toStyledString() const { StyledWriter writer; return writer.write( *this ); } Value::const_iterator Value::begin() const { switch ( type_ ) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if ( value_.array_ ) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator( it ); return const_iterator( it ); } break; case objectValue: if ( value_.map_ ) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator( it ); return const_iterator( it ); } break; #else case arrayValue: case objectValue: if ( value_.map_ ) return const_iterator( value_.map_->begin() ); break; #endif default: break; } return const_iterator(); } Value::const_iterator Value::end() const { switch ( type_ ) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if ( value_.array_ ) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator( it ); return const_iterator( it ); } break; case objectValue: if ( value_.map_ ) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator( it ); return const_iterator( it ); } break; #else case arrayValue: case objectValue: if ( value_.map_ ) return const_iterator( value_.map_->end() ); break; #endif default: break; } return const_iterator(); } Value::iterator Value::begin() { switch ( type_ ) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if ( value_.array_ ) { ValueInternalArray::IteratorState it; value_.array_->makeBeginIterator( it ); return iterator( it ); } break; case objectValue: if ( value_.map_ ) { ValueInternalMap::IteratorState it; value_.map_->makeBeginIterator( it ); return iterator( it ); } break; #else case arrayValue: case objectValue: if ( value_.map_ ) return iterator( value_.map_->begin() ); break; #endif default: break; } return iterator(); } Value::iterator Value::end() { switch ( type_ ) { #ifdef JSON_VALUE_USE_INTERNAL_MAP case arrayValue: if ( value_.array_ ) { ValueInternalArray::IteratorState it; value_.array_->makeEndIterator( it ); return iterator( it ); } break; case objectValue: if ( value_.map_ ) { ValueInternalMap::IteratorState it; value_.map_->makeEndIterator( it ); return iterator( it ); } break; #else case arrayValue: case objectValue: if ( value_.map_ ) return iterator( value_.map_->end() ); break; #endif default: break; } return iterator(); } // class PathArgument // ////////////////////////////////////////////////////////////////// PathArgument::PathArgument() : kind_( kindNone ) { } PathArgument::PathArgument( Value::UInt index ) : index_( index ) , kind_( kindIndex ) { } PathArgument::PathArgument( const char *key ) : key_( key ) , kind_( kindKey ) { } PathArgument::PathArgument( const std::string &key ) : key_( key.c_str() ) , kind_( kindKey ) { } // class Path // ////////////////////////////////////////////////////////////////// Path::Path( const std::string &path, const PathArgument &a1, const PathArgument &a2, const PathArgument &a3, const PathArgument &a4, const PathArgument &a5 ) { InArgs in; in.push_back( &a1 ); in.push_back( &a2 ); in.push_back( &a3 ); in.push_back( &a4 ); in.push_back( &a5 ); makePath( path, in ); } void Path::makePath( const std::string &path, const InArgs &in ) { const char *current = path.c_str(); const char *end = current + path.length(); InArgs::const_iterator itInArg = in.begin(); while ( current != end ) { if ( *current == '[' ) { ++current; if ( *current == '%' ) addPathInArg( path, in, itInArg, PathArgument::kindIndex ); else { Value::UInt index = 0; for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) index = index * 10 + Value::UInt(*current - '0'); args_.push_back( index ); } if ( current == end || *current++ != ']' ) invalidPath( path, int(current - path.c_str()) ); } else if ( *current == '%' ) { addPathInArg( path, in, itInArg, PathArgument::kindKey ); ++current; } else if ( *current == '.' ) { ++current; } else { const char *beginName = current; while ( current != end && !strchr( "[.", *current ) ) ++current; args_.push_back( std::string( beginName, current ) ); } } } void Path::addPathInArg( const std::string &path, const InArgs &in, InArgs::const_iterator &itInArg, PathArgument::Kind kind ) { if ( itInArg == in.end() ) { // Error: missing argument %d } else if ( (*itInArg)->kind_ != kind ) { // Error: bad argument type } else { args_.push_back( **itInArg ); } } void Path::invalidPath( const std::string &path, int location ) { // Error: invalid path. } const Value & Path::resolve( const Value &root ) const { const Value *node = &root; for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { const PathArgument &arg = *it; if ( arg.kind_ == PathArgument::kindIndex ) { if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) { // Error: unable to resolve path (array value expected at position... } node = &((*node)[arg.index_]); } else if ( arg.kind_ == PathArgument::kindKey ) { if ( !node->isObject() ) { // Error: unable to resolve path (object value expected at position...) } node = &((*node)[arg.key_]); if ( node == &Value::null ) { // Error: unable to resolve path (object has no member named '' at position...) } } } return *node; } Value Path::resolve( const Value &root, const Value &defaultValue ) const { const Value *node = &root; for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { const PathArgument &arg = *it; if ( arg.kind_ == PathArgument::kindIndex ) { if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) return defaultValue; node = &((*node)[arg.index_]); } else if ( arg.kind_ == PathArgument::kindKey ) { if ( !node->isObject() ) return defaultValue; node = &((*node)[arg.key_]); if ( node == &Value::null ) return defaultValue; } } return *node; } Value & Path::make( Value &root ) const { Value *node = &root; for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) { const PathArgument &arg = *it; if ( arg.kind_ == PathArgument::kindIndex ) { if ( !node->isArray() ) { // Error: node is not an array at position ... } node = &((*node)[arg.index_]); } else if ( arg.kind_ == PathArgument::kindKey ) { if ( !node->isObject() ) { // Error: node is not an object at position... } node = &((*node)[arg.key_]); } } return *node; } } // namespace Json ================================================ FILE: common/jsoncpp/writer.cpp ================================================ #include #include #include #include #include #include #include #include "json/writer.h" #if _MSC_VER >= 1400 // VC++ 8.0 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. #endif namespace Json { static bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } static bool containsControlCharacter( const char* str ) { while ( *str ) { if ( isControlCharacter( *(str++) ) ) return true; } return false; } static void uintToString( unsigned int value, char *¤t ) { *--current = 0; do { *--current = (value % 10) + '0'; value /= 10; } while ( value != 0 ); } std::string valueToString( Int value ) { char buffer[32]; char *current = buffer + sizeof(buffer); bool isNegative = value < 0; if ( isNegative ) value = -value; uintToString( UInt(value), current ); if ( isNegative ) *--current = '-'; assert( current >= buffer ); return current; } std::string valueToString( UInt value ) { char buffer[32]; char *current = buffer + sizeof(buffer); uintToString( value, current ); assert( current >= buffer ); return current; } std::string valueToString( double value ) { char buffer[32]; #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. sprintf_s(buffer, sizeof(buffer), "%#.16g", value); #else sprintf(buffer, "%#.16g", value); #endif char* ch = buffer + strlen(buffer) - 1; if (*ch != '0') return buffer; // nothing to truncate, so save time while(ch > buffer && *ch == '0'){ --ch; } char* last_nonzero = ch; while(ch >= buffer){ switch(*ch){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': --ch; continue; case '.': // Truncate zeroes to save bytes in output, but keep one. *(last_nonzero+2) = '\0'; return buffer; default: return buffer; } } return buffer; } std::string valueToString( bool value ) { return value ? "true" : "false"; } std::string valueToQuotedString( const char *value ) { // Not sure how to handle unicode... if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) return std::string("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to std::string is not efficient, but this should be rare. // (Note: forward slashes are *not* rare, but I am not escaping them.) unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL std::string result; result.reserve(maxsize); // to avoid lots of mallocs result += "\""; for (const char* c=value; *c != 0; ++c) { switch(*c) { case '\"': result += "\\\""; break; case '\\': result += "\\\\"; break; case '\b': result += "\\b"; break; case '\f': result += "\\f"; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; //case '/': // Even though \/ is considered a legal escape in JSON, a bare // slash is also legal, so I see no reason to escape it. // (I hope I am not misunderstanding something. // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); result += oss.str(); } else { result += *c; } break; } } result += "\""; return result; } // Class Writer // ////////////////////////////////////////////////////////////////// Writer::~Writer() { } // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() : yamlCompatiblityEnabled_( false ) { } void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } std::string FastWriter::write( const Value &root ) { document_ = ""; writeValue( root ); document_ += "\n"; return document_; } void FastWriter::writeValue( const Value &value ) { switch ( value.type() ) { case nullValue: document_ += "null"; break; case intValue: document_ += valueToString( value.asInt() ); break; case uintValue: document_ += valueToString( value.asUInt() ); break; case realValue: document_ += valueToString( value.asDouble() ); break; case stringValue: document_ += valueToQuotedString( value.asCString() ); break; case booleanValue: document_ += valueToString( value.asBool() ); break; case arrayValue: { document_ += "["; int size = value.size(); for ( int index =0; index < size; ++index ) { if ( index > 0 ) document_ += ","; writeValue( value[index] ); } document_ += "]"; } break; case objectValue: { Value::Members members( value.getMemberNames() ); document_ += "{"; for ( Value::Members::iterator it = members.begin(); it != members.end(); ++it ) { const std::string &name = *it; if ( it != members.begin() ) document_ += ","; document_ += valueToQuotedString( name.c_str() ); document_ += yamlCompatiblityEnabled_ ? ": " : ":"; writeValue( value[name] ); } document_ += "}"; } break; } } // Class StyledWriter // ////////////////////////////////////////////////////////////////// StyledWriter::StyledWriter() : rightMargin_( 74 ) , indentSize_( 3 ) { } std::string StyledWriter::write( const Value &root ) { document_ = ""; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue( root ); writeValue( root ); writeCommentAfterValueOnSameLine( root ); document_ += "\n"; return document_; } void StyledWriter::writeValue( const Value &value ) { switch ( value.type() ) { case nullValue: pushValue( "null" ); break; case intValue: pushValue( valueToString( value.asInt() ) ); break; case uintValue: pushValue( valueToString( value.asUInt() ) ); break; case realValue: pushValue( valueToString( value.asDouble() ) ); break; case stringValue: pushValue( valueToQuotedString( value.asCString() ) ); break; case booleanValue: pushValue( valueToString( value.asBool() ) ); break; case arrayValue: writeArrayValue( value); break; case objectValue: { Value::Members members( value.getMemberNames() ); if ( members.empty() ) pushValue( "{}" ); else { writeWithIndent( "{" ); indent(); Value::Members::iterator it = members.begin(); while ( true ) { const std::string &name = *it; const Value &childValue = value[name]; writeCommentBeforeValue( childValue ); writeWithIndent( valueToQuotedString( name.c_str() ) ); document_ += " : "; writeValue( childValue ); if ( ++it == members.end() ) { writeCommentAfterValueOnSameLine( childValue ); break; } document_ += ","; writeCommentAfterValueOnSameLine( childValue ); } unindent(); writeWithIndent( "}" ); } } break; } } void StyledWriter::writeArrayValue( const Value &value ) { unsigned size = value.size(); if ( size == 0 ) pushValue( "[]" ); else { bool isArrayMultiLine = isMultineArray( value ); if ( isArrayMultiLine ) { writeWithIndent( "[" ); indent(); bool hasChildValue = !childValues_.empty(); unsigned index =0; while ( true ) { const Value &childValue = value[index]; writeCommentBeforeValue( childValue ); if ( hasChildValue ) writeWithIndent( childValues_[index] ); else { writeIndent(); writeValue( childValue ); } if ( ++index == size ) { writeCommentAfterValueOnSameLine( childValue ); break; } document_ += ","; writeCommentAfterValueOnSameLine( childValue ); } unindent(); writeWithIndent( "]" ); } else // output on a single line { assert( childValues_.size() == size ); document_ += "[ "; for ( unsigned index =0; index < size; ++index ) { if ( index > 0 ) document_ += ", "; document_ += childValues_[index]; } document_ += " ]"; } } } bool StyledWriter::isMultineArray( const Value &value ) { int size = value.size(); bool isMultiLine = size*3 >= rightMargin_ ; childValues_.clear(); for ( int index =0; index < size && !isMultiLine; ++index ) { const Value &childValue = value[index]; isMultiLine = isMultiLine || ( (childValue.isArray() || childValue.isObject()) && childValue.size() > 0 ); } if ( !isMultiLine ) // check if line length > max line length { childValues_.reserve( size ); addChildValues_ = true; int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' for ( int index =0; index < size && !isMultiLine; ++index ) { writeValue( value[index] ); lineLength += int( childValues_[index].length() ); isMultiLine = isMultiLine && hasCommentForValue( value[index] ); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; } return isMultiLine; } void StyledWriter::pushValue( const std::string &value ) { if ( addChildValues_ ) childValues_.push_back( value ); else document_ += value; } void StyledWriter::writeIndent() { if ( !document_.empty() ) { char last = document_[document_.length()-1]; if ( last == ' ' ) // already indented return; if ( last != '\n' ) // Comments may add new-line document_ += '\n'; } document_ += indentString_; } void StyledWriter::writeWithIndent( const std::string &value ) { writeIndent(); document_ += value; } void StyledWriter::indent() { indentString_ += std::string( indentSize_, ' ' ); } void StyledWriter::unindent() { assert( int(indentString_.size()) >= indentSize_ ); indentString_.resize( indentString_.size() - indentSize_ ); } void StyledWriter::writeCommentBeforeValue( const Value &root ) { if ( !root.hasComment( commentBefore ) ) return; document_ += normalizeEOL( root.getComment( commentBefore ) ); document_ += "\n"; } void StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) { if ( root.hasComment( commentAfterOnSameLine ) ) document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); if ( root.hasComment( commentAfter ) ) { document_ += "\n"; document_ += normalizeEOL( root.getComment( commentAfter ) ); document_ += "\n"; } } bool StyledWriter::hasCommentForValue( const Value &value ) { return value.hasComment( commentBefore ) || value.hasComment( commentAfterOnSameLine ) || value.hasComment( commentAfter ); } std::string StyledWriter::normalizeEOL( const std::string &text ) { std::string normalized; normalized.reserve( text.length() ); const char *begin = text.c_str(); const char *end = begin + text.length(); const char *current = begin; while ( current != end ) { char c = *current++; if ( c == '\r' ) // mac or dos EOL { if ( *current == '\n' ) // convert dos EOL ++current; normalized += '\n'; } else // handle unix EOL & other char normalized += c; } return normalized; } // Class StyledStreamWriter // ////////////////////////////////////////////////////////////////// StyledStreamWriter::StyledStreamWriter( std::string indentation ) : document_(NULL) , rightMargin_( 74 ) , indentation_( indentation ) { } void StyledStreamWriter::write( std::ostream &out, const Value &root ) { document_ = &out; addChildValues_ = false; indentString_ = ""; writeCommentBeforeValue( root ); writeValue( root ); writeCommentAfterValueOnSameLine( root ); *document_ << "\n"; document_ = NULL; // Forget the stream, for safety. } void StyledStreamWriter::writeValue( const Value &value ) { switch ( value.type() ) { case nullValue: pushValue( "null" ); break; case intValue: pushValue( valueToString( value.asInt() ) ); break; case uintValue: pushValue( valueToString( value.asUInt() ) ); break; case realValue: pushValue( valueToString( value.asDouble() ) ); break; case stringValue: pushValue( valueToQuotedString( value.asCString() ) ); break; case booleanValue: pushValue( valueToString( value.asBool() ) ); break; case arrayValue: writeArrayValue( value); break; case objectValue: { Value::Members members( value.getMemberNames() ); if ( members.empty() ) pushValue( "{}" ); else { writeWithIndent( "{" ); indent(); Value::Members::iterator it = members.begin(); while ( true ) { const std::string &name = *it; const Value &childValue = value[name]; writeCommentBeforeValue( childValue ); writeWithIndent( valueToQuotedString( name.c_str() ) ); *document_ << " : "; writeValue( childValue ); if ( ++it == members.end() ) { writeCommentAfterValueOnSameLine( childValue ); break; } *document_ << ","; writeCommentAfterValueOnSameLine( childValue ); } unindent(); writeWithIndent( "}" ); } } break; } } void StyledStreamWriter::writeArrayValue( const Value &value ) { unsigned size = value.size(); if ( size == 0 ) pushValue( "[]" ); else { bool isArrayMultiLine = isMultineArray( value ); if ( isArrayMultiLine ) { writeWithIndent( "[" ); indent(); bool hasChildValue = !childValues_.empty(); unsigned index =0; while ( true ) { const Value &childValue = value[index]; writeCommentBeforeValue( childValue ); if ( hasChildValue ) writeWithIndent( childValues_[index] ); else { writeIndent(); writeValue( childValue ); } if ( ++index == size ) { writeCommentAfterValueOnSameLine( childValue ); break; } *document_ << ","; writeCommentAfterValueOnSameLine( childValue ); } unindent(); writeWithIndent( "]" ); } else // output on a single line { assert( childValues_.size() == size ); *document_ << "[ "; for ( unsigned index =0; index < size; ++index ) { if ( index > 0 ) *document_ << ", "; *document_ << childValues_[index]; } *document_ << " ]"; } } } bool StyledStreamWriter::isMultineArray( const Value &value ) { int size = value.size(); bool isMultiLine = size*3 >= rightMargin_ ; childValues_.clear(); for ( int index =0; index < size && !isMultiLine; ++index ) { const Value &childValue = value[index]; isMultiLine = isMultiLine || ( (childValue.isArray() || childValue.isObject()) && childValue.size() > 0 ); } if ( !isMultiLine ) // check if line length > max line length { childValues_.reserve( size ); addChildValues_ = true; int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' for ( int index =0; index < size && !isMultiLine; ++index ) { writeValue( value[index] ); lineLength += int( childValues_[index].length() ); isMultiLine = isMultiLine && hasCommentForValue( value[index] ); } addChildValues_ = false; isMultiLine = isMultiLine || lineLength >= rightMargin_; } return isMultiLine; } void StyledStreamWriter::pushValue( const std::string &value ) { if ( addChildValues_ ) childValues_.push_back( value ); else *document_ << value; } void StyledStreamWriter::writeIndent() { /* Some comments in this method would have been nice. ;-) if ( !document_.empty() ) { char last = document_[document_.length()-1]; if ( last == ' ' ) // already indented return; if ( last != '\n' ) // Comments may add new-line *document_ << '\n'; } */ *document_ << '\n' << indentString_; } void StyledStreamWriter::writeWithIndent( const std::string &value ) { writeIndent(); *document_ << value; } void StyledStreamWriter::indent() { indentString_ += indentation_; } void StyledStreamWriter::unindent() { assert( indentString_.size() >= indentation_.size() ); indentString_.resize( indentString_.size() - indentation_.size() ); } void StyledStreamWriter::writeCommentBeforeValue( const Value &root ) { if ( !root.hasComment( commentBefore ) ) return; *document_ << normalizeEOL( root.getComment( commentBefore ) ); *document_ << "\n"; } void StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) { if ( root.hasComment( commentAfterOnSameLine ) ) *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); if ( root.hasComment( commentAfter ) ) { *document_ << "\n"; *document_ << normalizeEOL( root.getComment( commentAfter ) ); *document_ << "\n"; } } bool StyledStreamWriter::hasCommentForValue( const Value &value ) { return value.hasComment( commentBefore ) || value.hasComment( commentAfterOnSameLine ) || value.hasComment( commentAfter ); } std::string StyledStreamWriter::normalizeEOL( const std::string &text ) { std::string normalized; normalized.reserve( text.length() ); const char *begin = text.c_str(); const char *end = begin + text.length(); const char *current = begin; while ( current != end ) { char c = *current++; if ( c == '\r' ) // mac or dos EOL { if ( *current == '\n' ) // convert dos EOL ++current; normalized += '\n'; } else // handle unix EOL & other char normalized += c; } return normalized; } std::ostream& operator<<( std::ostream &sout, const Value &root ) { Json::StyledStreamWriter writer; writer.write(sout, root); return sout; } } // namespace Json ================================================ FILE: common/util/base.cpp ================================================ #include "stdafx.h" #include #include "Base.h" namespace Util { namespace Base { int GetAccurateOSVersion() { static int lCurrentVersion = -1; if (-1 == lCurrentVersion) { lCurrentVersion = WINDOWS_OLDEST; OSVERSIONINFOW os = {sizeof(OSVERSIONINFOW)}; if (::GetVersionExW(&os) && os.dwPlatformId == VER_PLATFORM_WIN32_NT) { if (os.dwMajorVersion == 5) { if (os.dwMinorVersion == 0) lCurrentVersion = WINDOWS_2000; else if (os.dwMinorVersion == 1) { if (_wcsnicmp(L"Service Pack 1", os.szCSDVersion, 127) == 0) lCurrentVersion = WINDOWS_XP_SP_1; else if (_wcsnicmp(L"Service Pack 2", os.szCSDVersion, 127) == 0) lCurrentVersion = WINDOWS_XP_SP_2; else if (_wcsnicmp(L"Service Pack 3", os.szCSDVersion, 127) == 0) lCurrentVersion = WINDOWS_XP_SP_3; else lCurrentVersion = WINDOWS_XP_NO_SP; } else if (os.dwMinorVersion == 2) lCurrentVersion = WINDOWS_2003; } else if (os.dwMajorVersion == 6) { if (os.dwMinorVersion == 0) { if (_wcsnicmp(L"Service Pack 1", os.szCSDVersion, 127) == 0) lCurrentVersion = WINDOWS_VISTA_SP_1; else if (_wcsnicmp(L"Service Pack 2", os.szCSDVersion, 127) == 0) lCurrentVersion = WINDOWS_VISTA_SP_2; else lCurrentVersion = WINDOWS_VISTA_NO_SP; } else if (os.dwMinorVersion == 1) lCurrentVersion = WINDOWS_7; else if (os.dwMinorVersion == 2) lCurrentVersion = WINDOWS_8; else if (os.dwMinorVersion == 3) lCurrentVersion = WINDOWS_8_SP1; } else if (os.dwMajorVersion == 10) { lCurrentVersion = WINDOWS_11; } else { lCurrentVersion = WINDOWS_LATEST; } } } return lCurrentVersion; } std::string GetOSVersion() { long version = GetAccurateOSVersion(); std::string version_str = "unknown"; switch (version) { case WINDOWS_2000: { version_str = "Windows2000"; } break; case WINDOWS_XP_NO_SP: case WINDOWS_XP_SP_1: case WINDOWS_XP_SP_2: case WINDOWS_XP_SP_3: { version_str = "WindowsXP"; } break; case WINDOWS_2003: { version_str = "WindowsServer2003"; } break; case WINDOWS_VISTA_NO_SP: case WINDOWS_VISTA_SP_1: { version_str = "WindowsVista"; } break; case WINDOWS_7: { version_str = "Windows7"; } break; case WINDOWS_8: { version_str = "Windows8"; } break; case WINDOWS_8_SP1: { version_str = "Windows8.1"; } break; case WINDOWS_11: { version_str = "Windows11"; } break; default: break; } return version_str; } std::string longtochar(long l) { char s[50] = {0}; _snprintf_s(s, 50, _TRUNCATE, "%ld", l); std::string s_s = s; return s_s; } std::wstring longtocharw(long l) { WCHAR s[50] = {0}; _snwprintf_s(s, 50, _TRUNCATE, L"%ld", l); std::wstring s_s = s; return s_s; } std::wstring UTF8DecodeW(LPCSTR lpszUtf8Src) { std::wstring strUnicode(L""); if (!lpszUtf8Src) return strUnicode; int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src), NULL, 0); wchar_t* wszString = new wchar_t[wcsLen + 1]; if (wszString) { ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src), wszString, wcsLen); wszString[wcsLen] = L'\0'; strUnicode = wszString; delete[] wszString; } return strUnicode; } std::string UTF8DecodeA(LPCSTR lpszUtf8Src) { std::string strAnsi(""); if (!lpszUtf8Src) return strAnsi; int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src), NULL, 0); wchar_t* wszString = new wchar_t[wcsLen + 1]; if (wszString) { ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src), wszString, wcsLen); wszString[wcsLen] = L'\0'; int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), NULL, 0, NULL, NULL); char* szAnsi = new char[ansiLen + 1]; if (szAnsi) { ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), szAnsi, ansiLen, NULL, NULL); szAnsi[ansiLen] = '\0'; strAnsi = szAnsi; delete[] szAnsi; } delete[] wszString; } return strAnsi; } std::string WChar2Ansi(LPCWSTR pwszSrc) { int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL); if (nLen <= 0) return std::string(""); char* pszDst = new char[nLen]; if (NULL == pszDst) return std::string(""); WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL); pszDst[nLen - 1] = 0; std::string strTemp(pszDst); delete[] pszDst; return strTemp; } std::wstring Ansi2WChar(LPCSTR pszSrc, int nLen) { int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, 0, 0); if (nSize <= 0) return std::wstring(L""); WCHAR* pwszDst = new WCHAR[nSize + 1]; if (NULL == pwszDst) return std::wstring(L""); MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, pwszDst, nSize); pwszDst[nSize] = 0; if (pwszDst[0] == 0xFEFF) for (int i = 0; i < nSize; i++) pwszDst[i] = pwszDst[i + 1]; std::wstring wcharString(pwszDst); delete pwszDst; return wcharString; } std::string ws2s(std::wstring& inputws) { return WChar2Ansi(inputws.c_str()); } std::wstring s2ws(const std::string& s) { return Ansi2WChar(s.c_str(), s.size()); } std::string UnicodeToUTF8(LPCWSTR lpszUnicode) { std::string utf8(""); if (!lpszUnicode) return utf8; int u8Len = ::WideCharToMultiByte(CP_UTF8, NULL, lpszUnicode, wcslen(lpszUnicode), NULL, 0, NULL, NULL); char *szU8 = new char[u8Len + 1]; if (szU8) { ::WideCharToMultiByte(CP_UTF8, NULL, lpszUnicode, wcslen(lpszUnicode), szU8, u8Len, NULL, NULL); szU8[u8Len] = '\0'; utf8 = szU8; delete[] szU8; } return utf8; } std::wstring UTF8ToUnicode(LPCSTR lpszUtf8) { std::wstring strUnicode(L""); if (!lpszUtf8) return strUnicode; int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8, strlen(lpszUtf8), NULL, 0); wchar_t *wszString = new wchar_t[wcsLen + 1]; if (wszString) { ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8, strlen(lpszUtf8), wszString, wcsLen); wszString[wcsLen] = L'\0'; strUnicode = wszString; delete[] wszString; } return strUnicode; } std::wstring dwtos(const DWORD dw) { WCHAR ws[50] = { 0 }; _sntprintf_s(ws, 50, _TRUNCATE, _T("%u"), dw); return std::wstring(ws); } std::string dwtoss(const DWORD dw) { char ss[50] = { 0 }; _snprintf(ss, 50, "%u", dw); return std::string(ss); } DWORD stodw(std::string& strNum) { DWORD dw = strtoul(strNum.c_str(), NULL, 10); return dw; } std::string f2ss(const double f) { char ss[50] = { 0 }; _snprintf(ss, 50, "%f", f); return std::string(ss); } std::wstring f2ws(const double f) { WCHAR ws[50] = { 0 }; _sntprintf_s(ws, 50, _TRUNCATE, _T("%f"), f); return std::wstring(ws); } } // namespace Base } // namespace Util ================================================ FILE: common/util/base.h ================================================ #pragma once constexpr int WINDOWS_OLDEST = -1000; constexpr int WINDOWS_2000 = 1; constexpr int WINDOWS_XP_NO_SP = 2; constexpr int WINDOWS_XP_SP_1 = 3; constexpr int WINDOWS_XP_SP_2 = 4; constexpr int WINDOWS_XP_SP_3 = 5; constexpr int WINDOWS_2003 = 6; constexpr int WINDOWS_VISTA_NO_SP = 7; constexpr int WINDOWS_VISTA_SP_1 = 8; constexpr int WINDOWS_VISTA_SP_2 = 8; constexpr int WINDOWS_7 = 9; constexpr int WINDOWS_8 = 10; constexpr int WINDOWS_8_SP1 = 11; constexpr int WINDOWS_11 = 12; constexpr int WINDOWS_LATEST = 1000; namespace Util { namespace Base { int GetAccurateOSVersion(); std::string GetOSVersion(); std::string longtochar(long l); std::wstring longtocharw(long l); std::wstring UTF8DecodeW(LPCSTR lpszUtf8Src); std::string UTF8DecodeA(LPCSTR lpszUtf8Src); std::string WChar2Ansi(LPCWSTR pwszSrc); std::wstring Ansi2WChar(LPCSTR pszSrc, int nLen); std::string ws2s(std::wstring& inputws); std::wstring s2ws(const std::string& s); std::string UnicodeToUTF8(LPCWSTR lpszUnicodeSrc); std::wstring UTF8ToUnicode(LPCSTR lpszUtf8Src); std::wstring dwtos(const DWORD dw); std::string dwtoss(const DWORD dw); DWORD stodw(std::string& strNum); std::string f2ss(const double f); std::wstring f2ws(const double f); } // namespace Base } // namespace Util ================================================ FILE: common/util/def.h ================================================ #pragma once #define WM_DEL_GDI_OBJ WM_USER + 0x10E0C #define WM_IS_EXIST WM_USER + 0x10E0D namespace app { enum NotificationType { NOTIFICATION_APP_START = 0, NOTIFICATION_APP_DOWNLOAD_CANCAL, }; } extern UINT WM_TASKBARBUTTONCREATED; ================================================ FILE: common/util/md5.cpp ================================================ #include "md5.h" using namespace std; /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) \ { \ (a) += F((b), (c), (d)) + (x) + ac; \ (a) = ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) \ { \ (a) += G((b), (c), (d)) + (x) + ac; \ (a) = ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) \ { \ (a) += H((b), (c), (d)) + (x) + ac; \ (a) = ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) \ { \ (a) += I((b), (c), (d)) + (x) + ac; \ (a) = ROTATE_LEFT((a), (s)); \ (a) += (b); \ } const byte MD5::PADDING[64] = {0x80}; const char MD5::HEX[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; const unsigned int MD5::BUFFER_SIZE = 1024; /* Default construct. */ MD5::MD5() { reset(); } /* Construct a MD5 object with a input buffer. */ MD5::MD5(const void *input, size_t length) { reset(); update(input, length); } /* Construct a MD5 object with a string. */ MD5::MD5(const string &str) { reset(); update(str); } /* Construct a MD5 object with a file. */ MD5::MD5(ifstream &in) { reset(); update(in); } /* Return the message-digest */ const byte *MD5::digest() { if (!_finished) { _finished = true; final(); } return _digest; } /* Reset the calculate state */ void MD5::reset() { _finished = false; /* reset number of bits. */ _count[0] = _count[1] = 0; /* Load magic initialization constants. */ _state[0] = 0x67452301; _state[1] = 0xefcdab89; _state[2] = 0x98badcfe; _state[3] = 0x10325476; } /* Updating the context with a input buffer. */ void MD5::update(const void *input, size_t length) { update((const byte *)input, length); } /* Updating the context with a string. */ void MD5::update(const string &str) { update((const byte *)str.c_str(), str.length()); } /* Updating the context with a file. */ void MD5::update(ifstream &in) { if (!in) return; size_t length; char buffer[BUFFER_SIZE]; while (!in.eof()) { in.read(buffer, BUFFER_SIZE); length = static_cast(in.gcount()); if (length > 0) update(buffer, length); } in.close(); } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void MD5::update(const byte *input, size_t length) { uint32 i, index, partLen; _finished = false; /* Compute number of bytes mod 64 */ index = (uint32)((_count[0] >> 3) & 0x3f); /* update number of bits */ if ((_count[0] += ((uint32)length << 3)) < ((uint32)length << 3)) _count[1]++; _count[1] += ((uint32)length >> 29); partLen = 64 - index; /* transform as many times as possible. */ if (length >= partLen) { memcpy(&_buffer[index], input, partLen); transform(_buffer); for (i = partLen; i + 63 < length; i += 64) transform(&input[i]); index = 0; } else { i = 0; } /* Buffer remaining input */ memcpy(&_buffer[index], &input[i], length - i); } /* MD5 finalization. Ends an MD5 message-_digest operation, writing the the message _digest and zeroizing the context. */ void MD5::final() { byte bits[8]; uint32 oldState[4]; uint32 oldCount[2]; uint32 index, padLen; /* Save current state and count. */ memcpy(oldState, _state, 16); memcpy(oldCount, _count, 8); /* Save number of bits */ encode(_count, bits, 8); /* Pad out to 56 mod 64. */ index = (uint32)((_count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); update(PADDING, padLen); /* Append length (before padding) */ update(bits, 8); /* Store state in digest */ encode(_state, _digest, 16); /* Restore current state and count. */ memcpy(_state, oldState, 16); memcpy(_count, oldCount, 8); } /* MD5 basic transformation. Transforms _state based on block. */ void MD5::transform(const byte block[64]) { uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16]; decode(block, x, 64); /* Round 1 */ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ _state[0] += a; _state[1] += b; _state[2] += c; _state[3] += d; } /* Encodes input (ulong) into output (byte). Assumes length is a multiple of 4. */ void MD5::encode(const uint32 *input, byte *output, size_t length) { for (size_t i = 0, j = 0; j < length; i++, j += 4) { output[j] = (byte)(input[i] & 0xff); output[j + 1] = (byte)((input[i] >> 8) & 0xff); output[j + 2] = (byte)((input[i] >> 16) & 0xff); output[j + 3] = (byte)((input[i] >> 24) & 0xff); } } /* Decodes input (byte) into output (ulong). Assumes length is a multiple of 4. */ void MD5::decode(const byte *input, uint32 *output, size_t length) { for (size_t i = 0, j = 0; j < length; i++, j += 4) { output[i] = ((uint32)input[j]) | (((uint32)input[j + 1]) << 8) | (((uint32)input[j + 2]) << 16) | (((uint32)input[j + 3]) << 24); } } /* Convert byte array to hex string. */ string MD5::bytesToHexString(const byte *input, size_t length) { string str; str.reserve(length << 1); for (size_t i = 0; i < length; i++) { int t = input[i]; int a = t / 16; int b = t % 16; str.append(1, HEX[a]); str.append(1, HEX[b]); } return str; } /* Convert digest to string value */ string MD5::toString() { return bytesToHexString(digest(), 16); } ================================================ FILE: common/util/md5.h ================================================ #pragma once #include #include /* Type define */ typedef unsigned char byte; typedef unsigned int uint32; using std::ifstream; using std::string; /* MD5 declaration. */ class MD5 { public: MD5(); MD5(const void *input, size_t length); MD5(const string &str); MD5(ifstream &in); void update(const void *input, size_t length); void update(const string &str); void update(ifstream &in); const byte *digest(); string toString(); void reset(); private: void update(const byte *input, size_t length); void final(); void transform(const byte block[64]); void encode(const uint32 *input, byte *output, size_t length); void decode(const byte *input, uint32 *output, size_t length); string bytesToHexString(const byte *input, size_t length); /* class uncopyable */ MD5(const MD5 &); private: uint32 _state[4]; /* state (ABCD) */ uint32 _count[2]; /* number of bits, modulo 2^64 (low-order word first) */ byte _buffer[64]; /* input buffer */ byte _digest[16]; /* message digest */ bool _finished; /* calculate finished ? */ static const byte PADDING[64]; /* padding for calculate */ static const char HEX[16]; static const unsigned int BUFFER_SIZE; }; ================================================ FILE: common/util/system.cpp ================================================ #include "StdAfx.h" #include #include #include #include #include "xzip/XUnzip.h" #include "system.h" #pragma comment(lib, "Version") #pragma comment(lib, "Wininet") #pragma comment(lib, "Netapi32.lib") namespace SystemCommon { namespace FilePathHelper { BOOL ForceCreateDir(LPCTSTR pszFullPathFileName) { if (!pszFullPathFileName || !pszFullPathFileName[0]) return FALSE; if (PathIsRoot(pszFullPathFileName)) return TRUE; TCHAR Dir[MAX_PATH + 1] = {}; int nNeed; LPCTSTR p, pLast; BOOL Result; Result = FALSE; pLast = pszFullPathFileName; if (_tcslen(pLast) > _MAX_PATH) { return FALSE; } while (NULL != *pLast) { p = _tcsstr(pLast, _T("\\")); if (NULL == p) { p = _tcsstr(pLast, _T("/")); if (NULL == p) { return Result; } } nNeed = p - pszFullPathFileName; if (nNeed > 0) { memset(Dir, 0, sizeof(Dir)); _tcsncpy_s(Dir, pszFullPathFileName, p - pszFullPathFileName); Result = CreateMyDir(Dir); } p++; pLast = p; } return Result; } BOOL CreateDir(LPCTSTR lpszPath) { tstring strFile = lpszPath; tstring strPath = GetPath(strFile); strFile = strPath.substr(0, strPath.size() - 1); while (!PathIsDirectory(strFile.c_str())) { if (PathFileExists(strFile.c_str())) { SetFileAttributes(strFile.c_str(), FILE_ATTRIBUTE_NORMAL); DeleteFile(strFile.c_str()); } TCHAR wszPath[1024] = {}; _tcsncpy_s(wszPath, strFile.c_str(), _TRUNCATE); if ((_T('\\') == strFile[strFile.size() - 1]) || (_T('/') == strFile[strFile.size() - 1])) { PathRemoveFileSpec(wszPath); } PathRemoveFileSpec(wszPath); strFile = wszPath; } return ForceCreateDir(strPath.c_str()); } BOOL CreateMyDir(LPCTSTR pszDir) { assert(pszDir); if (!pszDir || !pszDir[0]) return FALSE; BOOL bRet; bRet = ::CreateDirectory(pszDir, NULL); if (FALSE == bRet) { if (ERROR_ALREADY_EXISTS == GetLastError()) return TRUE; } return bRet; } BOOL GetAppPath(HINSTANCE hInst, LPTSTR lpPath, DWORD dMaxLen, LPCTSTR pAddon) { if (!lpPath || dMaxLen <= 0) return FALSE; TCHAR FileName[MAX_PATH] = {}; TCHAR szFullPath[MAX_PATH] = {}; int nStrLen, i; if (!GetModuleFileName(hInst, szFullPath, MAX_PATH)) return FALSE; GetLongPathName(szFullPath, FileName, MAX_PATH); nStrLen = (int)_tcslen(FileName); for (i = nStrLen - 1; i > 0; i--) { if (FileName[i] == _T('\\') && i >= 2) { FileName[i + 1] = _T('\0'); break; } } if (NULL == pAddon) _sntprintf_s(lpPath, dMaxLen, _TRUNCATE, _T("%s"), FileName); else _sntprintf_s(lpPath, dMaxLen, _TRUNCATE, _T("%s%s"), FileName, pAddon); lpPath[dMaxLen - 1] = _T('\0'); return TRUE; } tstring GetAssignPath(DWORD assing, BOOL forecCreate) { TCHAR szAppPath[MAX_PATH + 1] = {0}; SHGetSpecialFolderPath(NULL, szAppPath, assing, forecCreate); return szAppPath; } tstring GetFileName(tstring pathname) { int i; for (i = pathname.length() - 1; i >= 0; --i) { if (pathname[i] == _T('\\') || pathname[i] == _T('/')) break; } return pathname.substr(i + 1); } tstring GetPath(tstring pathname) { int i; for (i = pathname.length() - 1; i >= 0; --i) { if (pathname[i] == _T('\\') || pathname[i] == _T('/')) break; } return pathname.substr(0, i + 1); } BOOL DeepDeleteFile(const tstring &strFile) { int nR = _taccess(strFile.c_str(), 0); if (nR != 0 || PathIsDirectory(strFile.c_str())) { return TRUE; } if (!PathFileExists(strFile.c_str())) return TRUE; SetFileAttributes(strFile.c_str(), FILE_ATTRIBUTE_NORMAL); BOOL bRet = ::DeleteFile(strFile.c_str()); if (!bRet) { tstring strDstTmp = strFile + _T(".tmp"); MoveFileEx(strFile.c_str(), strDstTmp.c_str(), MOVEFILE_REPLACE_EXISTING); if (!DeleteFile(strDstTmp.c_str())) { MoveFileEx(strDstTmp.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } } return bRet; } BOOL DeleteAllFiles(tstring strPath) { if (strPath.empty()) { return TRUE; } DeleteFile(strPath.c_str()); SHFILEOPSTRUCT fo; tstring strFrom = strPath; if (strPath[strPath.length() - 1] != _T('\\')) { strFrom = strFrom + _T("\\"); } strFrom = strFrom + _T("*.*") + _T('\0'); memset(&fo, 0, sizeof(fo)); fo.hwnd = NULL; fo.fFlags = FOF_SILENT | FOF_NOCONFIRMATION; fo.wFunc = FO_DELETE; fo.pFrom = strFrom.c_str(); SHFileOperation(&fo); RemoveDirectory(strPath.c_str()); return TRUE; } BOOL GetBackslashDir(tstring &strPath) { TCHAR szPath[MAX_PATH] = {}; int len = strPath.length(); _tcsncpy_s(szPath, strPath.c_str(), _TRUNCATE); if (len >= 1 && (_T('\\') != szPath[len - 1] || (_T('/') != szPath[len - 1]))) { PathAddBackslash(szPath); } strPath = szPath; return TRUE; } BOOL CopyFolder(const tstring &strSrc, const tstring &strDst, BOOL bForce) { tstring tmpFrom(strSrc); tstring tmpTo(strDst); BOOL bRet = FALSE; if (!PathFileExists(tmpTo.c_str())) { ForceCreateDir(tmpTo.c_str()); } if (PathFileExists(tmpFrom.c_str())) { WIN32_FIND_DATA FindFileData; tstring tmpFind(tmpFrom); tmpFind += _T("\\*.*"); HANDLE hFind = ::FindFirstFile(tmpFind.c_str(), &FindFileData); if (INVALID_HANDLE_VALUE == hFind) return bRet; while (TRUE) { tstring tmpFile(tmpTo); tmpFile += _T("\\"); tmpFile += FindFileData.cFileName; if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (FindFileData.cFileName[0] != '.') { if (!PathFileExists(tmpFile.c_str())) { GetBackslashDir(tmpFile); ForceCreateDir(tmpFile.c_str()); } bRet = CopyFolder(tmpFrom + _T("\\") + FindFileData.cFileName, tmpFile, bForce); } } else { if (bForce) { bRet = DeepCopyFile( (tmpFrom + _T("\\") + FindFileData.cFileName).c_str(), tmpFile.c_str()); } else if (!PathFileExists(tmpFile.c_str())) { bRet = ::CopyFile((tmpFrom + _T("\\") + FindFileData.cFileName).c_str(), tmpFile.c_str(), TRUE); } } if (!FindNextFile(hFind, &FindFileData)) break; } FindClose(hFind); } return bRet; } BOOL DeepCopyFile(const tstring &strSrc, const tstring &strDst) { BOOL bRet = FALSE; if (PathFileExists(strSrc.c_str())) { if (!StringHelper::CompareNoCase(strSrc, strDst)) { if (PathFileExists(strDst.c_str())) { SetFileAttributes(strDst.c_str(), FILE_ATTRIBUTE_NORMAL); } else { tstring strPath = GetPath(strDst); ForceCreateDir(strPath.c_str()); } if (!DeleteFile(strDst.c_str())) { tstring strDstTmp = strDst + _T(".tmp"); MoveFileEx(strDst.c_str(), strDstTmp.c_str(), MOVEFILE_REPLACE_EXISTING); if (!DeleteFile(strDstTmp.c_str())) { MoveFileEx(strDstTmp.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } } ::CopyFile(strSrc.c_str(), strDst.c_str(), FALSE); bRet = TRUE; } } return bRet; } BOOL UnzipFileToPath(LPCTSTR lpszFile, LPCTSTR lpszDir) { BOOL res = FALSE; TCHAR szPath[MAX_PATH] = { 0 }; GetCurrentDirectory(MAX_PATH, szPath); if (!SetCurrentDirectory(lpszDir)) return res; HZIP hz = OpenZip((LPVOID)lpszFile, 0, ZIP_FILENAME); if (hz) { ZIPENTRYW ze = { 0 }; if (ZR_OK == GetZipItem(hz, -1, &ze)) { res = TRUE; int nCount = ze.index; for (int i = 0; i < nCount; i++) { GetZipItem(hz, i, &ze); SetFileAttributes(ze.name, FILE_ATTRIBUTE_ARCHIVE); if (UnzipItem(hz, i, ze.name, 0, ZIP_FILENAME) != ZR_OK) { res = FALSE; break; } SetFileAttributes(ze.name, FILE_ATTRIBUTE_NORMAL); } } CloseZip(hz); } SetCurrentDirectory(szPath); return res; } DWORD GetFileSize(const tstring& path) { HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile && hFile != INVALID_HANDLE_VALUE) { DWORD dwFileSize = ::GetFileSize(hFile, NULL); CloseHandle(hFile); return dwFileSize; } return INVALID_FILE_SIZE; } } // namespace FilePathHelper namespace FileVersionHelper { BOOL GetFileVersion(LPCTSTR strFile, LPTSTR pszVersion, int nVersionLen) { if (!strFile || !strFile[0] || !pszVersion || nVersionLen <= 0) return FALSE; TCHAR szVersionBuffer[8192] = {}; DWORD dwVerSize; DWORD dwHandle; dwVerSize = GetFileVersionInfoSize(strFile, &dwHandle); if (dwVerSize == 0 || dwVerSize > (sizeof(szVersionBuffer) - 1)) return FALSE; if (GetFileVersionInfo(strFile, 0, dwVerSize, szVersionBuffer)) { VS_FIXEDFILEINFO *pInfo; unsigned int nInfoLen; if (VerQueryValue(szVersionBuffer, _T("\\"), (void **)&pInfo, &nInfoLen)) { _sntprintf_s( pszVersion, nVersionLen, _TRUNCATE, _T("%d.%d.%d.%d"), HIWORD(pInfo->dwFileVersionMS), LOWORD(pInfo->dwFileVersionMS), HIWORD(pInfo->dwFileVersionLS), LOWORD(pInfo->dwFileVersionLS)); pszVersion[nVersionLen - 1] = _T('\0'); return TRUE; } } return FALSE; } tstring GetFileVersion(LPCTSTR strFile) { if (!strFile || !strFile[0]) return _T(""); TCHAR szVersionBuffer[8192] = {}; if (GetFileVersion(strFile, szVersionBuffer, SIZEOF(szVersionBuffer))) { return szVersionBuffer; } return _T(""); } tstring GetFileVersion(HMODULE hModule) { if (!hModule) return _T(""); TCHAR szFilePath[MAX_PATH] = {}; GetModuleFileName(hModule, szFilePath, MAX_PATH); return GetFileVersion(szFilePath); } } // namespace FileVersionHelper namespace NetHelper { BOOL GetDomain(LPCTSTR url, LPTSTR buf, int cchBuf) { if (!url || !url[0] || !buf || cchBuf <= 0) return FALSE; URL_COMPONENTS uc = {}; uc.dwStructSize = sizeof(uc); uc.lpszHostName = buf; uc.dwHostNameLength = cchBuf; memset(buf, 0, cchBuf * sizeof(TCHAR)); __try { if (!InternetCrackUrl(url, lstrlen(url), (DWORD)ICU_DECODE, &uc)) { return FALSE; } else { LPTSTR lpstr = StrStr(buf, _T("\\")); if (lpstr) *lpstr = 0; } } __except (EXCEPTION_EXECUTE_HANDLER) { } if (_tcslen(buf) == 0) return FALSE; return TRUE; } } // namespace NetHelper namespace StringHelper { tstring Trim(tstring &s) { if (s.empty()) { return s; } s.erase(0, s.find_first_not_of(_T(" "))); s.erase(s.find_last_not_of(_T(" ")) + 1); return s; } tstring ReplaceAll(tstring &str, const tstring &old_value, const tstring &new_value) { for (tstring::size_type pos(0); pos != tstring::npos; pos += new_value.length()) { if ((pos = str.find(old_value, pos)) != tstring::npos) str.replace(pos, old_value.length(), new_value); else break; } return str; } tstring MakeLower(tstring &s) { if (s.empty()) { return s; } TCHAR *pBuf = new TCHAR[s.length() + 1]; _tcsncpy_s(pBuf, s.length() + 1, s.c_str(), _TRUNCATE); #if _MSC_VER < 1500 _tcslwr(pBuf); #else _tcslwr_s(pBuf, s.length() + 1); #endif s = pBuf; delete[] pBuf; return s; } BOOL CompareNoCase(tstring sA, tstring sB) { MakeLower(sA); MakeLower(sB); if (0 == sA.compare(sB)) { return TRUE; } else { return FALSE; } } int FindNoCase(tstring sA, tstring sB) { MakeLower(sA); MakeLower(sB); return sA.find(sB); } std::string TString2String(tstring str) { std::string result; #ifdef _UNICODE result = Wstring2String(str.c_str()); #else result = str; #endif return result; } std::string Wstring2String(const wchar_t *pwc) { if (!pwc || !pwc[0]) return ""; std::string result; int nLen = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pwc, -1, NULL, 0, NULL, NULL); if (nLen <= 0) { return std::string(""); } char *presult = new char[nLen]; if (NULL == presult) { return std::string(""); } WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pwc, -1, presult, nLen, NULL, NULL); presult[nLen - 1] = 0; result = presult; delete[] presult; return result; } std::wstring String2WString(const char *pc) { if (!pc || !pc[0]) return L""; int nLen = strlen(pc); int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pc, nLen, 0, 0); if (nSize <= 0) { return std::wstring(L""); } WCHAR *pDst = new WCHAR[nSize + 1]; if (NULL == pDst) { return NULL; } MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pc, nLen, pDst, nSize); pDst[nSize] = 0; if (0xFEFF == pDst[0]) { for (int i = 0; i < nSize; i++) { pDst[i] = pDst[i + 1]; } } std::wstring wcstr(pDst); delete[] pDst; return wcstr; } tstring String2TString(const char *pc) { tstring result; #ifdef _UNICODE result = String2WString(pc); #else result = pc; #endif return result; } } // namespace StringHelper namespace OS { using LPFN_ISWOW64PROCESS = BOOL(WINAPI*)(HANDLE, PBOOL); typedef struct { TCHAR szOperation[MAX_PATH]; TCHAR szFilePath[MAX_PATH + 1]; TCHAR szParam[MAX_PATH]; TCHAR szDirectory[MAX_PATH + 1]; int nShowCmd; } SHELLEXECUTE_PARAM; BOOL AysnShellExecute(LPCTSTR lpszOperation, LPCTSTR lpszFilePath, LPCTSTR lpszParam, LPCTSTR lpszDirectory, int nShowCmd) { SHELLEXECUTE_PARAM *pParam = new SHELLEXECUTE_PARAM; memset(pParam, 0, sizeof(SHELLEXECUTE_PARAM)); if (lpszOperation) _sntprintf_s(pParam->szOperation, _countof(pParam->szOperation), lpszOperation); if (lpszFilePath) _sntprintf_s(pParam->szFilePath, _countof(pParam->szFilePath), lpszFilePath); if (lpszParam) _sntprintf_s(pParam->szParam, _countof(pParam->szParam), lpszParam); if (lpszDirectory) _sntprintf_s(pParam->szDirectory, _countof(pParam->szDirectory), lpszDirectory); pParam->nShowCmd = nShowCmd; HANDLE hThread = CreateThread(NULL, 0, ShellExecuteProc, (LPVOID)pParam, 0, NULL); CloseHandle(hThread); return TRUE; } DWORD WINAPI ShellExecuteProc(LPVOID lpParam) { if (lpParam) { SHELLEXECUTE_PARAM *pParam = (SHELLEXECUTE_PARAM *)lpParam; ShellExecute(NULL, pParam->szOperation, pParam->szFilePath, pParam->szParam, pParam->szDirectory, pParam->nShowCmd); delete pParam; } return 0; } void SafeTerminateThread(HANDLE hThread, DWORD dwExitCode /* = -1*/) { ::SuspendThread(hThread); ::TerminateThread(hThread, dwExitCode); ::CloseHandle(hThread); } DWORD ProcesstoPid(const TCHAR *pid) { DWORD dwpid = 0; int nProcessCount = 0; HANDLE hProcessSnap = NULL; TCHAR buffer[MAX_PATH + 1]; PROCESSENTRY32 pe32 = {0}; int i; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == (HANDLE)-1) { return dwpid; } pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { lstrcpy(buffer, pe32.szExeFile); for (i = lstrlen(buffer); i > 0; i--) if (buffer[i] == _T('\\')) break; if (!lstrcmpi(pid, &buffer[i])) { nProcessCount++; dwpid = pe32.th32ProcessID; break; } } while (Process32Next(hProcessSnap, &pe32)); } else { return dwpid; } CloseHandle(hProcessSnap); return dwpid; } BOOL IsWow64() { BOOL bIsWow64 = FALSE; LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); if (NULL != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { } } return bIsWow64; } BOOL SetRegValue(HKEY hKey, LPCTSTR lpszKeyName, LPCTSTR lpszValueName, tstring& strVal) { HKEY hResKey; LONG lRet; DWORD dwType = 0; lRet = RegCreateKeyEx(hKey, lpszKeyName, 0, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hResKey, &dwType); if (lRet != ERROR_SUCCESS) return FALSE; lRet = RegSetValueExW(hResKey, lpszValueName, NULL, REG_SZ, (LPBYTE)strVal.c_str(), (strVal.length() + 1) * 2); if (lRet != ERROR_SUCCESS) return FALSE; RegCloseKey(hResKey); return TRUE; } BOOL CreateLowIntegrityProcess(LPCTSTR Param) { DWORD dwError = ERROR_SUCCESS; HANDLE hToken = NULL; HANDLE hNewToken = NULL; SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY; PSID pIntegritySid = NULL; TOKEN_MANDATORY_LABEL tml = { 0 }; STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY, &hToken)) { dwError = GetLastError(); goto Cleanup; } if (!DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) { dwError = GetLastError(); goto Cleanup; } if (!AllocateAndInitializeSid(&MLAuthority, 1, SECURITY_MANDATORY_MEDIUM_RID, 0, 0, 0, 0, 0, 0, 0, &pIntegritySid)) { dwError = GetLastError(); goto Cleanup; } tml.Label.Attributes = SE_GROUP_INTEGRITY; tml.Label.Sid = pIntegritySid; if (!SetTokenInformation(hNewToken, TokenIntegrityLevel, &tml, (sizeof(tml) + GetLengthSid(pIntegritySid)))) { dwError = GetLastError(); goto Cleanup; } if (!CreateProcessAsUser(hNewToken, NULL, (LPWSTR)Param, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { dwError = GetLastError(); goto Cleanup; } Cleanup: if (hToken) { CloseHandle(hToken); hToken = NULL; } if (hNewToken) { CloseHandle(hNewToken); hNewToken = NULL; } if (pIntegritySid) { FreeSid(pIntegritySid); pIntegritySid = NULL; } if (pi.hProcess) { CloseHandle(pi.hProcess); pi.hProcess = NULL; } if (pi.hThread) { CloseHandle(pi.hThread); pi.hThread = NULL; } if (ERROR_SUCCESS != dwError) { SetLastError(dwError); return FALSE; } else { return TRUE; } } } // namespace OS namespace Window { HWND FindWindowByProcess(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD nProcessID) { HWND hWnd = NULL; if (nProcessID == 0) nProcessID = GetCurrentProcessId(); DWORD dwWindowProcessID = 0; do { hWnd = FindWindowEx(NULL, hWnd, lpszClassName, lpszWindowName); if (hWnd != NULL) { GetWindowThreadProcessId(hWnd, &dwWindowProcessID); if (dwWindowProcessID == nProcessID) break; } } while (hWnd != NULL); return hWnd; } void StretchForegroundWindow(HWND hWnd) { HWND hForWnd = ::GetForegroundWindow(); if (hWnd == hForWnd) return; DWORD dwProcessId; DWORD dwThread1 = GetWindowThreadProcessId(hWnd, &dwProcessId); DWORD dwThread2 = GetWindowThreadProcessId(hForWnd, &dwProcessId); if (dwThread1 != dwThread2) { AttachThreadInput(dwThread1, dwThread2, TRUE); SetForegroundWindow(hWnd); AttachThreadInput(dwThread1, dwThread2, FALSE); } else { SetForegroundWindow(hWnd); } } } // namespace Window namespace Device { typedef struct _ASTAT_ { ADAPTER_STATUS adapt; NAME_BUFFER NameBuff[30]; } ASTAT, * PASTAT; ASTAT Adapter; static char g_strTempBuf[1024]; const char* GetTheFirstMac() { NCB ncb; UCHAR uRetCode; LANA_ENUM lana_enum_buf; memset(g_strTempBuf, 0, sizeof(g_strTempBuf)); memset(&ncb, 0, sizeof(ncb)); ncb.ncb_command = NCBENUM; ncb.ncb_buffer = (unsigned char*)&lana_enum_buf; ncb.ncb_length = sizeof(lana_enum_buf); uRetCode = Netbios(&ncb); if (uRetCode != 0) { return g_strTempBuf; } int nIndex = 0; { int lana_num = lana_enum_buf.lana[nIndex]; memset(&ncb, 0, sizeof(ncb)); ncb.ncb_command = NCBRESET; ncb.ncb_lana_num = lana_num; uRetCode = Netbios(&ncb); memset(&ncb, 0, sizeof(ncb)); ncb.ncb_command = NCBASTAT; ncb.ncb_lana_num = lana_num; strcpy((char*)ncb.ncb_callname, "* "); ncb.ncb_buffer = (unsigned char*)&Adapter; ncb.ncb_length = sizeof(Adapter); uRetCode = Netbios(&ncb); if (uRetCode == 0) { char szTemp[32] = { 0 }; _snprintf( szTemp, 32, "%02X%02X%02X%02X%02X%02X", Adapter.adapt.adapter_address[0], Adapter.adapt.adapter_address[1], Adapter.adapt.adapter_address[2], Adapter.adapt.adapter_address[3], Adapter.adapt.adapter_address[4], Adapter.adapt.adapter_address[5]); strcat(g_strTempBuf, szTemp); } } return g_strTempBuf; } } // namespace Device } // namespace SystemCommon ================================================ FILE: common/util/system.h ================================================ #pragma once #ifndef tstring #ifdef _UNICODE #define tstring std::wstring #else #define tstring std::string #endif #endif namespace SystemCommon { namespace FilePathHelper { BOOL ForceCreateDir(LPCTSTR pszFullPathFileName); BOOL CreateDir(LPCTSTR lpszPath); BOOL CreateMyDir(LPCTSTR pszDir); BOOL GetAppPath(HINSTANCE hInst, LPTSTR lpPath, DWORD dMaxLen, LPCTSTR pAddon); tstring GetAssignPath(DWORD assing, BOOL forceCreate); tstring GetFileName(tstring pathname); tstring GetPath(tstring pathname); BOOL DeepDeleteFile(const tstring &strFile); BOOL DeleteAllFiles(tstring strPath); BOOL GetBackslashDir(tstring &strPath); BOOL CopyFolder(const tstring &strSrc, const tstring &strDst, BOOL bForce = FALSE); BOOL DeepCopyFile(const tstring &strSrc, const tstring &strDst); BOOL UnzipFileToPath(LPCTSTR lpszFile, LPCTSTR lpszDir); DWORD GetFileSize(const tstring& path); } // namespace FilePathHelper namespace FileVersionHelper { BOOL GetFileVersion(LPCTSTR strFile, LPTSTR pszVersion, int nVersionLen); tstring GetFileVersion(LPCTSTR strFile); tstring GetFileVersion(HMODULE hModule); } // namespace FileVersionHelper namespace NetHelper { BOOL GetDomain(LPCTSTR url, LPTSTR buf, int cbBuf); } // namespace NetHelper namespace StringHelper { tstring Trim(tstring &s); tstring ReplaceAll(tstring &str, const tstring &old_value, const tstring &new_value); tstring MakeLower(tstring &s); BOOL CompareNoCase(tstring sA, tstring sB); int FindNoCase(tstring sA, tstring sB); std::string TString2String(tstring str); std::string Wstring2String(const wchar_t *pwc); std::wstring String2WString(const char *pc); tstring String2TString(const char *pc); } // namespace StringHelper namespace OS { BOOL AysnShellExecute(LPCTSTR lpszOperation, LPCTSTR lpszFile, LPCTSTR lpszParam = NULL, LPCTSTR lpszDirectory = NULL, int nShowCmd = SW_SHOW); DWORD WINAPI ShellExecuteProc(LPVOID lpParam); void SafeTerminateThread(HANDLE hThread, DWORD dwExitCode = -1); DWORD ProcesstoPid(const TCHAR *pid); BOOL IsWow64(); BOOL SetRegValue(HKEY hKey, LPCTSTR lpszKeyName, LPCTSTR lpszValueName, tstring& strVal); BOOL CreateLowIntegrityProcess(LPCTSTR); } // namespace OS namespace Window { HWND FindWindowByProcess(LPCTSTR lpszClassName, LPCTSTR lpszWindowName = NULL, DWORD nProcessID = 0 /*Current Process*/); void StretchForegroundWindow(HWND); } // namespace Window namespace Device { const char* GetTheFirstMac(); } // namespace Device }; // namespace SystemCommon ================================================ FILE: common/util/util_tools.cpp ================================================ #include "stdafx.h" #include "util_tools.h" CriticalSection::CriticalSection(void) { #ifdef _WIN32 InitializeCriticalSection(&m_cs); #else pthread_mutex_init(&m_cs, NULL); #endif } CriticalSection::~CriticalSection(void) { #ifdef _WIN32 DeleteCriticalSection(&m_cs); #else pthread_mutex_destroy(&m_cs); #endif } void CriticalSection::Lock(void) { #ifdef _WIN32 EnterCriticalSection(&m_cs); #else pthread_mutex_lock(&m_cs); #endif } void CriticalSection::UnLock(void) { #ifdef _WIN32 LeaveCriticalSection(&m_cs); #else pthread_mutex_unlock(&m_cs); #endif } BOOL CriticalSection::TryLock(void) { BOOL bReturn = FALSE; #ifdef _WIN32 bReturn = TryEnterCriticalSection(&m_cs); #else bReturn = pthread_mutex_trylock(&m_cs); #endif return bReturn; } ================================================ FILE: common/util/util_tools.h ================================================ #pragma once #include class CriticalSection { public: CriticalSection(void); ~CriticalSection(void); private: #ifdef _WIN32 CRITICAL_SECTION m_cs; #else pthread_mutex_t m_cs; #endif public: void Lock(void); void UnLock(void); BOOL TryLock(void); }; template class AutoCritSecLock { public: AutoCritSecLock(TLock &cs, bool bInitialLock = true); ~AutoCritSecLock() throw(); HRESULT Lock() throw(); void Unlock() throw(); private: TLock &m_cs; bool m_bLocked; AutoCritSecLock(const AutoCritSecLock &) throw(); AutoCritSecLock &operator=(const AutoCritSecLock &) throw(); }; template inline AutoCritSecLock::AutoCritSecLock(TLock &cs, bool bInitialLock) : m_cs(cs), m_bLocked(false) { if (bInitialLock) { Lock(); } } template inline AutoCritSecLock::~AutoCritSecLock() throw() { if (m_bLocked) { Unlock(); } } template inline HRESULT AutoCritSecLock::Lock() throw() { assert(!m_bLocked); m_cs.Lock(); m_bLocked = true; return (S_OK); } template inline void AutoCritSecLock::Unlock() throw() { assert(m_bLocked); m_cs.UnLock(); m_bLocked = false; } ================================================ FILE: common/xml/tinystr.cpp ================================================ /* www.sourceforge.net/projects/tinyxml This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "stdafx.h" #ifndef TIXML_USE_STL #include "tinystr.h" // Error value for find primitive const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); // Null rep. TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; void TiXmlString::reserve (size_type cap) { if (cap > capacity()) { TiXmlString tmp; tmp.init(length(), cap); memcpy(tmp.start(), data(), length()); swap(tmp); } } TiXmlString& TiXmlString::assign(const char* str, size_type len) { size_type cap = capacity(); if (len > cap || cap > 3*(len + 8)) { TiXmlString tmp; tmp.init(len); memcpy(tmp.start(), str, len); swap(tmp); } else { memmove(start(), str, len); set_size(len); } return *this; } TiXmlString& TiXmlString::append(const char* str, size_type len) { size_type newsize = length() + len; if (newsize > capacity()) { reserve (newsize + capacity()); } memmove(finish(), str, len); set_size(newsize); return *this; } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) { TiXmlString tmp; tmp.reserve(a.length() + b.length()); tmp += a; tmp += b; return tmp; } TiXmlString operator + (const TiXmlString & a, const char* b) { TiXmlString tmp; TiXmlString::size_type b_len = static_cast( strlen(b) ); tmp.reserve(a.length() + b_len); tmp += a; tmp.append(b, b_len); return tmp; } TiXmlString operator + (const char* a, const TiXmlString & b) { TiXmlString tmp; TiXmlString::size_type a_len = static_cast( strlen(a) ); tmp.reserve(a_len + b.length()); tmp.append(a, a_len); tmp += b; return tmp; } #endif // TIXML_USE_STL ================================================ FILE: common/xml/tinystr.h ================================================ /* www.sourceforge.net/projects/tinyxml This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TIXML_USE_STL #ifndef TIXML_STRING_INCLUDED #define TIXML_STRING_INCLUDED #include #include /* The support for explicit isn't that universal, and it isn't really required - it is used to check that the TiXmlString class isn't incorrectly used. Be nice to old compilers and macro it here: */ #if defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. #define TIXML_EXPLICIT explicit #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s #define TIXML_EXPLICIT explicit #else #define TIXML_EXPLICIT #endif /* TiXmlString is an emulation of a subset of the std::string template. Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. Only the member functions relevant to the TinyXML project have been implemented. The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase a string and there's no more room, we allocate a buffer twice as big as we need. */ class TiXmlString { public : // The size type used typedef size_t size_type; // Error value for find primitive static const size_type npos; // = -1; // TiXmlString empty constructor TiXmlString () : rep_(&nullrep_) { } // TiXmlString copy constructor TiXmlString ( const TiXmlString & copy) : rep_(0) { init(copy.length()); memcpy(start(), copy.data(), length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) { init( static_cast( strlen(copy) )); memcpy(start(), copy, length()); } // TiXmlString constructor, based on a string TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) { init(len); memcpy(start(), str, len); } // TiXmlString destructor ~TiXmlString () { quit(); } TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); } // += operator. Maps to append TiXmlString& operator += (const char * suffix) { return append(suffix, static_cast( strlen(suffix) )); } // += operator. Maps to append TiXmlString& operator += (char single) { return append(&single, 1); } // += operator. Maps to append TiXmlString& operator += (const TiXmlString & suffix) { return append(suffix.data(), suffix.length()); } // Convert a TiXmlString into a null-terminated char * const char * c_str () const { return rep_->str; } // Convert a TiXmlString into a char * (need not be null terminated). const char * data () const { return rep_->str; } // Return the length of a TiXmlString size_type length () const { return rep_->size; } // Alias for length() size_type size () const { return rep_->size; } // Checks if a TiXmlString is empty bool empty () const { return rep_->size == 0; } // Return capacity of string size_type capacity () const { return rep_->capacity; } // single char extraction const char& at (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // [] operator char& operator [] (size_type index) const { assert( index < length() ); return rep_->str[ index ]; } // find a char in a string. Return TiXmlString::npos if not found size_type find (char lookup) const { return find(lookup, 0); } // find a char in a string from an offset. Return TiXmlString::npos if not found size_type find (char tofind, size_type offset) const { if (offset >= length()) return npos; for (const char* p = c_str() + offset; *p != '\0'; ++p) { if (*p == tofind) return static_cast< size_type >( p - c_str() ); } return npos; } void clear () { //Lee: //The original was just too strange, though correct: // TiXmlString().swap(*this); //Instead use the quit & re-init: quit(); init(0,0); } /* Function to reserve a big amount of data when we know we'll need it. Be aware that this function DOES NOT clear the content of the TiXmlString if any exists. */ void reserve (size_type cap); TiXmlString& assign (const char* str, size_type len); TiXmlString& append (const char* str, size_type len); void swap (TiXmlString& other) { Rep* r = rep_; rep_ = other.rep_; other.rep_ = r; } private: void init(size_type sz) { init(sz, sz); } void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } char* start() const { return rep_->str; } char* finish() const { return rep_->str + rep_->size; } struct Rep { size_type size, capacity; char str[1]; }; void init(size_type sz, size_type cap) { if (cap) { // Lee: the original form: // rep_ = static_cast(operator new(sizeof(Rep) + cap)); // doesn't work in some cases of new being overloaded. Switching // to the normal allocation, although use an 'int' for systems // that are overly picky about structure alignment. const size_type bytesNeeded = sizeof(Rep) + cap; const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); rep_ = reinterpret_cast( new int[ intsNeeded ] ); rep_->str[ rep_->size = sz ] = '\0'; rep_->capacity = cap; } else { rep_ = &nullrep_; } } void quit() { if (rep_ != &nullrep_) { // The rep_ is really an array of ints. (see the allocator, above). // Cast it back before delete, so the compiler won't incorrectly call destructors. delete [] ( reinterpret_cast( rep_ ) ); } } Rep * rep_; static Rep nullrep_; } ; inline bool operator == (const TiXmlString & a, const TiXmlString & b) { return ( a.length() == b.length() ) // optimization on some platforms && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare } inline bool operator < (const TiXmlString & a, const TiXmlString & b) { return strcmp(a.c_str(), b.c_str()) < 0; } inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); TiXmlString operator + (const TiXmlString & a, const char* b); TiXmlString operator + (const char* a, const TiXmlString & b); /* TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. Only the operators that we need for TinyXML have been developped. */ class TiXmlOutStream : public TiXmlString { public : // TiXmlOutStream << operator. TiXmlOutStream & operator << (const TiXmlString & in) { *this += in; return *this; } // TiXmlOutStream << operator. TiXmlOutStream & operator << (const char * in) { *this += in; return *this; } } ; #endif // TIXML_STRING_INCLUDED #endif // TIXML_USE_STL ================================================ FILE: common/xml/tinyxml.cpp ================================================ /* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "stdafx.h" #include #ifdef TIXML_USE_STL #include #include #endif #include "tinyxml.h" FILE* TiXmlFOpen( const char* filename, const char* mode ); bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { return fopen( filename, mode ); } void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) { int i=0; while( i<(int)str.length() ) { unsigned char c = (unsigned char) str[i]; if ( c == '&' && i < ( (int)str.length() - 2 ) && str[i+1] == '#' && str[i+2] == 'x' ) { // Hexadecimal character reference. // Pass through unchanged. // © -- copyright symbol, for example. // // The -1 is a bug fix from Rob Laveaux. It keeps // an overflow from happening if there is no ';'. // There are actually 2 ways to exit this loop - // while fails (error case) and break (semicolon found). // However, there is no mechanism (currently) for // this function to return an error. while ( i<(int)str.length()-1 ) { outString->append( str.c_str() + i, 1 ); ++i; if ( str[i] == ';' ) break; } } else if ( c == '&' ) { outString->append( entity[0].str, entity[0].strLength ); ++i; } else if ( c == '<' ) { outString->append( entity[1].str, entity[1].strLength ); ++i; } else if ( c == '>' ) { outString->append( entity[2].str, entity[2].strLength ); ++i; } else if ( c == '\"' ) { outString->append( entity[3].str, entity[3].strLength ); ++i; } else if ( c == '\'' ) { outString->append( entity[4].str, entity[4].strLength ); ++i; } else if ( c < 32 ) { // Easy pass at non-alpha/numeric/symbol // Below 32 is symbolic. char buf[ 32 ]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); #else sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); #endif //*ME: warning C4267: convert 'size_t' to 'int' //*ME: Int-Cast to make compiler happy ... outString->append( buf, (int)strlen( buf ) ); ++i; } else { //char realc = (char) c; //outString->append( &realc, 1 ); *outString += (char) c; // somewhat more efficient function call. ++i; } } } TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() { parent = 0; type = _type; firstChild = 0; lastChild = 0; prev = 0; next = 0; } TiXmlNode::~TiXmlNode() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } } void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; target->location = location; } void TiXmlNode::Clear() { TiXmlNode* node = firstChild; TiXmlNode* temp = 0; while ( node ) { temp = node; node = node->next; delete temp; } firstChild = 0; lastChild = 0; } TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) { assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) { delete node; if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } node->parent = this; node->prev = lastChild; node->next = 0; if ( lastChild ) lastChild->next = node; else firstChild = node; // it was an empty list. lastChild = node; return node; } TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; return LinkEndChild( node ); } TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) { if ( !beforeThis || beforeThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->next = beforeThis; node->prev = beforeThis->prev; if ( beforeThis->prev ) { beforeThis->prev->next = node; } else { assert( firstChild == beforeThis ); firstChild = node; } beforeThis->prev = node; return node; } TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) { if ( !afterThis || afterThis->parent != this ) { return 0; } if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); if ( !node ) return 0; node->parent = this; node->prev = afterThis; node->next = afterThis->next; if ( afterThis->next ) { afterThis->next->prev = node; } else { assert( lastChild == afterThis ); lastChild = node; } afterThis->next = node; return node; } TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { if ( !replaceThis ) return 0; if ( replaceThis->parent != this ) return 0; if ( withThis.ToDocument() ) { // A document can never be a child. Thanks to Noam. TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; } bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { if ( !removeThis ) { return false; } if ( removeThis->parent != this ) { assert( 0 ); return false; } if ( removeThis->next ) removeThis->next->prev = removeThis->prev; else lastChild = removeThis->prev; if ( removeThis->prev ) removeThis->prev->next = removeThis->next; else firstChild = removeThis->next; delete removeThis; return true; } const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const { const TiXmlNode* node; for ( node = firstChild; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const { const TiXmlNode* node; for ( node = lastChild; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild(); } else { assert( previous->parent == this ); return previous->NextSibling(); } } const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const { if ( !previous ) { return FirstChild( val ); } else { assert( previous->parent == this ); return previous->NextSibling( val ); } } const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const { const TiXmlNode* node; for ( node = next; node; node = node->next ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const { const TiXmlNode* node; for ( node = prev; node; node = node->prev ) { if ( strcmp( node->Value(), _value ) == 0 ) return node; } return 0; } void TiXmlElement::RemoveAttribute( const char * name ) { #ifdef TIXML_USE_STL TIXML_STRING str( name ); TiXmlAttribute* node = attributeSet.Find( str ); #else TiXmlAttribute* node = attributeSet.Find( name ); #endif if ( node ) { attributeSet.Remove( node ); delete node; } } const TiXmlElement* TiXmlNode::FirstChildElement() const { const TiXmlNode* node; for ( node = FirstChild(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const { const TiXmlNode* node; for ( node = FirstChild( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement() const { const TiXmlNode* node; for ( node = NextSibling(); node; node = node->NextSibling() ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const { const TiXmlNode* node; for ( node = NextSibling( _value ); node; node = node->NextSibling( _value ) ) { if ( node->ToElement() ) return node->ToElement(); } return 0; } const TiXmlDocument* TiXmlNode::GetDocument() const { const TiXmlNode* node; for( node = this; node; node = node->parent ) { if ( node->ToDocument() ) return node->ToDocument(); } return 0; } TiXmlElement::TiXmlElement (const char * _value) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; } #endif TiXmlElement::TiXmlElement( const TiXmlElement& copy) : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); return *this; } TiXmlElement::~TiXmlElement() { ClearThis(); } void TiXmlElement::ClearThis() { Clear(); while( attributeSet.First() ) { TiXmlAttribute* node = attributeSet.First(); attributeSet.Remove( node ); delete node; } } const char* TiXmlElement::Attribute( const char* name ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( node ) return node->Value(); return 0; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( attrib ) return &attrib->ValueStr(); return 0; } #endif const char* TiXmlElement::Attribute( const char* name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( i ) { attrib->QueryIntValue( i ); } } return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const char* result = 0; if ( attrib ) { result = attrib->Value(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); const std::string* result = 0; if ( attrib ) { result = &attrib->ValueStr(); if ( d ) { attrib->QueryDoubleValue( d ); } } return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int ival = 0; int result = node->QueryIntValue( &ival ); *value = (unsigned)ival; return result; } int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; int result = TIXML_WRONG_TYPE; if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = true; result = TIXML_SUCCESS; } else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) { *bval = false; result = TIXML_SUCCESS; } return result; } #ifdef TIXML_USE_STL int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { const TiXmlAttribute* attrib = attributeSet.Find( name ); if ( !attrib ) return TIXML_NO_ATTRIBUTE; return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetIntValue( val ); } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); if ( attrib ) { attrib->SetDoubleValue( val ); } } #endif void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); if ( attrib ) { attrib->SetValue( cvalue ); } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); if ( attrib ) { attrib->SetValue( _value ); } } #endif void TiXmlElement::Print( FILE* cfile, int depth ) const { int i; assert( cfile ); for ( i=0; iNext() ) { fprintf( cfile, " " ); attrib->Print( cfile, depth ); } // There are 3 different formatting approaches: // 1) An element without children is printed as a node // 2) An element with only a text child is printed as text // 3) An element with children is printed on multiple lines. TiXmlNode* node; if ( !firstChild ) { fprintf( cfile, " />" ); } else if ( firstChild == lastChild && firstChild->ToText() ) { fprintf( cfile, ">" ); firstChild->Print( cfile, depth + 1 ); fprintf( cfile, "", value.c_str() ); } else { fprintf( cfile, ">" ); for ( node = firstChild; node; node=node->NextSibling() ) { if ( !node->ToText() ) { fprintf( cfile, "\n" ); } node->Print( cfile, depth+1 ); } fprintf( cfile, "\n" ); for( i=0; i", value.c_str() ); } } void TiXmlElement::CopyTo( TiXmlElement* target ) const { // superclass: TiXmlNode::CopyTo( target ); // Element class: // Clone the attributes, then clone the children. const TiXmlAttribute* attribute = 0; for( attribute = attributeSet.First(); attribute; attribute = attribute->Next() ) { target->SetAttribute( attribute->Name(), attribute->Value() ); } TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this, attributeSet.First() ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } TiXmlNode* TiXmlElement::Clone() const { TiXmlElement* clone = new TiXmlElement( Value() ); if ( !clone ) return 0; CopyTo( clone ); return clone; } const char* TiXmlElement::GetText() const { const TiXmlNode* child = this->FirstChild(); if ( child ) { const TiXmlText* childText = child->ToText(); if ( childText ) { return childText->Value(); } } return 0; } TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #ifdef TIXML_USE_STL TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; value = documentName; ClearError(); } #endif TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); } TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { TIXML_STRING filename( _filename ); value = filename; // reading in binary mode so that tinyxml can normalize the EOL FILE* file = TiXmlFOpen( value.c_str (), "rb" ); if ( file ) { bool result = LoadFile( file, encoding ); fclose( file ); return result; } else { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } } bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) { if ( !file ) { SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Delete the existing data: Clear(); location.Clear(); // Get the file size, so we can pre-allocate the string. HUGE speed impact. long length = 0; fseek( file, 0, SEEK_END ); length = ftell( file ); fseek( file, 0, SEEK_SET ); // Strange case, but good to handle up front. if ( length <= 0 ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // // // ...the XML processor MUST behave as if it normalized all line breaks in external // parsed entities (including the document entity) on input, before parsing, by translating // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to // a single #xA character. // // // It is not clear fgets does that, and certainly isn't clear it works cross platform. // Generally, you expect fgets to translate from the convention of the OS to the c/unix // convention, and not work generally. /* while( fgets( buf, sizeof(buf), file ) ) { data += buf; } */ char* buf = new char[ length+1 ]; buf[0] = 0; if ( fread( buf, length, 1, file ) != 1 ) { delete [] buf; SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); return false; } // Process the buffer in place to normalize new lines. (See comment above.) // Copies from the 'p' to 'q' pointer, where p can advance faster if // a newline-carriage return is hit. // // Wikipedia: // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 const char* p = buf; // the read head char* q = buf; // the write head const char CR = 0x0d; const char LF = 0x0a; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); assert( q <= (buf+length) ); assert( q <= p ); if ( *p == CR ) { *q++ = LF; p++; if ( *p == LF ) { // check for CR+LF (and skip LF) p++; } } else { *q++ = *p++; } } assert( q <= (buf+length) ); *q = 0; Parse( buf, 0, encoding ); delete [] buf; return !Error(); } bool TiXmlDocument::SaveFile( const char * filename ) const { // The old c stuff lives on... FILE* fp = TiXmlFOpen( filename, "w" ); if ( fp ) { bool result = SaveFile( fp ); fclose( fp ); return result; } return false; } bool TiXmlDocument::SaveFile( FILE* fp ) const { if ( useMicrosoftBOM ) { const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; fputc( TIXML_UTF_LEAD_0, fp ); fputc( TIXML_UTF_LEAD_1, fp ); fputc( TIXML_UTF_LEAD_2, fp ); } Print( fp, 0 ); return (ferror(fp) == 0); } void TiXmlDocument::CopyTo( TiXmlDocument* target ) const { TiXmlNode::CopyTo( target ); target->error = error; target->errorId = errorId; target->errorDesc = errorDesc; target->tabsize = tabsize; target->errorLocation = errorLocation; target->useMicrosoftBOM = useMicrosoftBOM; TiXmlNode* node = 0; for ( node = firstChild; node; node = node->NextSibling() ) { target->LinkEndChild( node->Clone() ); } } TiXmlNode* TiXmlDocument::Clone() const { TiXmlDocument* clone = new TiXmlDocument(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlDocument::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { node->Print( cfile, depth ); fprintf( cfile, "\n" ); } } bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const { if ( visitor->VisitEnter( *this ) ) { for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) break; } } return visitor->VisitExit( *this ); } const TiXmlAttribute* TiXmlAttribute::Next() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } /* TiXmlAttribute* TiXmlAttribute::Next() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( next->value.empty() && next->name.empty() ) return 0; return next; } */ const TiXmlAttribute* TiXmlAttribute::Previous() const { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } /* TiXmlAttribute* TiXmlAttribute::Previous() { // We are using knowledge of the sentinel. The sentinel // have a value or name. if ( prev->value.empty() && prev->name.empty() ) return 0; return prev; } */ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { TIXML_STRING n, v; EncodeString( name, &n ); EncodeString( value, &v ); if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; } } else { if ( cfile ) { fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; } } } int TiXmlAttribute::QueryIntValue( int* ival ) const { if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int TiXmlAttribute::QueryDoubleValue( double* dval ) const { if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } void TiXmlAttribute::SetIntValue( int _value ) { char buf [64]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); #else sprintf (buf, "%d", _value); #endif SetValue (buf); } void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); #else sprintf (buf, "%g", _value); #endif SetValue (buf); } int TiXmlAttribute::IntValue() const { return atoi (value.c_str ()); } double TiXmlAttribute::DoubleValue() const { return atof (value.c_str ()); } TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { copy.CopyTo( this ); } TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); return *this; } void TiXmlComment::Print( FILE* cfile, int depth ) const { assert( cfile ); for ( int i=0; i", value.c_str() ); } void TiXmlComment::CopyTo( TiXmlComment* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlComment::Clone() const { TiXmlComment* clone = new TiXmlComment(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlText::Print( FILE* cfile, int depth ) const { assert( cfile ); if ( cdata ) { int i; fprintf( cfile, "\n" ); for ( i=0; i\n", value.c_str() ); // unformatted output } else { TIXML_STRING buffer; EncodeString( value, &buffer ); fprintf( cfile, "%s", buffer.c_str() ); } } void TiXmlText::CopyTo( TiXmlText* target ) const { TiXmlNode::CopyTo( target ); target->cdata = cdata; } bool TiXmlText::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlText::Clone() const { TiXmlText* clone = 0; clone = new TiXmlText( "" ); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #ifdef TIXML_USE_STL TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; standalone = _standalone; } #endif TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { copy.CopyTo( this ); } TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); return *this; } void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const { if ( cfile ) fprintf( cfile, "" ); if ( str ) (*str) += "?>"; } void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const { TiXmlNode::CopyTo( target ); target->version = version; target->encoding = encoding; target->standalone = standalone; } bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlDeclaration::Clone() const { TiXmlDeclaration* clone = new TiXmlDeclaration(); if ( !clone ) return 0; CopyTo( clone ); return clone; } void TiXmlUnknown::Print( FILE* cfile, int depth ) const { for ( int i=0; i", value.c_str() ); } void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const { TiXmlNode::CopyTo( target ); } bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const { return visitor->Visit( *this ); } TiXmlNode* TiXmlUnknown::Clone() const { TiXmlUnknown* clone = new TiXmlUnknown(); if ( !clone ) return 0; CopyTo( clone ); return clone; } TiXmlAttributeSet::TiXmlAttributeSet() { sentinel.next = &sentinel; sentinel.prev = &sentinel; } TiXmlAttributeSet::~TiXmlAttributeSet() { assert( sentinel.next == &sentinel ); assert( sentinel.prev == &sentinel ); } void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) { #ifdef TIXML_USE_STL assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. #else assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. #endif addMe->next = &sentinel; addMe->prev = sentinel.prev; sentinel.prev->next = addMe; sentinel.prev = addMe; } void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) { TiXmlAttribute* node; for( node = sentinel.next; node != &sentinel; node = node->next ) { if ( node == removeMe ) { node->prev->next = node->next; node->next->prev = node->prev; node->next = 0; node->prev = 0; return; } } assert( 0 ); // we tried to remove a non-linked attribute. } #ifdef TIXML_USE_STL TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #endif TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; } return 0; } TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { TiXmlAttribute* attrib = Find( _name ); if ( !attrib ) { attrib = new TiXmlAttribute(); Add( attrib ); attrib->SetName( _name ); } return attrib; } #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) { TIXML_STRING tag; tag.reserve( 8 * 1000 ); base.StreamIn( &in, &tag ); base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); return in; } #endif #ifdef TIXML_USE_STL std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out << printer.Str(); return out; } std::string& operator<< (std::string& out, const TiXmlNode& base ) { TiXmlPrinter printer; printer.SetStreamPrinting(); base.Accept( &printer ); out.append( printer.Str() ); return out; } #endif TiXmlHandle TiXmlHandle::FirstChild() const { if ( node ) { TiXmlNode* child = node->FirstChild(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const { if ( node ) { TiXmlNode* child = node->FirstChild( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement() const { if ( node ) { TiXmlElement* child = node->FirstChildElement(); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const { if ( node ) { TiXmlElement* child = node->FirstChildElement( value ); if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild(); for ( i=0; child && iNextSibling(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const { if ( node ) { int i; TiXmlNode* child = node->FirstChild( value ); for ( i=0; child && iNextSibling( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement(); for ( i=0; child && iNextSiblingElement(), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const { if ( node ) { int i; TiXmlElement* child = node->FirstChildElement( value ); for ( i=0; child && iNextSiblingElement( value ), ++i ) { // nothing } if ( child ) return TiXmlHandle( child ); } return TiXmlHandle( 0 ); } bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) { return true; } bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) { DoIndent(); buffer += "<"; buffer += element.Value(); for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) { buffer += " "; attrib->Print( 0, 0, &buffer ); } if ( !element.FirstChild() ) { buffer += " />"; DoLineBreak(); } else { buffer += ">"; if ( element.FirstChild()->ToText() && element.LastChild() == element.FirstChild() && element.FirstChild()->ToText()->CDATA() == false ) { simpleTextPrint = true; // no DoLineBreak()! } else { DoLineBreak(); } } ++depth; return true; } bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) { --depth; if ( !element.FirstChild() ) { // nothing. } else { if ( simpleTextPrint ) { simpleTextPrint = false; } else { DoIndent(); } buffer += ""; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlText& text ) { if ( text.CDATA() ) { DoIndent(); buffer += ""; DoLineBreak(); } else if ( simpleTextPrint ) { TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; } else { DoIndent(); TIXML_STRING str; TiXmlBase::EncodeString( text.ValueTStr(), &str ); buffer += str; DoLineBreak(); } return true; } bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) { DoIndent(); declaration.Print( 0, 0, &buffer ); DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlComment& comment ) { DoIndent(); buffer += ""; DoLineBreak(); return true; } bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) { DoIndent(); buffer += "<"; buffer += unknown.Value(); buffer += ">"; DoLineBreak(); return true; } ================================================ FILE: common/xml/tinyxml.h ================================================ /* www.sourceforge.net/projects/tinyxml Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML_INCLUDED #define TINYXML_INCLUDED #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4530 ) #pragma warning( disable : 4786 ) #endif #include #include #include #include #include // Help out windows: #if defined( _DEBUG ) && !defined( DEBUG ) #define DEBUG #endif #ifdef TIXML_USE_STL #include #include #include #define TIXML_STRING std::string #else #include "tinystr.h" #define TIXML_STRING TiXmlString #endif // Deprecated library function hell. Compilers want to use the // new safe versions. This probably doesn't fully address the problem, // but it gets closer. There are too many compilers for me to fully // test. If you get compilation troubles, undefine TIXML_SAFE #define TIXML_SAFE #ifdef TIXML_SAFE #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #else #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #endif #endif class TiXmlDocument; class TiXmlElement; class TiXmlComment; class TiXmlUnknown; class TiXmlAttribute; class TiXmlText; class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; const int TIXML_MINOR_VERSION = 6; const int TIXML_PATCH_VERSION = 2; /* Internal structure for tracking location of items in the XML file. */ struct TiXmlCursor { TiXmlCursor() { Clear(); } void Clear() { row = col = -1; } int row; // 0 based. int col; // 0 based. }; /** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. You should never change the document from a callback. @sa TiXmlNode::Accept() */ class TiXmlVisitor { public: virtual ~TiXmlVisitor() {} /// Visit a document. virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } /// Visit a declaration virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } /// Visit a text node virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } /// Visit an unknown node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; // Only used by Attribute::Query functions enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE }; // Used by the parsing routines. enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY }; const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; /** TiXmlBase is a base class for every class in TinyXml. It does little except to establish that TinyXml classes can be printed and provide some utility functions. In XML, the document and elements can contain other elements and other types of nodes. @verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) A Decleration contains: Attributes (not on tree) @endverbatim */ class TiXmlBase { friend class TiXmlNode; friend class TiXmlElement; friend class TiXmlDocument; public: TiXmlBase() : userData(0) {} virtual ~TiXmlBase() {} /** All TinyXml classes can print themselves to a filestream or the string class (TiXmlString in non-STL mode, std::string in STL mode.) Either or both cfile and str can be null. This is a formatted print, and will insert tabs and newlines. (For an unformatted stream, use the << operator.) */ virtual void Print( FILE* cfile, int depth ) const = 0; /** The world does not agree on whether white space should be kept or not. In order to make everyone happy, these global, static functions are provided to set whether or not TinyXml will condense all white space into a single space or not. The default is to condense. Note changing this value is not thread safe. */ static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } /// Return the current white space setting. static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } /** Return the position, in the original source file, of this node or attribute. The row and column are 1-based. (That is the first row and first column is 1,1). If the returns values are 0 or less, then the parser does not have a row and column value. Generally, the row and column value will be set when the TiXmlDocument::Load(), TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set when the DOM was created from operator>>. The values reflect the initial load. Once the DOM is modified programmatically (by adding or changing nodes and attributes) the new values will NOT update to reflect changes in the document. There is a minor performance cost to computing the row and column. Computation can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. @sa TiXmlDocument::SetTabSize() */ int Row() const { return location.row + 1; } int Column() const { return location.col + 1; } ///< See Row() void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. // Table that returs, for a given lead byte, the total number of bytes // in the UTF-8 sequence. static const int utf8ByteTable[256]; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, or they will be transformed into entities! */ static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); enum { TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, TIXML_ERROR_READING_ATTRIBUTES, TIXML_ERROR_PARSING_EMPTY, TIXML_ERROR_READING_END_TAG, TIXML_ERROR_PARSING_UNKNOWN, TIXML_ERROR_PARSING_COMMENT, TIXML_ERROR_PARSING_DECLARATION, TIXML_ERROR_DOCUMENT_EMPTY, TIXML_ERROR_EMBEDDED_NULL, TIXML_ERROR_PARSING_CDATA, TIXML_ERROR_DOCUMENT_TOP_ONLY, TIXML_ERROR_STRING_COUNT }; protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); } inline static bool IsWhiteSpace( int c ) { if ( c < 256 ) return IsWhiteSpace( (char) c ); return false; // Again, only truly correct for English/Latin...but usually works. } #ifdef TIXML_USE_STL static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); #endif /* Reads an XML name into the string provided. Returns a pointer just past the last character of the name, or 0 if the function has an error. */ static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); /* Reads text. Returns a pointer past the given end tag. Wickedly complex options, but it keeps the (sensitive) code in one place. */ static const char* ReadText( const char* in, // where to start TIXML_STRING* text, // the string read bool ignoreWhiteSpace, // whether to keep the white space const char* endTag, // what ends this text bool ignoreCase, // whether to ignore case in the end tag TiXmlEncoding encoding ); // the current encoding // If an entity has been found, transform it into a character. static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); // Get a character, while interpreting entities. // The length can be from 0 to 4 bytes. inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) { assert( p ); if ( encoding == TIXML_ENCODING_UTF8 ) { *length = utf8ByteTable[ *((const unsigned char*)p) ]; assert( *length >= 0 && *length < 5 ); } else { *length = 1; } if ( *length == 1 ) { if ( *p == '&' ) return GetEntity( p, _value, length, encoding ); *_value = *p; return p+1; } else if ( *length ) { //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), // and the null terminator isn't needed for( int i=0; p[i] && i<*length; ++i ) { _value[i] = p[i]; } return p + (*length); } else { // Not valid text. return 0; } } // Return true if the next characters in the stream are any of the endTag sequences. // Ignore case only works for english, and should only be relied on when comparing // to English words: StringEqual( p, "version", true ) is fine. static bool StringEqual( const char* p, const char* endTag, bool ignoreCase, TiXmlEncoding encoding ); static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; TiXmlCursor location; /// Field containing a generic user pointer void* userData; // None of these methods are reliable for any language except English. // Good for approximation, not great for accuracy. static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); inline static int ToLower( int v, TiXmlEncoding encoding ) { if ( encoding == TIXML_ENCODING_UTF8 ) { if ( v < 128 ) return tolower( v ); return v; } else { return tolower( v ); } } static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); private: TiXmlBase( const TiXmlBase& ); // not implemented. void operator=( const TiXmlBase& base ); // not allowed. struct Entity { const char* str; unsigned int strLength; char chr; }; enum { NUM_ENTITY = 5, MAX_ENTITY_LENGTH = 6 }; static Entity entity[ NUM_ENTITY ]; static bool condenseWhiteSpace; }; /** The parent class for everything in the Document Object Model. (Except for attributes). Nodes have siblings, a parent, and children. A node can be in a document, or stand on its own. The type of a TiXmlNode can be queried, and it can be cast to its more defined type. */ class TiXmlNode : public TiXmlBase { friend class TiXmlDocument; friend class TiXmlElement; public: #ifdef TIXML_USE_STL /** An input stream operator, for every class. Tolerant of newlines and formatting, but doesn't expect them. */ friend std::istream& operator >> (std::istream& in, TiXmlNode& base); /** An output stream operator, for every class. Note that this outputs without any newlines or formatting, as opposed to Print(), which includes tabs and new lines. The operator<< and operator>> are not completely symmetric. Writing a node to a stream is very well defined. You'll get a nice stream of output, without any extra whitespace or newlines. But reading is not as well defined. (As it always is.) If you create a TiXmlElement (for example) and read that from an input stream, the text needs to define an element or junk will result. This is true of all input streams, but it's worth keeping in mind. A TiXmlDocument will read nodes until it reads a root element, and all the children of that root element. */ friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); /// Appends the XML node or attribute to a std::string. friend std::string& operator<< (std::string& out, const TiXmlNode& base ); #endif /** The types of XML nodes supported by TinyXml. (All the unsupported types are picked up by UNKNOWN.) */ enum NodeType { TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, TINYXML_DECLARATION, TINYXML_TYPECOUNT }; virtual ~TiXmlNode(); /** The meaning of 'value' changes for the specific type of TiXmlNode. @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim The subclasses will wrap this function. */ const char *Value() const { return value.c_str (); } #ifdef TIXML_USE_STL /** Return Value() as a std::string. If you only use STL, this is more efficient than calling Value(). Only available in STL mode. */ const std::string& ValueStr() const { return value; } #endif const TIXML_STRING& ValueTStr() const { return value; } /** Changes the value of the node. Defined as: @verbatim Document: filename of the xml file Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim */ void SetValue(const char * _value) { value = _value;} #ifdef TIXML_USE_STL /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Delete all the children of this node. Does not affect 'this'. void Clear(); /// One step up the DOM. TiXmlNode* Parent() { return parent; } const TiXmlNode* Parent() const { return parent; } const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. TiXmlNode* FirstChild() { return firstChild; } const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. /// The first child of this node with the matching 'value'. Will be null if none found. TiXmlNode* FirstChild( const char * _value ) { // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) // call the method, cast the return back to non-const. return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); } const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. TiXmlNode* LastChild() { return lastChild; } const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. TiXmlNode* LastChild( const char * _value ) { return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); } #ifdef TIXML_USE_STL const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. #endif /** An alternate way to walk the children of a node. One way to iterate over nodes is: @verbatim for( child = parent->FirstChild(); child; child = child->NextSibling() ) @endverbatim IterateChildren does the same thing with the syntax: @verbatim child = 0; while( child = parent->IterateChildren( child ) ) @endverbatim IterateChildren takes the previous child as input and finds the next one. If the previous child is null, it returns the first. IterateChildren will return null when done. */ const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); } /// This flavor of IterateChildren searches for children with a particular 'value' const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); } #ifdef TIXML_USE_STL const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. #endif /** Add a new node related to this. Adds a child past the LastChild. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child past the LastChild. NOTE: the node to be added is passed by pointer, and will be henceforth owned (and deleted) by tinyXml. This method is efficient and avoids an extra copy, but should be used with care as it uses a different memory model than the other insert functions. @sa InsertEndChild */ TiXmlNode* LinkEndChild( TiXmlNode* addThis ); /** Add a new node related to this. Adds a child before the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); /** Add a new node related to this. Adds a child after the specified child. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); /** Replace a child of this node. Returns a pointer to the new object or NULL if an error occured. */ TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); /// Delete a child of this node. bool RemoveChild( TiXmlNode* removeThis ); /// Navigate to a sibling node. const TiXmlNode* PreviousSibling() const { return prev; } TiXmlNode* PreviousSibling() { return prev; } /// Navigate to a sibling node. const TiXmlNode* PreviousSibling( const char * ) const; TiXmlNode* PreviousSibling( const char *_prev ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); } #ifdef TIXML_USE_STL const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. #endif /// Navigate to a sibling node. const TiXmlNode* NextSibling() const { return next; } TiXmlNode* NextSibling() { return next; } /// Navigate to a sibling node with the given 'value'. const TiXmlNode* NextSibling( const char * ) const; TiXmlNode* NextSibling( const char* _next ) { return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement() const; TiXmlElement* NextSiblingElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); } /** Convenience function to get through elements. Calls NextSibling and ToElement. Will skip all non-Element nodes. Returns 0 if there is not another element. */ const TiXmlElement* NextSiblingElement( const char * ) const; TiXmlElement* NextSiblingElement( const char *_next ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); } #ifdef TIXML_USE_STL const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. #endif /// Convenience function to get through elements. const TiXmlElement* FirstChildElement() const; TiXmlElement* FirstChildElement() { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); } /// Convenience function to get through elements. const TiXmlElement* FirstChildElement( const char * _value ) const; TiXmlElement* FirstChildElement( const char * _value ) { return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); } #ifdef TIXML_USE_STL const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. #endif /** Query the type (as an enumerated value, above) of this node. The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. */ int Type() const { return type; } /** Return a pointer to the Document this node lives in. Returns null if not in a document. */ const TiXmlDocument* GetDocument() const; TiXmlDocument* GetDocument() { return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); } /// Returns true if this node has no children. bool NoChildren() const { return !firstChild; } virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. /** Create an exact duplicate of this node and return it. The memory must be deleted by the caller. */ virtual TiXmlNode* Clone() const = 0; /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the TiXmlVisitor interface. This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): @verbatim TiXmlPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); @endverbatim */ virtual bool Accept( TiXmlVisitor* visitor ) const = 0; protected: TiXmlNode( NodeType _type ); // Copy to the allocated object. Shared functionality between Clone, Copy constructor, // and the assignment operator. void CopyTo( TiXmlNode* target ) const; #ifdef TIXML_USE_STL // The real work of the input operator. virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; #endif // Figure out what is at *p, and parse it. Returns null if it is not an xml node. TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); TiXmlNode* parent; NodeType type; TiXmlNode* firstChild; TiXmlNode* lastChild; TIXML_STRING value; TiXmlNode* prev; TiXmlNode* next; private: TiXmlNode( const TiXmlNode& ); // not implemented. void operator=( const TiXmlNode& base ); // not allowed. }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. @note The attributes are not TiXmlNodes, since they are not part of the tinyXML document object model. There are other suggested ways to look at this problem. */ class TiXmlAttribute : public TiXmlBase { friend class TiXmlAttributeSet; public: /// Construct an empty attribute. TiXmlAttribute() : TiXmlBase() { document = 0; prev = next = 0; } #ifdef TIXML_USE_STL /// std::string constructor. TiXmlAttribute( const std::string& _name, const std::string& _value ) { name = _name; value = _value; document = 0; prev = next = 0; } #endif /// Construct an attribute with a name and value. TiXmlAttribute( const char * _name, const char * _value ) { name = _name; value = _value; document = 0; prev = next = 0; } const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. #ifdef TIXML_USE_STL const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. #endif int IntValue() const; ///< Return the value of this attribute, converted to an integer. double DoubleValue() const; ///< Return the value of this attribute, converted to a double. // Get the tinyxml string representation const TIXML_STRING& NameTStr() const { return name; } /** QueryIntValue examines the value string. It is an alternative to the IntValue() method with richer error checking. If the value is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. A specialized but useful call. Note that for success it returns 0, which is the opposite of almost all other TinyXml calls. */ int QueryIntValue( int* _value ) const; /// QueryDoubleValue examines the value string. See QueryIntValue(). int QueryDoubleValue( double* _value ) const; void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. void SetValue( const char* _value ) { value = _value; } ///< Set the value. void SetIntValue( int _value ); ///< Set the value from an integer. void SetDoubleValue( double _value ); ///< Set the value from a double. #ifdef TIXML_USE_STL /// STL std::string form. void SetName( const std::string& _name ) { name = _name; } /// STL std::string form. void SetValue( const std::string& _value ) { value = _value; } #endif /// Get the next sibling attribute in the DOM. Returns null at end. const TiXmlAttribute* Next() const; TiXmlAttribute* Next() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); } /// Get the previous sibling attribute in the DOM. Returns null at beginning. const TiXmlAttribute* Previous() const; TiXmlAttribute* Previous() { return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); } bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } /* Attribute parsing starts: first letter of the name returns: the next char after the value end quote */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); // Prints this Attribute to a FILE stream. virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; // [internal use] // Set the document pointer so the attribute can report errors. void SetDocument( TiXmlDocument* doc ) { document = doc; } private: TiXmlAttribute( const TiXmlAttribute& ); // not implemented. void operator=( const TiXmlAttribute& base ); // not allowed. TiXmlDocument* document; // A pointer back to a document, for error reporting. TIXML_STRING name; TIXML_STRING value; TiXmlAttribute* prev; TiXmlAttribute* next; }; /* A class used to manage a group of attributes. It is only used internally, both by the ELEMENT and the DECLARATION. The set can be changed transparent to the Element and Declaration classes that use it, but NOT transparent to the Attribute which has to implement a next() and previous() method. Which makes it a bit problematic and prevents the use of STL. This version is implemented with circular lists because: - I like circular lists - it demonstrates some independence from the (typical) doubly linked list. */ class TiXmlAttributeSet { public: TiXmlAttributeSet(); ~TiXmlAttributeSet(); void Add( TiXmlAttribute* attribute ); void Remove( TiXmlAttribute* attribute ); const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Find( const char* _name ) const; TiXmlAttribute* FindOrCreate( const char* _name ); # ifdef TIXML_USE_STL TiXmlAttribute* Find( const std::string& _name ) const; TiXmlAttribute* FindOrCreate( const std::string& _name ); # endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), //*ME: this class must be also use a hidden/disabled copy-constructor !!! TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) TiXmlAttribute sentinel; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TiXmlElement : public TiXmlNode { public: /// Construct an element. TiXmlElement (const char * in_value); #ifdef TIXML_USE_STL /// std::string constructor. TiXmlElement( const std::string& _value ); #endif TiXmlElement( const TiXmlElement& ); TiXmlElement& operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. */ const char* Attribute( const char* name ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an integer, the integer value will be put in the return 'i', if 'i' is non-null. */ const char* Attribute( const char* name, int* i ) const; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. If the attribute exists and can be converted to an double, the double value will be put in the return 'd', if 'd' is non-null. */ const char* Attribute( const char* name, double* d ) const; /** QueryIntAttribute examines the attribute - it is an alternative to the Attribute() method with richer error checking. If the attribute is an integer, it is stored in 'value' and the call returns TIXML_SUCCESS. If it is not an integer, it returns TIXML_WRONG_TYPE. If the attribute does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). Note that '1', 'true', or 'yes' are considered true, while '0', 'false' and 'no' are considered false. */ int QueryBoolAttribute( const char* name, bool* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). int QueryFloatAttribute( const char* name, float* _value ) const { double d; int result = QueryDoubleAttribute( name, &d ); if ( result == TIXML_SUCCESS ) { *_value = (float)d; } return result; } #ifdef TIXML_USE_STL /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). int QueryStringAttribute( const char* name, std::string* _value ) const { const char* cstr = Attribute( name ); if ( cstr ) { *_value = std::string( cstr ); return TIXML_SUCCESS; } return TIXML_NO_ATTRIBUTE; } /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. NOTE: This method doesn't work correctly for 'string' types that contain spaces. @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; std::stringstream sstream( node->ValueStr() ); sstream >> *outValue; if ( !sstream.fail() ) return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; *outValue = node->ValueStr(); return TIXML_SUCCESS; } #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char* name, const char * _value ); #ifdef TIXML_USE_STL const std::string* Attribute( const std::string& name ) const; const std::string* Attribute( const std::string& name, int* i ) const; const std::string* Attribute( const std::string& name, double* d ) const; int QueryIntAttribute( const std::string& name, int* _value ) const; int QueryDoubleAttribute( const std::string& name, double* _value ) const; /// STL std::string form. void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); ///< STL std::string form. void SetDoubleAttribute( const std::string& name, double value ); #endif /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetAttribute( const char * name, int value ); /** Sets an attribute of name to a given value. The attribute will be created if it does not exist, or changed if it does. */ void SetDoubleAttribute( const char * name, double value ); /** Deletes an attribute with the given name. */ void RemoveAttribute( const char * name ); #ifdef TIXML_USE_STL void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. #endif const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the TiXmlText child and accessing it directly. If the first child of 'this' is a TiXmlText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: @verbatim This is text const char* str = fooElement->GetText(); @endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: @verbatim This is text @endverbatim GetText() will return "This is ". WARNING: GetText() accesses a child node - don't become confused with the similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are safe type casts on the referenced node. */ const char* GetText() const; /// Creates a new Element and returns it - the returned element is a copy. virtual TiXmlNode* Clone() const; // Print the Element to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: next char past '<' returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlElement* target ) const; void ClearThis(); // like clear, but initializes 'this' object as well // Used to be public [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif /* [internal use] Reads the "value" of the element -- another element, or text. This should terminate with the current end tag. */ const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: TiXmlAttributeSet attributeSet; }; /** An XML comment. */ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} /// Construct a comment from text. TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); TiXmlComment& operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} /// Returns a copy of this Comment. virtual TiXmlNode* Clone() const; // Write this Comment to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /* Attribtue parsing starts: at the ! of the !-- returns: next char past '>' */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlComment* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif // virtual void StreamOut( TIXML_OSTREAM * out ) const; private: }; /** XML text. A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCDATA() and query it with CDATA(). */ class TiXmlText : public TiXmlNode { friend class TiXmlElement; public: /** Constructor for text element. By default, it is treated as normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } virtual ~TiXmlText() {} #ifdef TIXML_USE_STL /// Constructor. TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } #endif TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; /// Queries whether this represents text using a CDATA section. bool CDATA() const { return cdata; } /// Turns on or off a CDATA representation of text. void SetCDATA( bool _cdata ) { cdata = _cdata; } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : /// [internal use] Creates a new Element and returns it. virtual TiXmlNode* Clone() const; void CopyTo( TiXmlText* target ) const; bool Blank() const; // returns true if all white space and new lines // [internal use] #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: bool cdata; // true if this should be input and output as a CDATA style text element }; /** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim TinyXml will happily read or write files without a declaration, however. There are 3 possible attributes to the declaration: version, encoding, and standalone. Note: In this version of the code, the attributes are handled as special cases, not generic attributes, simply because there can only be at most 3 and they are always the same. */ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ); #endif /// Construct. TiXmlDeclaration( const char* _version, const char* _encoding, const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} /// Version. Will return an empty string if none was found. const char *Version() const { return version.c_str (); } /// Encoding. Will return an empty string if none was found. const char *Encoding() const { return encoding.c_str (); } /// Is this a standalone document? const char *Standalone() const { return standalone.c_str (); } /// Creates a copy of this Declaration and returns it. virtual TiXmlNode* Clone() const; // Print this declaration to a FILE stream. virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; virtual void Print( FILE* cfile, int depth ) const { Print( cfile, depth, 0 ); } virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* visitor ) const; protected: void CopyTo( TiXmlDeclaration* target ) const; // used to be public #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: TIXML_STRING version; TIXML_STRING encoding; TIXML_STRING standalone; }; /** Any tag that tinyXml doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into TiXmlUnknowns. */ class TiXmlUnknown : public TiXmlNode { public: TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} virtual ~TiXmlUnknown() {} TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; // Print this Unknown to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected: void CopyTo( TiXmlUnknown* target ) const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: }; /** Always the top level node. A document binds together all the XML pieces. It can be saved, loaded, and printed to the screen. The 'value' of a document node is the xml file name. */ class TiXmlDocument : public TiXmlNode { public: /// Create an empty document, that has no name. TiXmlDocument(); /// Create a document with a name. The name of the document is also the filename of the xml. TiXmlDocument( const char * documentName ); #ifdef TIXML_USE_STL /// Constructor. TiXmlDocument( const std::string& documentName ); #endif TiXmlDocument( const TiXmlDocument& copy ); TiXmlDocument& operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} /** Load a file using the current document value. Returns true if successful. Will delete any existing document data before loading. */ bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the current document value. Returns true if successful. bool SaveFile() const; /// Load a file using the given filename. Returns true if successful. bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given filename. Returns true if successful. bool SaveFile( const char * filename ) const; /** Load a file using the given FILE*. Returns true if successful. Note that this method doesn't stream - the entire object pointed at by the FILE* will be interpreted as an XML file. TinyXML doesn't stream in XML from the current file location. Streaming may be added in the future. */ bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /// Save a file using the given FILE*. Returns true if successful. bool SaveFile( FILE* ) const; #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { return SaveFile( filename.c_str() ); } #endif /** Parse the given null terminated block of xml data. Passing in an encoding to this method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml to use that encoding, regardless of what TinyXml might otherwise try to detect. */ virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); /** Get the root element -- the only top level element -- of the document. In well formed XML, there should only be one. TinyXml is tolerant of multiple elements at the document level. */ const TiXmlElement* RootElement() const { return FirstChildElement(); } TiXmlElement* RootElement() { return FirstChildElement(); } /** If an error occurs, Error will be set to true. Also, - The ErrorId() will contain the integer identifier of the error (not generally useful) - The ErrorDesc() method will return the name of the error. (very useful) - The ErrorRow() and ErrorCol() will return the location of the error (if known) */ bool Error() const { return error; } /// Contains a textual (english) description of the error if one occurs. const char * ErrorDesc() const { return errorDesc.c_str (); } /** Generally, you probably want the error string ( ErrorDesc() ). But if you prefer the ErrorId, this function will fetch it. */ int ErrorId() const { return errorId; } /** Returns the location (if known) of the error. The first column is column 1, and the first row is row 1. A value of 0 means the row and column wasn't applicable (memory errors, for example, have no row/column) or the parser lost the error. (An error in the error reporting, in that case.) @sa SetTabSize, Row, Column */ int ErrorRow() const { return errorLocation.row+1; } int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) to report the correct values for row and column. It does not change the output or input in any way. By calling this method, with a tab size greater than 0, the row and column of each node and attribute is stored when the file is loaded. Very useful for tracking the DOM back in to the source file. The tab size is required for calculating the location of nodes. If not set, the default of 4 is used. The tabsize is set per document. Setting the tabsize to 0 disables row/column tracking. Note that row and column tracking is not supported when using operator>>. The tab size needs to be enabled before the parse or load. Correct usage: @verbatim TiXmlDocument doc; doc.SetTabSize( 8 ); doc.Load( "myfile.xml" ); @endverbatim @sa Row, Column */ void SetTabSize( int _tabsize ) { tabsize = _tabsize; } int TabSize() const { return tabsize; } /** If you have handled the error, it can be reset with this call. The error state is automatically cleared if you Parse a new XML block. */ void ClearError() { error = false; errorId = 0; errorDesc = ""; errorLocation.row = errorLocation.col = 0; //errorLocation.last = 0; } /** Write the document to standard out using formatted printing ("pretty print"). */ void Print() const { Print( stdout, 0 ); } /* Write the document to a string using formatted printing ("pretty print"). This will allocate a character array (new char[]) and return it as a pointer. The calling code pust call delete[] on the return char* to avoid a memory leak. */ //char* PrintToMemory() const; /// Print this Document to a FILE stream. virtual void Print( FILE* cfile, int depth = 0 ) const; // [internal use] void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ virtual bool Accept( TiXmlVisitor* content ) const; protected : // [internal use] virtual TiXmlNode* Clone() const; #ifdef TIXML_USE_STL virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); #endif private: void CopyTo( TiXmlDocument* target ) const; bool error; int errorId; TIXML_STRING errorDesc; int tabsize; TiXmlCursor errorLocation; bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. }; /** A TiXmlHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml DOM structure. It is a separate utility class. Take an example: @verbatim @endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: @verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity of such code. A TiXmlHandle checks for null pointers so it is perfectly safe and correct to use: @verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. @verbatim TiXmlHandle handleCopy = handle; @endverbatim What they should not be used for is iteration: @verbatim int i=0; while ( true ) { TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); if ( !child ) break; // do something ++i; } @endverbatim It seems reasonable, but it is in fact two embedded while loops. The Child method is a linear walk to find the element, so this code would iterate much more than it needs to. Instead, prefer: @verbatim TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); for( child; child; child=child->NextSiblingElement() ) { // do something } @endverbatim */ class TiXmlHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; /// Return a handle to the first child node with the given name. TiXmlHandle FirstChild( const char * value ) const; /// Return a handle to the first child element. TiXmlHandle FirstChildElement() const; /// Return a handle to the first child element with the given name. TiXmlHandle FirstChildElement( const char * value ) const; /** Return a handle to the "index" child with the given name. The first child is 0, the second 1, etc. */ TiXmlHandle Child( const char* value, int index ) const; /** Return a handle to the "index" child. The first child is 0, the second 1, etc. */ TiXmlHandle Child( int index ) const; /** Return a handle to the "index" child element with the given name. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( const char* value, int index ) const; /** Return a handle to the "index" child element. The first child element is 0, the second 1, etc. Note that only TiXmlElements are indexed: other types are not counted. */ TiXmlHandle ChildElement( int index ) const; #ifdef TIXML_USE_STL TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } #endif /** Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* ToNode() const { return node; } /** Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } /** Return the handle as a TiXmlText. This may return null. */ TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } /** Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } /** @deprecated use ToNode. Return the handle as a TiXmlNode. This may return null. */ TiXmlNode* Node() const { return ToNode(); } /** @deprecated use ToElement. Return the handle as a TiXmlElement. This may return null. */ TiXmlElement* Element() const { return ToElement(); } /** @deprecated use ToText() Return the handle as a TiXmlText. This may return null. */ TiXmlText* Text() const { return ToText(); } /** @deprecated use ToUnknown() Return the handle as a TiXmlUnknown. This may return null. */ TiXmlUnknown* Unknown() const { return ToUnknown(); } private: TiXmlNode* node; }; /** Print to memory functionality. The TiXmlPrinter is useful when you need to: -# Print to memory (especially in non-STL mode) -# Control formatting (line endings, etc.) When constructed, the TiXmlPrinter is in its default "pretty printing" mode. Before calling Accept() you can call methods to control the printing of the XML document. After TiXmlNode::Accept() is called, the printed document can be accessed via the CStr(), Str(), and Size() methods. TiXmlPrinter uses the Visitor API. @verbatim TiXmlPrinter printer; printer.SetIndent( "\t" ); doc.Accept( &printer ); fprintf( stdout, "%s", printer.CStr() ); @endverbatim */ class TiXmlPrinter : public TiXmlVisitor { public: TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), buffer(), indent( " " ), lineBreak( "\n" ) {} virtual bool VisitEnter( const TiXmlDocument& doc ); virtual bool VisitExit( const TiXmlDocument& doc ); virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); virtual bool VisitExit( const TiXmlElement& element ); virtual bool Visit( const TiXmlDeclaration& declaration ); virtual bool Visit( const TiXmlText& text ); virtual bool Visit( const TiXmlComment& comment ); virtual bool Visit( const TiXmlUnknown& unknown ); /** Set the indent characters for printing. By default 4 spaces but tab (\t) is also useful, or null/empty string for no indentation. */ void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } /// Query the indention string. const char* Indent() { return indent.c_str(); } /** Set the line breaking string. By default set to newline (\n). Some operating systems prefer other characters, or can be set to the null/empty string for no indenation. */ void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } /// Query the current line breaking string. const char* LineBreak() { return lineBreak.c_str(); } /** Switch over to "stream printing" which is the most dense formatting without linebreaks. Common when the XML is needed for network transmission. */ void SetStreamPrinting() { indent = ""; lineBreak = ""; } /// Return the result. const char* CStr() { return buffer.c_str(); } /// Return the length of the result string. size_t Size() { return buffer.size(); } #ifdef TIXML_USE_STL /// Return the result. const std::string& Str() { return buffer; } #endif private: void DoIndent() { for( int i=0; i #include #include "tinyxml.h" //#define DEBUG_PARSER #if defined( DEBUG_PARSER ) # if defined( DEBUG ) && defined( _MSC_VER ) # include # define TIXML_LOG OutputDebugString # else # define TIXML_LOG printf # endif #endif // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, { ">", 4, '>' }, { """, 6, '\"' }, { "'", 6, '\'' } }; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. // Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be // ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid }; void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; else if ( input < 0x10000 ) *length = 3; else if ( input < 0x200000 ) *length = 4; else { *length = 0; return; } // This code won't covert this correctly anyway. output += *length; // Scary scary fall throughs. switch (*length) { case 4: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: --output; *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalpha( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalpha( anyByte ); // } } /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) // { if ( anyByte < 127 ) return isalnum( anyByte ); else return 1; // What else to do? The unicode set is huge...get the english ones right. // } // else // { // return isalnum( anyByte ); // } } class TiXmlParsingData { friend class TiXmlDocument; public: void Stamp( const char* now, TiXmlEncoding encoding ); const TiXmlCursor& Cursor() const { return cursor; } private: // Only used by the document! TiXmlParsingData( const char* start, int _tabsize, int row, int col ) { assert( start ); stamp = start; tabsize = _tabsize; cursor.row = row; cursor.col = col; } TiXmlCursor cursor; const char* stamp; int tabsize; }; void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) { assert( now ); // Do nothing if the tabsize is 0. if ( tabsize < 1 ) { return; } // Get the current row, column. int row = cursor.row; int col = cursor.col; const char* p = stamp; assert( p ); while ( p < now ) { // Treat p as unsigned, so we have a happy compiler. const unsigned char* pU = (const unsigned char*)p; // Code contributed by Fletcher Dunn: (modified by lee) switch (*pU) { case 0: // We *should* never get here, but in case we do, don't // advance past the terminating null character, ever return; case '\r': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \r\n sequence, and treat this as a single character if (*p == '\n') { ++p; } break; case '\n': // bump down to the next line ++row; col = 0; // Eat the character ++p; // Check for \n\r sequence, and treat this as a single // character. (Yes, this bizarre thing does occur still // on some arcane platforms...) if (*p == '\r') { ++p; } break; case '\t': // Eat the character ++p; // Skip to next tab stop col = (col / tabsize + 1) * tabsize; break; case TIXML_UTF_LEAD_0: if ( encoding == TIXML_ENCODING_UTF8 ) { if ( *(p+1) && *(p+2) ) { // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) p += 3; else { p +=3; ++col; } // A normal character. } } else { ++p; ++col; } break; default: if ( encoding == TIXML_ENCODING_UTF8 ) { // Eat the 1 to 4 byte utf8 character. int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; if ( step == 0 ) step = 1; // Error case from bad encoding, but handle gracefully. p += step; // Just advance one column, of course. ++col; } else { ++p; ++col; } break; } } cursor.row = row; cursor.col = col; assert( cursor.row >= -1 ); assert( cursor.col >= -1 ); stamp = p; assert( stamp ); } const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) { if ( !p || !*p ) { return 0; } if ( encoding == TIXML_ENCODING_UTF8 ) { while ( *p ) { const unsigned char* pU = (const unsigned char*)p; // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbeU ) { p += 3; continue; } else if(*(pU+0)==TIXML_UTF_LEAD_0 && *(pU+1)==0xbfU && *(pU+2)==0xbfU ) { p += 3; continue; } if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. ++p; else break; } } else { while ( *p && IsWhiteSpace( *p ) ) ++p; } return p; } #ifdef TIXML_USE_STL /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) { for( ;; ) { if ( !in->good() ) return false; int c = in->peek(); // At this scope, we can't get to a document. So fail silently. if ( !IsWhiteSpace( c ) || c <= 0 ) return true; *tag += (char) in->get(); } } /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) { //assert( character > 0 && character < 128 ); // else it won't work in utf-8 while ( in->good() ) { int c = in->peek(); if ( c == character ) return true; if ( c <= 0 ) // Silent failure: can't get document at this scope return false; in->get(); *tag += (char) c; } return false; } #endif // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The // "assign" optimization removes over 10% of the execution time. // const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) { // Oddly, not supported on some comilers, //name->clear(); // So use this: *name = ""; assert( p ); // Names start with letters or underscores. // Of course, in unicode, tinyxml has no idea what a letter *is*. The // algorithm is generous. // // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' || *p == ':' ) ) { //(*name) += *p; // expensive ++p; } if ( p-start > 0 ) { name->assign( start, p-start ); } return p; } return 0; } const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) { // Presume an entity, and pull it out. TIXML_STRING ent; int i; *length = 0; if ( *(p+1) && *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; ptrdiff_t delta = 0; unsigned mult = 1; if ( *(p+2) == 'x' ) { // Hexadecimal. if ( !*(p+3) ) return 0; const char* q = p+3; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != 'x' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else if ( *q >= 'a' && *q <= 'f' ) ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); else return 0; mult *= 16; --q; } } else { // Decimal. if ( !*(p+2) ) return 0; const char* q = p+2; q = strchr( q, ';' ); if ( !q || !*q ) return 0; delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); else return 0; mult *= 10; --q; } } if ( encoding == TIXML_ENCODING_UTF8 ) { // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); } else { *value = (char)ucs; *length = 1; } return p + delta + 1; } // Now try to match it. for( i=0; iappend( cArr, len ); } } else { bool whitespace = false; // Remove leading white space: p = SkipWhiteSpace( p, encoding ); while ( p && *p && !StringEqual( p, endTag, caseInsensitive, encoding ) ) { if ( *p == '\r' || *p == '\n' ) { whitespace = true; ++p; } else if ( IsWhiteSpace( *p ) ) { whitespace = true; ++p; } else { // If we've found whitespace, add it before the // new character. Any whitespace just becomes a space. if ( whitespace ) { (*text) += ' '; whitespace = false; } int len; char cArr[4] = { 0, 0, 0, 0 }; p = GetChar( p, cArr, &len, encoding ); if ( len == 1 ) (*text) += cArr[0]; // more efficient else text->append( cArr, len ); } } } if ( p && *p ) p += strlen( endTag ); return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) { // The basic issue with a document is that we don't know what we're // streaming. Read something presumed to be a tag (and hope), then // identify it, and call the appropriate stream method on the tag. // // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } while ( in->good() ) { int tagIndex = (int) tag->length(); while ( in->good() && in->peek() != '>' ) { int c = in->get(); if ( c <= 0 ) { SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); break; } (*tag) += (char) c; } if ( in->good() ) { // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); if ( node ) { node->StreamIn( in, tag ); bool isElement = node->ToElement() != 0; delete node; node = 0; // If this is the root element, we're done. Parsing will be // done by the >> operator. if ( isElement ) { return; } } else { SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } } } // We should have returned sooner. SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); } #endif const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) { ClearError(); // Parse away, at the document level. Since a document // contains nothing but other tags, most of what happens // here is skipping white space. if ( !p || !*p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } // Note that, for a document, this needs to come // before the while space skip, so that parsing // starts from the pointer we are given. location.Clear(); if ( prevData ) { location.row = prevData->cursor.row; location.col = prevData->cursor.col; } else { location.row = 0; location.col = 0; } TiXmlParsingData data( p, TabSize(), location.row, location.col ); location = data.Cursor(); if ( encoding == TIXML_ENCODING_UNKNOWN ) { // Check for the Microsoft UTF-8 lead bytes. const unsigned char* pU = (const unsigned char*)p; if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) { encoding = TIXML_ENCODING_UTF8; useMicrosoftBOM = true; } } p = SkipWhiteSpace( p, encoding ); if ( !p ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } while ( p && *p ) { TiXmlNode* node = Identify( p, encoding ); if ( node ) { p = node->Parse( p, &data, encoding ); LinkEndChild( node ); } else { break; } // Did we get encoding info? if ( encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration() ) { TiXmlDeclaration* dec = node->ToDeclaration(); const char* enc = dec->Encoding(); assert( enc ); if ( *enc == 0 ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice else encoding = TIXML_ENCODING_LEGACY; } p = SkipWhiteSpace( p, encoding ); } // Was this empty? if ( !firstChild ) { SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); return 0; } // All is well. return p; } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) { // The first error in a chain is more accurate - don't set again! if ( error ) return; assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); error = true; errorId = err; errorDesc = errorString[ errorId ]; errorLocation.Clear(); if ( pError && data ) { data->Stamp( pError, encoding ); errorLocation = data->Cursor(); } } TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) { TiXmlNode* returnNode = 0; p = SkipWhiteSpace( p, encoding ); if( !p || !*p || *p != '<' ) { return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { return 0; } // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: "; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); // [ 1475201 ] TinyXML parses entities in comments // Oops - ReadText doesn't work, because we don't want to parse the entities. // p = ReadText( p, &value, false, endTag, false, encoding ); // // from the XML spec: /* [Definition: Comments may appear anywhere in a document outside other markup; in addition, they may appear within the document type declaration at places allowed by the grammar. They are not part of the document's character data; an XML processor MAY, but need not, make it possible for an application to retrieve the text of comments. For compatibility, the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity references MUST NOT be recognized within comments. An example of a comment: */ value = ""; // Keep all the white space. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value.append( p, 1 ); ++p; } if ( p && *p ) p += strlen( endTag ); return p; } const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } // Read the name, the '=' and the value. const char* pErr = p; p = ReadName( p, &name, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); return 0; } p = SkipWhiteSpace( p, encoding ); if ( !p || !*p || *p != '=' ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } ++p; // skip '=' p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) { if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } const char* end; const char SINGLE_QUOTE = '\''; const char DOUBLE_QUOTE = '\"'; if ( *p == SINGLE_QUOTE ) { ++p; end = "\'"; // single quote in string p = ReadText( p, &value, false, end, false, encoding ); } else if ( *p == DOUBLE_QUOTE ) { ++p; end = "\""; // double quote in string p = ReadText( p, &value, false, end, false, encoding ); } else { // All attribute values should be in single or double quotes. // But this is such a common error that the parser will try // its best, even without them. value = ""; while ( p && *p // existence && !IsWhiteSpace( *p ) // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { // [ 1451649 ] Attribute values with trailing quotes not handled correctly // We did not have an opening quote but seem to have a // closing one. Give up and throw an error. if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); return 0; } value += *p; ++p; } } return p; } #ifdef TIXML_USE_STL void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->peek(); if ( !cdata && (c == '<' ) ) { return; } if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; in->get(); // "commits" the peek made above if ( cdata && c == '>' && tag->size() >= 3 ) { size_t len = tag->size(); if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { // terminator of cdata. return; } } } } #endif const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) { value = ""; TiXmlDocument* document = GetDocument(); if ( data ) { data->Stamp( p, encoding ); location = data->Cursor(); } const char* const startTag = ""; if ( cdata || StringEqual( p, startTag, false, encoding ) ) { cdata = true; if ( !StringEqual( p, startTag, false, encoding ) ) { if ( document ) document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); // Keep all the white space, ignore the encoding, etc. while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) { value += *p; ++p; } TIXML_STRING dummy; p = ReadText( p, &dummy, false, endTag, false, encoding ); return p; } else { bool ignoreWhite = true; const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); if ( p && *p ) return p-1; // don't truncate the '<' return 0; } } #ifdef TIXML_USE_STL void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) { while ( in->good() ) { int c = in->get(); if ( c <= 0 ) { TiXmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); return; } (*tag) += (char) c; if ( c == '>' ) { // All is well. return; } } } #endif const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) { p = SkipWhiteSpace( p, _encoding ); // Find the beginning, find the end, and look for // the stuff in-between. TiXmlDocument* document = GetDocument(); if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); return 0; } if ( data ) { data->Stamp( p, _encoding ); location = data->Cursor(); } p += 5; version = ""; encoding = ""; standalone = ""; while ( p && *p ) { if ( *p == '>' ) { ++p; return p; } p = SkipWhiteSpace( p, _encoding ); if ( StringEqual( p, "version", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); version = attrib.Value(); } else if ( StringEqual( p, "encoding", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); encoding = attrib.Value(); } else if ( StringEqual( p, "standalone", true, _encoding ) ) { TiXmlAttribute attrib; p = attrib.Parse( p, data, _encoding ); standalone = attrib.Value(); } else { // Read over whatever it is. while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) ++p; } } return 0; } bool TiXmlText::Blank() const { for ( unsigned i=0; iValue()); } tstring CXmlHelper::GetElementValue(XmlElementPtr pElement) { return Util::Base::UTF8ToUnicode(pElement->GetText()); } std::vector CXmlHelper::GetChild(XmlElementPtr pElement) { std::vector vecChild; XmlElementPtr pChild = pElement->FirstChildElement(); while (pChild) { vecChild.push_back(pChild); pChild = pChild->NextSiblingElement(); } return vecChild; } tstring CXmlHelper::GetAttributeString(XmlElementPtr pElement, string lpszAttriName) { LPCSTR lpszValue = pElement->Attribute(lpszAttriName.c_str()); return Util::Base::UTF8ToUnicode(lpszValue); } int CXmlHelper::GetAttributeInt(XmlElementPtr pElement, string lpszAttriName) { int nValue = 0; pElement->Attribute(lpszAttriName.c_str(), &nValue); return nValue; } BOOL CXmlHelper::GetAttributeBool(XmlElementPtr pElement, string lpszAttriName) { bool bValue = TRUE; pElement->QueryBoolAttribute(lpszAttriName.c_str(), &bValue); if (bValue) return TRUE; else return FALSE; } double CXmlHelper::GetAttributeDouble(XmlElementPtr pElement, string lpszAttriName) { double dValue = 0.0; pElement->QueryDoubleAttribute(lpszAttriName.c_str(), &dValue); return dValue; } void CXmlHelper::InsertDeclaration(string strVer, string strEncode) { TiXmlDeclaration *dec = new TiXmlDeclaration(strVer.c_str(), strEncode.c_str(), ""); m_xmlDoc.LinkEndChild(dec); } XmlElementPtr CXmlHelper::InsertChild(string strName) { TiXmlElement *pChild = new TiXmlElement(strName.c_str()); m_xmlDoc.LinkEndChild(pChild); return pChild; } void CXmlHelper::InsertChild(XmlElementPtr pElement) { m_xmlDoc.LinkEndChild(pElement); } XmlElementPtr CXmlHelper::InsertChild(XmlElementPtr pElement, string strName) { TiXmlElement *pChild = new TiXmlElement(strName.c_str()); if (pChild) { pElement->LinkEndChild(pChild); } return pChild; } void CXmlHelper::SetElementString(XmlElementPtr pElement, tstring strVal) { #ifdef UNICODE TiXmlText *pStrName = new TiXmlText(Util::Base::UnicodeToUTF8(strVal.c_str()).c_str()); #else TiXmlText *pStrName = new TiXmlText(strVal.c_str()); #endif pElement->LinkEndChild(pStrName); } void CXmlHelper::SetElementInt(XmlElementPtr pElement, int nVal) { TCHAR szVal[64] = {0}; StringCchPrintf(szVal, 64, _T("%d"), nVal); SetElementString(pElement, szVal); } void CXmlHelper::SetAttributeString(XmlElementPtr pElement, string strAttriName, tstring strAttriVal) { #ifdef UNICODE pElement->SetAttribute(strAttriName.c_str(), Util::Base::UnicodeToUTF8(strAttriVal.c_str()).c_str()); #else pElement->SetAttribute(strAttriName.c_str(), strAttriVal.c_str()); #endif } void CXmlHelper::SetAttributeInt(XmlElementPtr pElement, string strAttriName, int nAttriVal) { TCHAR szVal[64] = {0}; StringCchPrintf(szVal, 64, _T("%d"), nAttriVal); SetAttributeString(pElement, strAttriName, szVal); } void CXmlHelper::SaveFile(LPCTSTR pFileName) { #ifdef UNICODE USES_CONVERSION; LPCSTR pAnsiFileName = T2A(pFileName); m_xmlDoc.SaveFile(pAnsiFileName); #else m_xmlDoc.SaveFile(pFileName); #endif } ================================================ FILE: common/xml/xmlhelper.h ================================================ #pragma once #include #include #include #include "tinyxml.h" #ifndef tstring #ifdef _UNICODE #define tstring std::wstring #else #define tstring std::string #endif #endif typedef TiXmlDocument XmlDocument; typedef TiXmlElement *XmlElementPtr; typedef TiXmlAttribute *XmlAttributePtr; class CXmlHelper { using string = std::string; using wstring = std::wstring; public: CXmlHelper(); virtual ~CXmlHelper(); static CXmlHelper &GetInstance() { static CXmlHelper This; return This; } BOOL LoadFile(LPCTSTR pFileName); BOOL loadResFile(HINSTANCE hInstance, LPCTSTR lpszResName, LPCTSTR lpszResType); BOOL LoadString(LPCTSTR lpszXmlStr); BOOL LoadStringW(WCHAR *lpzXmlStr); XmlElementPtr GetRoot(); std::vector GetChild(XmlElementPtr pElement); tstring GetElementName(XmlElementPtr pElement); tstring GetElementValue(XmlElementPtr pElement); tstring GetAttributeString(XmlElementPtr pElement, string lpszAttriName); int GetAttributeInt(XmlElementPtr pElement, string lpszAttriName); BOOL GetAttributeBool(XmlElementPtr pElement, string lpszAttriName); double GetAttributeDouble(XmlElementPtr pElement, string lpszAttriName); void InsertDeclaration(string strVer = "1.0", string strEncode = "UTF-8"); void InsertChild(XmlElementPtr pElement); XmlElementPtr InsertChild(string strName); XmlElementPtr InsertChild(XmlElementPtr pElement, string strName); void SetElementString(XmlElementPtr pElement, tstring strVal); void SetElementInt(XmlElementPtr pElement, int nVal); void SetAttributeString(XmlElementPtr pElement, string strAttriName, tstring strAttriVal); void SetAttributeInt(XmlElementPtr pElement, string strAttriName, int nAttriVal); void SaveFile(LPCTSTR pFileName); private: XmlDocument m_xmlDoc; }; ================================================ FILE: common/xzip/XUnzip.cpp ================================================ // XUnzip.cpp Version 1.3 // // Authors: Mark Adler et al. (see below) // // Modified by: Lucian Wischik // lu@wischik.com // // Version 1.0 - Turned C files into just a single CPP file // - Made them compile cleanly as C++ files // - Gave them simpler APIs // - Added the ability to zip/unzip directly in memory without // any intermediate files // // Modified by: Hans Dietrich // hdietrich@gmail.com // // Version 1.3: - Corrected size bug introduced by 1.2 // // Version 1.2: - Many bug fixes. See CodeProject article for list. // // Version 1.1: - Added Unicode support to CreateZip() and ZipAdd() // - Changed file names to avoid conflicts with Lucian's files // /////////////////////////////////////////////////////////////////////////////// // // Lucian Wischik's comments: // -------------------------- // THIS FILE is almost entirely based upon code by Info-ZIP. // It has been modified by Lucian Wischik. // The original code may be found at http://www.info-zip.org // The original copyright text follows. // /////////////////////////////////////////////////////////////////////////////// // // Original authors' comments: // --------------------------- // This is version 2002-Feb-16 of the Info-ZIP copyright and license. The // definitive version of this document should be available at // ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. // // Copyright (c) 1990-2002 Info-ZIP. All rights reserved. // // For the purposes of this copyright and license, "Info-ZIP" is defined as // the following set of individuals: // // Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, // Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, // Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, // David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, // Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, // Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, // Antoine Verheijen, Paul von Behren, Rich Wales, Mike White // // This software is provided "as is", without warranty of any kind, express // or implied. In no event shall Info-ZIP or its contributors be held liable // for any direct, indirect, incidental, special or consequential damages // arising out of the use of or inability to use this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. Redistributions of source code must retain the above copyright notice, // definition, disclaimer, and this list of conditions. // // 2. Redistributions in binary form (compiled executables) must reproduce // the above copyright notice, definition, disclaimer, and this list of // conditions in documentation and/or other materials provided with the // distribution. The sole exception to this condition is redistribution // of a standard UnZipSFX binary as part of a self-extracting archive; // that is permitted without inclusion of this license, as long as the // normal UnZipSFX banner has not been removed from the binary or // disabled. // // 3. Altered versions--including, but not limited to, ports to new // operating systems, existing ports with new graphical interfaces, and // dynamic, shared, or static library versions--must be plainly marked // as such and must not be misrepresented as being the original source. // Such altered versions also must not be misrepresented as being // Info-ZIP releases--including, but not limited to, labeling of the // altered versions with the names "Info-ZIP" (or any variation thereof, // including, but not limited to, different capitalizations), // "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of // Info-ZIP. Such altered versions are further prohibited from // misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or // of the Info-ZIP URL(s). // // 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip", // "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its // own source and binary releases. // /////////////////////////////////////////////////////////////////////////////// #define _USE_32BIT_TIME_T //+++1.2 #define STRICT #define WIN32_LEAN_AND_MEAN #include "stdafx.h" #include #include #include #include #include #include "XUnzip.h" #pragma warning(disable : 4996) // disable bogus deprecation warning // THIS FILE is almost entirely based upon code by Jean-loup Gailly // and Mark Adler. It has been modified by Lucian Wischik. // The original code may be found at http://www.gzip.org/zlib/ // The original copyright text follows. // // // // zlib.h -- interface of the 'zlib' general purpose compression library // version 1.1.3, July 9th, 1998 // // Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // // Jean-loup Gailly Mark Adler // jloup@gzip.org madler@alumni.caltech.edu // // // The data format used by the zlib library is described by RFCs (Request for // Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt // (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). // // // The 'zlib' compression library provides in-memory compression and // decompression functions, including integrity checks of the uncompressed // data. This version of the library supports only one compression method // (deflation) but other algorithms will be added later and will have the same // stream interface. // // Compression can be done in a single step if the buffers are large // enough (for example if an input file is mmap'ed), or can be done by // repeated calls of the compression function. In the latter case, the // application must provide more input and/or consume the output // (providing more output space) before each call. // // The library also supports reading and writing files in gzip (.gz) format // with an interface similar to that of stdio. // // The library does not install any signal handler. The decoder checks // the consistency of the compressed data, so the library should never // crash even in case of corrupted input. // // for more info about .ZIP format, see // ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip // PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip #define zmalloc(len) malloc(len) #define zfree(p) free(p) /* void *zmalloc(unsigned int len) { char *buf = new char[len+32]; for (int i=0; i<16; i++) { buf[i]=i; buf[len+31-i]=i; } *((unsigned int*)buf) = len; char c[1000]; wsprintf(c,"malloc 0x%lx - %lu",buf+16,len); OutputDebugString(c); return buf+16; } void zfree(void *buf) { char c[1000]; wsprintf(c,"free 0x%lx",buf); OutputDebugString(c); char *p = ((char*)buf)-16; unsigned int len = *((unsigned int*)p); bool blown=false; for (int i=0; i<16; i++) { char lo = p[i]; char hi = p[len+31-i]; if (hi!=i || (lo!=i && i>4)) blown=true; } if (blown) { OutputDebugString("BLOWN!!!"); } delete[] p; } */ #pragma warning(disable : 4702) // unreachable code static ZRESULT zopenerror = ZR_OK; //+++1.2 typedef struct tm_unz_s { unsigned int tm_sec; // seconds after the minute - [0,59] unsigned int tm_min; // minutes after the hour - [0,59] unsigned int tm_hour; // hours since midnight - [0,23] unsigned int tm_mday; // day of the month - [1,31] unsigned int tm_mon; // months since January - [0,11] unsigned int tm_year; // years - [1980..2044] } tm_unz; // unz_global_info structure contain global data about the ZIPfile typedef struct unz_global_info_s { unsigned long number_entry; // total number of entries in the central dir on this disk unsigned long size_comment; // size of the global comment of the zipfile } unz_global_info; // unz_file_info contain information about a file in the zipfile typedef struct unz_file_info_s { unsigned long version; // version made by 2 bytes unsigned long version_needed; // version needed to extract 2 bytes unsigned long flag; // general purpose bit flag 2 bytes unsigned long compression_method; // compression method 2 bytes unsigned long dosDate; // last mod file date in Dos fmt 4 bytes unsigned long crc; // crc-32 4 bytes unsigned long compressed_size; // compressed size 4 bytes unsigned long uncompressed_size; // uncompressed size 4 bytes unsigned long size_filename; // filename length 2 bytes unsigned long size_file_extra; // extra field length 2 bytes unsigned long size_file_comment; // file comment length 2 bytes unsigned long disk_num_start; // disk number start 2 bytes unsigned long internal_fa; // internal file attributes 2 bytes unsigned long external_fa; // external file attributes 4 bytes tm_unz tmu_date; } unz_file_info; #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) #define ZLIB_VERSION "1.1.3" // Allowed flush values; see deflate() for details #define Z_NO_FLUSH 0 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 // compression levels #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) // compression strategy; see deflateInit2() for details #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_DEFAULT_STRATEGY 0 // Possible values of the data_type field #define Z_BINARY 0 #define Z_ASCII 1 #define Z_UNKNOWN 2 // The deflate compression method (the only one supported in this version) #define Z_DEFLATED 8 // for initializing zalloc, zfree, opaque #define Z_NULL 0 // case sensitivity when searching for filenames #define CASE_SENSITIVE 1 #define CASE_INSENSITIVE 2 // Return codes for the compression/decompression functions. Negative // values are errors, positive values are used for special but normal events. #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) // Basic data types typedef unsigned char Byte; // 8 bits typedef unsigned int uInt; // 16 bits or more typedef unsigned long uLong; // 32 bits or more typedef void *voidpf; typedef void *voidp; typedef long z_off_t; typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { Byte *next_in; // next input byte uInt avail_in; // number of bytes available at next_in uLong total_in; // total nb of input bytes read so far Byte *next_out; // next output byte should be put there uInt avail_out; // remaining free space at next_out uLong total_out; // total nb of bytes output so far char *msg; // last error message, NULL if no error struct internal_state *state; // not visible by applications alloc_func zalloc; // used to allocate the internal state free_func zfree; // used to free the internal state voidpf opaque; // private data object passed to zalloc and zfree int data_type; // best guess about the data type: ascii or binary uLong adler; // adler32 value of the uncompressed data uLong reserved; // reserved for future use } z_stream; typedef z_stream *z_streamp; // The application must update next_in and avail_in when avail_in has // dropped to zero. It must update next_out and avail_out when avail_out // has dropped to zero. The application must initialize zalloc, zfree and // opaque before calling the init function. All other fields are set by the // compression library and must not be updated by the application. // // The opaque value provided by the application will be passed as the first // parameter for calls of zalloc and zfree. This can be useful for custom // memory management. The compression library attaches no meaning to the // opaque value. // // zalloc must return Z_NULL if there is not enough memory for the object. // If zlib is used in a multi-threaded application, zalloc and zfree must be // thread safe. // // The fields total_in and total_out can be used for statistics or // progress reports. After compression, total_in holds the total size of // the uncompressed data and may be saved for use in the decompressor // (particularly if the decompressor wants to decompress everything in // a single step). // // basic functions const char *zlibVersion(); // The application can compare zlibVersion and ZLIB_VERSION for consistency. // If the first character differs, the library code actually used is // not compatible with the zlib.h header file used by the application. // This check is automatically made by inflateInit. int inflate(z_streamp strm, int flush); // // inflate decompresses as much data as possible, and stops when the input // buffer becomes empty or the output buffer becomes full. It may some // introduce some output latency (reading input without producing any output) // except when forced to flush. // // The detailed semantics are as follows. inflate performs one or both of the // following actions: // // - Decompress more input starting at next_in and update next_in and avail_in // accordingly. If not all input can be processed (because there is not // enough room in the output buffer), next_in is updated and processing // will resume at this point for the next call of inflate(). // // - Provide more output starting at next_out and update next_out and avail_out // accordingly. inflate() provides as much output as possible, until there // is no more input data or no more space in the output buffer (see below // about the flush parameter). // // Before the call of inflate(), the application should ensure that at least // one of the actions is possible, by providing more input and/or consuming // more output, and updating the next_* and avail_* values accordingly. // The application can consume the uncompressed output when it wants, for // example when the output buffer is full (avail_out == 0), or after each // call of inflate(). If inflate returns Z_OK and with zero avail_out, it // must be called again after making room in the output buffer because there // might be more output pending. // // If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much // output as possible to the output buffer. The flushing behavior of inflate is // not specified for values of the flush parameter other than Z_SYNC_FLUSH // and Z_FINISH, but the current implementation actually flushes as much output // as possible anyway. // // inflate() should normally be called until it returns Z_STREAM_END or an // error. However if all decompression is to be performed in a single step // (a single call of inflate), the parameter flush should be set to // Z_FINISH. In this case all pending input is processed and all pending // output is flushed; avail_out must be large enough to hold all the // uncompressed data. (The size of the uncompressed data may have been saved // by the compressor for this purpose.) The next operation on this stream must // be inflateEnd to deallocate the decompression state. The use of Z_FINISH // is never required, but can be used to inform inflate that a faster routine // may be used for the single inflate() call. // // If a preset dictionary is needed at this point (see inflateSetDictionary // below), inflate sets strm-adler to the adler32 checksum of the // dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise // it sets strm->adler to the adler32 checksum of all output produced // so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or // an error code as described below. At the end of the stream, inflate() // checks that its computed adler32 checksum is equal to that saved by the // compressor and returns Z_STREAM_END only if the checksum is correct. // // inflate() returns Z_OK if some progress has been made (more input // processed // or more output produced), Z_STREAM_END if the end of the compressed data has // been reached and all uncompressed output has been produced, Z_NEED_DICT if a // preset dictionary is needed at this point, Z_DATA_ERROR if the input data // was corrupted (input stream not conforming to the zlib format or incorrect // adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent // (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not // enough memory, Z_BUF_ERROR if no progress is possible or if there was not // enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR // case, the application may then call inflateSync to look for a good // compression block. // int inflateEnd(z_streamp strm); // // All dynamically allocated data structures for this stream are freed. // This function discards any unprocessed input and does not flush any // pending output. // // inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state // was inconsistent. In the error case, msg may be set but then points to a // static string (which must not be deallocated). // Advanced functions // The following functions are needed only in some special applications. int inflateSetDictionary(z_streamp strm, const Byte *dictionary, uInt dictLength); // // Initializes the decompression dictionary from the given uncompressed byte // sequence. This function must be called immediately after a call of inflate // if this call returned Z_NEED_DICT. The dictionary chosen by the compressor // can be determined from the Adler32 value returned by this call of // inflate. The compressor and decompressor must use exactly the same // dictionary. // // inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a // parameter is invalid (such as NULL dictionary) or the stream state is // inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the // expected one (incorrect Adler32 value). inflateSetDictionary does not // perform any decompression: this will be done by subsequent calls of // inflate(). int inflateSync(z_streamp strm); // // Skips invalid compressed data until a full flush point can be found, or // until all // available input is skipped. No output is provided. // // inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR // if no more input was provided, Z_DATA_ERROR if no flush point has been // found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the // success case, the application may save the current current value of total_in // which indicates where valid compressed data was found. In the error case, // the application may repeatedly call inflateSync, providing more input each // time, until success or end of the input data. int inflateReset(z_streamp strm); // This function is equivalent to inflateEnd followed by inflateInit, // but does not free and reallocate all the internal decompression state. // The stream will keep attributes that may have been set by inflateInit2. // // inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source // stream state was inconsistent (such as zalloc or state being NULL). // // checksum functions // These functions are not related to compression but are exported // anyway because they might be useful in applications using the // compression library. uLong adler32(uLong adler, const Byte *buf, uInt len); // Update a running Adler-32 checksum with the bytes buf[0..len-1] and // return the updated checksum. If buf is NULL, this function returns // the required initial value for the checksum. // An Adler-32 checksum is almost as reliable as a CRC32 but can be computed // much faster. Usage example: // // uLong adler = adler32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // adler = adler32(adler, buffer, length); // } // if (adler != original_adler) error(); uLong ucrc32(uLong crc, const Byte *buf, uInt len); // Update a running crc with the bytes buf[0..len-1] and return the updated // crc. If buf is NULL, this function returns the required initial value // for the crc. Pre- and post-conditioning (one's complement) is performed // within this function so it shouldn't be done by the application. // Usage example: // // uLong crc = crc32(0L, Z_NULL, 0); // // while (read_buffer(buffer, length) != EOF) { // crc = crc32(crc, buffer, length); // } // if (crc != original_crc) error(); const char *zError(int err); int inflateSyncPoint(z_streamp z); const uLong *get_crc_table(void); typedef unsigned char uch; typedef uch uchf; typedef unsigned short ush; typedef ush ushf; typedef unsigned long ulg; const char *const z_errmsg[10] = { // indexed by 2-zlib_error "need dictionary", // Z_NEED_DICT 2 "stream end", // Z_STREAM_END 1 "", // Z_OK 0 "file error", // Z_ERRNO (-1) "stream error", // Z_STREAM_ERROR (-2) "data error", // Z_DATA_ERROR (-3) "insufficient memory", // Z_MEM_ERROR (-4) "buffer error", // Z_BUF_ERROR (-5) "incompatible version", // Z_VERSION_ERROR (-6) ""}; #define ERR_MSG(err) z_errmsg[Z_NEED_DICT - (err)] #define ERR_RETURN(strm, err) return (strm->msg = (char *)ERR_MSG(err), (err)) // To be used only when the state is known to be valid // common constants #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 // The three kinds of block type #define MIN_MATCH 3 #define MAX_MATCH 258 // The minimum and maximum match lengths #define PRESET_DICT 0x20 // preset dictionary flag in zlib header // target dependencies #define OS_CODE 0x0b // Window 95 & Windows NT // functions #define zmemzero(dest, len) memset(dest, 0, len) // Diagnostic functions #undef Assert #undef Trace #undef Tracev #undef Tracevv #undef Tracec #undef Tracecv #ifdef DEBUG int z_verbose = 0; void z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } #define Assert(cond, msg) \ { \ if (!(cond)) \ z_error(msg); \ } #define Trace(x) \ { \ if (z_verbose >= 0) \ fprintf x; \ } #define Tracev(x) \ { \ if (z_verbose > 0) \ fprintf x; \ } #define Tracevv(x) \ { \ if (z_verbose > 1) \ fprintf x; \ } #define Tracec(c, x) \ { \ if (z_verbose > 0 && (c)) \ fprintf x; \ } #define Tracecv(c, x) \ { \ if (z_verbose > 1 && (c)) \ fprintf x; \ } #else #ifndef __noop #if _MSC_VER < 1300 #define __noop ((void)0) #endif #endif #define Assert(cond, msg) __noop #define Trace(x) __noop #define Tracev(x) __noop #define Tracevv(x) __noop #define Tracec(c, x) __noop #define Tracecv(c, x) __noop #endif typedef uLong (*check_func)(uLong check, const Byte *buf, uInt len); voidpf zcalloc(voidpf opaque, unsigned items, unsigned size); void zcfree(voidpf opaque, voidpf ptr); #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) // void ZFREE(z_streamp strm,voidpf addr) //{ *((strm)->zfree))((strm)->opaque, addr); // } #define TRY_FREE(s, p) \ { \ if (p) \ ZFREE(s, p); \ } // Huffman code lookup table entry--this entry is four bytes for machines // that have 16-bit pointers (e.g. PC's in the small or medium model). typedef struct inflate_huft_s inflate_huft; struct inflate_huft_s { union { struct { Byte Exop; // number of extra bits or operation Byte Bits; // number of bits in this code or subcode } what; uInt pad; // pad structure to a power of 2 (4 bytes for } word; // 16-bit, 8 bytes for 32-bit int's) uInt base; // literal, length base, distance base, or table offset }; // Maximum size of dynamic tree. The maximum found in a long but non- // exhaustive search was 1004 huft structures (850 for length/literals // and 154 for distances, the latter actually the result of an // exhaustive search). The actual maximum is not known, but the // value below is more than safe. #define MANY 1440 int inflate_trees_bits(uInt *, // 19 code lengths uInt *, // bits tree desired/actual depth inflate_huft **, // bits tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_dynamic(uInt, // number of literal/length codes uInt, // number of distance codes uInt *, // that many (total) code lengths uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth inflate_huft **, // literal/length tree result inflate_huft **, // distance tree result inflate_huft *, // space for trees z_streamp); // for messages int inflate_trees_fixed(uInt *, // literal desired/actual bit depth uInt *, // distance desired/actual bit depth const inflate_huft **, // literal/length tree result const inflate_huft **, // distance tree result z_streamp); // for memory allocation struct inflate_blocks_state; typedef struct inflate_blocks_state inflate_blocks_statef; inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, // check function uInt w); // window size int inflate_blocks(inflate_blocks_statef *, z_streamp, int); // initial return code void inflate_blocks_reset(inflate_blocks_statef *, z_streamp, uLong *); // check value on output int inflate_blocks_free(inflate_blocks_statef *, z_streamp); void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, // dictionary uInt n); // dictionary length int inflate_blocks_sync_point(inflate_blocks_statef *s); struct inflate_codes_state; typedef struct inflate_codes_state inflate_codes_statef; inflate_codes_statef *inflate_codes_new(uInt, uInt, const inflate_huft *, const inflate_huft *, z_streamp); int inflate_codes(inflate_blocks_statef *, z_streamp, int); void inflate_codes_free(inflate_codes_statef *, z_streamp); typedef enum { IBM_TYPE, // get type bits (3, including end bit) IBM_LENS, // get lengths for stored IBM_STORED, // processing stored block IBM_TABLE, // get table lengths IBM_BTREE, // get bit lengths tree for a dynamic block IBM_DTREE, // get length, distance trees for a dynamic block IBM_CODES, // processing fixed or dynamic block IBM_DRY, // output remaining window bytes IBM_DONE, // finished last block, done IBM_BAD } // got a data error--stuck here inflate_block_mode; // inflate blocks semi-private state struct inflate_blocks_state { // mode inflate_block_mode mode; // current inflate_block mode // mode dependent information union { uInt left; // if STORED, bytes left to copy struct { uInt table; // table lengths (14 bits) uInt index; // index into blens (or border) uInt *blens; // bit lengths of codes uInt bb; // bit length tree depth inflate_huft *tb; // bit length decoding tree } trees; // if DTREE, decoding info for trees struct { inflate_codes_statef *codes; } decode; // if CODES, current state } sub; // submode uInt last; // true if this block is the last block // mode independent information uInt bitk; // bits in bit buffer uLong bitb; // bit buffer inflate_huft *hufts; // single malloc for tree space Byte *window; // sliding window Byte *end; // one byte after sliding window Byte *read; // window read pointer Byte *write; // window write pointer check_func checkfn; // check function uLong check; // check on output }; // defines for inflate input/output // update pointers and return #define UPDBITS \ { \ s->bitb = b; \ s->bitk = k; \ } #define UPDIN \ { \ z->avail_in = n; \ z->total_in += (uLong)(p - z->next_in); \ z->next_in = p; \ } #define UPDOUT \ { s->write = q; } #define UPDATE \ { UPDBITS UPDIN UPDOUT } #define LEAVE \ { UPDATE return inflate_flush(s, z, r); } // get bytes and bits #define LOADIN \ { \ p = z->next_in; \ n = z->avail_in; \ b = s->bitb; \ k = s->bitk; \ } #define NEEDBYTE \ { \ if (n) \ r = Z_OK; \ else \ LEAVE \ } #define NEXTBYTE (n--, *p++) #define NEEDBITS(j) \ { \ while (k < (j)) { \ NEEDBYTE; \ b |= ((uLong)NEXTBYTE) << k; \ k += 8; \ } \ } #define DUMPBITS(j) \ { \ b >>= (j); \ k -= (j); \ } // output bytes #define WAVAIL (uInt)(q < s->read ? s->read - q - 1 : s->end - q) #define LOADOUT \ { \ q = s->write; \ m = (uInt)WAVAIL; \ m; \ } #define WRAP \ { \ if (q == s->end && s->read != s->window) { \ q = s->window; \ m = (uInt)WAVAIL; \ } \ } #define FLUSH \ { \ UPDOUT r = inflate_flush(s, z, r); \ LOADOUT \ } #define NEEDOUT \ { \ if (m == 0) { \ WRAP if (m == 0) { FLUSH WRAP if (m == 0) LEAVE } \ } \ r = Z_OK; \ } #define OUTBYTE(a) \ { \ *q++ = (Byte)(a); \ m--; \ } // load local pointers #define LOAD \ { LOADIN LOADOUT } // masks for lower bits (size given to avoid silly warnings with Visual C++) // And'ing with mask[n] masks the lower n bits const uInt inflate_mask[17] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff}; // copy as much as possible from the sliding window to the output area int inflate_flush(inflate_blocks_statef *, z_streamp, int); int inflate_fast(uInt, uInt, const inflate_huft *, const inflate_huft *, inflate_blocks_statef *, z_streamp); const uInt fixed_bl = 9; const uInt fixed_bd = 5; const inflate_huft fixed_tl[] = { {{{96, 7}}, 256}, {{{0, 8}}, 80}, {{{0, 8}}, 16}, {{{84, 8}}, 115}, {{{82, 7}}, 31}, {{{0, 8}}, 112}, {{{0, 8}}, 48}, {{{0, 9}}, 192}, {{{80, 7}}, 10}, {{{0, 8}}, 96}, {{{0, 8}}, 32}, {{{0, 9}}, 160}, {{{0, 8}}, 0}, {{{0, 8}}, 128}, {{{0, 8}}, 64}, {{{0, 9}}, 224}, {{{80, 7}}, 6}, {{{0, 8}}, 88}, {{{0, 8}}, 24}, {{{0, 9}}, 144}, {{{83, 7}}, 59}, {{{0, 8}}, 120}, {{{0, 8}}, 56}, {{{0, 9}}, 208}, {{{81, 7}}, 17}, {{{0, 8}}, 104}, {{{0, 8}}, 40}, {{{0, 9}}, 176}, {{{0, 8}}, 8}, {{{0, 8}}, 136}, {{{0, 8}}, 72}, {{{0, 9}}, 240}, {{{80, 7}}, 4}, {{{0, 8}}, 84}, {{{0, 8}}, 20}, {{{85, 8}}, 227}, {{{83, 7}}, 43}, {{{0, 8}}, 116}, {{{0, 8}}, 52}, {{{0, 9}}, 200}, {{{81, 7}}, 13}, {{{0, 8}}, 100}, {{{0, 8}}, 36}, {{{0, 9}}, 168}, {{{0, 8}}, 4}, {{{0, 8}}, 132}, {{{0, 8}}, 68}, {{{0, 9}}, 232}, {{{80, 7}}, 8}, {{{0, 8}}, 92}, {{{0, 8}}, 28}, {{{0, 9}}, 152}, {{{84, 7}}, 83}, {{{0, 8}}, 124}, {{{0, 8}}, 60}, {{{0, 9}}, 216}, {{{82, 7}}, 23}, {{{0, 8}}, 108}, {{{0, 8}}, 44}, {{{0, 9}}, 184}, {{{0, 8}}, 12}, {{{0, 8}}, 140}, {{{0, 8}}, 76}, {{{0, 9}}, 248}, {{{80, 7}}, 3}, {{{0, 8}}, 82}, {{{0, 8}}, 18}, {{{85, 8}}, 163}, {{{83, 7}}, 35}, {{{0, 8}}, 114}, {{{0, 8}}, 50}, {{{0, 9}}, 196}, {{{81, 7}}, 11}, {{{0, 8}}, 98}, {{{0, 8}}, 34}, {{{0, 9}}, 164}, {{{0, 8}}, 2}, {{{0, 8}}, 130}, {{{0, 8}}, 66}, {{{0, 9}}, 228}, {{{80, 7}}, 7}, {{{0, 8}}, 90}, {{{0, 8}}, 26}, {{{0, 9}}, 148}, {{{84, 7}}, 67}, {{{0, 8}}, 122}, {{{0, 8}}, 58}, {{{0, 9}}, 212}, {{{82, 7}}, 19}, {{{0, 8}}, 106}, {{{0, 8}}, 42}, {{{0, 9}}, 180}, {{{0, 8}}, 10}, {{{0, 8}}, 138}, {{{0, 8}}, 74}, {{{0, 9}}, 244}, {{{80, 7}}, 5}, {{{0, 8}}, 86}, {{{0, 8}}, 22}, {{{192, 8}}, 0}, {{{83, 7}}, 51}, {{{0, 8}}, 118}, {{{0, 8}}, 54}, {{{0, 9}}, 204}, {{{81, 7}}, 15}, {{{0, 8}}, 102}, {{{0, 8}}, 38}, {{{0, 9}}, 172}, {{{0, 8}}, 6}, {{{0, 8}}, 134}, {{{0, 8}}, 70}, {{{0, 9}}, 236}, {{{80, 7}}, 9}, {{{0, 8}}, 94}, {{{0, 8}}, 30}, {{{0, 9}}, 156}, {{{84, 7}}, 99}, {{{0, 8}}, 126}, {{{0, 8}}, 62}, {{{0, 9}}, 220}, {{{82, 7}}, 27}, {{{0, 8}}, 110}, {{{0, 8}}, 46}, {{{0, 9}}, 188}, {{{0, 8}}, 14}, {{{0, 8}}, 142}, {{{0, 8}}, 78}, {{{0, 9}}, 252}, {{{96, 7}}, 256}, {{{0, 8}}, 81}, {{{0, 8}}, 17}, {{{85, 8}}, 131}, {{{82, 7}}, 31}, {{{0, 8}}, 113}, {{{0, 8}}, 49}, {{{0, 9}}, 194}, {{{80, 7}}, 10}, {{{0, 8}}, 97}, {{{0, 8}}, 33}, {{{0, 9}}, 162}, {{{0, 8}}, 1}, {{{0, 8}}, 129}, {{{0, 8}}, 65}, {{{0, 9}}, 226}, {{{80, 7}}, 6}, {{{0, 8}}, 89}, {{{0, 8}}, 25}, {{{0, 9}}, 146}, {{{83, 7}}, 59}, {{{0, 8}}, 121}, {{{0, 8}}, 57}, {{{0, 9}}, 210}, {{{81, 7}}, 17}, {{{0, 8}}, 105}, {{{0, 8}}, 41}, {{{0, 9}}, 178}, {{{0, 8}}, 9}, {{{0, 8}}, 137}, {{{0, 8}}, 73}, {{{0, 9}}, 242}, {{{80, 7}}, 4}, {{{0, 8}}, 85}, {{{0, 8}}, 21}, {{{80, 8}}, 258}, {{{83, 7}}, 43}, {{{0, 8}}, 117}, {{{0, 8}}, 53}, {{{0, 9}}, 202}, {{{81, 7}}, 13}, {{{0, 8}}, 101}, {{{0, 8}}, 37}, {{{0, 9}}, 170}, {{{0, 8}}, 5}, {{{0, 8}}, 133}, {{{0, 8}}, 69}, {{{0, 9}}, 234}, {{{80, 7}}, 8}, {{{0, 8}}, 93}, {{{0, 8}}, 29}, {{{0, 9}}, 154}, {{{84, 7}}, 83}, {{{0, 8}}, 125}, {{{0, 8}}, 61}, {{{0, 9}}, 218}, {{{82, 7}}, 23}, {{{0, 8}}, 109}, {{{0, 8}}, 45}, {{{0, 9}}, 186}, {{{0, 8}}, 13}, {{{0, 8}}, 141}, {{{0, 8}}, 77}, {{{0, 9}}, 250}, {{{80, 7}}, 3}, {{{0, 8}}, 83}, {{{0, 8}}, 19}, {{{85, 8}}, 195}, {{{83, 7}}, 35}, {{{0, 8}}, 115}, {{{0, 8}}, 51}, {{{0, 9}}, 198}, {{{81, 7}}, 11}, {{{0, 8}}, 99}, {{{0, 8}}, 35}, {{{0, 9}}, 166}, {{{0, 8}}, 3}, {{{0, 8}}, 131}, {{{0, 8}}, 67}, {{{0, 9}}, 230}, {{{80, 7}}, 7}, {{{0, 8}}, 91}, {{{0, 8}}, 27}, {{{0, 9}}, 150}, {{{84, 7}}, 67}, {{{0, 8}}, 123}, {{{0, 8}}, 59}, {{{0, 9}}, 214}, {{{82, 7}}, 19}, {{{0, 8}}, 107}, {{{0, 8}}, 43}, {{{0, 9}}, 182}, {{{0, 8}}, 11}, {{{0, 8}}, 139}, {{{0, 8}}, 75}, {{{0, 9}}, 246}, {{{80, 7}}, 5}, {{{0, 8}}, 87}, {{{0, 8}}, 23}, {{{192, 8}}, 0}, {{{83, 7}}, 51}, {{{0, 8}}, 119}, {{{0, 8}}, 55}, {{{0, 9}}, 206}, {{{81, 7}}, 15}, {{{0, 8}}, 103}, {{{0, 8}}, 39}, {{{0, 9}}, 174}, {{{0, 8}}, 7}, {{{0, 8}}, 135}, {{{0, 8}}, 71}, {{{0, 9}}, 238}, {{{80, 7}}, 9}, {{{0, 8}}, 95}, {{{0, 8}}, 31}, {{{0, 9}}, 158}, {{{84, 7}}, 99}, {{{0, 8}}, 127}, {{{0, 8}}, 63}, {{{0, 9}}, 222}, {{{82, 7}}, 27}, {{{0, 8}}, 111}, {{{0, 8}}, 47}, {{{0, 9}}, 190}, {{{0, 8}}, 15}, {{{0, 8}}, 143}, {{{0, 8}}, 79}, {{{0, 9}}, 254}, {{{96, 7}}, 256}, {{{0, 8}}, 80}, {{{0, 8}}, 16}, {{{84, 8}}, 115}, {{{82, 7}}, 31}, {{{0, 8}}, 112}, {{{0, 8}}, 48}, {{{0, 9}}, 193}, {{{80, 7}}, 10}, {{{0, 8}}, 96}, {{{0, 8}}, 32}, {{{0, 9}}, 161}, {{{0, 8}}, 0}, {{{0, 8}}, 128}, {{{0, 8}}, 64}, {{{0, 9}}, 225}, {{{80, 7}}, 6}, {{{0, 8}}, 88}, {{{0, 8}}, 24}, {{{0, 9}}, 145}, {{{83, 7}}, 59}, {{{0, 8}}, 120}, {{{0, 8}}, 56}, {{{0, 9}}, 209}, {{{81, 7}}, 17}, {{{0, 8}}, 104}, {{{0, 8}}, 40}, {{{0, 9}}, 177}, {{{0, 8}}, 8}, {{{0, 8}}, 136}, {{{0, 8}}, 72}, {{{0, 9}}, 241}, {{{80, 7}}, 4}, {{{0, 8}}, 84}, {{{0, 8}}, 20}, {{{85, 8}}, 227}, {{{83, 7}}, 43}, {{{0, 8}}, 116}, {{{0, 8}}, 52}, {{{0, 9}}, 201}, {{{81, 7}}, 13}, {{{0, 8}}, 100}, {{{0, 8}}, 36}, {{{0, 9}}, 169}, {{{0, 8}}, 4}, {{{0, 8}}, 132}, {{{0, 8}}, 68}, {{{0, 9}}, 233}, {{{80, 7}}, 8}, {{{0, 8}}, 92}, {{{0, 8}}, 28}, {{{0, 9}}, 153}, {{{84, 7}}, 83}, {{{0, 8}}, 124}, {{{0, 8}}, 60}, {{{0, 9}}, 217}, {{{82, 7}}, 23}, {{{0, 8}}, 108}, {{{0, 8}}, 44}, {{{0, 9}}, 185}, {{{0, 8}}, 12}, {{{0, 8}}, 140}, {{{0, 8}}, 76}, {{{0, 9}}, 249}, {{{80, 7}}, 3}, {{{0, 8}}, 82}, {{{0, 8}}, 18}, {{{85, 8}}, 163}, {{{83, 7}}, 35}, {{{0, 8}}, 114}, {{{0, 8}}, 50}, {{{0, 9}}, 197}, {{{81, 7}}, 11}, {{{0, 8}}, 98}, {{{0, 8}}, 34}, {{{0, 9}}, 165}, {{{0, 8}}, 2}, {{{0, 8}}, 130}, {{{0, 8}}, 66}, {{{0, 9}}, 229}, {{{80, 7}}, 7}, {{{0, 8}}, 90}, {{{0, 8}}, 26}, {{{0, 9}}, 149}, {{{84, 7}}, 67}, {{{0, 8}}, 122}, {{{0, 8}}, 58}, {{{0, 9}}, 213}, {{{82, 7}}, 19}, {{{0, 8}}, 106}, {{{0, 8}}, 42}, {{{0, 9}}, 181}, {{{0, 8}}, 10}, {{{0, 8}}, 138}, {{{0, 8}}, 74}, {{{0, 9}}, 245}, {{{80, 7}}, 5}, {{{0, 8}}, 86}, {{{0, 8}}, 22}, {{{192, 8}}, 0}, {{{83, 7}}, 51}, {{{0, 8}}, 118}, {{{0, 8}}, 54}, {{{0, 9}}, 205}, {{{81, 7}}, 15}, {{{0, 8}}, 102}, {{{0, 8}}, 38}, {{{0, 9}}, 173}, {{{0, 8}}, 6}, {{{0, 8}}, 134}, {{{0, 8}}, 70}, {{{0, 9}}, 237}, {{{80, 7}}, 9}, {{{0, 8}}, 94}, {{{0, 8}}, 30}, {{{0, 9}}, 157}, {{{84, 7}}, 99}, {{{0, 8}}, 126}, {{{0, 8}}, 62}, {{{0, 9}}, 221}, {{{82, 7}}, 27}, {{{0, 8}}, 110}, {{{0, 8}}, 46}, {{{0, 9}}, 189}, {{{0, 8}}, 14}, {{{0, 8}}, 142}, {{{0, 8}}, 78}, {{{0, 9}}, 253}, {{{96, 7}}, 256}, {{{0, 8}}, 81}, {{{0, 8}}, 17}, {{{85, 8}}, 131}, {{{82, 7}}, 31}, {{{0, 8}}, 113}, {{{0, 8}}, 49}, {{{0, 9}}, 195}, {{{80, 7}}, 10}, {{{0, 8}}, 97}, {{{0, 8}}, 33}, {{{0, 9}}, 163}, {{{0, 8}}, 1}, {{{0, 8}}, 129}, {{{0, 8}}, 65}, {{{0, 9}}, 227}, {{{80, 7}}, 6}, {{{0, 8}}, 89}, {{{0, 8}}, 25}, {{{0, 9}}, 147}, {{{83, 7}}, 59}, {{{0, 8}}, 121}, {{{0, 8}}, 57}, {{{0, 9}}, 211}, {{{81, 7}}, 17}, {{{0, 8}}, 105}, {{{0, 8}}, 41}, {{{0, 9}}, 179}, {{{0, 8}}, 9}, {{{0, 8}}, 137}, {{{0, 8}}, 73}, {{{0, 9}}, 243}, {{{80, 7}}, 4}, {{{0, 8}}, 85}, {{{0, 8}}, 21}, {{{80, 8}}, 258}, {{{83, 7}}, 43}, {{{0, 8}}, 117}, {{{0, 8}}, 53}, {{{0, 9}}, 203}, {{{81, 7}}, 13}, {{{0, 8}}, 101}, {{{0, 8}}, 37}, {{{0, 9}}, 171}, {{{0, 8}}, 5}, {{{0, 8}}, 133}, {{{0, 8}}, 69}, {{{0, 9}}, 235}, {{{80, 7}}, 8}, {{{0, 8}}, 93}, {{{0, 8}}, 29}, {{{0, 9}}, 155}, {{{84, 7}}, 83}, {{{0, 8}}, 125}, {{{0, 8}}, 61}, {{{0, 9}}, 219}, {{{82, 7}}, 23}, {{{0, 8}}, 109}, {{{0, 8}}, 45}, {{{0, 9}}, 187}, {{{0, 8}}, 13}, {{{0, 8}}, 141}, {{{0, 8}}, 77}, {{{0, 9}}, 251}, {{{80, 7}}, 3}, {{{0, 8}}, 83}, {{{0, 8}}, 19}, {{{85, 8}}, 195}, {{{83, 7}}, 35}, {{{0, 8}}, 115}, {{{0, 8}}, 51}, {{{0, 9}}, 199}, {{{81, 7}}, 11}, {{{0, 8}}, 99}, {{{0, 8}}, 35}, {{{0, 9}}, 167}, {{{0, 8}}, 3}, {{{0, 8}}, 131}, {{{0, 8}}, 67}, {{{0, 9}}, 231}, {{{80, 7}}, 7}, {{{0, 8}}, 91}, {{{0, 8}}, 27}, {{{0, 9}}, 151}, {{{84, 7}}, 67}, {{{0, 8}}, 123}, {{{0, 8}}, 59}, {{{0, 9}}, 215}, {{{82, 7}}, 19}, {{{0, 8}}, 107}, {{{0, 8}}, 43}, {{{0, 9}}, 183}, {{{0, 8}}, 11}, {{{0, 8}}, 139}, {{{0, 8}}, 75}, {{{0, 9}}, 247}, {{{80, 7}}, 5}, {{{0, 8}}, 87}, {{{0, 8}}, 23}, {{{192, 8}}, 0}, {{{83, 7}}, 51}, {{{0, 8}}, 119}, {{{0, 8}}, 55}, {{{0, 9}}, 207}, {{{81, 7}}, 15}, {{{0, 8}}, 103}, {{{0, 8}}, 39}, {{{0, 9}}, 175}, {{{0, 8}}, 7}, {{{0, 8}}, 135}, {{{0, 8}}, 71}, {{{0, 9}}, 239}, {{{80, 7}}, 9}, {{{0, 8}}, 95}, {{{0, 8}}, 31}, {{{0, 9}}, 159}, {{{84, 7}}, 99}, {{{0, 8}}, 127}, {{{0, 8}}, 63}, {{{0, 9}}, 223}, {{{82, 7}}, 27}, {{{0, 8}}, 111}, {{{0, 8}}, 47}, {{{0, 9}}, 191}, {{{0, 8}}, 15}, {{{0, 8}}, 143}, {{{0, 8}}, 79}, {{{0, 9}}, 255}}; const inflate_huft fixed_td[] = { {{{80, 5}}, 1}, {{{87, 5}}, 257}, {{{83, 5}}, 17}, {{{91, 5}}, 4097}, {{{81, 5}}, 5}, {{{89, 5}}, 1025}, {{{85, 5}}, 65}, {{{93, 5}}, 16385}, {{{80, 5}}, 3}, {{{88, 5}}, 513}, {{{84, 5}}, 33}, {{{92, 5}}, 8193}, {{{82, 5}}, 9}, {{{90, 5}}, 2049}, {{{86, 5}}, 129}, {{{192, 5}}, 24577}, {{{80, 5}}, 2}, {{{87, 5}}, 385}, {{{83, 5}}, 25}, {{{91, 5}}, 6145}, {{{81, 5}}, 7}, {{{89, 5}}, 1537}, {{{85, 5}}, 97}, {{{93, 5}}, 24577}, {{{80, 5}}, 4}, {{{88, 5}}, 769}, {{{84, 5}}, 49}, {{{92, 5}}, 12289}, {{{82, 5}}, 13}, {{{90, 5}}, 3073}, {{{86, 5}}, 193}, {{{192, 5}}, 24577}}; // copy as much as possible from the sliding window to the output area int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) { uInt n; Byte *p; Byte *q; // local copies of source and destination pointers p = z->next_out; q = s->read; // compute number of bytes to copy as far as end of window n = (uInt)((q <= s->write ? s->write : s->end) - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy as far as end of window if (n != 0) // check for n!=0 to avoid waking up CodeGuard { memcpy(p, q, n); p += n; q += n; } // see if more to copy at beginning of window if (q == s->end) { // wrap pointers q = s->window; if (s->write == s->end) s->write = s->window; // compute bytes to copy n = (uInt)(s->write - q); if (n > z->avail_out) n = z->avail_out; if (n && r == Z_BUF_ERROR) r = Z_OK; // update counters z->avail_out -= n; z->total_out += n; // update check information if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); // copy memcpy(p, q, n); p += n; q += n; } // update pointers z->next_out = p; s->read = q; // done return r; } // simplify the use of the inflate_huft type with some defines #define exop word.what.Exop #define bits word.what.Bits typedef enum { // waiting for "i:"=input, "o:"=output, "x:"=nothing START, // x: set up for LEN LEN, // i: get length/literal/eob next LENEXT, // i: getting length extra (have base) DIST, // i: get distance next DISTEXT, // i: getting distance extra COPY, // o: copying bytes in window, waiting for space LIT, // o: got literal, waiting for output space WASH, // o: got eob, possibly still output waiting END, // x: got eob and all data flushed BADCODE } // x: got error inflate_codes_mode; // inflate codes private state struct inflate_codes_state { // mode inflate_codes_mode mode; // current inflate_codes mode // mode dependent information uInt len; union { struct { const inflate_huft *tree; // pointer into tree uInt need; // bits needed } code; // if LEN or DIST, where in tree uInt lit; // if LIT, literal struct { uInt get; // bits to get for extra uInt dist; // distance back to copy from } copy; // if EXT or COPY, where and how much } sub; // submode // mode independent information Byte lbits; // ltree bits decoded per branch Byte dbits; // dtree bits decoder per branch const inflate_huft *ltree; // literal/length/eob tree const inflate_huft *dtree; // distance tree }; inflate_codes_statef *inflate_codes_new( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ z_streamp z) { inflate_codes_statef *c; if ((c = (inflate_codes_statef *)ZALLOC( z, 1, sizeof(struct inflate_codes_state))) != Z_NULL) { c->mode = START; c->lbits = (Byte)bl; c->dbits = (Byte)bd; c->ltree = tl; c->dtree = td; Tracev((stderr, "inflate: codes new\n")); } return c; } int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) { uInt j; // temporary storage const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer Byte *f; // pointer to copy strings from inflate_codes_statef *c = s->sub.decode.codes; // codes state // copy input/output information to locals (UPDATE macro restores) LOAD // process input and output based on current state for (;;) switch ( c->mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN #ifndef SLOW if (m >= 258 && n >= 10) { UPDATE r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); LOAD if (r != Z_OK) { c->mode = r == Z_STREAM_END ? WASH : BADCODE; break; } } #endif // !SLOW c->sub.code.need = c->lbits; c->sub.code.tree = c->ltree; c->mode = LEN; case LEN: // i: get length/literal/eob next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e == 0) // literal { c->sub.lit = t->base; Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", t->base)); c->mode = LIT; break; } if (e & 16) // length { c->sub.copy.get = e & 15; c->len = t->base; c->mode = LENEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } if (e & 32) // end of block { Tracevv((stderr, "inflate: end of block\n")); c->mode = WASH; break; } c->mode = BADCODE; // invalid code z->msg = (char *)"invalid literal/length code"; r = Z_DATA_ERROR; LEAVE case LENEXT: // i: getting length extra (have base) j = c->sub.copy.get; NEEDBITS(j) c->len += (uInt)b & inflate_mask[j]; DUMPBITS(j) c->sub.code.need = c->dbits; c->sub.code.tree = c->dtree; Tracevv((stderr, "inflate: length %u\n", c->len)); c->mode = DIST; case DIST: // i: get distance next j = c->sub.code.need; NEEDBITS(j) t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); DUMPBITS(t->bits) e = (uInt)(t->exop); if (e & 16) // distance { c->sub.copy.get = e & 15; c->sub.copy.dist = t->base; c->mode = DISTEXT; break; } if ((e & 64) == 0) // next table { c->sub.code.need = e; c->sub.code.tree = t + t->base; break; } c->mode = BADCODE; // invalid code z->msg = (char *)"invalid distance code"; r = Z_DATA_ERROR; LEAVE case DISTEXT: // i: getting distance extra j = c->sub.copy.get; NEEDBITS(j) c->sub.copy.dist += (uInt)b & inflate_mask[j]; DUMPBITS(j) Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: // o: copying bytes in window, waiting for space f = (uInt)(q - s->window) < c->sub.copy.dist ? s->end - (c->sub.copy.dist - (q - s->window)) : q - c->sub.copy.dist; while (c->len) { NEEDOUT OUTBYTE(*f++) if (f == s->end) f = s->window; c->len--; } c->mode = START; break; case LIT: // o: got literal, waiting for output space NEEDOUT OUTBYTE(c->sub.lit) c->mode = START; break; case WASH: // o: got eob, possibly more output if (k > 7) // return unused byte, if any { Assert(k < 16, "inflate_codes grabbed too many bytes"); k -= 8; n++; p--; // can always return one } FLUSH if (s->read != s->write) LEAVE c->mode = END; case END: r = Z_STREAM_END; LEAVE case BADCODE: // x: got error r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } void inflate_codes_free(inflate_codes_statef *c, z_streamp z) { ZFREE(z, c); Tracev((stderr, "inflate: codes free\n")); } // infblock.c -- interpret and process block types to last block // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // struct inflate_codes_state {int dummy;}; // for buggy compilers // Table for deflate from PKZIP's appnote.txt. const uInt border[] = { // Order of the bit length code lengths 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; // // Notes beyond the 1.93a appnote.txt: // // 1. Distance pointers never point before the beginning of the output stream. // 2. Distance pointers can point back across blocks, up to 32k away. // 3. There is an implied maximum of 7 bits for the bit length table and // 15 bits for the actual data. // 4. If only one code exists, then it is encoded using one bit. (Zero // would be more efficient, but perhaps a little confusing.) If two // codes exist, they are coded using one bit each (0 and 1). // 5. There is no way of sending zero distance codes--a dummy must be // sent if there are none. (History: a pre 2.0 version of PKZIP would // store blocks with no distance codes, but this was discovered to be // too harsh a criterion.) Valid only for 1.93a. 2.04c does allow // zero distance codes, which is sent as one code of zero bits in // length. // 6. There are up to 286 literal/length codes. Code 256 represents the // end-of-block. Note however that the static length tree defines // 288 codes just to fill out the Huffman codes. Codes 286 and 287 // cannot be used though, since there is no length base or extra bits // defined for them. Similarily, there are up to 30 distance codes. // However, static trees define 32 codes (all 5 bits) to fill out the // Huffman codes, but the last two had better not show up in the data. // 7. Unzip can check dynamic Huffman blocks for complete code sets. // The exception is that a single code would not be complete (see #4). // 8. The five bits following the block type is really the number of // literal codes sent minus 257. // 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits // (1+6+6). Therefore, to output three times the length, you output // three codes (1+1+1), whereas to output four times the same length, // you only need two codes (1+3). Hmm. // 10. In the tree reconstruction algorithm, Code = Code + Increment // only if BitLength(i) is not zero. (Pretty obvious.) // 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) // 12. Note: length code 284 can represent 227-258, but length code 285 // really is 258. The last length deserves its own, short code // since it gets used a lot in very redundant files. The length // 258 is special since 258 - 3 (the min match length) is 255. // 13. The literal/length and distance code bit lengths are read as a // single stream of lengths. It is possible (and advantageous) for // a repeat code (16, 17, or 18) to go across the boundary between // the two sets of lengths. void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) { if (c != Z_NULL) *c = s->check; if (s->mode == IBM_BTREE || s->mode == IBM_DTREE) ZFREE(z, s->sub.trees.blens); if (s->mode == IBM_CODES) inflate_codes_free(s->sub.decode.codes, z); s->mode = IBM_TYPE; s->bitk = 0; s->bitb = 0; s->read = s->write = s->window; if (s->checkfn != Z_NULL) z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); Tracev((stderr, "inflate: blocks reset\n")); } inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) { inflate_blocks_statef *s; if ((s = (inflate_blocks_statef *)ZALLOC( z, 1, sizeof(struct inflate_blocks_state))) == Z_NULL) return s; if ((s->hufts = (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) { ZFREE(z, s); return Z_NULL; } if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) { ZFREE(z, s->hufts); ZFREE(z, s); return Z_NULL; } s->end = s->window + w; s->checkfn = c; s->mode = IBM_TYPE; Tracev((stderr, "inflate: blocks allocated\n")); inflate_blocks_reset(s, z, Z_NULL); return s; } int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) { uInt t; // temporary storage uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer // copy input/output information to locals (UPDATE macro restores) LOAD // process input based on current state for (;;) switch (s->mode) { case IBM_TYPE: NEEDBITS(3) t = (uInt)b & 7; s->last = t & 1; switch (t >> 1) { case 0: // stored Tracev( (stderr, "inflate: stored block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) t = k & 7; // go to byte boundary DUMPBITS(t) s->mode = IBM_LENS; // get length of stored block break; case 1: // fixed Tracev((stderr, "inflate: fixed codes block%s\n", s->last ? " (last)" : "")); { uInt bl, bd; const inflate_huft *tl, *td; inflate_trees_fixed(&bl, &bd, &tl, &td, z); s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); if (s->sub.decode.codes == Z_NULL) { r = Z_MEM_ERROR; LEAVE } } DUMPBITS(3) s->mode = IBM_CODES; break; case 2: // dynamic Tracev((stderr, "inflate: dynamic codes block%s\n", s->last ? " (last)" : "")); DUMPBITS(3) s->mode = IBM_TABLE; break; case 3: // illegal DUMPBITS(3) s->mode = IBM_BAD; z->msg = (char *)"invalid block type"; r = Z_DATA_ERROR; LEAVE } break; case IBM_LENS: NEEDBITS(32) if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) { s->mode = IBM_BAD; z->msg = (char *)"invalid stored block lengths"; r = Z_DATA_ERROR; LEAVE } s->sub.left = (uInt)b & 0xffff; b = k = 0; // dump bits Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE); break; case IBM_STORED: if (n == 0) LEAVE NEEDOUT t = s->sub.left; if (t > n) t = n; if (t > m) t = m; memcpy(q, p, t); p += t; n -= t; q += t; m -= t; if ((s->sub.left -= t) != 0) break; Tracev( (stderr, "inflate: stored end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); s->mode = s->last ? IBM_DRY : IBM_TYPE; break; case IBM_TABLE: NEEDBITS(14) s->sub.trees.table = t = (uInt)b & 0x3fff; // remove this section to workaround bug in pkzip if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) { s->mode = IBM_BAD; z->msg = (char *)"too many length or distance symbols"; r = Z_DATA_ERROR; LEAVE } // end remove t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); if ((s->sub.trees.blens = (uInt *)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } DUMPBITS(14) s->sub.trees.index = 0; Tracev((stderr, "inflate: table sizes ok\n")); s->mode = IBM_BTREE; case IBM_BTREE: while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) { NEEDBITS(3) s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; DUMPBITS(3) } while (s->sub.trees.index < 19) s->sub.trees.blens[border[s->sub.trees.index++]] = 0; s->sub.trees.bb = 7; t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { ZFREE(z, s->sub.trees.blens); r = t; if (r == Z_DATA_ERROR) s->mode = IBM_BAD; LEAVE } s->sub.trees.index = 0; Tracev((stderr, "inflate: bits tree ok\n")); s->mode = IBM_DTREE; case IBM_DTREE: while (t = s->sub.trees.table, s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) { inflate_huft *h; uInt i, j, c; t = s->sub.trees.bb; NEEDBITS(t) h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); t = h->bits; c = h->base; if (c < 16) { DUMPBITS(t) s->sub.trees.blens[s->sub.trees.index++] = c; } else // c == 16..18 { i = c == 18 ? 7 : c - 14; j = c == 18 ? 11 : 3; NEEDBITS(t + i) DUMPBITS(t) j += (uInt)b & inflate_mask[i]; DUMPBITS(i) i = s->sub.trees.index; t = s->sub.trees.table; if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1)) { ZFREE(z, s->sub.trees.blens); s->mode = IBM_BAD; z->msg = (char *)"invalid bit length repeat"; r = Z_DATA_ERROR; LEAVE } c = c == 16 ? s->sub.trees.blens[i - 1] : 0; do { s->sub.trees.blens[i++] = c; } while (--j); s->sub.trees.index = i; } } s->sub.trees.tb = Z_NULL; { uInt bl, bd; inflate_huft *tl, *td; inflate_codes_statef *c; bl = 9; // must be <= 9 for lookahead assumptions bd = 6; // must be <= 9 for lookahead assumptions t = s->sub.trees.table; t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, s->hufts, z); ZFREE(z, s->sub.trees.blens); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) s->mode = IBM_BAD; r = t; LEAVE } Tracev((stderr, "inflate: trees ok\n")); if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) { r = Z_MEM_ERROR; LEAVE } s->sub.decode.codes = c; } s->mode = IBM_CODES; case IBM_CODES: UPDATE if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) return inflate_flush(s, z, r); r = Z_OK; inflate_codes_free(s->sub.decode.codes, z); LOAD Tracev( (stderr, "inflate: codes end, %lu total out\n", z->total_out + (q >= s->read ? q - s->read : (s->end - s->read) + (q - s->window)))); if (!s->last) { s->mode = IBM_TYPE; break; } s->mode = IBM_DRY; case IBM_DRY: FLUSH if (s->read != s->write) LEAVE s->mode = IBM_DONE; case IBM_DONE: r = Z_STREAM_END; LEAVE case IBM_BAD: r = Z_DATA_ERROR; LEAVE default: r = Z_STREAM_ERROR; LEAVE } } int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) { inflate_blocks_reset(s, z, Z_NULL); ZFREE(z, s->window); ZFREE(z, s->hufts); ZFREE(z, s); Tracev((stderr, "inflate: blocks freed\n")); return Z_OK; } // inftrees.c -- generate Huffman trees for efficient decoding // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // extern const char inflate_copyright[] = " "; // inflate 1.1.3 Copyright 1995-1998 Mark Adler "; // If you use the zlib library in a product, an acknowledgment is welcome // in the documentation of your product. If for some reason you cannot // include such an acknowledgment, I would appreciate that you keep this // copyright string in the executable of your product. int huft_build(uInt *, // code lengths in bits uInt, // number of codes uInt, // number of "simple" codes const uInt *, // list of base values for non-simple codes const uInt *, // list of extra bits for non-simple codes inflate_huft **, // result: starting table uInt *, // maximum lookup bits (returns actual) inflate_huft *, // space for trees uInt *, // hufts used in space uInt *); // space for values // Tables for deflate from PKZIP's appnote.txt. const uInt cplens[31] = { // Copy lengths for literal codes 257..285 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; // see note #13 above about 258 const uInt cplext[31] = { // Extra bits for literal codes 257..285 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid const uInt cpdist[30] = { // Copy offsets for distance codes 0..29 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; const uInt cpdext[30] = { // Extra bits for distance codes 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; // // Huffman code decoding is performed using a multi-level table lookup. // The fastest way to decode is to simply build a lookup table whose // size is determined by the longest code. However, the time it takes // to build this table can also be a factor if the data being decoded // is not very long. The most common codes are necessarily the // shortest codes, so those codes dominate the decoding time, and hence // the speed. The idea is you can have a shorter table that decodes the // shorter, more probable codes, and then point to subsidiary tables for // the longer codes. The time it costs to decode the longer codes is // then traded against the time it takes to make longer tables. // // This results of this trade are in the variables lbits and dbits // below. lbits is the number of bits the first level table for literal/ // length codes can decode in one step, and dbits is the same thing for // the distance codes. Subsequent tables are also less than or equal to // those sizes. These values may be adjusted either when all of the // codes are shorter than that, in which case the longest code length in // bits is used, or when the shortest code is *longer* than the requested // table size, in which case the length of the shortest code in bits is // used. // // There are two different values for the two tables, since they code a // different number of possibilities each. The literal/length table // codes 286 possible values, or in a flat code, a little over eight // bits. The distance table codes 30 possible values, or a little less // than five bits, flat. The optimum values for speed end up being // about one bit more than those, so lbits is 8+1 and dbits is 5+1. // The optimum values may differ though from machine to machine, and // possibly even between compilers. Your mileage may vary. // // If BMAX needs to be larger than 16, then h and x[] should be uLong. #define BMAX 15 // maximum bit length of any code int huft_build(uInt *b, // code lengths in bits (all assumed <= BMAX) uInt n, // number of codes (assumed <= 288) uInt s, // number of simple-valued codes (0..s-1) const uInt *d, // list of base values for non-simple codes const uInt *e, // list of extra bits for non-simple codes inflate_huft **t, // result: starting table uInt *m, // maximum lookup bits, returns actual inflate_huft *hp, // space for trees uInt *hn, // hufts used in space uInt *v) // working area: values in order of bit length // Given a list of code lengths and a maximum table size, make a set of // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR // if the given code set is incomplete (the tables are still built in this // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of // lengths), or Z_MEM_ERROR if not enough memory. { uInt a; // counter for codes of length k uInt c[BMAX + 1]; // bit length count table uInt f; // i repeats in table every f entries int g; // maximum code length int h; // table level register uInt i; // counter, current code register uInt j; // counter register int k; // number of bits in current code int l; // bits per table (returned in m) uInt mask; // (1 << w) - 1, to avoid cc -O bug on HP register uInt *p; // pointer into c[], b[], or v[] inflate_huft *q; // points to current table struct inflate_huft_s r; // table entry for structure assignment inflate_huft *u[BMAX]; // table stack register int w; // bits before this table == (l * h) uInt x[BMAX + 1]; // bit offsets, then code stack uInt *xp; // pointer into x int y; // number of dummy codes added uInt z; // number of entries in current table // Generate counts for each bit length p = c; #define C0 *p++ = 0; #define C2 C0 C0 C0 C0 #define C4 C2 C2 C2 C2 C4; p; // clear c[]--assume BMAX+1 is 16 p = b; i = n; do { c[*p++]++; // assume all entries <= BMAX } while (--i); if (c[0] == n) // null input--all zero length codes { *t = (inflate_huft *)Z_NULL; *m = 0; return Z_OK; } // Find minimum and maximum length, bound *m by those l = *m; for (j = 1; j <= BMAX; j++) if (c[j]) break; k = j; // minimum code length if ((uInt)l < j) l = j; for (i = BMAX; i; i--) if (c[i]) break; g = i; // maximum code length if ((uInt)l > i) l = i; *m = l; // Adjust last length count to fill out codes, if needed for (y = 1 << j; j < i; j++, y <<= 1) if ((y -= c[j]) < 0) return Z_DATA_ERROR; if ((y -= c[i]) < 0) return Z_DATA_ERROR; c[i] += y; // Generate starting offsets into the value table for each length x[1] = j = 0; p = c + 1; xp = x + 2; while (--i) { // note that i == g from above *xp++ = (j += *p++); } // Make a table of values in order of bit lengths p = b; i = 0; do { if ((j = *p++) != 0) v[x[j]++] = i; } while (++i < n); n = x[g]; // set n to length of v // Generate the Huffman codes and for each, make the table entries x[0] = i = 0; // first Huffman code is zero p = v; // grab values in bit order h = -1; // no tables yet--level -1 w = -l; // bits decoded == (l * h) u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy q = (inflate_huft *)Z_NULL; // ditto z = 0; // ditto // go through the bit lengths (k already is bits in shortest code) for (; k <= g; k++) { a = c[k]; while (a--) { // here i is the Huffman code of length k bits for value *p // make tables up to required level while (k > w + l) { h++; w += l; // previous table always l bits // compute minimum size table less than or equal to l bits z = g - w; z = z > (uInt)l ? l : z; // table size upper limit if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table { // too few codes for k-w bit table f -= a + 1; // deduct codes from patterns left xp = c + k; if (j < z) while (++j < z) // try smaller tables up to z bits { if ((f <<= 1) <= *++xp) break; // enough codes to use up j bits f -= *xp; // else deduct codes from patterns } } z = 1 << j; // table entries for j-bit table // allocate new table if (*hn + z > MANY) // (note: doesn't matter for fixed) return Z_MEM_ERROR; // not enough memory u[h] = q = hp + *hn; *hn += z; // connect to last table, if there is one if (h) { x[h] = i; // save pattern for backing up r.bits = (Byte)l; // bits to dump before this table r.exop = (Byte)j; // bits in this table j = i >> (w - l); r.base = (uInt)(q - u[h - 1] - j); // offset to this table u[h - 1][j] = r; // connect to last table } else *t = q; // first table is returned result } // set up table entry in r r.bits = (Byte)(k - w); if (p >= v + n) r.exop = 128 + 64; // out of values--invalid code else if (*p < s) { r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block r.base = *p++; // simple code is just the value } else { r.exop = (Byte)(e[*p - s] + 16 + 64); // non-simple--look up in lists r.base = d[*p++ - s]; } // fill code-like entries with r f = 1 << (k - w); for (j = i >> w; j < z; j += f) q[j] = r; // backwards increment the k-bit code i for (j = 1 << (k - 1); i & j; j >>= 1) i ^= j; i ^= j; // backup over finished tables mask = (1 << w) - 1; // needed on HP, cc -O bug while ((i & mask) != x[h]) { h--; // don't need to update q w -= l; mask = (1 << w) - 1; } } } // Return Z_BUF_ERROR if we were given an incomplete table return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; } int inflate_trees_bits(uInt *c, // 19 code lengths uInt *bb, // bits tree desired/actual depth inflate_huft **tb, // bits tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build if ((v = (uInt *)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; r = huft_build(c, 19, 19, (uInt *)Z_NULL, (uInt *)Z_NULL, tb, bb, hp, &hn, v); if (r == Z_DATA_ERROR) z->msg = (char *)"oversubscribed dynamic bit lengths tree"; else if (r == Z_BUF_ERROR || *bb == 0) { z->msg = (char *)"incomplete dynamic bit lengths tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } int inflate_trees_dynamic(uInt nl, // number of literal/length codes uInt nd, // number of distance codes uInt *c, // that many (total) code lengths uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth inflate_huft **tl, // literal/length tree result inflate_huft **td, // distance tree result inflate_huft *hp, // space for trees z_streamp z) // for messages { int r; uInt hn = 0; // hufts used in space uInt *v; // work area for huft_build // allocate work area if ((v = (uInt *)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) return Z_MEM_ERROR; // build literal/length tree r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); if (r != Z_OK || *bl == 0) { if (r == Z_DATA_ERROR) z->msg = (char *)"oversubscribed literal/length tree"; else if (r != Z_MEM_ERROR) { z->msg = (char *)"incomplete literal/length tree"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // build distance tree r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); if (r != Z_OK || (*bd == 0 && nl > 257)) { if (r == Z_DATA_ERROR) z->msg = (char *)"oversubscribed distance tree"; else if (r == Z_BUF_ERROR) { z->msg = (char *)"incomplete distance tree"; r = Z_DATA_ERROR; } else if (r != Z_MEM_ERROR) { z->msg = (char *)"empty distance tree with lengths"; r = Z_DATA_ERROR; } ZFREE(z, v); return r; } // done ZFREE(z, v); return Z_OK; } int inflate_trees_fixed(uInt *bl, // literal desired/actual bit depth uInt *bd, // distance desired/actual bit depth const inflate_huft **tl, // literal/length tree result const inflate_huft **td, // distance tree result z_streamp) // for memory allocation { *bl = fixed_bl; *bd = fixed_bd; *tl = fixed_tl; *td = fixed_td; return Z_OK; } // inffast.c -- process literals and length/distance pairs fast // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // // struct inflate_codes_state {int dummy;}; // for buggy compilers // macros for bit input with no checking and for returning unused bytes #define GRABBITS(j) \ { \ while (k < (j)) { \ b |= ((uLong)NEXTBYTE) << k; \ k += 8; \ } \ } #define UNGRAB \ { \ c = z->avail_in - n; \ c = (k >> 3) < c ? k >> 3 : c; \ n += c; \ p -= c; \ k -= c << 3; \ } // Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. int inflate_fast( uInt bl, uInt bd, const inflate_huft *tl, const inflate_huft *td, // need separate declaration for Borland C++ inflate_blocks_statef *s, z_streamp z) { const inflate_huft *t; // temporary pointer uInt e; // extra bits or operation uLong b; // bit buffer uInt k; // bits in bit buffer Byte *p; // input data pointer uInt n; // bytes available there Byte *q; // output window write pointer uInt m; // bytes to end of window or read pointer uInt ml; // mask for literal/length tree uInt md; // mask for distance tree uInt c; // bytes to copy uInt d; // distance back to copy from Byte *r; // copy source pointer // load input, output, bit values LOAD // initialize masks ml = inflate_mask[bl]; md = inflate_mask[bd]; // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code GRABBITS(20) // max bits for literal/length code if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) { DUMPBITS(t->bits) Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; continue; } for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits for length e &= 15; c = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) Tracevv((stderr, "inflate: * length %u\n", c)); // decode distance base of block to copy GRABBITS(15); // max bits for distance code e = (t = td + ((uInt)b & md))->exop; for (;;) { DUMPBITS(t->bits) if (e & 16) { // get extra bits to add to distance base e &= 15; GRABBITS(e) // get extra bits (up to 13) d = t->base + ((uInt)b & inflate_mask[e]); DUMPBITS(e) Tracevv((stderr, "inflate: * distance %u\n", d)); // do the copy m -= c; if ((uInt)(q - s->window) >= d) // offset before dest { // just copy r = q - d; *q++ = *r++; c--; // minimum count is three, *q++ = *r++; c--; // so unroll loop a little } else // else offset after destination { e = d - (uInt)(q - s->window); // bytes from offset to end r = s->end - e; // pointer to offset if (c > e) // if source crosses, { c -= e; // copy to end of window do { *q++ = *r++; } while (--e); r = s->window; // copy rest from start of window } } do { // copy all or what's left *q++ = *r++; } while (--c); break; } else if ((e & 64) == 0) { t += t->base; e = (t += ((uInt)b & inflate_mask[e]))->exop; } else { z->msg = (char *)"invalid distance code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; break; } if ((e & 64) == 0) { t += t->base; if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) { DUMPBITS(t->bits) Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? "inflate: * literal '%c'\n" : "inflate: * literal 0x%02x\n", t->base)); *q++ = (Byte)t->base; m--; break; } } else if (e & 32) { Tracevv((stderr, "inflate: * end of block\n")); UNGRAB UPDATE return Z_STREAM_END; } else { z->msg = (char *)"invalid literal/length code"; UNGRAB UPDATE return Z_DATA_ERROR; } }; } while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return UNGRAB UPDATE return Z_OK; } // crc32.c -- compute the CRC-32 of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ // Table of CRC-32's of all single-byte values (made by make_crc_table) const uLong crc_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL}; const uLong *get_crc_table() { return (const uLong *)crc_table; } #define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define CRC_DO2(buf) \ CRC_DO1(buf); \ CRC_DO1(buf); #define CRC_DO4(buf) \ CRC_DO2(buf); \ CRC_DO2(buf); #define CRC_DO8(buf) \ CRC_DO4(buf); \ CRC_DO4(buf); uLong ucrc32(uLong crc, const Byte *buf, uInt len) { if (buf == Z_NULL) return 0L; crc = crc ^ 0xffffffffL; while (len >= 8) { CRC_DO8(buf); len -= 8; } if (len) do { CRC_DO1(buf); } while (--len); return crc ^ 0xffffffffL; } // adler32.c -- compute the Adler-32 checksum of a data stream // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ #define BASE 65521L // largest prime smaller than 65536 #define NMAX 5552 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 #define AD_DO1(buf, i) \ { \ s1 += buf[i]; \ s2 += s1; \ } #define AD_DO2(buf, i) \ AD_DO1(buf, i); \ AD_DO1(buf, i + 1); #define AD_DO4(buf, i) \ AD_DO2(buf, i); \ AD_DO2(buf, i + 2); #define AD_DO8(buf, i) \ AD_DO4(buf, i); \ AD_DO4(buf, i + 4); #define AD_DO16(buf) \ AD_DO8(buf, 0); \ AD_DO8(buf, 8); // ========================================================================= uLong adler32(uLong adler, const Byte *buf, uInt len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == Z_NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { AD_DO16(buf); buf += 16; k -= 16; } if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } // zutil.c -- target dependent utility functions for the compression library // Copyright (C) 1995-1998 Jean-loup Gailly. // For conditions of distribution and use, see copyright notice in zlib.h // @(#) $Id$ const char *zlibVersion() { return ZLIB_VERSION; } // exported to allow conversion of error code to string for compress() and // uncompress() const char *zError(int err) { return ERR_MSG(err); } voidpf zcalloc(voidpf opaque, unsigned items, unsigned size) { if (opaque) items += size - size; // make compiler happy return (voidpf)calloc(items, size); } void zcfree(voidpf opaque, voidpf ptr) { zfree(ptr); if (opaque) return; // make compiler happy } // inflate.c -- zlib interface to inflate modules // Copyright (C) 1995-1998 Mark Adler // For conditions of distribution and use, see copyright notice in zlib.h // struct inflate_blocks_state {int dummy;}; // for buggy compilers typedef enum { IM_METHOD, // waiting for method byte IM_FLAG, // waiting for flag byte IM_DICT4, // four dictionary check bytes to go IM_DICT3, // three dictionary check bytes to go IM_DICT2, // two dictionary check bytes to go IM_DICT1, // one dictionary check byte to go IM_DICT0, // waiting for inflateSetDictionary IM_BLOCKS, // decompressing blocks IM_CHECK4, // four check bytes to go IM_CHECK3, // three check bytes to go IM_CHECK2, // two check bytes to go IM_CHECK1, // one check byte to go IM_DONE, // finished check, done IM_BAD } // got an error--stay here inflate_mode; // inflate private state struct internal_state { // mode inflate_mode mode; // current inflate mode // mode dependent information union { uInt method; // if IM_FLAGS, method byte struct { uLong was; // computed check value uLong need; // stream check value } check; // if CHECK, check values to compare uInt marker; // if IM_BAD, inflateSync's marker bytes count } sub; // submode // mode independent information int nowrap; // flag for no wrapper uInt wbits; // log2(window size) (8..15, defaults to 15) inflate_blocks_statef *blocks; // current inflate_blocks state }; int inflateReset(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL) return Z_STREAM_ERROR; z->total_in = z->total_out = 0; z->msg = Z_NULL; z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD; inflate_blocks_reset(z->state->blocks, z, Z_NULL); Tracev((stderr, "inflate: reset\n")); return Z_OK; } int inflateEnd(z_streamp z) { if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) return Z_STREAM_ERROR; if (z->state->blocks != Z_NULL) inflate_blocks_free(z->state->blocks, z); ZFREE(z, z->state); z->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int inflateInit2(z_streamp z) { const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream); if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) return Z_VERSION_ERROR; int w = -15; // MAX_WBITS: 32K LZ77 window. // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files // created by gzip. The memory requirements for deflate are (in bytes): // (1 << (windowBits+2)) + (1 << (memLevel+9)) // that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) // plus a few kilobytes for small objects. For example, if you want to reduce // the default memory requirements from 256K to 128K, compile with // make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" // Of course this will generally degrade compression (there's no free lunch). // // The memory requirements for inflate are (in bytes) 1 << windowBits // that is, 32K for windowBits=15 (default value) plus a few kilobytes // for small objects. // initialize state if (z == Z_NULL) return Z_STREAM_ERROR; z->msg = Z_NULL; if (z->zalloc == Z_NULL) { z->zalloc = zcalloc; z->opaque = (voidpf)0; } if (z->zfree == Z_NULL) z->zfree = zcfree; if ((z->state = (struct internal_state *)ZALLOC( z, 1, sizeof(struct internal_state))) == Z_NULL) return Z_MEM_ERROR; z->state->blocks = Z_NULL; // handle undocumented nowrap option (no zlib header or check) z->state->nowrap = 0; if (w < 0) { w = -w; z->state->nowrap = 1; } // set window size if (w < 8 || w > 15) { inflateEnd(z); return Z_STREAM_ERROR; } z->state->wbits = (uInt)w; // create inflate_blocks state if ((z->state->blocks = inflate_blocks_new( z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) == Z_NULL) { inflateEnd(z); return Z_MEM_ERROR; } Tracev((stderr, "inflate: allocated\n")); // reset state inflateReset(z); return Z_OK; } #define IM_NEEDBYTE \ { \ if (z->avail_in == 0) \ return r; \ r = f; \ } #define IM_NEXTBYTE (z->avail_in--, z->total_in++, *z->next_in++) int inflate(z_streamp z, int f) { int r; uInt b; if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) return Z_STREAM_ERROR; f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; r = Z_BUF_ERROR; for (;;) switch (z->state->mode) { case IM_METHOD: IM_NEEDBYTE if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) { z->state->mode = IM_BAD; z->msg = (char *)"unknown compression method"; z->state->sub.marker = 5; // can't try inflateSync break; } if ((z->state->sub.method >> 4) + 8 > z->state->wbits) { z->state->mode = IM_BAD; z->msg = (char *)"invalid window size"; z->state->sub.marker = 5; // can't try inflateSync break; } z->state->mode = IM_FLAG; case IM_FLAG: IM_NEEDBYTE b = IM_NEXTBYTE; if (((z->state->sub.method << 8) + b) % 31) { z->state->mode = IM_BAD; z->msg = (char *)"incorrect header check"; z->state->sub.marker = 5; // can't try inflateSync break; } Tracev((stderr, "inflate: zlib header ok\n")); if (!(b & PRESET_DICT)) { z->state->mode = IM_BLOCKS; break; } z->state->mode = IM_DICT4; case IM_DICT4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_DICT3; case IM_DICT3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_DICT2; case IM_DICT2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_DICT1; case IM_DICT1: IM_NEEDBYTE; r; z->state->sub.check.need += (uLong)IM_NEXTBYTE; z->adler = z->state->sub.check.need; z->state->mode = IM_DICT0; return Z_NEED_DICT; case IM_DICT0: z->state->mode = IM_BAD; z->msg = (char *)"need dictionary"; z->state->sub.marker = 0; // can try inflateSync return Z_STREAM_ERROR; case IM_BLOCKS: r = inflate_blocks(z->state->blocks, z, r); if (r == Z_DATA_ERROR) { z->state->mode = IM_BAD; z->state->sub.marker = 0; // can try inflateSync break; } if (r == Z_OK) r = f; if (r != Z_STREAM_END) return r; r = f; inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); if (z->state->nowrap) { z->state->mode = IM_DONE; break; } z->state->mode = IM_CHECK4; case IM_CHECK4: IM_NEEDBYTE z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24; z->state->mode = IM_CHECK3; case IM_CHECK3: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16; z->state->mode = IM_CHECK2; case IM_CHECK2: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8; z->state->mode = IM_CHECK1; case IM_CHECK1: IM_NEEDBYTE z->state->sub.check.need += (uLong)IM_NEXTBYTE; if (z->state->sub.check.was != z->state->sub.check.need) { z->state->mode = IM_BAD; z->msg = (char *)"incorrect data check"; z->state->sub.marker = 5; // can't try inflateSync break; } Tracev((stderr, "inflate: zlib check ok\n")); z->state->mode = IM_DONE; case IM_DONE: return Z_STREAM_END; case IM_BAD: return Z_DATA_ERROR; default: return Z_STREAM_ERROR; } } #ifdef _UNICODE static int GetAnsiFileName(LPCWSTR name, char *buf, int nBufSize) { memset(buf, 0, nBufSize); int n = WideCharToMultiByte(CP_ACP, // code page 0, // performance and mapping flags name, // wide-character string -1, // number of chars in string buf, // buffer for new string nBufSize, // size of buffer NULL, // default for unmappable chars NULL); // set when default char used return n; } static int GetUnicodeFileName(const char *name, LPWSTR buf, int nBufSize) { memset(buf, 0, nBufSize * sizeof(TCHAR)); int n = MultiByteToWideChar(CP_ACP, // code page 0, // character-type options name, // string to map -1, // number of bytes in string buf, // wide-character buffer nBufSize); // size of buffer return n; } #endif // unzip.c -- IO on .zip files using zlib // Version 0.15 beta, Mar 19th, 1998, // Read unzip.h for more info #define UNZ_BUFSIZE (16384) #define UNZ_MAXFILENAMEINZIP (256) #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " "; // unzip 0.15 Copyright 1998 Gilles Vollant "; // unz_file_info_interntal contain internal info about a file in zipfile typedef struct unz_file_info_internal_s { uLong offset_curfile; // relative offset of local header 4 bytes } unz_file_info_internal; typedef struct { bool is_handle; // either a handle or memory bool canseek; // for handles: HANDLE h; bool herr; unsigned long initial_offset; // for memory: void *buf; unsigned int len, pos; // if it's a memory block } LUFILE; LUFILE *lufopen(void *z, unsigned int len, DWORD flags, ZRESULT *err) { if (flags != ZIP_HANDLE && flags != ZIP_FILENAME && flags != ZIP_MEMORY) { *err = ZR_ARGS; return NULL; } // HANDLE h = 0; bool canseek = false; *err = ZR_OK; if (flags == ZIP_HANDLE || flags == ZIP_FILENAME) { if (flags == ZIP_HANDLE) { HANDLE hf = z; BOOL res = DuplicateHandle(GetCurrentProcess(), hf, GetCurrentProcess(), &h, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!res) { *err = ZR_NODUPH; return NULL; } } else { h = CreateFile((const TCHAR *)z, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { *err = ZR_NOFILE; return NULL; } } DWORD type = GetFileType(h); canseek = (type == FILE_TYPE_DISK); } LUFILE *lf = new LUFILE; if (flags == ZIP_HANDLE || flags == ZIP_FILENAME) { lf->is_handle = true; lf->canseek = canseek; lf->h = h; lf->herr = false; lf->initial_offset = 0; if (canseek) lf->initial_offset = SetFilePointer(h, 0, NULL, FILE_CURRENT); } else { lf->is_handle = false; lf->canseek = true; lf->buf = z; lf->len = len; lf->pos = 0; lf->initial_offset = 0; } *err = ZR_OK; return lf; } int lufclose(LUFILE *stream) { if (stream == NULL) return EOF; if (stream->is_handle) CloseHandle(stream->h); delete stream; return 0; } int luferror(LUFILE *stream) { if (stream->is_handle && stream->herr) return 1; else return 0; } long int luftell(LUFILE *stream) { if (stream->is_handle && stream->canseek) return SetFilePointer(stream->h, 0, NULL, FILE_CURRENT) - stream->initial_offset; else if (stream->is_handle) return 0; else return stream->pos; } int lufseek(LUFILE *stream, long offset, int whence) { if (stream->is_handle && stream->canseek) { if (whence == SEEK_SET) SetFilePointer(stream->h, stream->initial_offset + offset, 0, FILE_BEGIN); else if (whence == SEEK_CUR) SetFilePointer(stream->h, offset, NULL, FILE_CURRENT); else if (whence == SEEK_END) SetFilePointer(stream->h, offset, NULL, FILE_END); else return 19; // EINVAL return 0; } else if (stream->is_handle) return 29; // ESPIPE else { if (whence == SEEK_SET) stream->pos = offset; else if (whence == SEEK_CUR) stream->pos += offset; else if (whence == SEEK_END) stream->pos = stream->len + offset; return 0; } } size_t lufread(void *ptr, size_t size, size_t n, LUFILE *stream) { unsigned int toread = (unsigned int)(size * n); if (stream->is_handle) { DWORD red; BOOL res = ReadFile(stream->h, ptr, toread, &red, NULL); if (!res) stream->herr = true; return red / size; } if (stream->pos + toread > stream->len) toread = stream->len - stream->pos; memcpy(ptr, (char *)stream->buf + stream->pos, toread); DWORD red = toread; stream->pos += red; return red / size; } // file_in_zip_read_info_s contain internal information about a file in zipfile, // when reading and decompress it typedef struct { char *read_buffer; // internal buffer for compressed data z_stream stream; // zLib stream structure for inflate uLong pos_in_zipfile; // position in byte on the zipfile, for fseek uLong stream_initialised; // flag set if stream structure is initialised uLong offset_local_extrafield; // offset of the local extra field uInt size_local_extrafield; // size of the local extra field uLong pos_local_extrafield; // position in the local extra field in read uLong crc32; // crc32 of all data uncompressed uLong crc32_wait; // crc32 we must obtain after decompress all uLong rest_read_compressed; // number of byte to be decompressed uLong rest_read_uncompressed; // number of byte to be obtained after decomp LUFILE *file; // io structore of the zipfile uLong compression_method; // compression method (0==store) uLong byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx) } file_in_zip_read_info_s; // unz_s contain internal information about the zipfile typedef struct { LUFILE *file; // io structore of the zipfile unz_global_info gi; // public global information uLong byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx) uLong num_file; // number of the current file in the zipfile uLong pos_in_central_dir; // pos of the current file in the central dir uLong current_file_ok; // flag about the usability of the current file uLong central_pos; // position of the beginning of the central dir uLong size_central_dir; // size of the central directory uLong offset_central_dir; // offset of start of central directory with respect // to the starting disk number unz_file_info cur_file_info; // public info about the current file in zip unz_file_info_internal cur_file_info_internal; // private info about it file_in_zip_read_info_s *pfile_in_zip_read; // structure about the current // file if we are decompressing it } unz_s, *unzFile; int unzStringFileNameCompare(const char *fileName1, const char *fileName2, int iCaseSensitivity); // Compare two filename (fileName1,fileName2). z_off_t unztell(unzFile file); // Give the current position in uncompressed data int unzeof(unzFile file); // return 1 if the end of file was reached, 0 elsewhere int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len); // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // // if buf==NULL, it return the size of the local extra field // // if buf!=NULL, len is the size of the buffer, the extra header is copied in // buf. // the return value is the number of bytes copied in buf, or (if <0) // the error code // =========================================================================== // Read a byte from a gz_stream; update next_in and avail_in. Return EOF // for end of file. // IN assertion: the stream s has been sucessfully opened for reading. int unzlocal_getByte(LUFILE *fin, int *pi) { unsigned char c; int err = (int)lufread(&c, 1, 1, fin); if (err == 1) { *pi = (int)c; return UNZ_OK; } else { if (luferror(fin)) return UNZ_ERRNO; else return UNZ_EOF; } } // =========================================================================== // Reads a long in LSB order from the given gz_stream. Sets int unzlocal_getShort(LUFILE *fin, uLong *pX) { uLong x; int i; int err; err = unzlocal_getByte(fin, &i); x = (uLong)i; if (err == UNZ_OK) err = unzlocal_getByte(fin, &i); x += ((uLong)i) << 8; if (err == UNZ_OK) *pX = x; else *pX = 0; return err; } int unzlocal_getLong(LUFILE *fin, uLong *pX) { uLong x; int i; int err; err = unzlocal_getByte(fin, &i); x = (uLong)i; if (err == UNZ_OK) err = unzlocal_getByte(fin, &i); x += ((uLong)i) << 8; if (err == UNZ_OK) err = unzlocal_getByte(fin, &i); x += ((uLong)i) << 16; if (err == UNZ_OK) err = unzlocal_getByte(fin, &i); x += ((uLong)i) << 24; if (err == UNZ_OK) *pX = x; else *pX = 0; return err; } // My own strcmpi / strcasecmp int strcmpcasenosensitive_internal(const char *fileName1, const char *fileName2) { for (;;) { char c1 = *(fileName1++); char c2 = *(fileName2++); if ((c1 >= 'a') && (c1 <= 'z')) c1 -= (char)0x20; if ((c2 >= 'a') && (c2 <= 'z')) c2 -= (char)0x20; if (c1 == '\0') return ((c2 == '\0') ? 0 : -1); if (c2 == '\0') return 1; if (c1 < c2) return -1; if (c1 > c2) return 1; } } // // Compare two filename (fileName1,fileName2). // If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) // If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or // strcasecmp) // int unzStringFileNameCompare(const char *fileName1, const char *fileName2, int iCaseSensitivity) { if (iCaseSensitivity == 1) return strcmp(fileName1, fileName2); else return strcmpcasenosensitive_internal(fileName1, fileName2); } #define BUFREADCOMMENT (0x400) // Locate the Central directory of a zipfile (at the end, just before // the global comment) uLong unzlocal_SearchCentralDir(LUFILE *fin) { if (lufseek(fin, 0, SEEK_END) != 0) return 0; uLong uSizeFile = luftell(fin); uLong uMaxBack = 0xffff; // maximum size of global comment if (uMaxBack > uSizeFile) uMaxBack = uSizeFile; unsigned char *buf = (unsigned char *)zmalloc(BUFREADCOMMENT + 4); if (buf == NULL) return 0; uLong uPosFound = 0; uLong uBackRead = 4; while (uBackRead < uMaxBack) { uLong uReadSize, uReadPos; int i; if (uBackRead + BUFREADCOMMENT > uMaxBack) uBackRead = uMaxBack; else uBackRead += BUFREADCOMMENT; uReadPos = uSizeFile - uBackRead; uReadSize = ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos)) ? (BUFREADCOMMENT + 4) : (uSizeFile - uReadPos); if (lufseek(fin, uReadPos, SEEK_SET) != 0) break; if (lufread(buf, (uInt)uReadSize, 1, fin) != 1) break; for (i = (int)uReadSize - 3; (i--) > 0;) { if (((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) && ((*(buf + i + 2)) == 0x05) && ((*(buf + i + 3)) == 0x06)) { uPosFound = uReadPos + i; break; } } if (uPosFound != 0) break; } if (buf) zfree(buf); return uPosFound; } int unzGoToFirstFile(unzFile file); int unzCloseCurrentFile(unzFile file); // Open a Zip file. // If the zipfile cannot be opened (file don't exist or in not valid), return // NULL. Otherwise, the return value is a unzFile Handle, usable with other // unzip functions unzFile unzOpenInternal(LUFILE *fin) { zopenerror = ZR_OK; //+++1.2 if (fin == NULL) { zopenerror = ZR_ARGS; return NULL; } //+++1.2 if (unz_copyright[0] != ' ') { lufclose(fin); zopenerror = ZR_CORRUPT; return NULL; } //+++1.2 int err = UNZ_OK; unz_s us; uLong central_pos, uL; central_pos = unzlocal_SearchCentralDir(fin); if (central_pos == 0) err = UNZ_ERRNO; if (lufseek(fin, central_pos, SEEK_SET) != 0) err = UNZ_ERRNO; // the signature, already checked if (unzlocal_getLong(fin, &uL) != UNZ_OK) err = UNZ_ERRNO; // number of this disk uLong number_disk; // number of the current dist, used for spanning ZIP, // unsupported, always 0 if (unzlocal_getShort(fin, &number_disk) != UNZ_OK) err = UNZ_ERRNO; // number of the disk with the start of the central directory uLong number_disk_with_CD; // number the the disk with central dir, used for // spaning ZIP, unsupported, always 0 if (unzlocal_getShort(fin, &number_disk_with_CD) != UNZ_OK) err = UNZ_ERRNO; // total number of entries in the central dir on this disk if (unzlocal_getShort(fin, &us.gi.number_entry) != UNZ_OK) err = UNZ_ERRNO; // total number of entries in the central dir uLong number_entry_CD; // total number of entries in the central dir (same // than number_entry on nospan) if (unzlocal_getShort(fin, &number_entry_CD) != UNZ_OK) err = UNZ_ERRNO; if ((number_entry_CD != us.gi.number_entry) || (number_disk_with_CD != 0) || (number_disk != 0)) err = UNZ_BADZIPFILE; // size of the central directory if (unzlocal_getLong(fin, &us.size_central_dir) != UNZ_OK) err = UNZ_ERRNO; // offset of start of central directory with respect to the starting disk // number if (unzlocal_getLong(fin, &us.offset_central_dir) != UNZ_OK) err = UNZ_ERRNO; // zipfile comment length if (unzlocal_getShort(fin, &us.gi.size_comment) != UNZ_OK) err = UNZ_ERRNO; if ((central_pos + fin->initial_offset < us.offset_central_dir + us.size_central_dir) && (err == UNZ_OK)) err = UNZ_BADZIPFILE; // if (err!=UNZ_OK) {lufclose(fin);return NULL;} if (err != UNZ_OK) { lufclose(fin); zopenerror = err; return NULL; } //+++1.2 us.file = fin; us.byte_before_the_zipfile = central_pos + fin->initial_offset - (us.offset_central_dir + us.size_central_dir); us.central_pos = central_pos; us.pfile_in_zip_read = NULL; fin->initial_offset = 0; // since the zipfile itself is expected to handle this unz_s *s = (unz_s *)zmalloc(sizeof(unz_s)); *s = us; unzGoToFirstFile((unzFile)s); return (unzFile)s; } // Close a ZipFile opened with unzipOpen. // If there is files inside the .Zip opened with unzipOpenCurrentFile (see // later), // these files MUST be closed with unzipCloseCurrentFile before call // unzipClose. // return UNZ_OK if there is no problem. int unzClose(unzFile file) { unz_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); lufclose(s->file); if (s) zfree(s); // unused s=0; return UNZ_OK; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info) { unz_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; *pglobal_info = s->gi; return UNZ_OK; } // Translate date/time from Dos format to tm_unz (readable more easilty) void unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz *ptm) { uLong uDate; uDate = (uLong)(ulDosDate >> 16); ptm->tm_mday = (uInt)(uDate & 0x1f); ptm->tm_mon = (uInt)((((uDate)&0x1E0) / 0x20) - 1); ptm->tm_year = (uInt)(((uDate & 0x0FE00) / 0x0200) + 1980); ptm->tm_hour = (uInt)((ulDosDate & 0xF800) / 0x800); ptm->tm_min = (uInt)((ulDosDate & 0x7E0) / 0x20); ptm->tm_sec = (uInt)(2 * (ulDosDate & 0x1f)); } // Get Info about the current file in the zipfile, with internal only info int unzlocal_GetCurrentFileInfoInternal( unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize); int unzlocal_GetCurrentFileInfoInternal( unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz_s *s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err = UNZ_OK; uLong uMagic; long lSeek = 0; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; if (lufseek(s->file, s->pos_in_central_dir + s->byte_before_the_zipfile, SEEK_SET) != 0) err = UNZ_ERRNO; // we check the magic if (err == UNZ_OK) if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK) err = UNZ_ERRNO; else if (uMagic != 0x02014b50) err = UNZ_BADZIPFILE; if (unzlocal_getShort(s->file, &file_info.version) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.version_needed) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.flag) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.compression_method) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &file_info.dosDate) != UNZ_OK) err = UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date); if (unzlocal_getLong(s->file, &file_info.crc) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &file_info.compressed_size) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &file_info.uncompressed_size) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.size_filename) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.size_file_extra) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.size_file_comment) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.disk_num_start) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &file_info.internal_fa) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &file_info.external_fa) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &file_info_internal.offset_curfile) != UNZ_OK) err = UNZ_ERRNO; lSeek += file_info.size_filename; if ((err == UNZ_OK) && (szFileName != NULL)) { uLong uSizeRead; if (file_info.size_filename < fileNameBufferSize) { *(szFileName + file_info.size_filename) = '\0'; uSizeRead = file_info.size_filename; } else uSizeRead = fileNameBufferSize; if ((file_info.size_filename > 0) && (fileNameBufferSize > 0)) if (lufread(szFileName, (uInt)uSizeRead, 1, s->file) != 1) err = UNZ_ERRNO; lSeek -= uSizeRead; } if ((err == UNZ_OK) && (extraField != NULL)) { uLong uSizeRead; if (file_info.size_file_extra < extraFieldBufferSize) uSizeRead = file_info.size_file_extra; else uSizeRead = extraFieldBufferSize; if (lSeek != 0) if (lufseek(s->file, lSeek, SEEK_CUR) == 0) lSeek = 0; else err = UNZ_ERRNO; if ((file_info.size_file_extra > 0) && (extraFieldBufferSize > 0)) if (lufread(extraField, (uInt)uSizeRead, 1, s->file) != 1) err = UNZ_ERRNO; lSeek += file_info.size_file_extra - uSizeRead; } else lSeek += file_info.size_file_extra; if ((err == UNZ_OK) && (szComment != NULL)) { uLong uSizeRead; if (file_info.size_file_comment < commentBufferSize) { *(szComment + file_info.size_file_comment) = '\0'; uSizeRead = file_info.size_file_comment; } else uSizeRead = commentBufferSize; if (lSeek != 0) if (lufseek(s->file, lSeek, SEEK_CUR) == 0) { } // unused lSeek=0; else err = UNZ_ERRNO; if ((file_info.size_file_comment > 0) && (commentBufferSize > 0)) if (lufread(szComment, (uInt)uSizeRead, 1, s->file) != 1) err = UNZ_ERRNO; // unused lSeek+=file_info.size_file_comment - uSizeRead; } else { } // unused lSeek+=file_info.size_file_comment; if ((err == UNZ_OK) && (pfile_info != NULL)) *pfile_info = file_info; if ((err == UNZ_OK) && (pfile_info_internal != NULL)) *pfile_info_internal = file_info_internal; return err; } // Write info about the ZipFile in the *pglobal_info structure. // No preparation of the structure is needed // return UNZ_OK if there is no problem. int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { return unzlocal_GetCurrentFileInfoInternal( file, pfile_info, NULL, szFileName, fileNameBufferSize, extraField, extraFieldBufferSize, szComment, commentBufferSize); } // Set the current file of the zipfile to the first file. // return UNZ_OK if there is no problem int unzGoToFirstFile(unzFile file) { int err; unz_s *s; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; s->pos_in_central_dir = s->offset_central_dir; s->num_file = 0; err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); s->current_file_ok = (err == UNZ_OK); return err; } // Set the current file of the zipfile to the next file. // return UNZ_OK if there is no problem // return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. int unzGoToNextFile(unzFile file) { unz_s *s; int err; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->num_file + 1 == s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0); s->current_file_ok = (err == UNZ_OK); return err; } // Try locate the file szFileName in the zipfile. // For the iCaseSensitivity signification, see unzStringFileNameCompare // return value : // UNZ_OK if the file is found. It becomes the current file. // UNZ_END_OF_LIST_OF_FILE if the file is not found int unzLocateFile(unzFile file, const TCHAR *szFileName, int iCaseSensitivity) { unz_s *s; int err; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file == NULL) return UNZ_PARAMERROR; if (_tcslen(szFileName) >= UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; char szFileNameA[MAX_PATH]; #ifdef _UNICODE GetAnsiFileName(szFileName, szFileNameA, MAX_PATH - 1); #else strcpy(szFileNameA, szFileName); #endif s = (unz_s *)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1]; unzGetCurrentFileInfo(file, NULL, szCurrentFileName, sizeof(szCurrentFileName) - 1, NULL, 0, NULL, 0); if (unzStringFileNameCompare(szCurrentFileName, szFileNameA, iCaseSensitivity) == 0) return UNZ_OK; err = unzGoToNextFile(file); } s->num_file = num_fileSaved; s->pos_in_central_dir = pos_in_central_dirSaved; return err; } // Read the local header of the current zipfile // Check the coherency of the local header and info in the end of central // directory about this file // store in *piSizeVar the size of extra info in local header // (filename and size of extra field data) int unzlocal_CheckCurrentFileCoherencyHeader(unz_s *s, uInt *piSizeVar, uLong *poffset_local_extrafield, uInt *psize_local_extrafield) { uLong uMagic, uData, uFlags; uLong size_filename; uLong size_extra_field; int err = UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (lufseek(s->file, s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile, SEEK_SET) != 0) return UNZ_ERRNO; if (err == UNZ_OK) if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK) err = UNZ_ERRNO; else if (uMagic != 0x04034b50) err = UNZ_BADZIPFILE; if (unzlocal_getShort(s->file, &uData) != UNZ_OK) err = UNZ_ERRNO; // else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) // err=UNZ_BADZIPFILE; if (unzlocal_getShort(s->file, &uFlags) != UNZ_OK) err = UNZ_ERRNO; if (unzlocal_getShort(s->file, &uData) != UNZ_OK) err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uData != s->cur_file_info.compression_method)) err = UNZ_BADZIPFILE; if ((err == UNZ_OK) && (s->cur_file_info.compression_method != 0) && (s->cur_file_info.compression_method != Z_DEFLATED)) err = UNZ_BADZIPFILE; if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // date/time err = UNZ_ERRNO; if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // crc err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uData != s->cur_file_info.crc) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // size compr err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uData != s->cur_file_info.compressed_size) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // size uncompr err = UNZ_ERRNO; else if ((err == UNZ_OK) && (uData != s->cur_file_info.uncompressed_size) && ((uFlags & 8) == 0)) err = UNZ_BADZIPFILE; if (unzlocal_getShort(s->file, &size_filename) != UNZ_OK) err = UNZ_ERRNO; else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename)) err = UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(s->file, &size_extra_field) != UNZ_OK) err = UNZ_ERRNO; *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } // Open for reading data the current file in the zipfile. // If there is no error and the file is opened, the return value is UNZ_OK. int unzOpenCurrentFile(unzFile file) { int err; int Store; uInt iSizeVar; unz_s *s; file_in_zip_read_info_s *pfile_in_zip_read_info; uLong offset_local_extrafield; // offset of the local extra field uInt size_local_extrafield; // size of the local extra field if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader( s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s *)zmalloc(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info == NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer = (char *)zmalloc(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield = 0; if (pfile_in_zip_read_info->read_buffer == NULL) { if (pfile_in_zip_read_info != 0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised = 0; if ((s->cur_file_info.compression_method != 0) && (s->cur_file_info.compression_method != Z_DEFLATED)) { // unused err=UNZ_BADZIPFILE; } Store = s->cur_file_info.compression_method == 0; pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc; pfile_in_zip_read_info->crc32 = 0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->file = s->file; pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if (!Store) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; err = inflateInit2(&pfile_in_zip_read_info->stream); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised = 1; // windowBits is passed < 0 to tell that there is no zlib header. // Note that in this case inflate *requires* an extra "dummy" byte // after the compressed stream in order to complete decompression and // return Z_STREAM_END. // In unzip, i don't wait absolutely Z_STREAM_END because I known the // size of both compressed and uncompressed data } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; return UNZ_OK; } // Read bytes from the current file. // buf contain buffer where data must be copied // len the size of buf. // return the number of byte copied if somes bytes are copied // return 0 if the end of file was reached // return <0 with error code if there is an error // (UNZ_ERRNO for IO error, or zLib error for uncompress error) int unzReadCurrentFile(unzFile file, voidp buf, unsigned len) { int err = UNZ_OK; uInt iRead = 0; unz_s *s = (unz_s *)file; if (s == NULL) return UNZ_PARAMERROR; file_in_zip_read_info_s *pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE; if (len == 0) return 0; pfile_in_zip_read_info->stream.next_out = (Byte *)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if (len > pfile_in_zip_read_info->rest_read_uncompressed) { pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; } while (pfile_in_zip_read_info->stream.avail_out > 0) { if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed > 0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressed < uReadThis) uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, SEEK_SET) != 0) return UNZ_ERRNO; if (lufread(pfile_in_zip_read_info->read_buffer, uReadThis, 1, pfile_in_zip_read_info->file) != 1) return UNZ_ERRNO; pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed -= uReadThis; pfile_in_zip_read_info->stream.next_in = (Byte *)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if (pfile_in_zip_read_info->compression_method == 0) { uInt uDoCopy, i; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) { uDoCopy = pfile_in_zip_read_info->stream.avail_out; } else { uDoCopy = pfile_in_zip_read_info->stream.avail_in; } for (i = 0; i < uDoCopy; i++) { *(pfile_in_zip_read_info->stream.next_out + i) = *(pfile_in_zip_read_info->stream.next_in + i); } pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else { uLong uTotalOutBefore, uTotalOutAfter; const Byte *bufBefore; uLong uOutThis; int flush = Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; err = inflate(&pfile_in_zip_read_info->stream, flush); uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter - uTotalOutBefore; pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32, bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err == Z_STREAM_END) return (iRead == 0) ? UNZ_EOF : iRead; //+++1.3 // if (err==Z_STREAM_END) return (iRead==len) ? UNZ_EOF : iRead; // //+++1.2 if (err != Z_OK) break; } } if (err == Z_OK) return iRead; return iRead; } // Give the current position in uncompressed data z_off_t unztell(unzFile file) { unz_s *s; file_in_zip_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } // return 1 if the end of file was reached, 0 elsewhere int unzeof(unzFile file) { unz_s *s; file_in_zip_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } // Read extra field from the current file (opened by unzOpenCurrentFile) // This is the local-header version of the extra field (sometimes, there is // more info in the local-header version than in the central-header) // if buf==NULL, it return the size of the local extra field that can be read // if buf!=NULL, len is the size of the buffer, the extra header is copied in // buf. the return value is the number of bytes copied in buf, or (if <0) the // error code int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) { unz_s *s; file_in_zip_read_info_s *pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf == NULL) return (int)size_to_read; if (len > size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len; if (read_now == 0) return 0; if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, SEEK_SET) != 0) return UNZ_ERRNO; if (lufread(buf, (uInt)size_to_read, 1, pfile_in_zip_read_info->file) != 1) return UNZ_ERRNO; return (int)read_now; } // Close the file in zip opened with unzipOpenCurrentFile // Return UNZ_CRCERROR if all the file was read but the CRC is not good int unzCloseCurrentFile(unzFile file) { int err = UNZ_OK; unz_s *s; file_in_zip_read_info_s *pfile_in_zip_read_info; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; pfile_in_zip_read_info = s->pfile_in_zip_read; if (pfile_in_zip_read_info == NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err = UNZ_CRCERROR; } if (pfile_in_zip_read_info->read_buffer != 0) { void *buf = pfile_in_zip_read_info->read_buffer; zfree(buf); pfile_in_zip_read_info->read_buffer = 0; } pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; if (pfile_in_zip_read_info != 0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0; s->pfile_in_zip_read = NULL; return err; } // Get the global comment string of the ZipFile, in the szComment buffer. // uSizeBuf is the size of the szComment buffer. // return the number of byte copied or an error code <0 int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf) { // int err=UNZ_OK; unz_s *s; uLong uReadThis; if (file == NULL) return UNZ_PARAMERROR; s = (unz_s *)file; uReadThis = uSizeBuf; if (uReadThis > s->gi.size_comment) uReadThis = s->gi.size_comment; if (lufseek(s->file, s->central_pos + 22, SEEK_SET) != 0) return UNZ_ERRNO; if (uReadThis > 0) { *szComment = '\0'; if (lufread(szComment, (uInt)uReadThis, 1, s->file) != 1) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment + s->gi.size_comment) = '\0'; return (int)uReadThis; } int unzOpenCurrentFile(unzFile file); int unzReadCurrentFile(unzFile file, void *buf, unsigned len); int unzCloseCurrentFile(unzFile file); FILETIME timet2filetime(time_t timer) { struct tm *tm = gmtime(&timer); SYSTEMTIME st; st.wYear = (WORD)(tm->tm_year + 1900); st.wMonth = (WORD)(tm->tm_mon + 1); st.wDay = (WORD)(tm->tm_mday); st.wHour = (WORD)(tm->tm_hour); st.wMinute = (WORD)(tm->tm_min); st.wSecond = (WORD)(tm->tm_sec); st.wMilliseconds = 0; FILETIME ft; SystemTimeToFileTime(&st, &ft); return ft; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// class TUnzip { public: TUnzip() : uf(0), currentfile(-1), czei(-1) {} unzFile uf; int currentfile; ZIPENTRY cze; int czei; TCHAR rootdir[MAX_PATH]; ZRESULT Open(void *z, unsigned int len, DWORD flags); ZRESULT Get(int index, ZIPENTRY *ze); ZRESULT Find(const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); ZRESULT Unzip(int index, void *dst, unsigned int len, DWORD flags); ZRESULT Close(); }; ZRESULT TUnzip::Open(void *z, unsigned int len, DWORD flags) { if (uf != 0 || currentfile != -1) return ZR_NOTINITED; GetCurrentDirectory(MAX_PATH, rootdir); _tcscat(rootdir, _T("\\")); if (flags == ZIP_HANDLE) { DWORD type = GetFileType(z); if (type != FILE_TYPE_DISK) return ZR_SEEK; } ZRESULT e; LUFILE *f = lufopen(z, len, flags, &e); if (f == NULL) return e; uf = unzOpenInternal(f); // return ZR_OK; return zopenerror; //+++1.2 } ZRESULT TUnzip::Get(int index, ZIPENTRY *ze) { if (index < -1 || index >= (int)uf->gi.number_entry) return ZR_ARGS; if (currentfile != -1) unzCloseCurrentFile(uf); currentfile = -1; if (index == czei && index != -1) { memcpy(ze, &cze, sizeof(ZIPENTRY)); return ZR_OK; } if (index == -1) { ze->index = uf->gi.number_entry; ze->name[0] = 0; ze->attr = 0; ze->atime.dwLowDateTime = 0; ze->atime.dwHighDateTime = 0; ze->ctime.dwLowDateTime = 0; ze->ctime.dwHighDateTime = 0; ze->mtime.dwLowDateTime = 0; ze->mtime.dwHighDateTime = 0; ze->comp_size = 0; ze->unc_size = 0; return ZR_OK; } if (index < (int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file < index) unzGoToNextFile(uf); unz_file_info ufi; char fn[MAX_PATH]; unzGetCurrentFileInfo(uf, &ufi, fn, MAX_PATH, NULL, 0, NULL, 0); // now get the extra header. We do this ourselves, instead of // calling unzOpenCurrentFile &c., to avoid allocating more than necessary. unsigned int extralen, iSizeVar; unsigned long offset; int res = unzlocal_CheckCurrentFileCoherencyHeader(uf, &iSizeVar, &offset, &extralen); if (res != UNZ_OK) return ZR_CORRUPT; if (lufseek(uf->file, offset, SEEK_SET) != 0) return ZR_READ; char *extra = new char[extralen]; if (lufread(extra, 1, (uInt)extralen, uf->file) != extralen) { delete[] extra; return ZR_READ; } // ze->index = uf->num_file; strcpy(ze->name, fn); // zip has an 'attribute' 32bit value. Its lower half is windows stuff // its upper half is standard unix attr. unsigned long a = ufi.external_fa; bool uisdir = (a & 0x40000000) != 0; // bool uwriteable= (a&0x08000000)!=0; bool uwriteable = (a & 0x00800000) != 0; // ***hd*** // bool ureadable= (a&0x01000000)!=0; // bool uexecutable=(a&0x00400000)!=0; bool wreadonly = (a & 0x00000001) != 0; bool whidden = (a & 0x00000002) != 0; bool wsystem = (a & 0x00000004) != 0; bool wisdir = (a & 0x00000010) != 0; bool warchive = (a & 0x00000020) != 0; ze->attr = FILE_ATTRIBUTE_NORMAL; if (uisdir || wisdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY; if (warchive) ze->attr |= FILE_ATTRIBUTE_ARCHIVE; if (whidden) ze->attr |= FILE_ATTRIBUTE_HIDDEN; if (!uwriteable || wreadonly) ze->attr |= FILE_ATTRIBUTE_READONLY; if (wsystem) ze->attr |= FILE_ATTRIBUTE_SYSTEM; ze->comp_size = ufi.compressed_size; ze->unc_size = ufi.uncompressed_size; // WORD dostime = (WORD)(ufi.dosDate & 0xFFFF); WORD dosdate = (WORD)((ufi.dosDate >> 16) & 0xFFFF); FILETIME ft; DosDateTimeToFileTime(dosdate, dostime, &ft); ze->atime = ft; ze->ctime = ft; ze->mtime = ft; // the zip will always have at least that dostime. But if it also has // an extra header, then we'll instead get the info from that. unsigned int epos = 0; while (epos + 4 < extralen) { char etype[3]; etype[0] = extra[epos + 0]; etype[1] = extra[epos + 1]; etype[2] = 0; int size = extra[epos + 2]; if (strcmp(etype, "UT") != 0) { epos += 4 + size; continue; } int flags = extra[epos + 4]; bool hasmtime = (flags & 1) != 0; bool hasatime = (flags & 2) != 0; bool hasctime = (flags & 4) != 0; epos += 5; if (hasmtime) { time_t mtime = *(time_t *)(extra + epos); epos += 4; ze->mtime = timet2filetime(mtime); } if (hasatime) { time_t atime = *(time_t *)(extra + epos); epos += 4; ze->atime = timet2filetime(atime); } if (hasctime) { time_t ctime = *(time_t *)(extra + epos); ze->ctime = timet2filetime(ctime); } break; } // if (extra != 0) delete[] extra; memcpy(&cze, ze, sizeof(ZIPENTRY)); czei = index; return ZR_OK; } ZRESULT TUnzip::Find(const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) { int res = unzLocateFile(uf, name, ic ? CASE_INSENSITIVE : CASE_SENSITIVE); if (res != UNZ_OK) { if (index != 0) *index = -1; if (ze != NULL) { ZeroMemory(ze, sizeof(ZIPENTRY)); ze->index = -1; } return ZR_NOTFOUND; } if (currentfile != -1) unzCloseCurrentFile(uf); currentfile = -1; int i = (int)uf->num_file; if (index != NULL) *index = i; if (ze != NULL) { ZRESULT zres = Get(i, ze); if (zres != ZR_OK) return zres; } return ZR_OK; } void EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) { if (dir == NULL || dir[0] == _T('\0')) return; const TCHAR *lastslash = dir, *c = lastslash; while (*c != _T('\0')) { if (*c == _T('/') || *c == _T('\\')) lastslash = c; c++; } const TCHAR *name = lastslash; if (lastslash != dir) { TCHAR tmp[MAX_PATH]; _tcsncpy(tmp, dir, lastslash - dir); tmp[lastslash - dir] = _T('\0'); EnsureDirectory(rootdir, tmp); name++; } TCHAR cd[MAX_PATH]; _tcscpy(cd, rootdir); //_tcscat(cd,name); _tcscat(cd, dir); //+++1.2 CreateDirectory(cd, NULL); } ZRESULT TUnzip::Unzip(int index, void *dst, unsigned int len, DWORD flags) { if (flags != ZIP_MEMORY && flags != ZIP_FILENAME && flags != ZIP_HANDLE) return ZR_ARGS; if (flags == ZIP_MEMORY) { if (index != currentfile) { if (currentfile != -1) unzCloseCurrentFile(uf); currentfile = -1; if (index >= (int)uf->gi.number_entry) return ZR_ARGS; if (index < (int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file < index) unzGoToNextFile(uf); unzOpenCurrentFile(uf); currentfile = index; } int res = unzReadCurrentFile(uf, dst, len); if (res > 0) return ZR_MORE; unzCloseCurrentFile(uf); currentfile = -1; if (res == 0) return ZR_OK; else return ZR_FLATE; } // otherwise we're writing to a handle or a file if (currentfile != -1) unzCloseCurrentFile(uf); currentfile = -1; if (index >= (int)uf->gi.number_entry) return ZR_ARGS; if (index < (int)uf->num_file) unzGoToFirstFile(uf); while ((int)uf->num_file < index) unzGoToNextFile(uf); ZIPENTRY ze; Get(index, &ze); // zipentry=directory is handled specially if ((ze.attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { if (flags == ZIP_HANDLE) return ZR_OK; // don't do anything #ifdef _UNICODE TCHAR uname[MAX_PATH]; GetUnicodeFileName(ze.name, uname, MAX_PATH - 1); EnsureDirectory(rootdir, uname); #else EnsureDirectory(rootdir, ze.name); #endif return ZR_OK; } // otherwise, we write the zipentry to a file/handle HANDLE h; if (flags == ZIP_HANDLE) h = dst; else { const TCHAR *name = (const TCHAR *)dst; const TCHAR *c = name; while (*c) { if (*c == _T('/') || *c == _T('\\')) name = c + 1; c++; } // if it's a relative filename, ensure directories. We do this as a service // to the caller so they can just unzip straight unto ze.name. if (name != (const TCHAR *)dst) { TCHAR dir[MAX_PATH]; _tcscpy(dir, (const TCHAR *)dst); dir[name - (const TCHAR *)dst - 1] = _T('\0'); bool isabsolute = (dir[0] == _T('/') || dir[0] == _T('\\') || dir[1] == _T(':')); isabsolute |= (_tcsstr(dir, _T("../")) != 0) | (_tcsstr(dir, _T("..\\")) != 0); if (!isabsolute) EnsureDirectory(rootdir, dir); } h = ::CreateFile((const TCHAR *)dst, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, ze.attr, NULL); } if (h == INVALID_HANDLE_VALUE) return ZR_NOFILE; unzOpenCurrentFile(uf); BYTE buf[16384]; bool haderr = false; for (;;) { int res = unzReadCurrentFile(uf, buf, 16384); if (res < 0) { haderr = true; break; } if (res == 0) break; DWORD writ; BOOL bres = WriteFile(h, buf, res, &writ, NULL); if (!bres) { haderr = true; break; } } bool settime = false; DWORD type = GetFileType(h); if (type == FILE_TYPE_DISK && !haderr) settime = true; if (settime) SetFileTime(h, &ze.ctime, &ze.atime, &ze.mtime); if (flags != ZIP_HANDLE) CloseHandle(h); unzCloseCurrentFile(uf); if (haderr) return ZR_WRITE; return ZR_OK; } ZRESULT TUnzip::Close() { if (currentfile != -1) unzCloseCurrentFile(uf); currentfile = -1; if (uf != 0) unzClose(uf); uf = 0; return ZR_OK; } ZRESULT lasterrorU = ZR_OK; unsigned int FormatZipMessageU(ZRESULT code, char *buf, unsigned int len) { if (code == ZR_RECENT) code = lasterrorU; const char *msg = "unknown zip result code"; switch (code) { case ZR_OK: msg = "Success"; break; case ZR_NODUPH: msg = "Culdn't duplicate handle"; break; case ZR_NOFILE: msg = "Couldn't create/open file"; break; case ZR_NOALLOC: msg = "Failed to allocate memory"; break; case ZR_WRITE: msg = "Error writing to file"; break; case ZR_NOTFOUND: msg = "File not found in the zipfile"; break; case ZR_MORE: msg = "Still more data to unzip"; break; case ZR_CORRUPT: msg = "Zipfile is corrupt or not a zipfile"; break; case ZR_READ: msg = "Error reading file"; break; case ZR_ARGS: msg = "Caller: faulty arguments"; break; case ZR_PARTIALUNZ: msg = "Caller: the file had already been partially unzipped"; break; case ZR_NOTMMAP: msg = "Caller: can only get memory of a memory zipfile"; break; case ZR_MEMSIZE: msg = "Caller: not enough space allocated for memory zipfile"; break; case ZR_FAILED: msg = "Caller: there was a previous error"; break; case ZR_ENDED: msg = "Caller: additions to the zip have already been ended"; break; case ZR_ZMODE: msg = "Caller: mixing creation and opening of zip"; break; case ZR_NOTINITED: msg = "Zip-bug: internal initialisation not completed"; break; case ZR_SEEK: msg = "Zip-bug: trying to seek the unseekable"; break; case ZR_MISSIZE: msg = "Zip-bug: the anticipated size turned out wrong"; break; case ZR_NOCHANGE: msg = "Zip-bug: tried to change mind, but not allowed"; break; case ZR_FLATE: msg = "Zip-bug: an internal error during flation"; break; } unsigned int mlen = (unsigned int)strlen(msg); if (buf == 0 || len == 0) return mlen; unsigned int n = mlen; if (n + 1 > len) n = len - 1; strncpy(buf, msg, n); buf[n] = 0; return mlen; } typedef struct { DWORD flag; TUnzip *unz; } TUnzipHandleData; HZIP OpenZipU(void *z, unsigned int len, DWORD flags) { TUnzip *unz = new TUnzip(); lasterrorU = unz->Open(z, len, flags); if (lasterrorU != ZR_OK) { delete unz; return 0; } TUnzipHandleData *han = new TUnzipHandleData; han->flag = 1; han->unz = unz; return (HZIP)han; } ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; lasterrorU = unz->Get(index, ze); return lasterrorU; } ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *zew) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; ZIPENTRY ze; lasterrorU = unz->Get(index, &ze); if (lasterrorU == ZR_OK) { zew->index = ze.index; zew->attr = ze.attr; zew->atime = ze.atime; zew->ctime = ze.ctime; zew->mtime = ze.mtime; zew->comp_size = ze.comp_size; zew->unc_size = ze.unc_size; #ifdef _UNICODE GetUnicodeFileName(ze.name, zew->name, MAX_PATH - 1); #else strcpy(zew->name, ze.name); #endif } return lasterrorU; } ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; lasterrorU = unz->Find(name, ic, index, ze); return lasterrorU; } ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *zew) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; ZIPENTRY ze; lasterrorU = unz->Find(name, ic, index, &ze); if (lasterrorU == ZR_OK) { zew->index = ze.index; zew->attr = ze.attr; zew->atime = ze.atime; zew->ctime = ze.ctime; zew->mtime = ze.mtime; zew->comp_size = ze.comp_size; zew->unc_size = ze.unc_size; #ifdef _UNICODE GetUnicodeFileName(ze.name, zew->name, MAX_PATH - 1); #else strcpy(zew->name, ze.name); #endif } return lasterrorU; } ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; lasterrorU = unz->Unzip(index, dst, len, flags); return lasterrorU; } ZRESULT CloseZipU(HZIP hz) { if (hz == 0) { lasterrorU = ZR_ARGS; return ZR_ARGS; } TUnzipHandleData *han = (TUnzipHandleData *)hz; if (han->flag != 1) { lasterrorU = ZR_ZMODE; return ZR_ZMODE; } TUnzip *unz = han->unz; lasterrorU = unz->Close(); delete unz; delete han; return lasterrorU; } bool IsZipHandleU(HZIP hz) { if (hz == 0) return true; TUnzipHandleData *han = (TUnzipHandleData *)hz; return (han->flag == 1); } ================================================ FILE: common/xzip/XUnzip.h ================================================ // XUnzip.h Version 1.3 // // Authors: Mark Adler et al. (see below) // // Modified by: Lucian Wischik // lu@wischik.com // // Version 1.0 - Turned C files into just a single CPP file // - Made them compile cleanly as C++ files // - Gave them simpler APIs // - Added the ability to zip/unzip directly in memory without // any intermediate files // // Modified by: Hans Dietrich // hdietrich@gmail.com // /////////////////////////////////////////////////////////////////////////////// // // Lucian Wischik's comments: // -------------------------- // THIS FILE is almost entirely based upon code by info-zip. // It has been modified by Lucian Wischik. // The original code may be found at http://www.info-zip.org // The original copyright text follows. // /////////////////////////////////////////////////////////////////////////////// // // Original authors' comments: // --------------------------- // This is version 2002-Feb-16 of the Info-ZIP copyright and license. The // definitive version of this document should be available at // ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely. // // Copyright (c) 1990-2002 Info-ZIP. All rights reserved. // // For the purposes of this copyright and license, "Info-ZIP" is defined as // the following set of individuals: // // Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, // Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase, // Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, // David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, // Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, // Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, // Antoine Verheijen, Paul von Behren, Rich Wales, Mike White // // This software is provided "as is", without warranty of any kind, express // or implied. In no event shall Info-ZIP or its contributors be held liable // for any direct, indirect, incidental, special or consequential damages // arising out of the use of or inability to use this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. Redistributions of source code must retain the above copyright notice, // definition, disclaimer, and this list of conditions. // // 2. Redistributions in binary form (compiled executables) must reproduce // the above copyright notice, definition, disclaimer, and this list of // conditions in documentation and/or other materials provided with the // distribution. The sole exception to this condition is redistribution // of a standard UnZipSFX binary as part of a self-extracting archive; // that is permitted without inclusion of this license, as long as the // normal UnZipSFX banner has not been removed from the binary or disabled. // // 3. Altered versions--including, but not limited to, ports to new // operating systems, existing ports with new graphical interfaces, and // dynamic, shared, or static library versions--must be plainly marked // as such and must not be misrepresented as being the original source. // Such altered versions also must not be misrepresented as being // Info-ZIP releases--including, but not limited to, labeling of the // altered versions with the names "Info-ZIP" (or any variation thereof, // including, but not limited to, different capitalizations), // "Pocket UnZip", "WiZ" or "MacZip" without the explicit permission of // Info-ZIP. Such altered versions are further prohibited from // misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or // of the Info-ZIP URL(s). // // 4. Info-ZIP retains the right to use the names "Info-ZIP", "Zip", "UnZip", // "UnZipSFX", "WiZ", "Pocket UnZip", "Pocket Zip", and "MacZip" for its // own source and binary releases. // /////////////////////////////////////////////////////////////////////////////// #ifndef XUNZIP_H #define XUNZIP_H #ifndef XZIP_H DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened #endif typedef DWORD ZRESULT; // return codes from any of the zip functions. Listed later. #define ZIP_HANDLE 1 #define ZIP_FILENAME 2 #define ZIP_MEMORY 3 typedef struct { int index; // index of this file within the zip char name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRY; typedef struct { int index; // index of this file within the zip TCHAR name[MAX_PATH]; // filename within the zip DWORD attr; // attributes, as in GetFileAttributes. FILETIME atime,ctime,mtime;// access, create, modify filetimes long comp_size; // sizes of item, compressed and uncompressed. These long unc_size; // may be -1 if not yet known (e.g. being streamed in) } ZIPENTRYW; // #ifdef _UNICODE // #define ZIPENTRY ZIPENTRYW // #else // #define ZIPENTRY ZIPENTRYA // #endif /////////////////////////////////////////////////////////////////////////////// // // OpenZip() // // Purpose: Open an existing zip archive file // // Parameters: z - archive file name if flags is ZIP_FILENAME; for other // uses see below // len - for memory (ZIP_MEMORY) should be the buffer size; // for other uses, should be 0 // flags - indicates usage, see below; for files, this will be // ZIP_FILENAME // // Returns: HZIP - non-zero if zip archive opened ok, otherwise 0 // HZIP OpenZip(void *z, unsigned int len, DWORD flags); // OpenZip - opens a zip file and returns a handle with which you can // subsequently examine its contents. You can open a zip file from: // from a pipe: OpenZip(hpipe_read,0, ZIP_HANDLE); // from a file (by handle): OpenZip(hfile,0, ZIP_HANDLE); // from a file (by name): OpenZip("c:\\test.zip",0, ZIP_FILENAME); // from a memory block: OpenZip(bufstart, buflen, ZIP_MEMORY); // If the file is opened through a pipe, then items may only be // accessed in increasing order, and an item may only be unzipped once, // although GetZipItem can be called immediately before and after unzipping // it. If it's opened i n any other way, then full random access is possible. // Note: pipe input is not yet implemented. /////////////////////////////////////////////////////////////////////////////// // // GetZipItem() // // Purpose: Get information about an item in an open zip archive // // Parameters: hz - handle of open zip archive // index - index number (0 based) of item in zip // ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct // (if Unicode) // // Returns: ZRESULT - ZR_OK if success, otherwise some other value // #ifdef _UNICODE #define GetZipItem GetZipItemW #else #define GetZipItem GetZipItemA #endif ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze); ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze); // GetZipItem - call this to get information about an item in the zip. // If index is -1 and the file wasn't opened through a pipe, // then it returns information about the whole zipfile // (and in particular ze.index returns the number of index items). // Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY) // See below for notes on what happens when you unzip such an item. // Note: if you are opening the zip through a pipe, then random access // is not possible and GetZipItem(-1) fails and you can't discover the number // of items except by calling GetZipItem on each one of them in turn, // starting at 0, until eventually the call fails. Also, in the event that // you are opening through a pipe and the zip was itself created into a pipe, // then then comp_size and sometimes unc_size as well may not be known until // after the item has been unzipped. /////////////////////////////////////////////////////////////////////////////// // // FindZipItem() // // Purpose: Find item by name and return information about it // // Parameters: hz - handle of open zip archive // name - name of file to look for inside zip archive // ic - TRUE = case insensitive // index - pointer to index number returned, or -1 // ze - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct // (if Unicode) // // Returns: ZRESULT - ZR_OK if success, otherwise some other value // #ifdef _UNICODE #define FindZipItem FindZipItemW #else #define FindZipItem FindZipItemA #endif ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze); ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze); // FindZipItem - finds an item by name. ic means 'insensitive to case'. // It returns the index of the item, and returns information about it. // If nothing was found, then index is set to -1 and the function returns // an error code. /////////////////////////////////////////////////////////////////////////////// // // UnzipItem() // // Purpose: Find item by index and unzip it // // Parameters: hz - handle of open zip archive // index - index number of file to unzip // dst - target file name of unzipped file // len - for memory (ZIP_MEMORY. length of buffer; // otherwise 0 // flags - indicates usage, see below; for files, this will be // ZIP_FILENAME // // Returns: ZRESULT - ZR_OK if success, otherwise some other value // ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags); // UnzipItem - given an index to an item, unzips it. You can unzip to: // to a pipe: UnzipItem(hz,i, hpipe_write,0,ZIP_HANDLE); // to a file (by handle): UnzipItem(hz,i, hfile,0,ZIP_HANDLE); // to a file (by name): UnzipItem(hz,i, ze.name,0,ZIP_FILENAME); // to a memory block: UnzipItem(hz,i, buf,buflen,ZIP_MEMORY); // In the final case, if the buffer isn't large enough to hold it all, // then the return code indicates that more is yet to come. If it was // large enough, and you want to know precisely how big, GetZipItem. // Note: zip files are normally stored with relative pathnames. If you // unzip with ZIP_FILENAME a relative pathname then the item gets created // relative to the current directory - it first ensures that all necessary // subdirectories have been created. Also, the item may itself be a directory. // If you unzip a directory with ZIP_FILENAME, then the directory gets created. // If you unzip it to a handle or a memory block, then nothing gets created // and it emits 0 bytes. /////////////////////////////////////////////////////////////////////////////// // // CloseZip() // // Purpose: Close an open zip archive // // Parameters: hz - handle to an open zip archive // // Returns: ZRESULT - ZR_OK if success, otherwise some other value // ZRESULT CloseZip(HZIP hz); // CloseZip - the zip handle must be closed with this function. unsigned int FormatZipMessage(ZRESULT code, char *buf,unsigned int len); // FormatZipMessage - given an error code, formats it as a string. // It returns the length of the error message. If buf/len points // to a real buffer, then it also writes as much as possible into there. // These are the result codes: #define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned, #define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage. // The following come from general system stuff (e.g. files not openable) #define ZR_GENMASK 0x0000FF00 #define ZR_NODUPH 0x00000100 // couldn't duplicate the handle #define ZR_NOFILE 0x00000200 // couldn't create/open the file #define ZR_NOALLOC 0x00000300 // failed to allocate some resource #define ZR_WRITE 0x00000400 // a general error writing to the file #define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip #define ZR_MORE 0x00000600 // there's still more data to be unzipped #define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile #define ZR_READ 0x00000800 // a general error reading the file // The following come from mistakes on the part of the caller #define ZR_CALLERMASK 0x00FF0000 #define ZR_ARGS 0x00010000 // general mistake with the arguments #define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't #define ZR_MEMSIZE 0x00030000 // the memory size is too small #define ZR_FAILED 0x00040000 // the thing was already failed when you called this function #define ZR_ENDED 0x00050000 // the zip creation has already been closed #define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken #define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped #define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip // The following come from bugs within the zip library itself #define ZR_BUGMASK 0xFF000000 #define ZR_NOTINITED 0x01000000 // initialisation didn't work #define ZR_SEEK 0x02000000 // trying to seek in an unseekable file #define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed #define ZR_FLATE 0x05000000 // an internal error in the de/inflation code // e.g. // // SetCurrentDirectory("c:\\docs\\stuff"); // HZIP hz = OpenZip("c:\\stuff.zip",0,ZIP_FILENAME); // ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index; // for (int i=0; i Debug Win32 Release Win32 17.0 Downloader {D175BBA1-8E6A-4592-8F6C-3ABA862250BB} Downloader 10.0 Application v143 false Unicode Application v143 false Unicode <_ProjectFileVersion>17.0.34018.303 .\Release\ .\Release\ false false false .\Debug\ .\Debug\ true false false NDEBUG;%(PreprocessorDefinitions) true true Win32 .\Release\Downloader.tlb MinSpace Default false Size false false ./;../common;../WTL;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;UNICODE;SQLITE_HAS_CODEC;COMPILER_MSVC;_USE_32BIT_TIME_T;%(PreprocessorDefinitions) true MultiThreaded true false Use stdafx.h .\Release\$(ProjectName).pch .\Release\ .\Release\ .\Release\ Level2 true ProgramDatabase stdcpp14 Async NDEBUG;%(PreprocessorDefinitions) 0x0804 .\Release\$(ProjectName).exe true %(AdditionalLibraryDirectories) RequireAdministrator false true .\Release\$(ProjectName).pdb Windows false false MachineX86 false true .\Release\$(ProjectName).bsc del /f /q ..\0utPut\Release xcopy /Y $(OutDir)$(TargetFileName) ..\0utPut\Release\ ..\bin\upx-4.1.0-win32\upx.exe ..\0utPut\Release\Downloader.exe -o ..\0utPut\Release\CompressedDownloader.exe _DEBUG;%(PreprocessorDefinitions) true true Win32 .\Debug\Downloader.tlb /EHa %(AdditionalOptions) Disabled ./;../common;../WTL;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;UNICODE;SQLITE_HAS_CODEC;COMPILER_MSVC;_USE_32BIT_TIME_T;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug false Use stdafx.h .\Debug\$(ProjectName).pch .\Debug\ .\Debug\ .\Debug\ true Level3 true EditAndContinue stdcpp14 Async _DEBUG;%(PreprocessorDefinitions) 0x0804 .\Debug\$(ProjectName).exe true %(AdditionalLibraryDirectories) RequireAdministrator true .\Debug\$(ProjectName).pdb Windows false false MachineX86 false true .\Debug\$(ProjectName).bsc xcopy $(OutDir)$(TargetFileName) ..\0utPut\Debug\ /Y NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing NotUsing Use Create Create ================================================ FILE: src/App.vcxproj.filters ================================================  {36f9056a-636c-40bc-96cd-25e4593e0c6c} ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe {fca6d130-8e3d-4966-9e99-c1844aef3e18} {2db7664e-c8fb-4e80-b5b5-6f9d455d4b20} {c64e9972-b794-47dc-8084-1b1ff1849fdc} {0bfba4d8-4763-41f4-b73e-8ca8b37d9a5f} h;hpp;hxx;hm;inl {2a1a6d63-56a0-44dd-9507-2b1afd266b54} cpp;c;cxx;rc;def;r;odl;idl;hpj;bat {79608960-972b-4ef6-8402-d1badcb3d89e} {3177097e-e870-4533-839c-ff574fcea022} {02db92af-b773-4c23-8db0-69921050af59} {f2292b24-3b2c-4df8-ad50-aa59b70f48dd} {6d1bdfe8-e533-40c7-92f0-9f8ee843fe73} {d7cf154b-894a-4f17-ba2c-57aa29546709} {b1d7c97d-e37c-4702-8e4a-fea518bc67a9} {ebeb2e1b-6ecb-42b6-850c-647eb39e0436} {a461547a-0e97-40c5-91a8-cbdecd80186a} {7b4c229b-5ab9-42ae-bc7c-7736a3d3d6c4} {c78cdafb-789f-48cc-b4cc-81126be49e04} {547d1d3c-aa70-4228-9a56-63fc1d3250aa} Resource Files Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\asset Resource Files\xml Resource Files\xml Resource Files\xml Resource Files\xml Resource Files\xml Resource Files\xml Resource Files\xml Resource Files\xml UI UI UI Event Source Files Source Files DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI Time Net Base Base Base Base Base Base Base Base Base Base Base Base DownLoader DownLoader DownLoader LogAssist Base Base Language UI UI Common Xml Xml Xml Xml Xml Uzip Json Json Json Common Common Common Common UI UI UI Event Header Files Header Files DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI DirectUI Time Net Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base Base DownLoader DownLoader DownLoader LogAssist Base Base Base Base Base Base Language UI UI Common Xml Xml Xml Uzip Common Common Common Common Common Header Files Header Files Resource Files ================================================ FILE: src/DirectUI/DUIButton.cpp ================================================ #include "StdAfx.h" #include "DUIButton.h" CButtonCtl::CButtonCtl(HWND father, BOOL trans) { _host = father; _class = _T("DirectButton"); _transparent = trans; _tracking = FALSE; _down = FALSE; _state = DUI_STATE_NORMAL; _bmpBtn = NULL; _bmpIcon = NULL; _bmpSmallIcon = NULL; _colText = RGB(0, 0, 0); _colHover = RGB(0, 0, 0); _colDown = RGB(0, 0, 0); _colDisable = RGB(0, 0, 0); _vertical_flag = FALSE; _nTextLimitLength = 0; _textFont = NULL; _hdelta = 0; } CButtonCtl::CButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans) : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _host = father; _class = _T("DirectButton"); _transparent = trans; _tracking = FALSE; _down = FALSE; _state = DUI_STATE_NORMAL; _bmpBtn = NULL; _bmpIcon = NULL; _bmpSmallIcon = NULL; _colText = RGB(0, 0, 0); _colHover = RGB(0, 0, 0); _colDown = RGB(0, 0, 0); _colDisable = RGB(0, 0, 0); _vertical_flag = FALSE; _nTextLimitLength = 0; _textFont = NULL; _hdelta = 0; } CButtonCtl::~CButtonCtl(void) {} void CButtonCtl::SetColor(COLORREF colText, COLORREF colHover, COLORREF colDown) { _colText = colText; _colHover = colHover; _colDown = colDown; } void CButtonCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBtn = GetBitmapAttribute(element, "image"); _bmpIcon = GetBitmapAttribute(element, "icon"); _bmpSmallIcon = GetBitmapAttribute(element, "smallicon"); _colText = GetRGBAttribute(element, "textcolor"); _colHover = GetRGBAttribute(element, "hovercolor"); _colDown = GetRGBAttribute(element, "downcolor"); _colDisable = GetRGBAttribute(element, "discolor"); _rcCorners = GetRectAttribute(element, "corner"); _hdelta = GetIntegerAttribute(element, "hdelta"); if (GetIntegerAttribute(element, "bigfont")) { _textFont = CGDIResource::GetInstance().GDI_GetBiggerFont(); } } void CButtonCtl::SetCorner(DUI_Rect rcCorners) { CopyRect(&_rcCorners, &rcCorners); } void CButtonCtl::Disable() { _state = DUI_STATE_DISABLE; Refresh(DUI_STATE_DISABLE); } void CButtonCtl::Enable(BOOL enable) { DUI_BUTTON_STATE state; if (enable) state = DUI_STATE_NORMAL; else state = DUI_STATE_DISABLE; if (_state != state) { _state = state; RaiseInvalidate(TRUE); } } void CButtonCtl::SetImage(LPCTSTR lpszImageRes) { _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG); } void CButtonCtl::SetImage(HBITMAP bmp) { _bmpBtn = bmp; } void CButtonCtl::SetImageFile(LPCTSTR lpszImageFile) { _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(lpszImageFile); } void CButtonCtl::SetIcon(LPCTSTR lpszImageRes) { _bmpIcon = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG); } void CButtonCtl::SetIcon(HBITMAP hIcon) { _bmpIcon = hIcon; } void CButtonCtl::SetSmallIcon(LPCTSTR lpszImageRes) { _bmpSmallIcon = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG); } void CButtonCtl::SetSmallIconFile(LPCTSTR lpszImageFile) { _bmpSmallIcon = CGDIResource::GetInstance().GDI_GetBitmap(lpszImageFile); } void CButtonCtl::SetVertical() { _vertical_flag = TRUE; } void CButtonCtl::SetTitle(const tstring &title) { _title = title; } void CButtonCtl::OnPaint(HDC hDC) { if (_visible) { BITMAP bmpInfor; GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor); DUI_Rect rcDest(_location, _size); int nImageOffset = 0; COLORREF col = _colText; switch (_state) { case DUI_STATE_NORMAL: nImageOffset = 0; col = _colText; break; case DUI_STATE_HOVER: nImageOffset = 1; col = _colHover; break; case DUI_STATE_DOWN: nImageOffset = 2; col = _colDown; break; case DUI_STATE_DISABLE: nImageOffset = 3; col = _colDisable; break; } DUI_Rect rcSrc; DUI_Size sz; if (!_vertical_flag) { sz.cx = bmpInfor.bmWidth / 4; sz.cy = bmpInfor.bmHeight; rcSrc.left = nImageOffset * sz.cx; rcSrc.top = 0; rcSrc.right = rcSrc.left + sz.cx; rcSrc.bottom = rcSrc.top + sz.cy; } else { sz.cx = bmpInfor.bmWidth; sz.cy = bmpInfor.bmHeight / 4; rcSrc.left = 0; rcSrc.top = nImageOffset * sz.cy; rcSrc.right = rcSrc.left + sz.cx; rcSrc.bottom = rcSrc.top + sz.cy; } if (_bmpBtn) { if (rcDest.Width() > rcSrc.Width() || rcDest.Height() > rcSrc.Height()) { if (_rcCorners.Width() == 0 && _rcCorners.Height() == 0) { CopyRect(&_rcCorners, CRect(3, 6, 3, 6)); } CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpBtn, rcDest, rcSrc, 255, _rcCorners); } else { CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcDest, rcSrc, DUI_BT_ALPHA); } } DUI_Rect rcIcon; if (_bmpIcon) { BITMAP bmpInfo; GetObject(_bmpIcon, sizeof(bmpInfo), &bmpInfo); DUI_Rect rcBmp; sz.cx = bmpInfo.bmWidth / 4; sz.cy = bmpInfo.bmHeight; rcBmp.left = nImageOffset * sz.cx; rcBmp.top = 0; rcBmp.right = rcBmp.left + sz.cx; rcBmp.bottom = rcBmp.top + sz.cy; rcIcon.CopyRect(&rcBmp); POINT point; point.y = rcDest.top; point.x = rcDest.left; CSize size; SelectObject(hDC, CGDIResource::GetInstance().GDI_GetNormalFont()); if (::GetTextExtentPoint32(hDC, _title.c_str(), _title.size(), &size)) { if (size.cx > 0) size.cx += 5; int nLeft = (rcDest.Width() - size.cx - rcIcon.Width()) / 2; point.x = nLeft > 0 ? point.x + nLeft : point.x; int nTop = (rcDest.Height() - rcIcon.Height()) / 2; point.y = nTop > 0 ? point.y + nTop : point.y; } rcIcon.MoveToXY(point); CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, rcIcon, rcBmp, DUI_BT_ALPHA); } if (_bmpSmallIcon) { BITMAP bmpInfo; GetObject(_bmpSmallIcon, sizeof(bmpInfo), &bmpInfo); CSize Txtsize; ::GetTextExtentPoint32(hDC, _title.c_str(), _title.length(), &Txtsize); rcIcon.left = rcDest.left + (rcDest.right - rcDest.left - (bmpInfo.bmWidth + Txtsize.cx + 5)) / 2; rcIcon.top = rcDest.top + (rcDest.Height() - bmpInfo.bmHeight) / 2; rcIcon.right = rcIcon.left + bmpInfo.bmWidth; rcIcon.bottom = rcIcon.top + bmpInfo.bmHeight; CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpSmallIcon, rcIcon); } if (!_title.empty()) { rcDest.top += _hdelta; UINT nFormat = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; if (_bmpIcon || _bmpSmallIcon) { rcDest.left = rcIcon.right + 5; if (_nTextLimitLength > 0) rcDest.right = rcDest.left + _nTextLimitLength; nFormat = nFormat | DT_LEFT; } else nFormat = nFormat | DT_CENTER; if (_transparent) { if (!_textFont) CGDIResource::GetInstance().GDI_DrawText_Trans(hDC, _title.c_str(), &rcDest, col, nFormat); else if (DUI_STATE_DISABLE == _state) CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcDest, _textFont, col, nFormat); else CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcDest, _textFont, col, nFormat); } else { CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcDest, _textFont, col, nFormat); } } } } void CButtonCtl::OnMouseHover(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { if (_down) { Refresh(DUI_STATE_DOWN); } else { Refresh(DUI_STATE_HOVER); } } } void CButtonCtl::OnMouseLeave() { _down = FALSE; _tracking = FALSE; if (_state != DUI_STATE_DISABLE) { Refresh(DUI_STATE_NORMAL); } } void CButtonCtl::Refresh(DUI_BUTTON_STATE nowstate) { if (_state != nowstate) { _state = nowstate; RaiseInvalidate(TRUE); } } void CButtonCtl::OnMouseDown(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { _down = TRUE; Refresh(DUI_STATE_DOWN); OnMouseDownClick(); } } void CButtonCtl::OnMouseUp(UINT nFlags, CPoint point) { if (_visible) { if (_state != DUI_STATE_DISABLE) { DUI_BUTTON_STATE state = _state; Refresh(DUI_STATE_HOVER); if (_down && (state == DUI_STATE_DOWN)) { OnMouseClick(); } _down = FALSE; } } } void CButtonCtl::OnMouseDownClick() { _leftdown_event.Invoke(); } void CButtonCtl::SetTextLimitLength(int nLength) { _nTextLimitLength = nLength; } void CButtonCtl::OnCall_LeftUp() { if (_leftup_event.m_func_no_para) _leftup_event.Invoke(); else if (_leftup_event.m_func_para_string) _leftup_event.Invoke(_id.c_str()); } void CButtonCtl::OnCall_RightUp() { if (_rightup_event.m_func_no_para) _rightup_event.Invoke(); else if (_rightup_event.m_func_para_string) _rightup_event.Invoke(_id.c_str()); } ================================================ FILE: src/DirectUI/DUIButton.h ================================================ #pragma once #include "DUIDef.h" #include "DUIElement.h" class CButtonCtl : public CBaseElementCtl { public: CButtonCtl(HWND father, BOOL trans = FALSE); CButtonCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE); ~CButtonCtl(void); void Disable(); void Enable(BOOL enable); void CreateElement(XmlElementPtr element); void SetImage(LPCTSTR lpszImageRes); void SetImage(HBITMAP bmp); void SetIcon(LPCTSTR lpszImageRes); virtual void SetIcon(HBITMAP hIcon); void SetSmallIcon(LPCTSTR lpszImageRes); void SetSmallIconFile(LPCTSTR lpszImageFile); void SetImageFile(LPCTSTR lpszImageFile); void SetVertical(); void SetTitle(const tstring &title); void SetColor(COLORREF colText, COLORREF colHover, COLORREF colDown); void SetTextLimitLength(int nLength); void SetCorner(DUI_Rect rcCorners); void OnCall_LeftUp(); void OnCall_RightUp(); void SetTextFont(HFONT font) { _textFont = font; } protected: BOOL _tracking; BOOL _down; DUI_BUTTON_STATE _state; HBITMAP _bmpBtn; HBITMAP _bmpIcon; HBITMAP _bmpSmallIcon; COLORREF _colText; COLORREF _colHover; COLORREF _colDown; COLORREF _colDisable; BOOL _vertical_flag; int _nTextLimitLength; DUI_Rect _rcCorners; HFONT _textFont; int _hdelta; public: void Refresh(DUI_BUTTON_STATE nowstate); virtual void OnPaint(HDC hDC); virtual void OnMouseHover(UINT nFlags, CPoint point); virtual void OnMouseLeave(); virtual void OnMouseDown(UINT nFlags, CPoint point); virtual void OnMouseUp(UINT nFlags, CPoint point); virtual void OnMouseDownClick(); }; ================================================ FILE: src/DirectUI/DUICheckBox.cpp ================================================ #include "StdAfx.h" #include "DUICheckBox.h" CCheckBoxCtl::CCheckBoxCtl(HWND father, BOOL trans) : CButtonCtl(father) { _class = _T(""); _transparent = trans; _txtColor = RGB(67, 75, 94); _bChecked = FALSE; _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("CHECK_BOX"), PNG); } CCheckBoxCtl::CCheckBoxCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _class = _T(""); _txtColor = RGB(67, 75, 94); _bChecked = FALSE; _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("CHECK_BOX"), PNG); } CCheckBoxCtl::~CCheckBoxCtl(void) {} void CCheckBoxCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBtn = GetBitmapAttribute(element, "image"); _txtColor = GetRGBAttribute(element, "textcolor"); } void CCheckBoxCtl::Enable(BOOL enable) { if (enable) { switch (_state) { case DUI_STATE_NORMAL_DISABLE: _state = DUI_STATE_NORMAL; break; case DUI_STATE_DOWN_DISABLE: _state = DUI_STATE_DOWN; break; default: break; } } else { Disable(); } } void CCheckBoxCtl::OnPaint(HDC hDC) { BITMAP bmpInfor; GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor); int nCheckWidth = bmpInfor.bmWidth / 2; DUI_Size szCheckImage(nCheckWidth, bmpInfor.bmHeight); DUI_Point ptCheckImage(_location.x, _location.y + (_size.cy - bmpInfor.bmHeight) / 2); DUI_Rect rcImage(ptCheckImage, szCheckImage); int nImageOffset = 0; switch (_state) { case DUI_STATE_NORMAL: case DUI_STATE_HOVER: nImageOffset = 0; break; case DUI_STATE_DOWN: nImageOffset = 1; break; case DUI_STATE_NORMAL_DISABLE: nImageOffset = 2; break; case DUI_STATE_DOWN_DISABLE: nImageOffset = 3; break; } DUI_Rect rcSrc(DUI_Point(nImageOffset * nCheckWidth, 0), DUI_Size(nCheckWidth, bmpInfor.bmHeight)); CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcImage, rcSrc); DUI_Rect rcText(DUI_Point(rcImage.right + 5, _location.y), DUI_Size(_size.cx - rcImage.Width() - 1, _size.cy)); if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcText, _txtColor, DT_LEFT | DT_SINGLELINE | DT_VCENTER); } else { CGDIResource::GetInstance().GDI_DrawText( hDC, _title.c_str(), &rcText, _txtColor, DT_LEFT | DT_SINGLELINE | DT_VCENTER); } } void CCheckBoxCtl::Disable() { switch (_state) { case DUI_STATE_NORMAL: _state = DUI_STATE_NORMAL_DISABLE; break; case DUI_STATE_DOWN: _state = DUI_STATE_DOWN_DISABLE; break; default: break; } } void CCheckBoxCtl::OnMouseDown(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { _down = !_down; if (_down) { Refresh(DUI_STATE_DOWN); _bChecked = TRUE; } else { Refresh(DUI_STATE_NORMAL); _bChecked = FALSE; } OnMouseDClick(); } } void CCheckBoxCtl::OnMouseUp(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { OnMouseClick(); } } void CCheckBoxCtl::OnMouseHover(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { if (_down) { Refresh(DUI_STATE_DOWN); } else { Refresh(DUI_STATE_HOVER); } } } void CCheckBoxCtl::OnMouseLeave() { _tracking = FALSE; if (_state != DUI_STATE_DISABLE) { if (!_down) { Refresh(DUI_STATE_NORMAL); } } } void CCheckBoxCtl::SetCheck(BOOL bCheck) { _bChecked = bCheck; if (_state != DUI_STATE_DISABLE) { if (_bChecked) { _state = DUI_STATE_DOWN; _down = TRUE; } else { _state = DUI_STATE_NORMAL; _down = FALSE; } } } BOOL CCheckBoxCtl::GetCheck() { return _bChecked; } ================================================ FILE: src/DirectUI/DUICheckBox.h ================================================ #pragma once #include "DUIButton.h" class CCheckBoxCtl : public CButtonCtl { public: CCheckBoxCtl(HWND father, BOOL trans = FALSE); CCheckBoxCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); ~CCheckBoxCtl(void); void SetCheck(BOOL bCheck); BOOL GetCheck(); void Disable(); void Enable(BOOL enable); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void OnMouseDown(UINT nFlags, CPoint point); void OnMouseUp(UINT nFlags, CPoint point); void OnMouseHover(UINT nFlags, CPoint point); void OnMouseLeave(); protected: COLORREF _txtColor; BOOL _bChecked; }; ================================================ FILE: src/DirectUI/DUIDef.h ================================================ #pragma once #include #include #include #include #include #include #include "../resource.h" #include "xml/xmlhelper.h" typedef WTL::CPoint DUI_Point; typedef WTL::CSize DUI_Size; typedef WTL::CRect DUI_Rect; typedef enum { DUI_BT_NORMAL = 0, DUI_BT_TRANS, DUI_BT_ALPHA } DUI_BITMAP_TYPE; typedef enum { DUI_ALIGNMENT_NONE = 0, DUI_ALIGNMENT_LEFT, DUI_ALIGNMENT_TOP, DUI_ALIGNMENT_RIGHT, DUI_ALIGNMENT_BOTTOM, DUI_ALIGNMENT_CENTER } DUI_ALIGNMENT; typedef enum { DUI_STRETCH_NONE = 0, DUI_STRETCH_SCALE, DUI_STRETCH_FILL, DUI_STRETCH_HORIZONTAL, DUI_STRETCH_VERTICAL } DUI_STRETCH; typedef enum { DUI_STATE_NORMAL = 0, DUI_STATE_DOWN, DUI_STATE_HOVER, DUI_STATE_DISABLE, DUI_STATE_NORMAL_DISABLE, DUI_STATE_DOWN_DISABLE, DUI_STATE_HOVER_DISABLE } DUI_BUTTON_STATE; void TrackMouseLeave(HWND hWnd); #define TRANSPARENT_COLOR RGB(255, 0, 255) #define WM_MSG_TIPS WM_USER + 0x1000 #define WM_MSG_CURSOR WM_USER + 0x1001 #define WM_MSG_ICON_NOTIFY WM_USER + 0x1002 #define WM_MSG_POP_MENU WM_USER + 0x1003 #define WM_MSG_TREE_SCROLLBAR WM_USER + 0x1004 #define WM_MSG_BEGIN_SCROLL WM_USER + 0x1005 #define WM_MSG_ACTIVE WM_USER + 0x1006 #define WM_ASYNC_CALL_LUP WM_USER + 0x1020 #define WM_ASYNC_CALL_RUP WM_USER + 0x1021 #define WM_ASYNC_CALL_DROPUP WM_USER + 0x1022 #define WM_ASYNC_CALL_ENTERKEY WM_USER + 0x1023 #define WM_ASYNC_CALL_TABKEY WM_USER + 0x1024 #define WM_ASYNC_CALL_LDBCLICK WM_USER + 0x1025 #define WM_ASYNC_CALL_LDOWN WM_USER + 0x1026 #define WM_RADIOBUTTON_DOWN WM_USER + 0x2ae0 #define WM_CONTROL_TAB WM_USER + 0x2ae1 #define WM_PATH_ILLCHARACTER WM_USER + 0x2ae2 #define MSG_UPDATE_WINDOW_INVALIDATE (WM_USER + 0x5000) #define ACTIVE_TIMER 0x200 ================================================ FILE: src/DirectUI/DUIElement.cpp ================================================ #include "StdAfx.h" #include "DUIElement.h" CBaseElementCtl::CBaseElementCtl() : _editCheckPath(FALSE) { _handleMouse = TRUE; _handleKeyboard = FALSE; _viscur = FALSE; _active = FALSE; _host = NULL; _visible = TRUE; _transparent = FALSE; _id = _T(""); _name = _T(""); _base_pt.x = 0; _base_pt.y = 0; _location.x = 0; _location.y = 0; _size.cx = 0; _size.cy = 0; _cursor = LoadCursor(NULL, IDC_ARROW); } CBaseElementCtl::CBaseElementCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : _editCheckPath(FALSE) { _handleMouse = TRUE; _handleKeyboard = FALSE; _viscur = FALSE; _active = FALSE; _host = father; _visible = TRUE; _id = lpszID; _name = lpszID; _title = lpszTitle; _tip = lpszTooptip; _base_pt.x = 0; _base_pt.y = 0; _location.x = rcElement.left; _location.y = rcElement.top; _size.cx = rcElement.Width(); _size.cy = rcElement.Height(); _cursor = LoadCursor(NULL, IDC_ARROW); } CBaseElementCtl::~CBaseElementCtl(void) {} void CBaseElementCtl::CreateElement(XmlElementPtr element) {} void CBaseElementCtl::GetElementStyle(XmlElementPtr element) { CXmlHelper helper; _id = helper.GetAttributeString(element, "id"); _name = helper.GetAttributeString(element, "name"); _title = helper.GetAttributeString(element, "title"); _tip = helper.GetAttributeString(element, "tip"); _style = helper.GetAttributeInt(element, "style"); _ex_style = helper.GetAttributeInt(element, "style_ex"); _location.x = helper.GetAttributeInt(element, "left"); _location.y = helper.GetAttributeInt(element, "top"); _size.cx = helper.GetAttributeInt(element, "width"); _size.cy = helper.GetAttributeInt(element, "height"); _ori_location = _location; _ori_size = _size; LoadStyle(element); } void CBaseElementCtl::OnKeyDown(DWORD dwFlag) {} void CBaseElementCtl::OnKeyUp(DWORD dwFlag) {} void CBaseElementCtl::OnMouseClick() { ::PostMessage(_host, WM_ASYNC_CALL_LUP, (WPARAM)this, 0); } void CBaseElementCtl::OnMouseDClick() { ::PostMessage(_host, WM_ASYNC_CALL_LDOWN, (WPARAM)this, 0); } void CBaseElementCtl::OnCall_LeftUp() { _leftup_event.Invoke(); } void CBaseElementCtl::OnCall_LeftDown() { _leftdown_event.Invoke(); } void CBaseElementCtl::OnMove() {} void CBaseElementCtl::OnMouseDblDown(UINT nFlags, CPoint point) { OnMouseDClick(); } void CBaseElementCtl::OnMouseDown(UINT nFlags, CPoint point) {} void CBaseElementCtl::OnMouseUp(UINT nFlags, CPoint point) {} void CBaseElementCtl::OnMouseLDbClick(UINT nFlags, CPoint point) {} void CBaseElementCtl::OnMouseRUp(UINT nFlags, CPoint point) { ::PostMessage(_host, WM_ASYNC_CALL_RUP, (WPARAM)this, 0); } void CBaseElementCtl::OnCall_RightUp() { _rightup_event.Invoke(); } void CBaseElementCtl::OnCall_LDbClick() { if (_leftDbclick_event.m_func_no_para) _leftDbclick_event.Invoke(); else if (_leftDbclick_event.m_func_para_string) _leftDbclick_event.Invoke(_id.c_str()); } void CBaseElementCtl::OnEnterKey() { ::PostMessage(_host, WM_ASYNC_CALL_ENTERKEY, (WPARAM)this, 0); } void CBaseElementCtl::OnCall_EnterKey() { _enterkey_event.Invoke(); } void CBaseElementCtl::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) {} void CBaseElementCtl::OnMouseHover(UINT nFlags, CPoint point) { _hover_event.Invoke(); } void CBaseElementCtl::OnMouseLeave() { _leave_event.Invoke(); } void CBaseElementCtl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) {} void CBaseElementCtl::OnPaint(HDC hDC) {} void CBaseElementCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) { CRect rc; rc = StyleRectToWindowRect(DUI_Rect(_location, _size), _ori_location, wndChangingSize, CSize(w, h), _xAlignment, _yAlignment, _xStretch, _yStretch); _location.x = rc.left; _location.y = rc.top; _size.cx = rc.Width(); _size.cy = rc.Height(); } void CBaseElementCtl::RaiseInvalidate(BOOL forceRedraw) { if (_host != NULL) { if (forceRedraw) { if (_transparent) { ::PostMessage(_host, MSG_UPDATE_WINDOW_INVALIDATE, 0, 100); } else { ::InvalidateRect(_host, Rectangle(), TRUE); } } } } int CBaseElementCtl::GetTextWidth(LPCTSTR lpszText, HFONT hFont) { CPaintDC dc(_host); HFONT hOldFont = dc.SelectFont(hFont); ::SetBkMode(dc.m_hDC, TRANSPARENT); CSize szText; ::GetTextExtentPoint32(dc.m_hDC, lpszText, lstrlen(lpszText), &szText); dc.SelectFont(hOldFont); return szText.cx; } ================================================ FILE: src/DirectUI/DUIElement.h ================================================ #pragma once #include "DUIDef.h" #include "DUIGDIResource.h" #include "DUIWindowStyle.h" #include "EventHandler.h" class __declspec(novtable) CBaseElementCtl : public CWindowCtlStyle { public: CBaseElementCtl(); CBaseElementCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); virtual ~CBaseElementCtl(void); virtual void CreateElement(XmlElementPtr element); virtual tstring GetID(); virtual tstring GetName(); virtual tstring GetTitle(); virtual tstring GetTooltip(); virtual tstring &GetWndClassName(); virtual void SetTitle(const tstring &csName); virtual void SetTooltip(const tstring &strTip); virtual void SetID(const tstring &id); virtual void SetName(const tstring &id); virtual void SetHandleMouse(BOOL mouse); virtual BOOL GetVisible(); virtual BOOL GetHandleMouse(); virtual void SetVisible(BOOL bVisible); virtual void SetHandleKeyboard(BOOL keyboard); virtual BOOL GetHandleKeyboard(); virtual void SetActive(BOOL active); virtual void SetActive(CBaseElementCtl *element); virtual BOOL GetActive(); virtual void SetVisibleCur(BOOL bVisible); virtual BOOL GetVisibleCur(); virtual void SetPos(WTL::CPoint pt, WTL::CSize sz); virtual void SetOriginPos(CPoint pt, CSize sz); virtual void SetPos(WTL::CRect rc); virtual void SetOriginPos(WTL::CRect rc); virtual CRect Rectangle(); virtual CRect OriginRectangle(); virtual HCURSOR GetCursor(); virtual void SetCursor(HCURSOR cursor); virtual void RegisterLButtonDownEvent(EventHandler event); virtual void RegisterLButtonUpEvent(EventHandler event); virtual void RegisterRButtonUpEvent(EventHandler event); virtual void RegisterHoverEvent(EventHandler event); virtual void RegisterLeaveEvent(EventHandler event); virtual void RegisterEnterKeyEvent(EventHandler event); virtual void RegisterLButtonDbCEvent(EventHandler event); virtual void RaiseInvalidate(BOOL forceRedraw = TRUE); virtual int GetTextWidth(LPCTSTR lpszText, HFONT hFont); virtual HWND GetHost(); virtual void DrawCursor() { ; } virtual void VerticalOffset(int i = 0) { _location.y += i; } virtual BOOL IsPanel() { return FALSE; } virtual void OnMove(); virtual void OnKeyDown(DWORD dwFlag); virtual void OnKeyUp(DWORD dwFlag); virtual void OnMouseDClick(); virtual void OnMouseClick(); virtual void OnMouseLDbClick(UINT nFlags, CPoint point); virtual void OnMouseDown(UINT nFlags, CPoint point); virtual void OnMouseDblDown(UINT nFlags, CPoint point); virtual void OnMouseUp(UINT nFlags, CPoint point); virtual void OnMouseRUp(UINT nFlags, CPoint point); virtual void OnMouseHover(UINT nFlags, CPoint point); virtual void OnMouseLeave(); virtual void OnPaint(HDC hDC); virtual void OnSizeChanged(DUI_Size wndChangingSize, int w, int h); virtual void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); virtual BOOL PointInRect(CPoint pt, CRect rect); virtual void OnCall_LeftUp(); virtual void OnCall_RightUp(); virtual void OnCall_EnterKey(); virtual void OnCall_LeftDown(); virtual void OnEnterKey(); virtual void OnTabKey() {} virtual void OnCall_LDbClick(); virtual void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); public: virtual void GetElementStyle(XmlElementPtr element); HWND _host; tstring _id; tstring _name; tstring _title; tstring _class; tstring _tip; DWORD _style; DWORD _ex_style; CPoint _location; CPoint _ori_location; CSize _size; CSize _ori_size; CPoint _base_pt; BOOL _handleMouse; BOOL _handleKeyboard; BOOL _active; BOOL _visible; BOOL _viscur; HCURSOR _cursor; BOOL _transparent; BOOL _editCheckPath; EventHandler _leftdown_event; EventHandler _leftup_event; EventHandler _rightup_event; EventHandler _hover_event; EventHandler _leave_event; EventHandler _enterkey_event; EventHandler _leftDbclick_event; }; inline HWND CBaseElementCtl::GetHost() { return _host; } inline void CBaseElementCtl::SetID(const tstring &id) { _id = id; } inline tstring CBaseElementCtl::GetID() { return _id; } inline tstring CBaseElementCtl::GetTitle() { return _title; } inline void CBaseElementCtl::SetTitle(const tstring &title) { _title = title; } inline void CBaseElementCtl::SetVisible(BOOL visible) { if (_visible != visible) { _visible = visible; RaiseInvalidate(TRUE); } } inline BOOL CBaseElementCtl::GetVisible() { return _visible; } inline tstring CBaseElementCtl::GetTooltip() { return _tip; } inline void CBaseElementCtl::SetTooltip(const tstring &csTooltip) { _tip = csTooltip; } inline void CBaseElementCtl::SetHandleMouse(BOOL mouse) { _handleMouse = mouse; } inline BOOL CBaseElementCtl::GetHandleMouse() { return _handleMouse; } inline void CBaseElementCtl::SetHandleKeyboard(BOOL keyboard) { _handleKeyboard = keyboard; } inline BOOL CBaseElementCtl::GetHandleKeyboard() { return _handleKeyboard; } inline void CBaseElementCtl::SetActive(BOOL active) { _active = active; if (_active) { } } inline void CBaseElementCtl::SetActive(CBaseElementCtl *element) { if (element == this) _active = TRUE; else _active = FALSE; } inline BOOL CBaseElementCtl::GetActive() { return _active; } inline void CBaseElementCtl::SetVisibleCur(BOOL bVisible) { _viscur = bVisible; } inline BOOL CBaseElementCtl::GetVisibleCur() { return _viscur; } inline void CBaseElementCtl::SetName(const tstring &name) { _name = name; } inline tstring CBaseElementCtl::GetName() { return _name; } inline CRect CBaseElementCtl::Rectangle() { CPoint pt(_base_pt.x + _location.x, _base_pt.y + _location.y); return CRect(pt.x, pt.y, pt.x + _size.cx, pt.y + _size.cy); } inline CRect CBaseElementCtl::OriginRectangle() { CPoint pt(_ori_location.x, _ori_location.y); return CRect(pt.x, pt.y, pt.x + _ori_size.cx, pt.y + _ori_size.cy); } inline void CBaseElementCtl::SetPos(CPoint pt, CSize sz) { _location.x = pt.x; _location.y = pt.y; _size.cx = sz.cx; _size.cy = sz.cy; } inline void CBaseElementCtl::SetOriginPos(CPoint pt, CSize sz) { _ori_location = pt; _ori_size = sz; } inline void CBaseElementCtl::SetPos(WTL::CRect rc) { _location.x = rc.left; _location.y = rc.top; _size.cx = rc.Width(); _size.cy = rc.Height(); } inline void CBaseElementCtl::SetOriginPos(WTL::CRect rc) { _ori_location.x = rc.left; _ori_location.y = rc.top; _ori_size.cx = rc.Width(); _ori_size.cy = rc.Height(); } inline HCURSOR CBaseElementCtl::GetCursor() { return _cursor; } inline void CBaseElementCtl::SetCursor(HCURSOR cursor) { _cursor = cursor; } inline tstring &CBaseElementCtl::GetWndClassName() { return _class; } inline void CBaseElementCtl::RegisterLButtonUpEvent(EventHandler event) { _leftup_event = event; } inline void CBaseElementCtl::RegisterRButtonUpEvent(EventHandler event) { _rightup_event = event; } inline void CBaseElementCtl::RegisterLButtonDownEvent(EventHandler event) { _leftdown_event = event; } inline void CBaseElementCtl::RegisterHoverEvent(EventHandler event) { _hover_event = event; } inline void CBaseElementCtl::RegisterLeaveEvent(EventHandler event) { _leave_event = event; } inline void CBaseElementCtl::RegisterEnterKeyEvent(EventHandler event) { _enterkey_event = event; } inline void CBaseElementCtl::RegisterLButtonDbCEvent(EventHandler event) { _leftDbclick_event = event; } inline BOOL CBaseElementCtl::PointInRect(CPoint pt, CRect rect) { return (((pt.x >= rect.left) && (pt.x <= rect.right)) && ((pt.y >= rect.top) && (pt.y <= rect.bottom))); } ================================================ FILE: src/DirectUI/DUIElementsMgr.cpp ================================================ #include "StdAfx.h" #include "DUIPanel.h" #include "DUIElementsMgr.h" using namespace std; CAnyElementsMgr::CAnyElementsMgr(void) { _last_mouseon_element = NULL; _owner = NULL; _rearrange_element = NULL; } CAnyElementsMgr::~CAnyElementsMgr(void) {} void CAnyElementsMgr::AddElement(CBaseElementCtl *element) { _controls.push_back(element); } void CAnyElementsMgr::AddElement2(CBaseElementCtl *element) { if (_controls.size() == 0 || _controls.size() == 1) _controls.push_back(element); else { list::iterator Iter; Iter = _controls.begin(); Iter++; _controls.insert(Iter, element); } } void CAnyElementsMgr::OnKeyDown(DWORD dwFlag) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; element->OnKeyDown(dwFlag); } } void CAnyElementsMgr::OnKeyUp(DWORD dwFlag) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; element->OnKeyUp(dwFlag); } } void CAnyElementsMgr::OnMove() { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if (element->GetVisible() && element->GetHandleMouse()) { element->OnMove(); } } } BOOL CAnyElementsMgr::MouseOnElement(CPoint pt) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if ((element->GetVisible() && element->GetHandleMouse()) && PointInRect(pt, element->Rectangle())) { return TRUE; } } return FALSE; } void CAnyElementsMgr::OnMouseClick(CPoint pt) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if (element->GetVisible() && element->GetHandleMouse()) { PointInRect(CPoint(pt.x, pt.y), element->Rectangle()); } } } void CAnyElementsMgr::OnMouseDown(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if ((element->GetVisible() && element->GetHandleMouse()) && PointInRect(pt, element->Rectangle())) { element->OnMouseDown(nFlags, pt); } } if (_rearrange_element != NULL) { list::iterator ite = find(_controls.begin(), _controls.end(), _rearrange_element); _controls.erase(ite); _controls.push_back(_rearrange_element); _rearrange_element = NULL; } } void CAnyElementsMgr::OnMouseLDbClick(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; CBaseElementCtl *cur_element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { cur_element = *ite; if (cur_element->GetVisible() && cur_element->GetHandleMouse()) { if (PointInRect(pt, cur_element->Rectangle())) { cur_element->OnMouseLDbClick(nFlags, pt); } } } } void CAnyElementsMgr::OnMouseUp(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; CBaseElementCtl *cur_element = NULL; list::iterator ite = _controls.begin(); for (; ite != _controls.end(); ite++) { cur_element = *ite; if (cur_element->GetVisible() && cur_element->GetHandleMouse()) { if (PointInRect(pt, cur_element->Rectangle())) { cur_element->OnMouseUp(nFlags, pt); if (!cur_element->GetWndClassName().compare(_T("DirectButton"))) { break; } } } } } void CAnyElementsMgr::OnMouseRUp(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; CBaseElementCtl *cur_element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { cur_element = *ite; if (cur_element->GetVisible() && cur_element->GetHandleMouse()) { if (PointInRect(pt, cur_element->Rectangle())) { cur_element->OnMouseRUp(nFlags, pt); } } } } void CAnyElementsMgr::OnMouseLeave() { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if ((element->GetVisible() && element->GetHandleMouse()) && (_last_mouseon_element == element)) { element->OnMouseLeave(); } } } void CAnyElementsMgr::OnMouseMove(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; CBaseElementCtl *element2 = NULL; CBaseElementCtl *element3 = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element3 = *ite; if (element3->GetVisible() && element3->GetHandleMouse()) { if (PointInRect(pt, element3->Rectangle())) { element = element3; } else if (_last_mouseon_element == element3) { element2 = element3; } } } if (((element != NULL) && (_last_mouseon_element != element)) && (element2 == NULL)) { element2 = _last_mouseon_element; } if (element2 != NULL) { element2->OnMouseLeave(); ::SendMessage(_owner, WM_MSG_TIPS, FALSE, 0); ::SendMessage(_owner, WM_MSG_CURSOR, (WPARAM)element2->GetCursor(), 0); } if ((element != NULL)) { if (!lstrcmp(element->GetWndClassName().c_str(), _T("Panel"))) { element->OnMouseHover(nFlags, pt); } else { element->OnMouseHover(nFlags, pt); if (_last_mouseon_element != element) { ::SendMessage(_owner, WM_MSG_TIPS, TRUE, (LPARAM)element->GetTooltip().c_str()); ::SendMessage(_owner, WM_MSG_CURSOR, (WPARAM)element->GetCursor(), 0); } } } _last_mouseon_element = element; } void CAnyElementsMgr::DrawCursor() { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if ((element->GetVisible() && element->GetHandleKeyboard())) { element->DrawCursor(); } } } void CAnyElementsMgr::SetActive(CBaseElementCtl *element) { CBaseElementCtl *ele = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { ele = *ite; ele->SetActive(element); } } void CAnyElementsMgr::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *ele = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { ele = *ite; ele->OnMsg(nMsg, wParam, lParam, bHandled); } } void CAnyElementsMgr::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { CBaseElementCtl *element = NULL; CBaseElementCtl *cur_element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { cur_element = *ite; if (cur_element->GetVisible() && cur_element->GetHandleMouse()) { if (PointInRect(pt, cur_element->Rectangle())) { cur_element->OnMouseWheel(nFlags, zDelta, pt); } } } } void CAnyElementsMgr::OnPaint(HDC hDC) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if (element->GetVisible()) { element->OnPaint(hDC); } } } void CAnyElementsMgr::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; element->OnSizeChanged(wndChangingSize, w, h); } } void CAnyElementsMgr::RearrangeElement(CBaseElementCtl *e) { if (e != NULL) { list::iterator ite = find(_controls.begin(), _controls.end(), e); _controls.erase(ite); _controls.push_back(e); } } CBaseElementCtl *CAnyElementsMgr::Search(const tstring id) { CBaseElementCtl *filterEle = NULL; CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if (!lstrcmp(element->GetWndClassName().c_str(), _T("Panel"))) { filterEle = ((CPanelCtl *)element)->_elementmgr.Search(id); if (filterEle) { break; } } if (element->GetID() == id) { filterEle = element; break; } } return filterEle; } void CAnyElementsMgr::Reset() { _cur_pos = _controls.begin(); } CBaseElementCtl *CAnyElementsMgr::GetElement() { CBaseElementCtl *element = NULL; while (_cur_pos != _controls.end()) { element = *_cur_pos; _cur_pos++; return element; } return NULL; } void CAnyElementsMgr::Dispose() { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (; ite != _controls.end(); ++ite) { element = *ite; if (element) { delete element; } } _controls.clear(); _last_mouseon_element = NULL; _rearrange_element = NULL; } void CAnyElementsMgr::Dispose(const tstring id) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end();) { element = *ite; if (element->GetID() == id) { delete element; _controls.erase(ite++); } else { ite++; } } _last_mouseon_element = NULL; } void CAnyElementsMgr::OnMouseDblDown(UINT nFlags, CPoint pt) { CBaseElementCtl *element = NULL; list::iterator ite = _controls.begin(); for (ite; ite != _controls.end(); ite++) { element = *ite; if ((element->GetVisible() && element->GetHandleMouse()) && PointInRect(pt, element->Rectangle())) { element->OnMouseDblDown(nFlags, pt); } } } list *CAnyElementsMgr::GetAllElement() { return &_controls; } ================================================ FILE: src/DirectUI/DUIElementsMgr.h ================================================ #pragma once #include "DUIElement.h" class CAnyElementsMgr { public: CAnyElementsMgr(void); CAnyElementsMgr(HWND owner) { _owner = owner; } ~CAnyElementsMgr(void); void InitOwner(HWND hWnd) { _owner = hWnd; } void OnMove(); BOOL MouseOnElement(CPoint pt); void OnKeyDown(DWORD dwFlag); void OnKeyUp(DWORD dwFlag); void OnMouseClick(CPoint pt); void OnMouseDown(UINT nFlags, CPoint pt); void OnMouseDblDown(UINT nFlags, CPoint pt); void OnMouseUp(UINT nFlags, CPoint pt); void OnMouseRUp(UINT nFlags, CPoint pt); void OnMouseLDbClick(UINT nFlags, CPoint pt); void OnMouseLeave(); void OnMouseMove(UINT nFlags, CPoint pt); void OnPaint(HDC hDC); void OnSizeChanged(DUI_Size wndChangingSize, int w, int h); void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); void RearrangeElement(CBaseElementCtl *e); void AddElement(CBaseElementCtl *element); void AddElement2(CBaseElementCtl *element); void DrawCursor(); void SetActive(CBaseElementCtl *element); void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); CBaseElementCtl *Search(const tstring id); CBaseElementCtl *GetElement(); void Reset(); void Dispose(); void Dispose(const tstring id); std::list *GetAllElement(); DWORD EleNum() { return _controls.size(); } private: std::list _controls; CBaseElementCtl *_last_mouseon_element; HWND _owner; CBaseElementCtl *_rearrange_element; BOOL _visible; std::list::iterator _cur_pos; protected: BOOL PointInRect(CPoint pt, CRect rect); }; inline BOOL CAnyElementsMgr::PointInRect(CPoint pt, CRect rect) { return (((pt.x >= rect.left) && (pt.x <= rect.right)) && ((pt.y >= rect.top) && (pt.y <= rect.bottom))); } ================================================ FILE: src/DirectUI/DUIGDIResource.cpp ================================================ #include "stdafx.h" #include "Util/UtilApi.h" #include "DUIGDIResource.h" using namespace std; static constexpr LPCTSTR glpszFontName[] = { _T("Tahoma"), _T("Microsoft Yahei") }; HFONT CGDIResource::m_hNormalFont = NULL; HFONT CGDIResource::m_hNormalBoldFont = NULL; HFONT CGDIResource::m_hBiggerBoldFont = NULL; HFONT CGDIResource::m_hSmallFont = NULL; HFONT CGDIResource::m_BiggerFont = NULL; HFONT CGDIResource::m_hUnderLineFont = NULL; ULONG_PTR CGDIResource::m_Token = 0; map CGDIResource::m_mapAllRes; int CGDIResource::m_nRef = 0; CriticalSection CGDIResource::m_cs; CGDIResource::CGDIResource() {} CGDIResource::~CGDIResource() {} void CGDIResource::Initialize(LPCTSTR lpszResPath) { m_strResPath = lpszResPath; m_cs.Lock(); if (m_nRef == 0) { Gdiplus::GdiplusStartupInput input; Gdiplus::GdiplusStartup(&m_Token, &input, NULL); } m_nRef = m_nRef + 1; m_cs.UnLock(); } void CGDIResource::UnInitialize() { m_cs.Lock(); if (m_nRef > 0) m_nRef = m_nRef - 1; if (m_nRef == 0) { Dispose(); Gdiplus::GdiplusShutdown(m_Token); } m_cs.UnLock(); } void CGDIResource::Dispose() { HBITMAP hBitmap = NULL; map::iterator ite = m_mapAllRes.begin(); for (ite; ite != m_mapAllRes.end(); ite++) { hBitmap = ite->second; if (hBitmap) { ::DeleteObject(hBitmap); } } m_mapAllRes.clear(); if (m_hNormalFont) { ::DeleteObject(m_hNormalFont); m_hNormalFont = NULL; } if (m_hNormalBoldFont) { ::DeleteObject(m_hNormalBoldFont); m_hNormalBoldFont = NULL; } if (m_hBiggerBoldFont) { ::DeleteObject(m_hBiggerBoldFont); m_hBiggerBoldFont = NULL; } if (m_hSmallFont) { ::DeleteObject(m_hSmallFont); m_hSmallFont = NULL; } if (m_hUnderLineFont) { ::DeleteObject(m_hUnderLineFont); m_hUnderLineFont = NULL; } } void CGDIResource::GDI_DrawImageStretch(HDC hDC, HBITMAP hBitmap, CRect rcDest, CRect rcBmp, BYTE uFade, CRect rcCorners) { HDC hdcMem = CreateCompatibleDC(hDC); HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap); ATLASSERT(rcBmp.Width() > rcCorners.left + rcCorners.right); ATLASSERT(rcBmp.Height() > rcCorners.top + rcCorners.bottom); BLENDFUNCTION bf = {AC_SRC_OVER, 0, uFade, AC_SRC_ALPHA}; AlphaBlend(hDC, rcDest.left, rcDest.top, rcCorners.left, rcCorners.top, hdcMem, rcBmp.left, rcBmp.top, rcCorners.left, rcCorners.top, bf); AlphaBlend(hDC, rcDest.left + rcCorners.left, rcDest.top, rcDest.Width() - rcCorners.left - rcCorners.right, rcCorners.top, hdcMem, rcBmp.left + rcCorners.left, rcBmp.top, rcBmp.Width() - rcCorners.left - rcCorners.right, rcCorners.top, bf); AlphaBlend(hDC, rcDest.right - rcCorners.right, rcDest.top, rcCorners.right, rcCorners.top, hdcMem, rcBmp.right - rcCorners.right, rcBmp.top, rcCorners.right, rcCorners.top, bf); AlphaBlend(hDC, rcDest.left, rcDest.top + rcCorners.top, rcCorners.left, rcDest.Height() - rcCorners.top - rcCorners.bottom, hdcMem, rcBmp.left, rcBmp.top + rcCorners.top, rcCorners.left, rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf); AlphaBlend(hDC, rcDest.left + rcCorners.left, rcDest.top + rcCorners.top, rcDest.Width() - rcCorners.left - rcCorners.right, rcDest.Height() - rcCorners.top - rcCorners.bottom, hdcMem, rcBmp.left + rcCorners.left, rcBmp.top + rcCorners.top, rcBmp.Width() - rcCorners.left - rcCorners.right, rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf); AlphaBlend( hDC, rcDest.right - rcCorners.right, rcDest.top + rcCorners.top, rcCorners.right, rcDest.Height() - rcCorners.top - rcCorners.bottom, hdcMem, rcBmp.right - rcCorners.right, rcBmp.top + rcCorners.top, rcCorners.right, rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf); AlphaBlend(hDC, rcDest.left, rcDest.bottom - rcCorners.bottom, rcCorners.left, rcCorners.bottom, hdcMem, rcBmp.left, rcBmp.bottom - rcCorners.bottom, rcCorners.left, rcCorners.bottom, bf); AlphaBlend( hDC, rcDest.left + rcCorners.left, rcDest.bottom - rcCorners.bottom, rcDest.Width() - rcCorners.left - rcCorners.right, rcCorners.bottom, hdcMem, rcBmp.left + rcCorners.left, rcBmp.bottom - rcCorners.bottom, rcBmp.Width() - rcCorners.left - rcCorners.right, rcCorners.bottom, bf); AlphaBlend( hDC, rcDest.right - rcCorners.right, rcDest.bottom - rcCorners.bottom, rcCorners.right, rcCorners.bottom, hdcMem, rcBmp.right - rcCorners.right, rcBmp.bottom - rcCorners.bottom, rcCorners.right, rcCorners.bottom, bf); SelectObject(hdcMem, hBmpOld); DeleteDC(hdcMem); } void CGDIResource::GDI_DrawImage(HDC hDC, Bitmap *pBmp, int nLeft, int nTop, int nWidth, int nHeight, BOOL bTransparent) { Graphics g(hDC); if (bTransparent) { ImageAttributes imageAtt; imageAtt.SetColorKey(Color(255, 0, 255), Color(255, 0, 255)); Rect rcDst(nLeft, nTop, nWidth, nHeight); g.DrawImage(pBmp, rcDst, 0, 0, pBmp->GetWidth(), pBmp->GetHeight(), UnitPixel, &imageAtt); } else { TextureBrush brush(pBmp, WrapModeTile, Rect(0, 0, pBmp->GetWidth(), pBmp->GetHeight())); brush.TranslateTransform((REAL)nLeft, (REAL)nTop); g.FillRectangle(&brush, nLeft, nTop, nWidth, nHeight); } } void CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, int nLeft, int nTop, int nWidth, int nHeight, DUI_BITMAP_TYPE bmpType, DWORD trans) { HDC hdcMem = CreateCompatibleDC(hDC); HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap); BITMAP bmInfor; GetObject(hBitmap, sizeof(bmInfor), &bmInfor); if (bmpType != DUI_BT_ALPHA) { TransparentBlt(hDC, nLeft, nTop, nWidth, nHeight, hdcMem, 0, 0, bmInfor.bmWidth, bmInfor.bmHeight, TRANSPARENT_COLOR); } else { BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; if (trans < 0 || trans > 0xFF) trans = 0xFF; bf.SourceConstantAlpha = static_cast(trans); bf.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(hDC, nLeft, nTop, nWidth, nHeight, hdcMem, 0, 0, bmInfor.bmWidth, bmInfor.bmHeight, bf); } SelectObject(hdcMem, hBmpOld); DeleteDC(hdcMem); } void CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, LPRECT rcDest, DUI_BITMAP_TYPE bmpType, DWORD trans) { GDI_DrawImage(hDC, hBitmap, rcDest->left, rcDest->top, rcDest->right - rcDest->left, rcDest->bottom - rcDest->top, bmpType, trans); } void CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, DUI_Rect &rcDest, DUI_Rect &rcSrc, DUI_BITMAP_TYPE bmpType) { HDC hdcMem = CreateCompatibleDC(hDC); HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap); if (bmpType != DUI_BT_ALPHA) { TransparentBlt(hDC, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(), hdcMem, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), TRANSPARENT_COLOR); } else { BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 0xFF; bf.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(), hdcMem, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(), bf); } SelectObject(hdcMem, hBmpOld); DeleteDC(hdcMem); } void CGDIResource::GDI_DrawIcon(HDC hDC, HICON hIcon, int nLeft, int nTop) { ::DrawIcon(hDC, nLeft, nTop, hIcon); } void CGDIResource::GDI_DrawIconEx(HDC hDC, HICON hIcon, int nLeft, int nTop, int nWidth, int nHeight) { ::DrawIconEx(hDC, nLeft, nTop, hIcon, nWidth, nHeight, 0, NULL, DI_IMAGE | DI_MASK); } void CGDIResource::GDI_DrawLine(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine) { HPEN hPen = CreatePen(PS_SOLID, 0, colLine); HPEN hPenOld = (HPEN)SelectObject(hDC, hPen); MoveToEx(hDC, nBegX, nBegY, (LPPOINT)NULL); LineTo(hDC, nEndX, nEndY); SelectObject(hDC, hPenOld); DeleteObject(hPen); } void CGDIResource::GDI_DrawLine_trans(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine) { Graphics g(hDC); Color col(Color::MakeARGB(254, GetRValue(colLine), GetGValue(colLine), GetBValue(colLine))); Pen p(col, 1.0); g.DrawLine(&p, nBegX, nBegY, nEndX, nEndY); } void CGDIResource::GDI_DrawDotLine(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine) { HPEN hPen = CreatePen(PS_DOT, 0, colLine); HPEN hPenOld = (HPEN)SelectObject(hDC, hPen); MoveToEx(hDC, nBegX, nBegY, (LPPOINT)NULL); LineTo(hDC, nEndX, nEndY); SelectObject(hDC, hPenOld); DeleteObject(hPen); } void CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, HFONT hFont, COLORREF colText, UINT nFormat) { CDCHandle dc(hDC); dc.SetBkMode(TRANSPARENT); HFONT hOldFont = dc.SelectFont(hFont); dc.SetTextColor(colText); dc.DrawText(strText, lstrlen(strText), rcText, nFormat); dc.SelectFont(hOldFont); } void CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, UINT nFormat) { GDI_DrawText(hDC, strText, rcText, GDI_GetNormalFont(), RGB(0, 0, 0), nFormat); } void CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, COLORREF colText, UINT nFormat) { GDI_DrawText(hDC, strText, rcText, GDI_GetNormalFont(), colText, nFormat); } void CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, HFONT hFont, COLORREF colText, UINT nFormat) { Graphics g(hDC); Color col(Color::MakeARGB(254, GetRValue(colText), GetGValue(colText), GetBValue(colText))); SolidBrush brush(col); Gdiplus::Font font(hDC, hFont); RectF rf(rcText->left, rcText->top, rcText->right - rcText->left, rcText->bottom - rcText->top); StringFormat sf; if (nFormat & DT_LEFT) { sf.SetAlignment(StringAlignmentNear); } else if (nFormat & DT_CENTER) { sf.SetAlignment(StringAlignmentCenter); } else if (nFormat & DT_RIGHT) { sf.SetAlignment(StringAlignmentFar); } if (nFormat & DT_VCENTER) { sf.SetLineAlignment(StringAlignmentCenter); } else { sf.SetLineAlignment(StringAlignmentNear); } if (nFormat & DT_SINGLELINE) { sf.SetFormatFlags(StringFormatFlagsNoWrap); } if (nFormat & DT_END_ELLIPSIS) { sf.SetTrimming(StringTrimmingEllipsisCharacter); } g.SetTextRenderingHint(TextRenderingHintClearTypeGridFit); g.DrawString(strText, -1, &font, rf, &sf, &brush); } void CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, COLORREF colText, UINT nFormat) { GDI_DrawText_Trans(hDC, strText, rcText, GDI_GetNormalFont(), colText, nFormat); } void CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, UINT nFormat) { GDI_DrawText_Trans(hDC, strText, rcText, GDI_GetNormalFont(), RGB(0, 0, 0), nFormat); } void CGDIResource::GDI_FillRectBack(HDC hDC, LPRECT rc, COLORREF colBrush) { CDCHandle dc(hDC); HBRUSH hBrush = CreateSolidBrush(colBrush); HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hBrush); dc.FillRect(rc, hBrush); ::SelectObject(hDC, hOldBrush); DeleteObject(hBrush); } void CGDIResource::GDI_DrawRectangle(HDC hDC, LPRECT rc, COLORREF colBorder, COLORREF colBrush) { HPEN hPen = CreatePen(PS_SOLID, 1, colBorder); HPEN hOldPen = (HPEN)SelectObject(hDC, hPen); HBRUSH hBrush = CreateSolidBrush(colBrush); HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, rc->left, rc->top, rc->right, rc->bottom); SelectObject(hDC, hOldPen); SelectObject(hDC, hOldBrush); DeleteObject(hPen); DeleteObject(hBrush); } void CGDIResource::GDI_DrawRectangle_Trans(HDC hDC, LPRECT rc, COLORREF colBorder, COLORREF colBrush) { Graphics g(hDC); Color colPen(Color::MakeARGB(254, GetRValue(colBorder), GetGValue(colBorder), GetBValue(colBorder))); Color colBru(Color::MakeARGB(254, GetRValue(colBrush), GetGValue(colBrush), GetBValue(colBrush))); SolidBrush brush(colBru); Pen pen(colPen); g.FillRectangle(&brush, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top); g.DrawRectangle(&pen, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top); g.ReleaseHDC(hDC); } void CGDIResource::GDI_DrawRoundRectangle(HDC hDC, LPRECT rc, COLORREF colBorder, COLORREF colBrush) { HPEN hPen = CreatePen(PS_SOLID, 1, colBorder); HPEN hOldPen = (HPEN)SelectObject(hDC, hPen); HBRUSH hBrush = CreateSolidBrush(colBrush); HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); RoundRect(hDC, rc->left, rc->top, rc->right, rc->bottom, 3, 3); SelectObject(hDC, hOldPen); SelectObject(hDC, hOldBrush); DeleteObject(hPen); DeleteObject(hBrush); } void CGDIResource::GDI_DrawRoundRectangle_Trans(HDC hDC, LPRECT rc, COLORREF colBorder, COLORREF colBrush) { Graphics g(hDC); Color colPen(Color::MakeARGB(254, GetRValue(colBorder), GetGValue(colBorder), GetBValue(colBorder))); Color colBru(Color::MakeARGB(254, GetRValue(colBrush), GetGValue(colBrush), GetBValue(colBrush))); SolidBrush brush(colBru); Pen pen(colPen); GraphicsPath *path = MakeRoundRect(rc, 6); g.FillPath(&brush, path); g.DrawPath(&pen, path); delete path; } HBITMAP CGDIResource::GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName, int nResType) { map::iterator ite = m_mapAllRes.find(pszResName); if (ite != m_mapAllRes.end()) { return (HBITMAP)(ite->second); } HGLOBAL hGlobalReal = NULL; HRSRC hRes = FindResource(hInstance, pszResName, MAKEINTRESOURCE(nResType)); if (hRes) { HGLOBAL hGlobal = LoadResource(hInstance, hRes); if (hGlobal) { DWORD dwSize = SizeofResource(hInstance, hRes); hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize); LPVOID pDest = ::GlobalLock(hGlobalReal); LPVOID pSrc = ::LockResource(hGlobal); ::CopyMemory(pDest, pSrc, dwSize); ::FreeResource(hRes); } } Gdiplus::Bitmap *pBitmap = NULL; if (hGlobalReal) { CComPtr pStm; HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm); if (hr == S_OK && pStm) pBitmap = new Gdiplus::Bitmap(pStm, FALSE); GlobalUnlock(hGlobalReal); GlobalFree(hGlobalReal); hGlobalReal = NULL; } if (pBitmap == NULL) return NULL; HBITMAP hBitmap = NULL; if (pBitmap->GetLastStatus() == Gdiplus::Ok) pBitmap->GetHBITMAP(NULL, &hBitmap); delete pBitmap; m_mapAllRes[pszResName] = hBitmap; return hBitmap; } HBITMAP CGDIResource::GDI_GetBitmap_NoCache(HINSTANCE hInstance, LPCTSTR pszResName, int nResType) { HGLOBAL hGlobalReal = NULL; HRSRC hRes = FindResource(hInstance, pszResName, MAKEINTRESOURCE(nResType)); if (hRes) { HGLOBAL hGlobal = LoadResource(hInstance, hRes); if (hGlobal) { DWORD dwSize = SizeofResource(hInstance, hRes); hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize); LPVOID pDest = ::GlobalLock(hGlobalReal); LPVOID pSrc = ::LockResource(hGlobal); ::CopyMemory(pDest, pSrc, dwSize); ::FreeResource(hRes); } } Gdiplus::Bitmap *pBitmap = NULL; if (hGlobalReal) { CComPtr pStm; HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm); if (hr == S_OK && pStm) pBitmap = new Gdiplus::Bitmap(pStm, FALSE); GlobalUnlock(hGlobalReal); GlobalFree(hGlobalReal); hGlobalReal = NULL; } if (pBitmap == NULL) return NULL; HBITMAP hBitmap = NULL; if (pBitmap->GetLastStatus() == Gdiplus::Ok) pBitmap->GetHBITMAP(NULL, &hBitmap); delete pBitmap; return hBitmap; } HBITMAP CGDIResource::GDI_GetBitmap_NoCache(LPCTSTR lpszFileName) { if (lstrlen(lpszFileName) == 0) { return NULL; } HBITMAP hBitmap = NULL; Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromFile(lpszFileName); if (pBitmap->GetLastStatus() == Gdiplus::Ok) pBitmap->GetHBITMAP(NULL, &hBitmap); delete pBitmap; return hBitmap; } HBITMAP CGDIResource::GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName, LPCTSTR lpszResType) { map::iterator ite = m_mapAllRes.find(pszResName); if (ite != m_mapAllRes.end()) { return (HBITMAP)(ite->second); } HGLOBAL hGlobalReal = NULL; HRSRC hRes = FindResource(hInstance, pszResName, lpszResType); if (hRes) { HGLOBAL hGlobal = LoadResource(hInstance, hRes); if (hGlobal) { DWORD dwSize = SizeofResource(hInstance, hRes); hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize); LPVOID pDest = ::GlobalLock(hGlobalReal); LPVOID pSrc = ::LockResource(hGlobal); ::CopyMemory(pDest, pSrc, dwSize); ::FreeResource(hRes); } } Gdiplus::Bitmap *pBitmap = NULL; if (hGlobalReal) { CComPtr pStm; HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm); if (hr == S_OK && pStm) pBitmap = new Gdiplus::Bitmap(pStm, FALSE); GlobalUnlock(hGlobalReal); GlobalFree(hGlobalReal); hGlobalReal = NULL; } if (pBitmap == NULL) return NULL; HBITMAP hBitmap = NULL; if (pBitmap->GetLastStatus() == Gdiplus::Ok) pBitmap->GetHBITMAP(NULL, &hBitmap); delete pBitmap; m_mapAllRes[pszResName] = hBitmap; return hBitmap; } HBITMAP CGDIResource::GDI_GetBitmap(LPCTSTR lpszFileName) { if (lstrlen(lpszFileName) == 0) { return NULL; } map::iterator ite = m_mapAllRes.find(lpszFileName); if (ite != m_mapAllRes.end()) { return (HBITMAP)(ite->second); } HBITMAP hBitmap = NULL; Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromFile(lpszFileName); if (pBitmap->GetLastStatus() == Gdiplus::Ok) pBitmap->GetHBITMAP(NULL, &hBitmap); delete pBitmap; m_mapAllRes[lpszFileName] = hBitmap; return hBitmap; } HFONT CGDIResource::GDI_GetNormalFont() { if (m_hNormalFont) return m_hNormalFont; LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {13, 18}; if (0x804 == lanId) { m_hNormalFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_hNormalFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Arial")); } return m_hNormalFont; } HFONT CGDIResource::GDI_GetNormalBoldFont() { if (m_hNormalBoldFont) return m_hNormalBoldFont; LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {13, 18}; if (0x804 == lanId) { m_hNormalBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_hNormalBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial"); } return m_hNormalBoldFont; } HFONT CGDIResource::GDI_GetBiggerFont() { if (m_BiggerFont) return m_BiggerFont; LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {16, 21}; if (0x804 == lanId) { m_BiggerFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_BiggerFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial"); } return m_BiggerFont; } HFONT CGDIResource::GDI_GetBiggerBoldFont() { if (m_hBiggerBoldFont) { return m_hBiggerBoldFont; } LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {16, 20}; if (0x804 == lanId) { m_hBiggerBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_hBiggerBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial"); } return m_hBiggerBoldFont; } HFONT CGDIResource::GDI_GetSmallFont() { if (m_hSmallFont) return m_hSmallFont; LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {12, 14}; if (0x804 == lanId) { m_hSmallFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_hSmallFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, L"Arial"); } return m_hSmallFont; } HFONT CGDIResource::GDI_GetUnderlineFont() { if (m_hUnderLineFont) return m_hUnderLineFont; LANGID lanId = GetSystemDefaultLangID(); int nIndex = Util::Tools::IsWin7() ? 1 : 0; int nFontSize[] = {13, 18}; if (0x804 == lanId) { m_hUnderLineFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, glpszFontName[nIndex]); } else { m_hUnderLineFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, L"Arial"); } return m_hUnderLineFont; } tstring CGDIResource::GDI_GetIconPath(LPCTSTR lpszIconFileName) { TCHAR szPath[MAX_PATH] = {0}; _sntprintf_s(szPath, MAX_PATH, _TRUNCATE, _T("%s"), m_strResPath.c_str()); PathAppend(szPath, lpszIconFileName); return szPath; } HICON CGDIResource::GDI_GetIcon(LPCTSTR lpszIconFileName) { return (HICON)LoadImage(NULL, lpszIconFileName, IMAGE_ICON, 0, 0, LR_LOADFROMFILE); } HICON CGDIResource::GDI_GetIcon(LPCTSTR lpszIconFileName, int cx, int cy) { return (HICON)LoadImage(NULL, lpszIconFileName, IMAGE_ICON, cx, cy, LR_LOADFROMFILE); } HICON CGDIResource::GDI_GetIcon(UINT nResourceID) { return (HICON)LoadImage(_hInstance, MAKEINTRESOURCE(nResourceID), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); } GraphicsPath *CGDIResource::MakeRoundRect(LPRECT rc, INT percentageRounded) { INT left = rc->left; INT right = rc->right; INT top = rc->top; INT bottom = rc->bottom; INT offsetX = (right - left) * percentageRounded / 100; INT offsetY = (bottom - top) * percentageRounded / 100; GraphicsPath pt; GraphicsPath *path = pt.Clone(); path->AddArc(right - offsetX, top, offsetX, offsetY, 270, 90); path->AddArc(right - offsetX, bottom - offsetY, offsetX, offsetY, 0, 90); path->AddArc(left, bottom - offsetY, offsetX, offsetY, 90, 90); path->AddArc(left, top, offsetX, offsetY, 180, 90); path->AddLine(left + offsetX, top, right - offsetX / 2, top); return path; } ================================================ FILE: src/DirectUI/DUIGDIResource.h ================================================ #pragma once #include #include "util/util_tools.h" #include "DUIDef.h" using namespace Gdiplus; class CGDIResource { public: CGDIResource(); virtual ~CGDIResource(); static CGDIResource &GetInstance() { static CGDIResource This; return This; } void Initialize(LPCTSTR lpszResPath); void UnInitialize(); void Dispose(); virtual void GDI_DrawImageStretch(HDC hDC, HBITMAP hBitmap, CRect rcDest, CRect rcBmp, BYTE uFade, CRect rcCorners); virtual void GDI_DrawImage(HDC hDC, Bitmap *pBmp, int nLeft, int nTop, int nWidth, int nHeight, BOOL bTransparent = TRUE); virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, int nLeft, int nTop, int nWidth, int nHeight, DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA, DWORD dwtrans = 0xFF); virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, LPRECT rcDest, DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA, DWORD dwtrans = 0xFF); virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, DUI_Rect &rcDest, DUI_Rect &rcSrc, DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA); virtual void GDI_DrawIcon(HDC hDC, HICON hIcon, int nLeft, int nTop); virtual void GDI_DrawIconEx(HDC hDC, HICON hIcon, int nLeft, int nTop, int nWidth, int nHeight); virtual void GDI_DrawLine(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine = RGB(0, 0, 0)); virtual void GDI_DrawDotLine(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine = RGB(0, 0, 0)); virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, HFONT hFont, COLORREF colText = RGB(0, 0, 0), UINT nFormat = DT_LEFT); virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, COLORREF colText, UINT nFormat = DT_LEFT); virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText, UINT nFormat = DT_LEFT); virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, HFONT hFont, COLORREF colText = RGB(0, 0, 0), UINT nFormat = DT_LEFT); virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, COLORREF colText, UINT nFormat = DT_LEFT); virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText, UINT nFormat = DT_LEFT); virtual void GDI_FillRectBack(HDC hDC, LPRECT rc, COLORREF colBrush); virtual void GDI_DrawRectangle(HDC hDC, LPRECT rc, COLORREF colBorder = RGB(0, 0, 0), COLORREF colBrush = RGB(255, 255, 255)); virtual void GDI_DrawRectangle_Trans(HDC hDC, LPRECT rc, COLORREF colBorder = RGB(0, 0, 0), COLORREF colBrush = RGB(255, 255, 255)); virtual void GDI_DrawRoundRectangle(HDC hDC, LPRECT rc, COLORREF colBorder = RGB(0, 0, 0), COLORREF colBrush = RGB(255, 255, 255)); virtual void GDI_DrawRoundRectangle_Trans(HDC hDC, LPRECT rc, COLORREF colBorder = RGB(0, 0, 0), COLORREF colBrush = RGB(255, 255, 255)); virtual HBITMAP GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName, int nResType); virtual HBITMAP GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName, LPCTSTR lpszResType); virtual HBITMAP GDI_GetBitmap(LPCTSTR lpszFileName); virtual HBITMAP GDI_GetBitmap_NoCache(HINSTANCE hInstance, LPCTSTR pszResName, int nResType); virtual HBITMAP GDI_GetBitmap_NoCache(LPCTSTR lpszFileName); virtual HFONT GDI_GetNormalFont(); virtual HFONT GDI_GetNormalBoldFont(); virtual HFONT GDI_GetBiggerBoldFont(); virtual HFONT GDI_GetBiggerFont(); virtual HFONT GDI_GetSmallFont(); virtual HFONT GDI_GetUnderlineFont(); tstring GDI_GetIconPath(LPCTSTR lpszIconFileName); virtual HICON GDI_GetIcon(LPCTSTR lpszIconFileName); virtual HICON GDI_GetIcon(LPCTSTR lpszIconFileName, int cx, int cy); virtual HICON GDI_GetIcon(UINT nResourceID); virtual void GDI_DrawLine_trans(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY, COLORREF colLine = RGB(0, 0, 0)); protected: GraphicsPath *MakeRoundRect(LPRECT rc, INT percentageRounded); protected: tstring m_strResPath; static HFONT m_hNormalFont; static HFONT m_hNormalBoldFont; static HFONT m_hBiggerBoldFont; static HFONT m_hSmallFont; static HFONT m_BiggerFont; static HFONT m_hUnderLineFont; static ULONG_PTR m_Token; static std::map m_mapAllRes; static int m_nRef; static CriticalSection m_cs; }; ================================================ FILE: src/DirectUI/DUIHyperLink.cpp ================================================ #include "StdAfx.h" #include "DUIHyperLink.h" CHyperLinkCtl::CHyperLinkCtl(HWND father, BOOL trans) : CButtonCtl(father) { _host = father; _transparent = trans; _class = _T(""); _textFormat = DT_LEFT; _bmpIcon = NULL; _textFont = CGDIResource::GetInstance().GDI_GetNormalFont(); _textUnderLineFont = CGDIResource::GetInstance().GDI_GetUnderlineFont(); } CHyperLinkCtl::CHyperLinkCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _host = father; _class = _T(""); _linkColor = RGB(54, 151, 242); _visitedColour = RGB(54, 151, 242); _hoverColor = RGB(54, 151, 242); _textFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER; _bmpIcon = NULL; _textFont = CGDIResource::GetInstance().GDI_GetNormalFont(); _textUnderLineFont = CGDIResource::GetInstance().GDI_GetUnderlineFont(); } CHyperLinkCtl::~CHyperLinkCtl(void) {} void CHyperLinkCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _linkColor = GetRGBAttribute(element, "linkcolor"); _visitedColour = GetRGBAttribute(element, "visitedcolor"); _hoverColor = GetRGBAttribute(element, "hovercolor"); } void CHyperLinkCtl::SetLinkColor(COLORREF colLink) { _linkColor = colLink; } void CHyperLinkCtl::SetHoverColor(COLORREF colHover) { _hoverColor = colHover; } void CHyperLinkCtl::SetIcon(LPCTSTR lpszIconRes) { _bmpIcon = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszIconRes, PNG); } void CHyperLinkCtl::OnPaint(HDC hDC) { if (_visible) { HFONT textFont = _textFont; DUI_Rect rcLink(_location, _size); COLORREF color = RGB(0, 0, 0); switch (_state) { case DUI_STATE_NORMAL: color = _linkColor; break; case DUI_STATE_DOWN: { textFont = _textUnderLineFont; color = _visitedColour; } break; case DUI_STATE_HOVER: { textFont = _textUnderLineFont; color = _hoverColor; } break; case DUI_STATE_DISABLE: color = RGB(153, 153, 153); break; } if (_bmpIcon) { BITMAP bmpIconInfor; GetObject(_bmpIcon, sizeof(bmpIconInfor), &bmpIconInfor); int nY = _location.y + (_size.cy - bmpIconInfor.bmHeight) / 2; CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, _location.x, nY, bmpIconInfor.bmWidth, bmpIconInfor.bmHeight); rcLink.left = _location.x + bmpIconInfor.bmWidth + 2; } if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcLink, textFont, color, _textFormat); } else { CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcLink, textFont, color, _textFormat); } } } void CHyperLinkCtl::OnMouseHover(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { CButtonCtl::OnMouseHover(nFlags, point); _cursor = LoadCursor(NULL, IDC_HAND); } } void CHyperLinkCtl::OnMouseLeave() { CButtonCtl::OnMouseLeave(); _cursor = LoadCursor(NULL, IDC_ARROW); } void CHyperLinkCtl::OnCall_LeftUp() { _leftup_event.Invoke(); _leftup_event.Invoke(m_strURL.c_str()); } void CHyperLinkCtl::GotoURL() { HINSTANCE result = ShellExecute(NULL, _T("open"), m_strURL.c_str(), NULL, NULL, SW_SHOW); if ((UINT)result <= HINSTANCE_ERROR) { } } void CHyperLinkCtl::SetAlignRight() { _textFormat = DT_RIGHT; int nTextWidth = GetTextWidth( _title.c_str(), CGDIResource::GetInstance().GDI_GetNormalFont()); _location.x = Rectangle().right - nTextWidth; if (_size.cx > nTextWidth) { _size.cx = nTextWidth; } } ================================================ FILE: src/DirectUI/DUIHyperLink.h ================================================ #pragma once #include "DUIButton.h" class CHyperLinkCtl : public CButtonCtl { public: CHyperLinkCtl(HWND father, BOOL trans = FALSE); CHyperLinkCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); ~CHyperLinkCtl(void); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void SetURL(tstring strURL); void SetAlignRight(); void SetLinkColor(COLORREF colLink); void SetHoverColor(COLORREF colHover); void SetIcon(LPCTSTR lpszIconRes); virtual void OnMouseHover(UINT nFlags, CPoint point); virtual void OnMouseLeave(); virtual void OnCall_LeftUp(); protected: tstring m_strURL; COLORREF _linkColor; COLORREF _visitedColour; COLORREF _hoverColor; UINT _textFormat; HBITMAP _bmpIcon; HFONT _textFont; HFONT _textUnderLineFont; void GotoURL(); }; inline void CHyperLinkCtl::SetURL(tstring strURL) { m_strURL = strURL; } ================================================ FILE: src/DirectUI/DUILayeredEdit.cpp ================================================ #include "StdAfx.h" #include #include "util/def.h" #include "../Global.h" #include "DUILayeredEdit.h" CLayeredEditCtl::CLayeredEditCtl(HWND father) : _bmpBack(NULL) { _host = father; _class = _T(""); _state = DUI_STATE_NORMAL; _borderColor = RGB(60, 152, 208); _bmpNormal = NULL; _bmpHover = NULL; _bmpIcon = NULL; _readonly = FALSE; _transparent = TRUE; _password = FALSE; _index = 0; _hPopUpWnd = NULL; _LimitText = 5000; _brushColor = RGB(255, 255, 255); _textcolor = RGB(0, 0, 0); } void CLayeredEditCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _tab = CXmlHelper::GetInstance().GetAttributeInt(element, "tab"); _index = CXmlHelper::GetInstance().GetAttributeInt(element, "index"); _bmpNormal = GetBitmapAttribute(element, "normalBack"); _bmpHover = GetBitmapAttribute(element, "hoverBack"); _bmpBack = GetBitmapAttribute(element, "image"); _bmpIcon = GetBitmapAttribute(element, "icon"); _password = CXmlHelper::GetInstance().GetAttributeInt(element, "pWd"); _readonly = CXmlHelper::GetInstance().GetAttributeInt(element, "readonly"); _borderColor = GetRGBAttribute(element, "bordercolor"); _brushColor = GetRGBAttribute(element, "backcolor"); _textcolor = GetRGBAttribute(element, "textcolor"); _editCheckPath = GetIntegerAttribute(element, "checkpath"); if (!_bmpIcon) { DUI_Rect rcEdit(_location, _size); rcEdit.left += 10; rcEdit.right -= 10; rcEdit.top += 5; rcEdit.bottom -= 2; _rcEdit = rcEdit; } else { BITMAP bmpInfor; GetObject(_bmpIcon, sizeof(bmpInfor), &bmpInfor); DUI_Rect rcEdit(_location, _size); rcEdit.left += bmpInfor.bmWidth + 10; rcEdit.right -= 10; rcEdit.top += 5; rcEdit.bottom -= 2; _rcEdit = rcEdit; } } void CLayeredEditCtl::SetLimitText(int uMax) { _LimitText = uMax; } void CLayeredEditCtl::OnPaint(HDC hDC) { if (_visible) { DUI_Rect rc(_location, _size); if (_bmpBack) CGDIResource::GetInstance().GDI_DrawImage( hDC, _bmpBack, _location.x, _location.y, _size.cx, _size.cy); else CGDIResource::GetInstance().GDI_DrawRectangle_Trans( hDC, &rc, _borderColor, _brushColor); if (_password) { const int c = _title.length(); int i = c; WCHAR *s = new WCHAR[++i]; for (int k = 0; k < c; ++k) { s[k] = _T('*'); } s[c] = NULL; if (c > 0) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, s, &_rcEdit, _textcolor, DT_SINGLELINE); } delete[] s; return; } CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &_rcEdit, _textcolor, DT_SINGLELINE); } } void CLayeredEditCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) {} void CLayeredEditCtl::OnMove() {} LRESULT EditPopWindow::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (::IsWindow(m_hWnd)) { RECT rc; GetClientRect(&rc); DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL; m_edit.Create(m_hWnd, rc, NULL, dwStyle, WS_EX_TOOLWINDOW); if (::IsWindow(m_edit.m_hWnd)) { m_edit.SetFont(CGDIResource::GetInstance().GDI_GetNormalFont(), TRUE); ::SetFocus(m_edit.m_hWnd); } } return 0; } LRESULT EditPopWindow::OnPaintChild(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { ::SetBkColor((HDC)wParam, RGB(69, 68, 73)); ::SetTextColor((HDC)wParam, RGB(255, 255, 255)); return (LRESULT)_hbrush; } LRESULT EditPopWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DestroyWindow(); return 0; } void EditPopWindow::OnFinalMessage(HWND hWnd) { delete this; } void CLayeredEditCtl::GetTitleIn() { BSTR strText = NULL; _hPopUpWnd->m_edit.GetWindowText(strText); CString strRes = strText; _title = (LPCTSTR)strRes; SysFreeString(strText); } void CMyEditEx::DeleObj(void *p) { delete p; } LRESULT CMyEditEx::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { WCHAR nChar = (WCHAR)wParam; if (nChar == 13) { if (m_pOwner) { m_pOwner->OnTabKey(); m_pOwner->OnEnterKey(); } } if (nChar == 9) { if (m_pOwner) { m_pOwner->OnTabKey(); } } if (m_pOwner && ::IsWindow(m_pOwner->_host) && m_pOwner->_editCheckPath) { ::PostMessage(m_pOwner->_host, WM_PATH_ILLCHARACTER, (WPARAM)m_pOwner->_editCheckPath, 0); } bHandled = FALSE; return 0; } LRESULT CMyEditEx::OnActiving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (m_pOwner) { ((CLayeredEditCtl *)m_pOwner)->GetTitleIn(); HWND hParent = ::GetParent(m_hWnd); ((CLayeredEditCtl *)m_pOwner)->_hPopUpWnd = NULL; ::ShowWindow(hParent, SW_HIDE); m_pOwner->RaiseInvalidate(TRUE); ::PostMessage(global.hUitlWnd_, WM_DEL_GDI_OBJ, 0, (LPARAM)hParent); } return 0; } void CLayeredEditCtl::OnMouseDown(UINT nFlags, CPoint point) { ForceCreate(); } void CLayeredEditCtl::ForceCreate() { if (NULL == _hPopUpWnd) { _hPopUpWnd = new EditPopWindow; } if (!_hPopUpWnd) { ATLASSERT(0); return; } if (::IsWindow(_hPopUpWnd->m_hWnd)) { return; } _hPopUpWnd->m_edit.SetOwner(this); _hPopUpWnd->m_hWnd = NULL; RECT src = {0}; DUI_Rect rcParent = src; ::GetWindowRect(_host, &rcParent); DUI_Rect rc( DUI_Point(rcParent.left + _rcEdit.left, rcParent.top + _rcEdit.top), _rcEdit.Size()); DWORD style = WS_POPUP | WS_VISIBLE; _hPopUpWnd->Create(_host, rc, _T(""), style); if (::IsWindow(_hPopUpWnd->m_edit.m_hWnd)) { _hPopUpWnd->m_edit.SetLimitText(_LimitText); ::SetWindowText(_hPopUpWnd->m_edit.m_hWnd, _title.c_str()); } else { ATLASSERT(0); } } void CLayeredEditCtl::DestroyEditWindow() { if (_hPopUpWnd && IsWindow(_hPopUpWnd->m_hWnd)) { GetTitleIn(); void *p = _hPopUpWnd; RaiseInvalidate(TRUE); ::DestroyWindow(_hPopUpWnd->m_hWnd); ::PostMessage(global.hUitlWnd_, WM_DEL_GDI_OBJ, 0, (LPARAM)p); } } ================================================ FILE: src/DirectUI/DUILayeredEdit.h ================================================ #pragma once #include "DUIElement.h" class CLayeredEditCtl; class CMyEditEx : public CWindowImpl { public: CMyEditEx() { m_pOwner = NULL; } static void DeleObj(void *p); BEGIN_MSG_MAP(CMyEditEx) MESSAGE_HANDLER(WM_CHAR, OnChar) MESSAGE_HANDLER(WM_KILLFOCUS, OnActiving) END_MSG_MAP() LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnActiving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); void SetOwner(CBaseElementCtl *pOwner) { m_pOwner = pOwner; } void OnFinalMessage(HWND hWnd) {} private: CBaseElementCtl *m_pOwner; }; class EditPopWindow : public CWindowImpl { public: EditPopWindow() { _hbrush = CreateSolidBrush(RGB(69, 68, 73)); } ~EditPopWindow() { if (_hbrush) DeleteObject((HGDIOBJ)_hbrush); } BEGIN_MSG_MAP(EditPopWindow) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnPaintChild) MESSAGE_HANDLER(WM_CLOSE, OnClose) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnPaintChild(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); void OnFinalMessage(HWND hWnd); CMyEditEx m_edit; private: HBRUSH _hbrush; }; class CLayeredEditCtl : public CBaseElementCtl { public: friend CMyEditEx; CLayeredEditCtl(HWND father); ~CLayeredEditCtl(void) {} void OnMouseDown(UINT nFlags, CPoint point); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void OnSizeChanged(DUI_Size wndChangingSize, int w, int h); void OnMove(); void SetVisible(BOOL visible); void SetPos(WTL::CRect rc); void SetPos(CPoint pt, CSize sz); void SetLimitText(int uMax); tstring GetTitle() override; void SetTitle(const tstring &csName); virtual void OnTabKey(); EditPopWindow *_hPopUpWnd; CRect _rcEdit; DUI_BUTTON_STATE _state; void DestroyEditWindow(); void ForceCreate(); protected: void GetTitleIn(); COLORREF _borderColor; COLORREF _brushColor; COLORREF _textcolor; HBITMAP _bmpNormal; HBITMAP _bmpHover; HBITMAP _bmpIcon; BOOL _password; BOOL _tab; BOOL _readonly; HBITMAP _bmpBack; int _index; int _LimitText; }; inline void CLayeredEditCtl::OnTabKey() { if (_tab) { ::PostMessage(_host, WM_ASYNC_CALL_TABKEY, (WPARAM)this, _index); } } inline void CLayeredEditCtl::SetTitle(const tstring &csName) { _title = csName; RaiseInvalidate(); } inline void CLayeredEditCtl::SetVisible(BOOL visible) { if (_visible != visible) { _visible = visible; } } inline tstring CLayeredEditCtl::GetTitle() { if (_hPopUpWnd && ::IsWindow(_hPopUpWnd->m_hWnd)) { BSTR strText = NULL; _hPopUpWnd->m_edit.GetWindowText(strText); CString strRes = strText; _title = (LPCTSTR)strRes; SysFreeString(strText); } return _title; } inline void CLayeredEditCtl::SetPos(CPoint pt, CSize sz) { _location.x = pt.x; _location.y = pt.y; _size.cx = sz.cx; _size.cy = sz.cy; if (!_bmpIcon) { DUI_Rect rcEdit(_location, _size); rcEdit.left += 10; rcEdit.right -= 10; rcEdit.top += 5; rcEdit.bottom -= 2; _rcEdit = rcEdit; } else { BITMAP bmpInfor; GetObject(_bmpIcon, sizeof(bmpInfor), &bmpInfor); DUI_Rect rcEdit(_location, _size); rcEdit.left += bmpInfor.bmWidth + 10; rcEdit.right -= 10; rcEdit.top += 5; rcEdit.bottom -= 2; _rcEdit = rcEdit; } } inline void CLayeredEditCtl::SetPos(WTL::CRect rc) { DUI_Point pt; pt.x = rc.left; pt.y = rc.top; DUI_Size sz; sz.cx = rc.Width(); sz.cy = rc.Height(); SetPos(pt, sz); } ================================================ FILE: src/DirectUI/DUIOptionLine.cpp ================================================ #include "StdAfx.h" #include "DUIOptionLine.h" COptionLineCtl::COptionLineCtl(HWND father, BOOL trans) { _host = father; _class = _T("DUIOptionLine"); _transparent = trans; _textFont = NULL; _textCol = RGB(0, 0, 0); _lineCol = RGB(0, 0, 0); } COptionLineCtl::COptionLineCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans) : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _host = father; _class = _T("DUIOptionLine"); _transparent = trans; _textFont = NULL; _textCol = RGB(0, 0, 0); _lineCol = RGB(0, 0, 0); } COptionLineCtl::~COptionLineCtl(void) {} void COptionLineCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _textFont = CGDIResource::GetInstance().GDI_GetNormalFont(); _textCol = GetRGBAttribute(element, "textcolor"); _lineCol = GetRGBAttribute(element, "linecolor"); } void COptionLineCtl::SetTextFont(HFONT font) { _textFont = font; } void COptionLineCtl::OnPaint(HDC hDC) { if (_visible) { UINT nTextFormat = DT_LEFT; DUI_Rect rc(_location, _size); int nWidth = 0; if (_title.size() > 0) { nWidth = GetTextWidth(_title.c_str(), _textFont) + 10; DUI_Rect rcText; CopyRect(&rcText, &rc); rcText.right = rcText.left + nWidth; if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcText, _textFont, _textCol, DT_LEFT); } else { CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcText, _textFont, _textCol, DT_LEFT); } } int nMiddle = rc.top + rc.Height() / 2; int nLeft = rc.left + nWidth; if (_transparent) { CGDIResource::GetInstance().GDI_DrawLine_trans( hDC, nLeft, nMiddle, rc.right, nMiddle, _lineCol); } else { CGDIResource::GetInstance().GDI_DrawLine(hDC, nLeft, nMiddle, rc.right, nMiddle, _lineCol); } } } ================================================ FILE: src/DirectUI/DUIOptionLine.h ================================================ #pragma once #include "DUIElement.h" class COptionLineCtl : public CBaseElementCtl { public: COptionLineCtl(HWND father, BOOL trans = FALSE); COptionLineCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE); ~COptionLineCtl(void); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void SetTextFont(HFONT font); protected: HFONT _textFont; COLORREF _textCol; COLORREF _lineCol; }; ================================================ FILE: src/DirectUI/DUIPanel.cpp ================================================ #include "StdAfx.h" #include "DUIButton.h" #include "DUICheckBox.h" #include "DUIHyperLink.h" #include "DUILayeredEdit.h" #include "DUIProgress.h" #include "DUIRadioButton.h" #include "DUIStatic.h" #include "DUITabList.h" #include "DUIPanel.h" using namespace std; CPanelCtl::CPanelCtl(HWND father, BOOL trans) { _host = father; _handleKeyboard = TRUE; _class = _T("Panel"); _transparent = trans; _colBack = RGB(255, 255, 255); _colBorder = RGB(255, 255, 255); _bmpBackground = NULL; _elementmgr.InitOwner(_host); _draw_border = FALSE; } CPanelCtl::CPanelCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : CBaseElementCtl(hWnd, lpszID, lpszTitle, lpszTooptip, rcElement) { _class = _T("Panel"); _host = hWnd; _handleKeyboard = TRUE; _colBack = RGB(255, 255, 255); _colBorder = RGB(255, 255, 255); _bmpBackground = NULL; _elementmgr.InitOwner(_host); _draw_border = FALSE; } CPanelCtl::~CPanelCtl(void) { CBaseElementCtl *pEle = NULL; _elementmgr.Reset(); while ((pEle = _elementmgr.GetElement()) != NULL) { delete pEle; pEle = NULL; } } void CPanelCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBackground = GetBitmapAttribute(element, "background"); _colBack = GetRGBAttribute(element, "backcolor"); _colBorder = GetRGBAttribute(element, "bordercolor"); _draw_border = GetIntegerAttribute(element, "border") == 1 ? TRUE : FALSE; CXmlHelper helper; vector pAllElement = helper.GetChild(element); vector::iterator ite = pAllElement.begin(); tstring strEleName; CBaseElementCtl *pElement = NULL; for (ite; ite != pAllElement.end(); ite++) { strEleName = helper.GetElementName(*ite); if (!strEleName.compare(_T("panel"))) { pElement = new CPanelCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("button"))) { pElement = new CButtonCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("tablist"))) { pElement = new CTabListCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("static"))) { pElement = new CStaticCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("link"))) { pElement = new CHyperLinkCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("progress"))) { pElement = new CProgressCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("checkbox"))) { pElement = new CCheckBoxCtl(_host, _transparent); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("radiobutton"))) { pElement = new CRadioButtonCtl(_host); pElement->CreateElement(*ite); AddElement(pElement); continue; } if (!strEleName.compare(_T("layedit"))) { pElement = new CLayeredEditCtl(_host); pElement->CreateElement(*ite); AddElement(pElement); continue; } } } void CPanelCtl::SetBackImage(LPCTSTR lpszImageRes) { _bmpBackground = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG); } void CPanelCtl::AddElement(CBaseElementCtl *element) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top), DUI_Size(rcElement.Width(), rcElement.Height())); _elementmgr.AddElement(element); } void CPanelCtl::AddElement2(CBaseElementCtl *element) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top), DUI_Size(rcElement.Width(), rcElement.Height())); _elementmgr.AddElement2(element); } void CPanelCtl::OnMove() { _elementmgr.OnMove(); } void CPanelCtl::OnMouseDown(UINT nFlags, CPoint pt) { _elementmgr.OnMouseDown(nFlags, pt); } void CPanelCtl::OnKeyDown(DWORD dwFlag) { _elementmgr.OnKeyDown(dwFlag); } void CPanelCtl::OnKeyUp(DWORD dwFlag) { _elementmgr.OnKeyUp(dwFlag); } void CPanelCtl::OnMouseDblDown(UINT nFlags, CPoint pt) { _elementmgr.OnMouseDblDown(nFlags, pt); } void CPanelCtl::OnMouseUp(UINT nFlags, CPoint pt) { _elementmgr.OnMouseUp(nFlags, pt); } void CPanelCtl::OnMouseRUp(UINT nFlags, CPoint pt) { _elementmgr.OnMouseRUp(nFlags, pt); } void CPanelCtl::OnMouseLeave() { _elementmgr.OnMouseLeave(); } void CPanelCtl::OnMouseHover(UINT nFlags, CPoint pt) { _elementmgr.OnMouseMove(nFlags, pt); } void CPanelCtl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { _elementmgr.OnMouseWheel(nFlags, zDelta, pt); } void CPanelCtl::OnPaint(HDC hDC) { if (_visible) { if (!_transparent) { DUI_Rect rc(_location, _size); CGDIResource::GetInstance().GDI_DrawRectangle(hDC, &rc, _colBorder, _colBack); if (_bmpBackground) { BITMAP bmpBackInfor; GetObject(_bmpBackground, sizeof(bmpBackInfor), &bmpBackInfor); DUI_Rect rcSrc; rcSrc.left = 0; rcSrc.top = 0; rcSrc.right = bmpBackInfor.bmWidth; rcSrc.bottom = bmpBackInfor.bmHeight; CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpBackground, rc, rcSrc, 255, CRect(10, 10, 10, 10)); } } else { DUI_Rect rc(_location, _size); if (_draw_border) { CGDIResource::GetInstance().GDI_DrawRectangle_Trans( hDC, &rc, _colBorder, _colBack); } } _elementmgr.OnPaint(hDC); } } void CPanelCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) { _elementmgr.Reset(); CBaseElementCtl *element = NULL; while ((element = _elementmgr.GetElement()) != NULL) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y), DUI_Size(rcElement.Width(), rcElement.Height())); } DUI_Size szOldPanel = _size; CBaseElementCtl::OnSizeChanged(wndChangingSize, w, h); DUI_Size szNewPanel = _size; _elementmgr.Reset(); while ((element = _elementmgr.GetElement()) != NULL) { element->OnSizeChanged(szOldPanel, szNewPanel.cx, szNewPanel.cy); DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top), DUI_Size(rcElement.Width(), rcElement.Height())); } } void CPanelCtl::SetVisible(BOOL visible) { if (_visible != visible) { _visible = visible; CBaseElementCtl *pEle = NULL; _elementmgr.Reset(); while ((pEle = _elementmgr.GetElement()) != NULL) { pEle->SetVisible(_visible); } RaiseInvalidate(TRUE); } } void CPanelCtl::Invlidate() { if (_visible) { RaiseInvalidate(TRUE); CBaseElementCtl *pEle = NULL; _elementmgr.Reset(); while ((pEle = _elementmgr.GetElement()) != NULL) { pEle->RaiseInvalidate(TRUE); } } } void CPanelCtl::Dispose() { _elementmgr.Dispose(); } void CPanelCtl::Dispose(LPCTSTR lpszID) { _elementmgr.Dispose(lpszID); } CBaseElementCtl *CPanelCtl::GetElement() { return _elementmgr.GetElement(); } void CPanelCtl::ResetElement() { _elementmgr.Reset(); } void CPanelCtl::DrawCursor() { _elementmgr.DrawCursor(); } void CPanelCtl::SetActive(CBaseElementCtl *element) { _elementmgr.SetActive(element); } void CPanelCtl::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementmgr.OnMsg(nMsg, wParam, lParam, bHandled); } ================================================ FILE: src/DirectUI/DUIPanel.h ================================================ #pragma once #include "DUIElement.h" #include "DUIElementsMgr.h" class CPanelCtl : public CBaseElementCtl { public: CPanelCtl(HWND father, BOOL trans = FALSE); CPanelCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); ~CPanelCtl(void); void SetPos(CPoint pt, CSize sz); void SetPos(WTL::CRect rc); void CreateElement(XmlElementPtr element); void SetBackImage(LPCTSTR lpszImageRes); void AddElement(CBaseElementCtl *element); void AddElement2(CBaseElementCtl *element); void OnMove(); void OnKeyDown(DWORD dwFlag); void OnKeyUp(DWORD dwFlag); void OnMouseDown(UINT nFlags, CPoint pt); void OnMouseDblDown(UINT nFlags, CPoint pt); void OnMouseUp(UINT nFlags, CPoint pt); void OnMouseRUp(UINT nFlags, CPoint pt); void OnMouseLeave(); void OnMouseHover(UINT nFlags, CPoint pt); void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); void OnPaint(HDC hDC); void OnSizeChanged(DUI_Size wndChangingSize, int w, int h); void SetVisible(BOOL visible); void Invlidate(); void Dispose(); void Dispose(LPCTSTR lpszID); void ResetElement(); CBaseElementCtl *GetElement(); void DrawCursor(); void SetActive(CBaseElementCtl *element); void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); DWORD EleNum() { return _elementmgr.EleNum(); } public: CAnyElementsMgr _elementmgr; protected: HBITMAP _bmpBackground; COLORREF _colBack; COLORREF _colBorder; BOOL _draw_border; }; inline void CPanelCtl::SetPos(CPoint pt, CSize sz) { _elementmgr.Reset(); CBaseElementCtl *element = NULL; while ((element = _elementmgr.GetElement()) != NULL) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y), DUI_Size(rcElement.Width(), rcElement.Height())); } _location.x = pt.x; _location.y = pt.y; _size.cx = sz.cx; _size.cy = sz.cy; _elementmgr.Reset(); while ((element = _elementmgr.GetElement()) != NULL) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top), DUI_Size(rcElement.Width(), rcElement.Height())); } } inline void CPanelCtl::SetPos(WTL::CRect rc) { _elementmgr.Reset(); CBaseElementCtl *element = NULL; while ((element = _elementmgr.GetElement()) != NULL) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y), DUI_Size(rcElement.Width(), rcElement.Height())); } _location.x = rc.left; _location.y = rc.top; _size.cx = rc.Width(); _size.cy = rc.Height(); _elementmgr.Reset(); while ((element = _elementmgr.GetElement()) != NULL) { DUI_Rect rcElement = element->Rectangle(); element->SetPos( DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top), DUI_Size(rcElement.Width(), rcElement.Height())); } } ================================================ FILE: src/DirectUI/DUIProgress.cpp ================================================ #include "StdAfx.h" #include "DUIProgress.h" CProgressCtl::CProgressCtl(HWND father, BOOL trans) : _bmpLightPoint(NULL), _nCurPos(0.0), _nActualWidth(0), _lightpointdela(0) { _host = father; _handleMouse = FALSE; _class = _T(""); _bmpBackground = NULL; _bmpProgress = NULL; _backcolor = RGB(53, 53, 61); _progresscolor = RGB(144, 197, 38); _transparent = trans; } CProgressCtl::CProgressCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans) : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement), _bmpLightPoint(NULL), _nCurPos(0.0), _nActualWidth(0), _lightpointdela(0) { _host = father; _handleMouse = FALSE; _class = _T(""); _bmpBackground = NULL; _bmpProgress = NULL; _backcolor = RGB(53, 53, 61); _progresscolor = RGB(144, 197, 38); _transparent = trans; } CProgressCtl::~CProgressCtl(void) {} void CProgressCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBackground = GetBitmapAttribute(element, "background"); _bmpProgress = GetBitmapAttribute(element, "progress"); _nActualWidth = GetIntegerAttribute(element, "progress_width"); _bmpLightPoint = GetBitmapAttribute(element, "image"); _lightpointdela = GetIntegerAttribute(element, "lightpointdela"); } void CProgressCtl::SetPos(double nPos) { _nCurPos = nPos; RaiseInvalidate(TRUE); } void CProgressCtl::OnPaint(HDC hDC) { if (_visible) { if (_bmpBackground) { int nWidth = _size.cx; int nHeight = _nActualWidth; CGDIResource::GetInstance().GDI_DrawImage( hDC, _bmpBackground, _location.x, _location.y, nWidth, nHeight); } else { DUI_Rect rcDest(_location.x, _location.y, _location.x + _nActualWidth, _location.y + _size.cy); if (_transparent) CGDIResource::GetInstance().GDI_DrawRectangle_Trans( hDC, &rcDest, _backcolor, _backcolor); else CGDIResource::GetInstance().GDI_DrawRectangle(hDC, &rcDest, _backcolor, _backcolor); } if (_bmpProgress) { int nDrawWidth = static_cast(_nActualWidth * _nCurPos); BITMAP bmpProgressInfor; GetObject(_bmpProgress, sizeof(bmpProgressInfor), &bmpProgressInfor); int nDrawLeft = _location.x + 8; int nDrawTop = _location.y + 7; CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpProgress, nDrawLeft, nDrawTop, nDrawWidth, bmpProgressInfor.bmHeight); } else { int nDrawWidth = static_cast(_nActualWidth * _nCurPos); DUI_Rect rcDest(_location.x, _location.y, _location.x + nDrawWidth, _location.y + _size.cy); if (_transparent) CGDIResource::GetInstance().GDI_DrawRectangle_Trans( hDC, &rcDest, _progresscolor, _progresscolor); else CGDIResource::GetInstance().GDI_DrawRectangle( hDC, &rcDest, _progresscolor, _progresscolor); } if (_bmpLightPoint) { BITMAP bmpBackInfor; GetObject(_bmpLightPoint, sizeof(bmpBackInfor), &bmpBackInfor); int nWidth = bmpBackInfor.bmWidth; int nHeight = bmpBackInfor.bmHeight; int px = _location.x + static_cast(_nActualWidth * _nCurPos) - nWidth / 2 + _lightpointdela; int py = _location.y + _size.cy / 2 - nHeight / 2; CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpLightPoint, px, py, nWidth, nHeight); } TCHAR szArgs[25] = {0}; _sntprintf_s(szArgs, 25, _TRUNCATE, _T("%.1f%%"), _nCurPos * 100); CRect rcText; rcText.left = _nActualWidth + 30; rcText.top = _location.y - 10; rcText.right = rcText.left + 55; rcText.bottom = rcText.top + 20; UINT nFormat = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; nFormat = nFormat | DT_LEFT; if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, szArgs, &rcText, CGDIResource::GetInstance().GDI_GetSmallFont(), RGB(250, 250, 250), nFormat); } else { CGDIResource::GetInstance().GDI_DrawText( hDC, szArgs, &rcText, CGDIResource::GetInstance().GDI_GetSmallFont(), RGB(250, 250, 250), nFormat); } } } ================================================ FILE: src/DirectUI/DUIProgress.h ================================================ #pragma once #include "DUIElement.h" class CProgressCtl : public CBaseElementCtl { public: CProgressCtl(HWND father, BOOL trans = FALSE); CProgressCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE); ~CProgressCtl(void); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void SetPos(double nPos); protected: HBITMAP _bmpBackground; HBITMAP _bmpProgress; HBITMAP _bmpLightPoint; COLORREF _backcolor; COLORREF _progresscolor; int _lightpointdela; int _nActualWidth; double _nCurPos; }; ================================================ FILE: src/DirectUI/DUIRadioButton.cpp ================================================ #include "StdAfx.h" #include "DUIRadioButton.h" CRadioButtonCtl::CRadioButtonCtl(HWND father, BOOL trans) : CButtonCtl(father) { _class = _T(""); _transparent = trans; _txtColor = RGB(67, 75, 94); _bChecked = FALSE; _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("RadioButton"), PNG); } CRadioButtonCtl::CRadioButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _class = _T(""); _txtColor = RGB(67, 75, 94); _bChecked = FALSE; _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("RadioButton"), PNG); } CRadioButtonCtl::~CRadioButtonCtl(void) {} void CRadioButtonCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBtn = GetBitmapAttribute(element, "image"); } void CRadioButtonCtl::Enable(BOOL enable) { if (enable) { switch (_state) { case DUI_STATE_NORMAL_DISABLE: _state = DUI_STATE_NORMAL; break; case DUI_STATE_DOWN_DISABLE: _state = DUI_STATE_DOWN; break; default: break; } } else { Disable(); } } void CRadioButtonCtl::OnPaint(HDC hDC) { BITMAP bmpInfor; GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor); int nCheckWidth = bmpInfor.bmWidth / 2; DUI_Size szCheckImage(nCheckWidth, bmpInfor.bmHeight); DUI_Point ptCheckImage(_location.x, _location.y + (_size.cy - bmpInfor.bmHeight) / 2); DUI_Rect rcImage(ptCheckImage, szCheckImage); int nImageOffset = 0; switch (_state) { case DUI_STATE_NORMAL: case DUI_STATE_HOVER: nImageOffset = 0; break; case DUI_STATE_DOWN: nImageOffset = 1; break; case DUI_STATE_NORMAL_DISABLE: nImageOffset = 2; break; case DUI_STATE_DOWN_DISABLE: nImageOffset = 3; break; } DUI_Rect rcSrc(DUI_Point(nImageOffset * nCheckWidth, 0), DUI_Size(nCheckWidth, bmpInfor.bmHeight)); CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcImage, rcSrc); DUI_Rect rcText(DUI_Point(rcImage.right + 5, _location.y), DUI_Size(_size.cx - rcImage.Width() - 1, _size.cy)); if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcText, _txtColor, DT_LEFT | DT_SINGLELINE | DT_VCENTER); } else { CGDIResource::GetInstance().GDI_DrawText( hDC, _title.c_str(), &rcText, _txtColor, DT_LEFT | DT_SINGLELINE | DT_VCENTER); } } void CRadioButtonCtl::Disable() { switch (_state) { case DUI_STATE_NORMAL: _state = DUI_STATE_NORMAL_DISABLE; break; case DUI_STATE_DOWN: _state = DUI_STATE_DOWN_DISABLE; break; default: break; } } void CRadioButtonCtl::OnMouseDown(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { if (_bChecked == FALSE) { _down = TRUE; if (_down) { Refresh(DUI_STATE_DOWN); _bChecked = TRUE; ::SendMessageW(_host, WM_RADIOBUTTON_DOWN, (WPARAM)this, 0); } else { Refresh(DUI_STATE_NORMAL); _bChecked = FALSE; } } } } void CRadioButtonCtl::OnMouseUp(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { OnMouseClick(); } } void CRadioButtonCtl::OnMouseHover(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { if (_down) { Refresh(DUI_STATE_DOWN); } else { Refresh(DUI_STATE_HOVER); } } } void CRadioButtonCtl::OnMouseLeave() { _tracking = FALSE; if (_state != DUI_STATE_DISABLE) { if (!_down) { Refresh(DUI_STATE_NORMAL); } } } void CRadioButtonCtl::SetCheck(BOOL bCheck) { _bChecked = bCheck; if (_state != DUI_STATE_DISABLE) { if (_bChecked) { _state = DUI_STATE_DOWN; _down = TRUE; } else { _state = DUI_STATE_NORMAL; _down = FALSE; } RaiseInvalidate(TRUE); } } BOOL CRadioButtonCtl::GetCheck() { return _bChecked; } ================================================ FILE: src/DirectUI/DUIRadioButton.h ================================================ #pragma once #include "DUIButton.h" class CRadioButtonCtl : public CButtonCtl { public: CRadioButtonCtl(HWND father, BOOL trans = FALSE); CRadioButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); ~CRadioButtonCtl(void); void SetCheck(BOOL bCheck); BOOL GetCheck(); void Disable(); void Enable(BOOL enable); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void OnMouseDown(UINT nFlags, CPoint point); void OnMouseUp(UINT nFlags, CPoint point); void OnMouseHover(UINT nFlags, CPoint point); void OnMouseLeave(); protected: COLORREF _txtColor; BOOL _bChecked; }; ================================================ FILE: src/DirectUI/DUIStatic.cpp ================================================ #include "StdAfx.h" #include "DUIStatic.h" CStaticCtl::CStaticCtl(HWND father, BOOL trans) { _host = father; _down = FALSE; _class = _T(""); _transparent = trans; _bmpBackground = NULL; _bmpIcon = NULL; _textFont = CGDIResource::GetInstance().GDI_GetNormalFont(); _textCol = RGB(0, 0, 0); _textFormat = DT_LEFT; _viewport = 0; _scrollDelta = 0; } CStaticCtl::CStaticCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans) : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) { _host = father; _class = _T(""); _bmpBackground = NULL; _bmpIcon = NULL; _textFont = CGDIResource::GetInstance().GDI_GetNormalFont(); _textCol = RGB(0, 0, 0); _textFormat = DT_LEFT; _transparent = trans; _viewport = 0; _scrollDelta = 0; } CStaticCtl::~CStaticCtl(void) {} void CStaticCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); _bmpBackground = GetBitmapAttribute(element, "background"); _textCol = GetRGBAttribute(element, "color"); _bmpIcon = GetBitmapAttribute(element, "icon"); if (GetIntegerAttribute(element, "bigfont")) { _textFont = CGDIResource::GetInstance().GDI_GetBiggerFont(); } if (GetIntegerAttribute(element, "samllfont")) { _textFont = CGDIResource::GetInstance().GDI_GetSmallFont(); } _viewport = GetIntegerAttribute(element, "viewport"); } void CStaticCtl::SetTextFont(HFONT font) { _textFont = font; } void CStaticCtl::SetTextColor(COLORREF colText) { _textCol = colText; } void CStaticCtl::SetImage(LPCTSTR lpszImageRes) { _bmpBackground = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG); } void CStaticCtl::SetIcon(LPCTSTR lpszIconRes) { _bmpIcon = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszIconRes, PNG); } void CStaticCtl::SetTextFormat(UINT nTextFormat) { _textFormat = nTextFormat; } void CStaticCtl::OnPaint(HDC hDC) { if (_visible) { UINT nTextFormat = DT_LEFT; DUI_Rect rcText(_location, _size); if (_bmpIcon) { BITMAP bmpIconInfor; GetObject(_bmpIcon, sizeof(bmpIconInfor), &bmpIconInfor); int nY = _location.y + (_size.cy - bmpIconInfor.bmHeight) / 2; CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, _location.x, nY, bmpIconInfor.bmWidth, bmpIconInfor.bmHeight); rcText.left = _location.x + bmpIconInfor.bmWidth + 2; nTextFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; } if (_title.size() > 0) { if (_viewport) { ::SetWindowOrgEx(hDC, 0, _scrollDelta, NULL); rcText.bottom += _scrollDelta; } if (_textFormat != 0) { nTextFormat = _textFormat; } if (_transparent) { CGDIResource::GetInstance().GDI_DrawText_Trans( hDC, _title.c_str(), &rcText, _textFont, _textCol, nTextFormat); } else { CGDIResource::GetInstance().GDI_DrawText( hDC, _title.c_str(), &rcText, _textFont, _textCol, nTextFormat); } if (_viewport) { ::SetWindowOrgEx(hDC, 0, 0, NULL); } } if (_bmpBackground) { int nWidth = _size.cx; int nHeight = _size.cy; CGDIResource::GetInstance().GDI_DrawImage( hDC, _bmpBackground, _location.x, _location.y, nWidth, nHeight); } } } void CStaticCtl::OnMouseDown(UINT nFlags, CPoint point) { if (_visible) { _down = TRUE; } } void CStaticCtl::OnMouseUp(UINT nFlags, CPoint point) { if (_visible) { if (_down) { OnMouseClick(); } _down = FALSE; } } void CStaticCtl::OnCall_LeftUp() { if (_leftup_event.m_func_no_para) _leftup_event.Invoke(); } ================================================ FILE: src/DirectUI/DUIStatic.h ================================================ #pragma once #include "DUIElement.h" class CStaticCtl : public CBaseElementCtl { public: CStaticCtl(HWND father, BOOL trans = FALSE); CStaticCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE); ~CStaticCtl(void); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void OnMouseDown(UINT nFlags, CPoint point); void OnMouseUp(UINT nFlags, CPoint point); void OnCall_LeftUp(); void SetTextFont(HFONT font); void SetTextColor(COLORREF colText); void SetImage(LPCTSTR lpszImageRes); void SetIcon(LPCTSTR lpszIconRes); void SetTextFormat(UINT nTextFormat); protected: HBITMAP _bmpBackground; HBITMAP _bmpIcon; HFONT _textFont; COLORREF _textCol; BOOL _down; UINT _textFormat; BOOL _viewport; public: int _scrollDelta; }; ================================================ FILE: src/DirectUI/DUITab.cpp ================================================ #include "StdAfx.h" #include "DUITab.h" #include "DUITabList.h" CTabCtl::CTabCtl(HWND father, CTabListCtl *pList, BOOL trans) : CButtonCtl(father, trans) { _class = _T(""); _tab_list = pList; _bSel = FALSE; _bmpUpdate = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("TABUPDATE"), PNG); _nCount = 0; _transparent = trans; } CTabCtl::CTabCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement) : CButtonCtl(hWnd, lpszID, lpszTitle, lpszTooptip, rcElement) { _class = _T(""); _bSel = FALSE; _bmpUpdate = CGDIResource::GetInstance().GDI_GetBitmap( _hInstance, _T("CHANNELUPDATE"), PNG); _nCount = 0; } CTabCtl::~CTabCtl(void) {} void CTabCtl::OnPaint(HDC hDC) { CButtonCtl::OnPaint(hDC); } void CTabCtl::OnMouseHover(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { if (_down) { Refresh(DUI_STATE_DOWN); } else { Refresh(DUI_STATE_HOVER); } } } void CTabCtl::OnMouseLeave() { _tracking = FALSE; if (_state != DUI_STATE_DISABLE) { if (_down) { Refresh(DUI_STATE_DOWN); } else { Refresh(DUI_STATE_NORMAL); } } } void CTabCtl::OnMouseUp(UINT nFlags, CPoint point) { if (_state != DUI_STATE_DISABLE) { DUI_BUTTON_STATE state = _state; if (_down && (state == DUI_STATE_DOWN)) { OnMouseClick(); if (_tab_list) _tab_list->SelTab(_id); } } } void CTabCtl::SetSel(BOOL bSel) { _bSel = bSel; if (_state != DUI_STATE_DISABLE) { if (_bSel) { _down = TRUE; Refresh(DUI_STATE_DOWN); } else { _down = FALSE; Refresh(DUI_STATE_NORMAL); } } } BOOL CTabCtl::GetSel() { return _bSel; } void CTabCtl::SetUpdate(int nCount) { _nCount = nCount; RaiseInvalidate(TRUE); } void CTabCtl::RaiseInvalidate(BOOL forceRedraw) { if (_host != NULL) { if (forceRedraw) { DUI_Rect rcTab = Rectangle(); rcTab.top -= 2; rcTab.right += 2; ::InvalidateRect(_host, rcTab, TRUE); } } } ================================================ FILE: src/DirectUI/DUITab.h ================================================ #pragma once #include "DUIButton.h" class CTabListCtl; class CTabCtl : public CButtonCtl { public: CTabCtl(HWND father, CTabListCtl *pList = NULL, BOOL trans = FALSE); CTabCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip, DUI_Rect rcElement); ~CTabCtl(void); public: void SetUpdate(int nCount); void SetSel(BOOL bSel); BOOL GetSel(); void OnPaint(HDC hDC); virtual void OnMouseHover(UINT nFlags, CPoint point); virtual void OnMouseLeave(); virtual void OnMouseUp(UINT nFlags, CPoint point); void RaiseInvalidate(BOOL forceRedraw); protected: HBITMAP _bmpUpdate; BOOL _bSel; int _nCount; CTabListCtl *_tab_list; }; ================================================ FILE: src/DirectUI/DUITabList.cpp ================================================ #include "StdAfx.h" #include "DUITabList.h" using namespace std; CTabListCtl::CTabListCtl(HWND father, BOOL trans) : CPanelCtl(father) { _host = father; _class = _T(""); _transparent = trans; } CTabListCtl::~CTabListCtl(void) {} void CTabListCtl::CreateElement(XmlElementPtr element) { GetElementStyle(element); CXmlHelper helper; vector pAllElement = helper.GetChild(element); vector::iterator ite = pAllElement.begin(); tstring strEleName; CBaseElementCtl *pElement = NULL; for (ite; ite != pAllElement.end(); ite++) { strEleName = helper.GetElementName(*ite); if (!strEleName.compare(_T("tab"))) { pElement = new CTabCtl(_host, this, _transparent); pElement->CreateElement(*ite); _elementmgr.AddElement(pElement); } } } void CTabListCtl::AddPage(const tstring &strTabID, CBaseElementCtl *pElement) { if (strTabID.empty()) return; _mapTabPage[strTabID] = pElement; } void CTabListCtl::SelTab(const tstring &strTabID) { CTabCtl *pTab = NULL; ResetElement(); while ((pTab = (CTabCtl *)GetElement()) != NULL) { if (pTab->GetID() == strTabID) { pTab->SetSel(TRUE); } else { pTab->SetSel(FALSE); } } map::iterator ite = _mapTabPage.begin(); for (ite; ite != _mapTabPage.end(); ite++) { if (ite->first == strTabID) { ite->second->SetVisible(TRUE); } else { ite->second->SetVisible(FALSE); } } } void CTabListCtl::UnSelTab(void) { CTabCtl *pTab = NULL; ResetElement(); while ((pTab = (CTabCtl *)GetElement()) != NULL) { pTab->SetSel(FALSE); } map::iterator ite = _mapTabPage.begin(); for (ite; ite != _mapTabPage.end(); ite++) { ite->second->SetVisible(FALSE); } } void CTabListCtl::OnPaint(HDC hDC) { if (_visible) { _elementmgr.OnPaint(hDC); } } ================================================ FILE: src/DirectUI/DUITabList.h ================================================ #pragma once #include "DUIPanel.h" #include "DUITab.h" class CTabListCtl : public CPanelCtl { public: CTabListCtl(HWND father, BOOL trans = FALSE); ~CTabListCtl(void); void CreateElement(XmlElementPtr element); void OnPaint(HDC hDC); void AddPage(const tstring &strTabID, CBaseElementCtl *pElement); void SelTab(const tstring &strID); void UnSelTab(void); protected: std::map _mapTabPage; }; ================================================ FILE: src/DirectUI/DUITransWindow.cpp ================================================ #include "StdAfx.h" #include "util/util_tools.h" #include "../base/Thread.h" #include "../base/common_threads.h" #include "DUITransWindow.h" using namespace std; const int WINDOW_WIDTH = 960; const int WINDOW_HEIGHT = 600; CTransWindow::CTransWindow() : _bRoundCorner(0) { _bIsWin7 = FALSE; _bActived = FALSE; _nTimerID = 0; _transparent = TRUE; _nMinWidth = 307; _nMinHeight = 451; _nTitleHeight = 20; _bmpFrame = NULL; _bmpFrameBack = NULL; _bmpResize = NULL; _bmpTitle = NULL; _bmpLogo = NULL; _bIsCenter = FALSE; m_ptips = NULL; _bSupportChangeSize = FALSE; _bSupportDblTitle = FALSE; _bOK = FALSE; } CTransWindow::~CTransWindow() { Detach(); } BOOL CTransWindow::DUICreateW(HWND hParentWnd, WCHAR *lpszXml) { CXmlHelper helper; helper.LoadStringW(lpszXml); m_pXmlWindow = helper.GetRoot(); if (m_pXmlWindow == NULL) { return FALSE; } if (helper.GetElementName(m_pXmlWindow).compare(_T("window"))) { return FALSE; } CreateElement(m_pXmlWindow); SetWndPos(_location, _size); SetWndStyle(); DUI_Rect rcWnd(_location, _size); DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style); if (hWnd == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } ::SetForegroundWindow(m_hWnd); OnLoaded(); return TRUE; } BOOL CTransWindow::DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow) { _strXmlWindow = lpszXmlWidow; CXmlHelper helper; helper.loadResFile(_hInstance, _strXmlWindow.c_str(), _T("xml")); m_pXmlWindow = helper.GetRoot(); if (m_pXmlWindow == NULL) { return FALSE; } if (helper.GetElementName(m_pXmlWindow).compare(_T("window"))) { return FALSE; } CreateElement(m_pXmlWindow); SetWndPos(_location, _size); SetWndStyle(); DUI_Rect rcWnd(_location, _size); DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style); if (hWnd == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } ::SetForegroundWindow(m_hWnd); OnLoaded(); return TRUE; } BOOL CTransWindow::DUICreate(HWND hParentWnd, DWORD dwExStyle) { SetWndPos(_location, _size); DUI_Rect rcWnd(_location, _size); DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP; if (Create(hParentWnd, rcWnd, _T(""), dwStyle, dwExStyle) == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } ::SetForegroundWindow(m_hWnd); return TRUE; } void CTransWindow::SetWndPos(DUI_Point &pt, DUI_Size &sz) {} BOOL CTransWindow::DoModal() { HWND hWndParent = ::GetWindow(m_hWnd, GW_OWNER); ::ShowWindow(m_hWnd, SW_SHOWNORMAL); ::EnableWindow(hWndParent, FALSE); std::auto_ptr message_loop; message_loop.reset( new base::MessageLoop::LayerLoop(base::MessageLoop::TYPE_UI)); CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current()); (static_cast(message_loop->pump_win())) ->upPumpLayer(static_cast( base::Threads::Get(Threads::UI)->pump_win())); base::MessageLoop::LayerLoop::PushBackLoop(message_loop.get()); message_loop->Run(); base::MessageLoop::LayerLoop::PopBackLoop(); ::EnableWindow(hWndParent, TRUE); ::SetFocus(hWndParent); return _bOK; } LRESULT CTransWindow::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _host = m_hWnd; if (_bIsCenter) CenterWindow(); _elementManager.InitOwner(m_hWnd); OnDynamicCreate(); if (!m_ptips) m_ptips = new CToolTipCtrl; m_ptips->Create(m_hWnd); m_ptips->Activate(FALSE); m_ptips->AddTool(m_hWnd); m_ptips->SetMaxTipWidth(260); OnLoad(); SetWindowText(_title.c_str()); OnLoadIcon(); return 0; } LRESULT CTransWindow::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (m_ptips) { if (::IsWindow((m_ptips->m_hWnd))) { m_ptips->DestroyWindow(); } delete m_ptips; m_ptips = NULL; } return 0; } void CTransWindow::OnLoadIcon() { static HICON hIcon = (HICON)::LoadImage( _Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); if (hIcon) { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); } } void CTransWindow::OnDynamicCreate() { CXmlHelper helper; vector pAllElement = helper.GetChild(m_pXmlWindow); vector::iterator ite = pAllElement.begin(); tstring strEleName; CBaseElementCtl *pElement = NULL; for (ite; ite != pAllElement.end(); ite++) { CXmlHelper helper; strEleName = helper.GetElementName(*ite); if (!strEleName.compare(_T("button"))) { pElement = new CButtonCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("static"))) { pElement = new CStaticCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("tablist"))) { pElement = new CTabListCtl(_host, _transparent); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("link"))) { pElement = new CHyperLinkCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("layedit"))) { pElement = new CLayeredEditCtl(m_hWnd); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("panel"))) { pElement = new CPanelCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("progress"))) { pElement = new CProgressCtl(m_hWnd); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("checkbox"))) { pElement = new CCheckBoxCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } } } void CTransWindow::SetWndStyle() {} void CTransWindow::CreateElement(XmlElementPtr element) { GetElementStyle(element); _nMinWidth = GetIntegerAttribute(element, "minWidth"); _nMinHeight = GetIntegerAttribute(element, "minHeight"); _nTitleHeight = GetIntegerAttribute(element, "titleHeight"); _strIconFile = GetStringAttribute(element, "icon"); _bmpFrame = GetBitmapAttribute(element, "frame"); _rcFrameCorner = GetRectAttribute(element, "frameCorner"); _bmpFrameBack = GetBitmapAttribute(element, "frameBack"); _rcFrameBackCorner = GetRectAttribute(element, "frameBackCorner"); _rcFrameBackPos = GetRectAttribute(element, "frameBackPos"); _bIsCenter = GetIntegerAttribute(element, "center") == 1 ? TRUE : FALSE; _bmpResize = GetBitmapAttribute(element, "resize"); _bmpTitle = GetBitmapAttribute(element, "title"); _bmpLogo = GetBitmapAttribute(element, "logo"); _bRoundCorner = GetIntegerAttribute(element, "roundcorner"); } HRESULT CTransWindow::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { bHandled = TRUE; return 0; } void CTransWindow::DrawBg(HDC hDC) { DrawBorder(hDC); DrawTitle(hDC); } void CTransWindow::OnDraw(HDC hDC) { _elementManager.OnPaint(hDC); } void CTransWindow::DrawFrame(CDCHandle dc) { RECT rcClient; GetClientRect(&rcClient); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawRectangle( hDC, &rcClient, RGB(110, 150, 177), RGB(182, 234, 253)); } void CTransWindow::DrawBorder(CDCHandle dc) { DUI_Rect wndRect; GetClientRect(&wndRect); HDC hDC = dc.m_hDC; BITMAP bmpFrameData; GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData); if (_bmpFrame) { CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpFrame, wndRect, DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255, _rcFrameCorner); } if (_bmpFrameBack) { BITMAP bmpBackData; GetObject(_bmpFrameBack, sizeof(bmpBackData), &bmpBackData); CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpFrameBack, _rcFrameBackPos, DUI_Rect(0, 0, bmpBackData.bmWidth, bmpBackData.bmHeight), 255, _rcFrameBackCorner); } } void CTransWindow::DrawTitle(CDCHandle dc) { BITMAP bmpLogoInfor; if (_bmpLogo) { GetObject(_bmpLogo, sizeof(bmpLogoInfor), &bmpLogoInfor); int nLeft = 10; int nTop = 10; CGDIResource::GetInstance().GDI_DrawImage( dc.m_hDC, _bmpLogo, nLeft, nTop, bmpLogoInfor.bmWidth, bmpLogoInfor.bmHeight, DUI_BT_ALPHA); } if (_title.size() > 0) { RECT rcClient; GetClientRect(&rcClient); RECT rcText; rcText.left = _bmpLogo != NULL ? 10 + bmpLogoInfor.bmWidth + 7 : 18; rcText.right = rcClient.right - 1; rcText.top = 9; rcText.bottom = _nTitleHeight > 0 ? _nTitleHeight : rcText.top + 20; CGDIResource::GetInstance().GDI_DrawText_Trans( dc.m_hDC, _title.c_str(), &rcText, CGDIResource::GetInstance().GDI_GetNormalFont(), RGB(255, 255, 255)); } } LRESULT CTransWindow::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { RECT rect; GetWindowRect(&rect); int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); DUI_Point pt(x, y); ScreenToClient(&pt); if (_elementManager.MouseOnElement(pt)) return HTCLIENT; UINT nFlags = 0; _elementManager.OnMouseMove(nFlags, pt); int nTop = 4; int nLeft = 4; int nRight = 4; int nBottom = 4; if (IsZoomed()) { if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; return HTCLIENT; } if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (_bSupportChangeSize) { if (x >= rect.left && x <= rect.left + nLeft) { if (y < rect.top + nTop) return HTTOPLEFT; else if (y > rect.bottom - nBottom) return HTBOTTOMLEFT; return HTLEFT; } if (x <= rect.right && x >= rect.right - nRight) { if (y < rect.top + nTop) return HTTOPRIGHT; else if (y > rect.bottom - nBottom) return HTBOTTOMRIGHT; return HTRIGHT; } if (y >= rect.top && y <= rect.top + nTop) return HTTOP; if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (y <= rect.bottom && y >= rect.bottom - nBottom) { return HTBOTTOM; } } return HTCLIENT; } LRESULT CTransWindow::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { int cx = GET_X_LPARAM(lParam); int cy = GET_Y_LPARAM(lParam); _elementManager.OnSizeChanged(_size, cx, cy); _size.cx = cx; _size.cy = cy; SetSkinedWindowRgn(_bRoundCorner); return 0; } LRESULT CTransWindow::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyDown((DWORD)wParam); return 0; } LRESULT CTransWindow::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyUp((DWORD)wParam); return 0; } LRESULT CTransWindow::OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyDown((DWORD)wParam); return 0; } LRESULT CTransWindow::OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyUp((DWORD)wParam); return 0; } LRESULT CTransWindow::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { MINMAXINFO *lpMMI = (MINMAXINFO *)lParam; lpMMI->ptMinTrackSize.x = _nMinWidth; lpMMI->ptMinTrackSize.y = _nMinHeight; RECT rt; SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rt, 0); lpMMI->ptMaxPosition.x = rt.left; lpMMI->ptMaxPosition.y = rt.top; lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x = rt.right - rt.left; lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y = rt.bottom - rt.top; return 0; } LRESULT CTransWindow::OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (_bSupportDblTitle) { if (IsZoomed()) ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0); else ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); } return 0; } LRESULT CTransWindow::OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (IsZoomed() && !_bIsWin7) { ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0); } else { ModifyStyle(WS_SYSMENU, 0, 0); } return 0; } LRESULT CTransWindow::OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0); bHandled = FALSE; return 0; } LRESULT CTransWindow::OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return 0; } LRESULT CTransWindow::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseDown(uMsg, pt); return 0; } LRESULT CTransWindow::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseUp(uMsg, pt); return 0; } LRESULT CTransWindow::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } LRESULT CTransWindow::OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseRUp(uMsg, pt); return 0; } LRESULT CTransWindow::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { MSG msg; msg.hwnd = m_hWnd; msg.message = WM_MOUSEMOVE; msg.wParam = 0; msg.lParam = GetMessagePos(); if (m_ptips) m_ptips->RelayEvent(&msg); DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseMove(uMsg, pt); TrackMouseLeave(m_hWnd); return 0; } LRESULT CTransWindow::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseMove(uMsg, pt); return 0; } LRESULT CTransWindow::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return 0; } LRESULT CTransWindow::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (!IsWindow()) { return 0; } UINT nState = (UINT)wParam; if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) { _bActived = TRUE; } else { _bActived = FALSE; } RECT rcClient; GetClientRect(&rcClient); rcClient.bottom = rcClient.top + _nTitleHeight; InvalidateRect(&rcClient); return 0; } LRESULT CTransWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { ShowWindow(SW_HIDE); OnExit(); return 0; } LRESULT CTransWindow::OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnMove(); return 0; } LRESULT CTransWindow::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (wParam == ACTIVE_TIMER) { _elementManager.DrawCursor(); } return 0; } void CTransWindow::SetSkinedWindowRgn(BOOL bRound) { if (!bRound) { ::SetWindowRgn(m_hWnd, NULL, TRUE); } else { RECT rect; GetWindowRect(&rect); OffsetRect(&rect, -rect.left, -rect.top); const int nRgnCornerSize = 5; HRGN hRgn1 = CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom, nRgnCornerSize, nRgnCornerSize); HRGN hRgn2 = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right, rect.bottom); HRGN hRgn = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right, rect.bottom); CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR); DeleteObject(hRgn1); DeleteObject(hRgn2); ::SetWindowRgn(m_hWnd, hRgn, TRUE); } } BOOL CTransWindow::PreTranslateMessage(MSG *pMsg) { if (m_ptips && ::IsWindow(m_ptips->m_hWnd)) { m_ptips->RelayEvent(pMsg); } return FALSE; } LRESULT CTransWindow::OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (!m_ptips) return 0; BOOL bTips = (BOOL)wParam; if (bTips) { LPCTSTR lpszText = (LPCTSTR)lParam; m_ptips->UpdateTipText(lpszText, m_hWnd); m_ptips->Activate(TRUE); } else { m_ptips->Activate(FALSE); } return 0; } LRESULT CTransWindow::OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; _elementManager.SetActive(pOwner); return 0; } LRESULT CTransWindow::OnChainMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnMsg(nMsg, wParam, lParam, bHandled); return 0; } LRESULT CTransWindow::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { HCURSOR hCur = (HCURSOR)wParam; if (hCur == LoadCursor(NULL, IDC_HAND)) { ::SetClassLong(m_hWnd, GCL_HCURSOR, (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND))); } else if (hCur == LoadCursor(NULL, IDC_IBEAM)) { ::SetClassLong(m_hWnd, GCL_HCURSOR, (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_IBEAM))); } else { ::SetClassLong(m_hWnd, GCL_HCURSOR, (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); } return 0; } LRESULT CTransWindow::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { UINT fwKeys = LOWORD(wParam); /* key flags */ short zDelta = (short)HIWORD(wParam); /* wheel rotation */ int xPos = (short)LOWORD(lParam); /* horizontal position of pointer */ int yPos = (short)HIWORD(lParam); /* vertical position of pointer */ CPoint pt(xPos, yPos); ScreenToClient(&pt); _elementManager.OnMouseWheel(fwKeys, zDelta, pt); return 0; } void CTransWindow::OnLoad() {} void CTransWindow::OnLoaded() {} void CTransWindow::OnExit() { _elementManager.Dispose(); } DWORD CTransWindow::OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_NOTIFYITEMDRAW; } DWORD CTransWindow::OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_DODEFAULT; } DWORD CTransWindow::OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_DODEFAULT; } ================================================ FILE: src/DirectUI/DUITransWindow.h ================================================ #pragma once #include "DUIButton.h" #include "DUICheckBox.h" #include "DUIElement.h" #include "DUIElementsMgr.h" #include "DUIHyperLink.h" #include "DUILayeredEdit.h" #include "DUIPanel.h" #include "DUIProgress.h" #include "DUIStatic.h" #include "DUITab.h" #include "DUITabList.h" #include "UpdateWindowBase.h" #define CHAIN_ALL_MSG(func) \ { \ if (func(uMsg, wParam, lParam, bHandled)) \ return TRUE; \ } class __declspec(novtable) CTransWindow : public CMessageFilter, public CBaseElementCtl, public CUpdateWindowBase { public: CTransWindow(); virtual ~CTransWindow(); DECLARE_WND_CLASS(NULL) BEGIN_MSG_MAP(CTransWindow) CHAIN_MSG_MAP(CUpdateWindowBase) CHAIN_ALL_MSG(OnChainMsg) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown) MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp) MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk) MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNcMouseMove) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP) MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown) MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUP) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_MOVE, OnMove) MESSAGE_HANDLER(WM_CLOSE, OnClose) MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) MESSAGE_HANDLER(WM_GETICON, OnGetIcon) MESSAGE_HANDLER(WM_MSG_TIPS, OnTips) MESSAGE_HANDLER(WM_MSG_CURSOR, OnSetCursor) MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseWheel) MESSAGE_HANDLER(WM_ASYNC_CALL_LUP, OnAsynCall_LUp) MESSAGE_HANDLER(WM_ASYNC_CALL_RUP, OnAsynCall_RUp) MESSAGE_HANDLER(WM_MSG_ACTIVE, OnElementActive) END_MSG_MAP() BOOL DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow); BOOL DUICreateW(HWND hParentWnd, WCHAR *lpszXml); BOOL DUICreate(HWND hParentWnd, DWORD dwExStyle = 0); BOOL DoModal(); virtual void DrawBg(HDC hDC); virtual void OnDraw(HDC hDC); virtual void DrawFrame(CDCHandle dc); virtual void DrawBorder(CDCHandle dc); virtual void DrawTitle(CDCHandle dc); virtual LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnChainMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual BOOL PreTranslateMessage(MSG *pMsg); virtual void SetWndPos(DUI_Point &pt, DUI_Size &sz); virtual void OnLoad(); virtual void OnLoaded(); virtual void OnExit(); virtual void OnLoadIcon(); virtual DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); virtual DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); virtual DWORD OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); BOOL _bOK; protected: virtual void OnDynamicCreate(); virtual void SetSkinedWindowRgn(BOOL bZoomed); virtual void CreateElement(XmlElementPtr element); virtual void SetWndStyle(); BOOL _bIsWin7; BOOL _bActived; int _nTimerID; CAnyElementsMgr _elementManager; CToolTipCtrl *m_ptips; BOOL _bSupportDblTitle; BOOL _bSupportChangeSize; int _nMinWidth; int _nMinHeight; int _nTitleHeight; BOOL _bIsCenter; BOOL _bRoundCorner; tstring _strXmlWindow; tstring _strIconFile; HBITMAP _bmpSingleBack; HBITMAP _bmpArrow; HBITMAP _bmpBackgroundTL; HBITMAP _bmpBackgroundT; HBITMAP _bmpBackgroundTR; HBITMAP _bmpBackgroundL; HBITMAP _bmpBackgroundC; HBITMAP _bmpBackgroundR; HBITMAP _bmpBackgroundBL; HBITMAP _bmpBackgroundB; HBITMAP _bmpBackgroundBR; HBITMAP _bmpFrame; DUI_Rect _rcFrameCorner; HBITMAP _bmpFrameBack; DUI_Rect _rcFrameBackCorner; DUI_Rect _rcFrameBackPos; HBITMAP _bmpResize; HBITMAP _bmpTitle; HBITMAP _bmpLogo; XmlElementPtr m_pXmlWindow; }; inline LRESULT CTransWindow::OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_LeftUp(); return S_OK; } inline LRESULT CTransWindow::OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_RightUp(); return S_OK; } ================================================ FILE: src/DirectUI/DUITransWindowEx.cpp ================================================ #include "stdafx.h" #include "DUITransWindowEx.h" ================================================ FILE: src/DirectUI/DUITransWindowEx.h ================================================ #pragma once #include "util/system.h" #include "DUIButton.h" #include "DUICheckBox.h" #include "DUIElement.h" #include "DUIElementsMgr.h" #include "DUIHyperLink.h" #include "DUILayeredEdit.h" #include "DUIOptionLine.h" #include "DUIPanel.h" #include "DUIProgress.h" #include "DUIStatic.h" #include "DUITab.h" #include "DUITabList.h" #include "UpdateWindowBaseEx.h" enum enumShakeWindow { SHAKEWINDOW_ERROR = 0 }; #define SHAKEWINDOW 0x10 template class __declspec(novtable) CTransWindowEx : public CMessageFilter, public CBaseElementCtl, public CUpdateWindowBaseEx { public: CTransWindowEx(); virtual ~CTransWindowEx(); BEGIN_MSG_MAP(CTransWindowEx) CHAIN_MSG_MAP(CUpdateWindowBaseEx) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown) MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp) MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk) MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNcMouseMove) MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP) MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown) MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUP) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_ACTIVATE, OnActivate) MESSAGE_HANDLER(WM_MOVE, OnMove) MESSAGE_HANDLER(WM_CLOSE, OnClose) MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo) MESSAGE_HANDLER(WM_GETICON, OnGetIcon) MESSAGE_HANDLER(WM_TIMER, OnTimer) MESSAGE_HANDLER(WM_MSG_TIPS, OnTips) MESSAGE_HANDLER(WM_MSG_CURSOR, OnSetCursor) MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseWheel) MESSAGE_HANDLER(WM_ASYNC_CALL_LUP, OnAsynCall_LUp) MESSAGE_HANDLER(WM_ASYNC_CALL_RUP, OnAsynCall_RUp) MESSAGE_HANDLER(WM_ASYNC_CALL_ENTERKEY, OnAsynCall_EnterKey) MESSAGE_HANDLER(WM_ASYNC_CALL_TABKEY, OnAsynCall_TabKey) MESSAGE_HANDLER(WM_ASYNC_CALL_LDOWN, OnAsynCall_LDown) MESSAGE_HANDLER(WM_MSG_ACTIVE, OnElementActive) MESSAGE_HANDLER(WM_PATH_ILLCHARACTER, OnPathIllCharacter) END_MSG_MAP() BOOL DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow); BOOL DUICreateW(HWND hParentWnd, WCHAR *lpszXml); BOOL DUICreate(HWND hParentWnd, DWORD dwExStyle = 0); BOOL DoModal(); virtual void DrawBg(HDC hDC); virtual void OnDraw(HDC hDC); virtual void DrawFrame(CDCHandle dc); virtual void DrawBorder(CDCHandle dc); virtual void DrawTitle(CDCHandle dc); virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_EnterKey(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_TabKey(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnAsynCall_LDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual BOOL PreTranslateMessage(MSG *pMsg); virtual void SetWndPos(DUI_Point &pt, DUI_Size &sz); virtual void OnLoad(); virtual void OnLoaded(); virtual void OnExit(); virtual void OnLoadIcon(); virtual DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); virtual DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); virtual DWORD OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD); void ChangeSize(int w, int h); protected: virtual void OnDynamicCreate(); virtual void SetSkinedWindowRgn(BOOL bZoomed); virtual void CreateElement(XmlElementPtr element); virtual void SetWndStyle(); BOOL _bIsWin7; BOOL _bActived; int _nTimerID; CAnyElementsMgr _elementManager; CToolTipCtrl m_tips; BOOL _bSupportDblTitle; BOOL _bSupportChangeSize; int _nMinWidth; int _nMinHeight; int _nTitleHeight; BOOL _bIsCenter; tstring _strXmlWindow; tstring _strIconFile; HBITMAP _bmpSingleBack; HBITMAP _bmpArrow; HBITMAP _bmpBackgroundTL; HBITMAP _bmpBackgroundT; HBITMAP _bmpBackgroundTR; HBITMAP _bmpBackgroundL; HBITMAP _bmpBackgroundC; HBITMAP _bmpBackgroundR; HBITMAP _bmpBackgroundBL; HBITMAP _bmpBackgroundB; HBITMAP _bmpBackgroundBR; HBITMAP _bmpFrame; DUI_Rect _rcFrameCorner; HBITMAP _bmpFrameBack; DUI_Rect _rcFrameBackCorner; DUI_Rect _rcFrameBackPos; HBITMAP _bmpResize; HBITMAP _bmpTitle; HBITMAP _bmpLogo; XmlElementPtr m_pXmlWindow; BOOL _bOK; bool bshaking_; protected: virtual void StartShake() {} virtual void Shaked() {} public: void ShakeWindow(int reason = 0); RECT m_WindowRect; int m_count; int m_Lrud; void LmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) { o_rc = i_rc; o_rc.left -= delta; o_rc.right -= delta; } void UmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) { o_rc = i_rc; o_rc.top -= delta; o_rc.bottom -= delta; } void RmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) { o_rc = i_rc; o_rc.left += delta; o_rc.right += delta; } void DmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) { o_rc = i_rc; o_rc.top += delta; o_rc.bottom += delta; } }; template LRESULT CTransWindowEx::OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_LeftUp(); return S_OK; } template LRESULT CTransWindowEx::OnAsynCall_LDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_LeftDown(); return S_OK; } template LRESULT CTransWindowEx::OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_RightUp(); return S_OK; } template LRESULT CTransWindowEx::OnAsynCall_EnterKey(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; pOwner->OnCall_EnterKey(); return S_OK; } template LRESULT CTransWindowEx::OnAsynCall_TabKey(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return S_OK; } template CTransWindowEx::CTransWindowEx() : bshaking_(false) { _bIsWin7 = FALSE; _bActived = FALSE; _nTimerID = 0; _transparent = TRUE; _nMinWidth = 307; _nMinHeight = 451; _nTitleHeight = 20; _bmpArrow = NULL; _bmpFrame = NULL; _bmpFrameBack = NULL; _bmpResize = NULL; _bmpTitle = NULL; _bmpLogo = NULL; _bIsCenter = FALSE; _bSupportChangeSize = FALSE; _bSupportDblTitle = FALSE; _bOK = FALSE; m_count = 0; m_Lrud = 0; } template CTransWindowEx::~CTransWindowEx() { Detach(); } template BOOL CTransWindowEx::DUICreateW(HWND hParentWnd, WCHAR *lpszXml) { CXmlHelper helper; helper.LoadStringW(lpszXml); m_pXmlWindow = helper.GetRoot(); if (m_pXmlWindow == NULL) { return FALSE; } if (helper.GetElementName(m_pXmlWindow).compare(_T("window"))) { return FALSE; } CreateElement(m_pXmlWindow); SetWndPos(_location, _size); SetWndStyle(); DUI_Rect rcWnd(_location, _size); _CUpdateWindowBaseEx_WndRect_con = rcWnd; DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME; _style |= DS_MODALFRAME; HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style); if (hWnd == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } ::SetForegroundWindow(m_hWnd); OnLoaded(); return TRUE; } template BOOL CTransWindowEx::DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow) { _strXmlWindow = lpszXmlWidow; CXmlHelper helper; helper.loadResFile(_hInstance, _strXmlWindow.c_str(), _T("xml")); m_pXmlWindow = helper.GetRoot(); if (m_pXmlWindow == NULL) { return FALSE; } if (helper.GetElementName(m_pXmlWindow).compare(_T("window"))) { return FALSE; } CreateElement(m_pXmlWindow); SetWndPos(_location, _size); SetWndStyle(); DUI_Rect rcWnd(_location, _size); _CUpdateWindowBaseEx_WndRect_con = rcWnd; DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME; _style |= DS_MODALFRAME; HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style); if (hWnd == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } ::SetForegroundWindow(m_hWnd); OnLoaded(); return TRUE; } template BOOL CTransWindowEx::DUICreate(HWND hParentWnd, DWORD dwExStyle) { SetWndPos(_location, _size); DUI_Rect rcWnd(_location, _size); _CUpdateWindowBaseEx_WndRect_con = rcWnd; DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME; if (Create(hParentWnd, rcWnd, _T(""), dwStyle, dwExStyle) == NULL) { ATLTRACE(_T("Main window creation failed!\n")); return FALSE; } if (dwExStyle & WS_EX_TOOLWINDOW) { ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } else { ::SetForegroundWindow(m_hWnd); } return TRUE; } template void CTransWindowEx::SetWndPos(DUI_Point &pt, DUI_Size &sz) {} template BOOL CTransWindowEx::DoModal() { // todo return _bOK; } template LRESULT CTransWindowEx::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _host = m_hWnd; if (_bIsCenter) { CenterWindow(); GetWindowRect(&_CUpdateWindowBaseEx_WndRect_con); } _elementManager.InitOwner(m_hWnd); OnDynamicCreate(); m_tips.Create(m_hWnd); m_tips.Activate(FALSE); m_tips.AddTool(m_hWnd); m_tips.SetMaxTipWidth(260); OnLoad(); OnLoadIcon(); return 0; } template void CTransWindowEx::OnLoadIcon() { static HICON hIcon = (HICON)::LoadImage( _Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); if (hIcon) { SetIcon(hIcon, TRUE); SetIcon(hIcon, FALSE); } } template void CTransWindowEx::OnDynamicCreate() { CXmlHelper helper; std::vector pAllElement = helper.GetChild(m_pXmlWindow); std::vector::iterator ite = pAllElement.begin(); tstring strEleName; CBaseElementCtl *pElement = NULL; for (ite; ite != pAllElement.end(); ite++) { CXmlHelper helper; strEleName = helper.GetElementName(*ite); if (!strEleName.compare(_T("button"))) { pElement = new CButtonCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("tab"))) { pElement = new CTabCtl(m_hWnd); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("static"))) { pElement = new CStaticCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("link"))) { pElement = new CHyperLinkCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("layedit"))) { pElement = new CLayeredEditCtl(m_hWnd); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("panel"))) { pElement = new CPanelCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("progress"))) { pElement = new CProgressCtl(m_hWnd); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); } if (!strEleName.compare(_T("checkbox"))) { pElement = new CCheckBoxCtl(m_hWnd, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("tablist"))) { pElement = new CTabListCtl(_host, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); continue; } if (!strEleName.compare(_T("optionline"))) { pElement = new COptionLineCtl(_host, TRUE); pElement->CreateElement(*ite); _elementManager.AddElement(pElement); } } } template void CTransWindowEx::CreateElement(XmlElementPtr element) { GetElementStyle(element); _nMinWidth = GetIntegerAttribute(element, "minWidth"); _nMinHeight = GetIntegerAttribute(element, "minHeight"); _nTitleHeight = GetIntegerAttribute(element, "titleHeight"); _strIconFile = GetStringAttribute(element, "icon"); _bmpFrame = GetBitmapAttribute(element, "frame"); _rcFrameCorner = GetRectAttribute(element, "frameCorner"); _bmpFrameBack = GetBitmapAttribute(element, "frameBack"); _rcFrameBackCorner = GetRectAttribute(element, "frameBackCorner"); _rcFrameBackPos = GetRectAttribute(element, "frameBackPos"); _bIsCenter = GetIntegerAttribute(element, "center") == 1 ? TRUE : FALSE; GetIntegerAttribute(element, "topmost") ? (_ex_style |= WS_EX_TOPMOST) : _ex_style; _bmpResize = GetBitmapAttribute(element, "resize"); _bmpTitle = GetBitmapAttribute(element, "title"); _bmpLogo = GetBitmapAttribute(element, "logo"); } template void CTransWindowEx::DrawBg(HDC hDC) { DrawBorder(hDC); DrawTitle(hDC); } template void CTransWindowEx::OnDraw(HDC hDC) { _elementManager.OnPaint(hDC); } template void CTransWindowEx::DrawFrame(CDCHandle dc) { RECT rcClient; GetClientRect(&rcClient); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawRectangle( hDC, &rcClient, RGB(110, 150, 177), RGB(182, 234, 253)); } template void CTransWindowEx::DrawBorder(CDCHandle dc) { if (!_bmpFrame) return; DUI_Rect wndRect(0, 0, 0, 0); if (_bCUpdateWindowBaseEx_TransShow) { HDC hDC = dc.m_hDC; BITMAP bmpFrameData; GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData); wndRect.right = _CUpdateWindowBaseEx_WndRect_con.Width(); wndRect.bottom = _CUpdateWindowBaseEx_WndRect_con.Height(); CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpFrame, wndRect, DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255, _rcFrameCorner); } else { GetClientRect(&wndRect); HDC hDC = dc.m_hDC; BITMAP bmpFrameData; GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData); CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpFrame, wndRect, DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255, _rcFrameCorner); } } template void CTransWindowEx::DrawTitle(CDCHandle dc) { BITMAP bmpLogoInfor; if (_bmpLogo) { GetObject(_bmpLogo, sizeof(bmpLogoInfor), &bmpLogoInfor); int nLeft = 12; int nTop = 10; if (nTop < 0) nTop = 0; CGDIResource::GetInstance().GDI_DrawImage( dc.m_hDC, _bmpLogo, nLeft, nTop, bmpLogoInfor.bmWidth, bmpLogoInfor.bmHeight, DUI_BT_ALPHA); } if (_title.size() > 0) { RECT rcClient = {0, 0, 0, 0}; if (_bCUpdateWindowBaseEx_TransShow) { rcClient.right = _CUpdateWindowBaseEx_WndRect_con.Width(); rcClient.bottom = _CUpdateWindowBaseEx_WndRect_con.Height(); } else GetClientRect(&rcClient); RECT rcText; rcText.left = _bmpLogo != NULL ? 8 + bmpLogoInfor.bmWidth + 8 : 14; rcText.right = rcClient.right - 1; rcText.top = 9; rcText.bottom = _nTitleHeight > 0 ? _nTitleHeight : rcText.top + 20; if (1) { CGDIResource::GetInstance().GDI_DrawText_Trans( dc.m_hDC, _title.c_str(), &rcText, RGB(255, 255, 255)); } } } template LRESULT CTransWindowEx::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (bshaking_) { bHandled = TRUE; return S_OK; } RECT rect; GetWindowRect(&rect); int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); DUI_Point pt(x, y); ScreenToClient(&pt); if (_elementManager.MouseOnElement(pt)) return HTCLIENT; UINT nFlags = 0; _elementManager.OnMouseMove(nFlags, pt); int nTop = 4; int nLeft = 4; int nRight = 4; int nBottom = 4; if (IsZoomed()) { if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; return HTCLIENT; } if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (_bSupportChangeSize) { if (x >= rect.left && x <= rect.left + nLeft) { if (y < rect.top + nTop) return HTTOPLEFT; else if (y > rect.bottom - nBottom) return HTBOTTOMLEFT; return HTLEFT; } if (x <= rect.right && x >= rect.right - nRight) { if (y < rect.top + nTop) return HTTOPRIGHT; else if (y > rect.bottom - nBottom) return HTBOTTOMRIGHT; return HTRIGHT; } if (y >= rect.top && y <= rect.top + nTop) return HTTOP; if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (y <= rect.bottom && y >= rect.bottom - nBottom) { return HTBOTTOM; } } return HTCLIENT; } template LRESULT CTransWindowEx::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (_bCUpdateWindowBaseEx_TransShow) return 0; int cx = GET_X_LPARAM(lParam); int cy = GET_Y_LPARAM(lParam); _elementManager.OnSizeChanged(_size, cx, cy); _size.cx = cx; _size.cy = cy; return 0; } template void CTransWindowEx::ChangeSize(int a, int b) { _size.cx = a; _size.cy = b; _elementManager.OnSizeChanged(_size, a, b); } template LRESULT CTransWindowEx::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyDown((DWORD)wParam); return 0; } template LRESULT CTransWindowEx::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyUp((DWORD)wParam); return 0; } template LRESULT CTransWindowEx::OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyDown((DWORD)wParam); return 0; } template LRESULT CTransWindowEx::OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnKeyUp((DWORD)wParam); return 0; } template LRESULT CTransWindowEx::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { MINMAXINFO *lpMMI = (MINMAXINFO *)lParam; lpMMI->ptMinTrackSize.x = _nMinWidth; lpMMI->ptMinTrackSize.y = _nMinHeight; RECT rt; SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rt, 0); lpMMI->ptMaxPosition.x = rt.left; lpMMI->ptMaxPosition.y = rt.top; lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x = rt.right - rt.left; lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y = rt.bottom - rt.top; return 0; } template LRESULT CTransWindowEx::OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (_bSupportDblTitle) { if (IsZoomed()) ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0); else ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0); } return 0; } template LRESULT CTransWindowEx::OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (IsZoomed() && !_bIsWin7) { ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0); } else { ModifyStyle(WS_SYSMENU, 0, 0); } return 0; } template LRESULT CTransWindowEx::OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0); bHandled = FALSE; return 0; } template LRESULT CTransWindowEx::OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return 0; } template LRESULT CTransWindowEx::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseDown(uMsg, pt); return 0; } template LRESULT CTransWindowEx::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseUp(uMsg, pt); return 0; } template LRESULT CTransWindowEx::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } template LRESULT CTransWindowEx::OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseRUp(uMsg, pt); return 0; } template LRESULT CTransWindowEx::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { MSG msg; msg.hwnd = m_hWnd; msg.message = WM_MOUSEMOVE; msg.wParam = 0; msg.lParam = GetMessagePos(); if (IsWindow()) m_tips.RelayEvent(&msg); DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseMove(uMsg, pt); TrackMouseLeave(m_hWnd); return 0; } template LRESULT CTransWindowEx::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { bHandled = TRUE; DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); _elementManager.OnMouseMove(uMsg, pt); return 0; } template LRESULT CTransWindowEx::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return 0; } template LRESULT CTransWindowEx::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (!IsWindow()) { return 0; } UINT nState = (UINT)wParam; if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) { _bActived = TRUE; } else { _bActived = FALSE; } RECT rcClient; GetClientRect(&rcClient); rcClient.bottom = rcClient.top + _nTitleHeight; InvalidateRect(&rcClient); return 0; } template LRESULT CTransWindowEx::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { this->OnExit(); return 0; } template LRESULT CTransWindowEx::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (::IsWindow((m_tips.m_hWnd))) { m_tips.DestroyWindow(); } m_tips.m_hWnd = NULL; KillTimer(SHAKEWINDOW); return 0; } template LRESULT CTransWindowEx::OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { return 0; } template void CTransWindowEx::OnExit() { _elementManager.Dispose(); } template LRESULT CTransWindowEx::OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { _elementManager.OnMove(); return 0; } template void CTransWindowEx::SetSkinedWindowRgn(BOOL bZoomed) { if (bZoomed) { ::SetWindowRgn(m_hWnd, NULL, TRUE); } else { RECT rect; GetWindowRect(&rect); OffsetRect(&rect, -rect.left, -rect.top); const int nRgnCornerSize = 5; HRGN hRgn1 = CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom, nRgnCornerSize, nRgnCornerSize); HRGN hRgn2 = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right, rect.bottom); HRGN hRgn = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right, rect.bottom); CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR); DeleteObject(hRgn1); DeleteObject(hRgn2); ::SetWindowRgn(m_hWnd, hRgn, TRUE); } } template BOOL CTransWindowEx::PreTranslateMessage(MSG *pMsg) { if (::IsWindow(m_tips.m_hWnd)) { m_tips.RelayEvent(pMsg); } return FALSE; } template LRESULT CTransWindowEx::OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { BOOL bTips = (BOOL)wParam; if (bTips) { LPCTSTR lpszText = (LPCTSTR)lParam; m_tips.UpdateTipText(lpszText, m_hWnd); m_tips.Activate(TRUE); } else { m_tips.Activate(FALSE); } return 0; } template LRESULT CTransWindowEx::OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam; _elementManager.SetActive(pOwner); return 0; } template LRESULT CTransWindowEx::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { HCURSOR hCur = (HCURSOR)wParam; if (hCur == LoadCursor(NULL, IDC_HAND)) { ::SetClassLong(m_hWnd, GCL_HCURSOR, (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND))); } else { ::SetClassLong(m_hWnd, GCL_HCURSOR, (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); } return 0; } template LRESULT CTransWindowEx::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { UINT fwKeys = LOWORD(wParam); /* key flags */ short zDelta = (short)HIWORD(wParam); /* wheel rotation */ int xPos = (short)LOWORD(lParam); /* horizontal position of pointer */ int yPos = (short)HIWORD(lParam); /* vertical position of pointer */ CPoint pt(xPos, yPos); ScreenToClient(&pt); _elementManager.OnMouseWheel(fwKeys, zDelta, pt); return 0; } template void CTransWindowEx::OnLoad() {} template void CTransWindowEx::OnLoaded() {} template DWORD CTransWindowEx::OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_NOTIFYITEMDRAW; } template DWORD CTransWindowEx::OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_DODEFAULT; } template DWORD CTransWindowEx::OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) { return CDRF_DODEFAULT; } template void CTransWindowEx::ShakeWindow(int reason) { SystemCommon::Window::StretchForegroundWindow(m_hWnd); ::SetFocus(m_hWnd); if (reason == SHAKEWINDOW_ERROR) { StartShake(); bshaking_ = true; GetWindowRect(&m_WindowRect); KillTimer(SHAKEWINDOW); m_count = 11; m_Lrud = 0; SetTimer(SHAKEWINDOW, 45, NULL); return; } } template LRESULT CTransWindowEx::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { switch (wParam) { case ACTIVE_TIMER: { _elementManager.DrawCursor(); } break; case SHAKEWINDOW: { if (m_count <= 0) { Shaked(); bshaking_ = false; KillTimer(SHAKEWINDOW); m_count = 0; SetWindowPos(0, &m_WindowRect, SWP_NOZORDER | SWP_NOSIZE); } else { m_count--; RECT rc; int delta = 2; if (m_Lrud == 0) { m_Lrud++; LmoveRect(m_WindowRect, delta, rc); SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE); } else if (m_Lrud == 1) { m_Lrud++; UmoveRect(m_WindowRect, delta, rc); SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE); } else if (m_Lrud == 2) { m_Lrud++; RmoveRect(m_WindowRect, delta, rc); SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE); } else if (m_Lrud == 3) { m_Lrud = 0; DmoveRect(m_WindowRect, delta, rc); SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE); } } } break; } return 0; } template void CTransWindowEx::SetWndStyle() {} ================================================ FILE: src/DirectUI/DUIWindowStyle.cpp ================================================ #include "stdafx.h" #include "DUIWindowStyle.h" #include "DUIGDIResource.h" CWindowCtlStyle::CWindowCtlStyle() : _xAlignment(DUI_ALIGNMENT_NONE), _yAlignment(DUI_ALIGNMENT_NONE), _xStretch(DUI_STRETCH_NONE), _yStretch(DUI_STRETCH_NONE) {} CWindowCtlStyle::~CWindowCtlStyle() {} void CWindowCtlStyle::LoadStyle(XmlElementPtr element) { CXmlHelper helper; _xAlignment = AlignmentStringToValue( helper.GetAttributeString(element, "xAlignment").c_str(), DUI_ALIGNMENT_LEFT); _yAlignment = AlignmentStringToValue( helper.GetAttributeString(element, "yAlignment").c_str(), DUI_ALIGNMENT_TOP); _xStretch = StretchStringToValue( helper.GetAttributeString(element, "xStretch").c_str(), DUI_STRETCH_NONE); _yStretch = StretchStringToValue( helper.GetAttributeString(element, "yStretch").c_str(), DUI_STRETCH_NONE); } tstring CWindowCtlStyle::GetStringAttribute(XmlElementPtr element, string attrName) { CXmlHelper helper; return helper.GetAttributeString(element, attrName.c_str()); } HBITMAP CWindowCtlStyle::GetBitmapAttribute(XmlElementPtr element, string attrName, string key_mid_string) { HBITMAP hBitmap = NULL; CXmlHelper helper; tstring attrValue = helper.GetAttributeString(element, attrName); if (attrValue != _T("")) { hBitmap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, attrValue.c_str(), PNG); } return hBitmap; } int CWindowCtlStyle::GetIntegerAttribute(XmlElementPtr element, string attrName) { CXmlHelper helper; return helper.GetAttributeInt(element, attrName); } COLORREF CWindowCtlStyle::GetColorAttribute(XmlElementPtr element, string attrName) { COLORREF color_ret; tstring s_value = GetStringAttribute(element, attrName); if (!s_value.empty()) { color_ret = _tcstol(s_value.c_str(), NULL, 16); } return color_ret; } std::vector CWindowCtlStyle::split(const tstring src, tstring delimit, tstring null_subst) { std::vector v; int npos = -1; if (src.empty() || delimit.empty()) return v; int deli_len = delimit.size(); long index = npos, last_search_position = 0; while ((index = src.find(delimit, last_search_position)) != npos) { if (index == last_search_position) v.push_back(null_subst); else v.push_back( src.substr(last_search_position, index - last_search_position)); last_search_position = index + deli_len; } tstring last_one = src.substr(last_search_position); v.push_back(last_one.empty() ? null_subst : last_one); return v; } COLORREF CWindowCtlStyle::GetRGBAttribute(XmlElementPtr element, string attrName) { COLORREF colour_ret = 0; tstring s_value = GetStringAttribute(element, attrName); if (!s_value.empty()) { tstring src_value = s_value.c_str(); std::vector v = split(src_value, _T(",")); if (v.size() == 3) { int r = _ttoi(v[0].c_str()); int g = _ttoi(v[1].c_str()); int b = _ttoi(v[2].c_str()); colour_ret = RGB(r, g, b); } } return colour_ret; } DUI_Rect CWindowCtlStyle::GetRectAttribute(XmlElementPtr element, string attrName) { DUI_Rect rect_ret; tstring s_value = GetStringAttribute(element, attrName); if (!s_value.empty()) { tstring src_value = s_value.c_str(); std::vector v = split(src_value, _T(",")); if (v.size() == 4) { rect_ret.left = _ttoi(v[0].c_str()); rect_ret.top = _ttoi(v[1].c_str()); rect_ret.right = _ttoi(v[2].c_str()); rect_ret.bottom = _ttoi(v[3].c_str()); } } return rect_ret; } DUI_Size CWindowCtlStyle::StyleSizeToWindowSize(DUI_Size &eleSize, DUI_Size &wndChangingSize, DUI_Size &wndChangedSize, DUI_STRETCH xFlag, DUI_STRETCH yFlag) { DUI_Size newSize(eleSize.cx, eleSize.cy); switch (xFlag) { case DUI_STRETCH_FILL: newSize.cx = eleSize.cx + wndChangedSize.cx - wndChangingSize.cx; break; case DUI_STRETCH_SCALE: newSize.cx = (int)((double)(eleSize.cx * wndChangedSize.cx) / (double)wndChangingSize.cx); break; default: break; } switch (yFlag) { case DUI_STRETCH_FILL: newSize.cy = eleSize.cy + wndChangedSize.cy - wndChangingSize.cy; break; case DUI_STRETCH_SCALE: newSize.cy = (int)((double)(eleSize.cy * wndChangedSize.cy) / (double)wndChangingSize.cy); break; default: break; } return newSize; } DUI_Point CWindowCtlStyle::StyleLocationToWindowLocation(DUI_Rect &rc, DUI_Point fixPt, int alignX, int alignY, DUI_Size &windowSize) { DUI_Point point(rc.left, rc.top); DUI_Size size(rc.Width(), rc.Height()); if (alignX == DUI_ALIGNMENT_LEFT) point.x = point.x; else if (alignX == DUI_ALIGNMENT_RIGHT) point.x = windowSize.cx - fixPt.x; if (alignY == DUI_ALIGNMENT_TOP) point.y = point.y; else if (alignY == DUI_ALIGNMENT_BOTTOM) point.y = windowSize.cy - fixPt.y; if (alignX == DUI_ALIGNMENT_CENTER) point.x = (windowSize.cx - size.cx) / 2; if (alignY == DUI_ALIGNMENT_CENTER) point.y = (windowSize.cy - size.cy) / 2; return DUI_Point(point.x, point.y); } DUI_Rect CWindowCtlStyle::StyleRectToWindowRect( DUI_Rect rc, DUI_Point oriPt, DUI_Size &wndChangingSize, DUI_Size &wndChangedSize, DUI_ALIGNMENT alignX, DUI_ALIGNMENT alignY, DUI_STRETCH stretchHor, DUI_STRETCH stretchVer) { DUI_Point newPos = StyleLocationToWindowLocation(rc, oriPt, alignX, alignY, wndChangedSize); SIZE newSize = StyleSizeToWindowSize(DUI_Size(rc.Width(), rc.Height()), wndChangingSize, wndChangedSize, stretchHor, stretchVer); return DUI_Rect(newPos, newSize); } DUI_STRETCH CWindowCtlStyle::StretchStringToValue(tstring s, DUI_STRETCH stretch) { if (s == _T("none")) { return DUI_STRETCH_NONE; } else if (s == _T("fill")) { return DUI_STRETCH_FILL; } else if (s == _T("scale")) { return DUI_STRETCH_SCALE; } else { return DUI_STRETCH_NONE; } return stretch; } DUI_ALIGNMENT CWindowCtlStyle::AlignmentStringToValue(tstring s, DUI_ALIGNMENT align) { if (s.empty()) { return align; } std::map dict1; dict1[_T("left")] = DUI_ALIGNMENT_LEFT; dict1[_T("top")] = DUI_ALIGNMENT_TOP; dict1[_T("right")] = DUI_ALIGNMENT_RIGHT; dict1[_T("bottom")] = DUI_ALIGNMENT_BOTTOM; dict1[_T("center")] = DUI_ALIGNMENT_CENTER; if (dict1.find(s) != dict1.end()) { return dict1[s]; } return align; } HCURSOR CWindowCtlStyle::NameToCursor(tstring name) { HCURSOR default_cursor = LoadCursor(NULL, IDC_ARROW); std::map dict1; dict1[_T("AppStarting")] = LoadCursor(NULL, IDC_APPSTARTING); dict1[_T("Arrow")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("Cross")] = LoadCursor(NULL, IDC_CROSS); dict1[_T("Default")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("Help")] = LoadCursor(NULL, IDC_HELP); dict1[_T("HSplit")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("IBeam")] = LoadCursor(NULL, IDC_IBEAM); dict1[_T("No")] = LoadCursor(NULL, IDC_NO); dict1[_T("NoMove2D")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("NoMoveHoriz")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("NoMoveVert")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanEast")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanNE")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanNorth")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanNW")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanSE")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanSouth")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanSW")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("PanWest")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("SizeAll")] = LoadCursor(NULL, IDC_SIZEALL); dict1[_T("SizeNESW")] = LoadCursor(NULL, IDC_SIZENESW); dict1[_T("SizeNS")] = LoadCursor(NULL, IDC_SIZENS); dict1[_T("SizeNWSE")] = LoadCursor(NULL, IDC_SIZENWSE); dict1[_T("SizeWE")] = LoadCursor(NULL, IDC_SIZEWE); dict1[_T("UpArrow")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("VSplit")] = LoadCursor(NULL, IDC_ARROW); dict1[_T("WaitCursor")] = LoadCursor(NULL, IDC_WAIT); tstring key = name.c_str(); if (dict1.find(key) != dict1.end()) { return HCURSOR(dict1[key]); } return default_cursor; } ================================================ FILE: src/DirectUI/DUIWindowStyle.h ================================================ #pragma once #include #include "DUIDef.h" class __declspec(novtable) CWindowCtlStyle { using string = std::string; public: CWindowCtlStyle(); virtual ~CWindowCtlStyle(); public: virtual void LoadStyle(XmlElementPtr element); tstring GetStringAttribute(XmlElementPtr element, string attrName); HBITMAP GetBitmapAttribute(XmlElementPtr element, string attrName, string key_mid_string = ""); int GetIntegerAttribute(XmlElementPtr element, string attrName); COLORREF GetColorAttribute(XmlElementPtr element, string attrName); COLORREF GetRGBAttribute(XmlElementPtr element, string attrName); DUI_Rect GetRectAttribute(XmlElementPtr element, string attrName); DUI_Size StyleSizeToWindowSize(DUI_Size &eleSize, DUI_Size &wndChangingSize, DUI_Size &wndChangedSize, DUI_STRETCH xFlag, DUI_STRETCH yFlag); DUI_Point StyleLocationToWindowLocation(DUI_Rect &rc, DUI_Point oriPt, int alignX, int alignY, DUI_Size &windowSize); DUI_Rect StyleRectToWindowRect(DUI_Rect rc, DUI_Point oriPt, DUI_Size &wndChangingSize, DUI_Size &wndChangedSize, DUI_ALIGNMENT alignX, DUI_ALIGNMENT alignY, DUI_STRETCH stretchHor, DUI_STRETCH stretchVer); DUI_ALIGNMENT AlignmentStringToValue(tstring s, DUI_ALIGNMENT align); DUI_STRETCH StretchStringToValue(tstring s, DUI_STRETCH stretch); HCURSOR NameToCursor(tstring name); std::vector split(const tstring src, tstring delimit, tstring null_subst = _T("")); public: tstring _NameID; DUI_ALIGNMENT _xAlignment; DUI_ALIGNMENT _yAlignment; DUI_STRETCH _xStretch; DUI_STRETCH _yStretch; }; ================================================ FILE: src/DirectUI/Draw.cpp ================================================ #include "stdafx.h" #include "Draw.h" #define KEYDOWN(Key) ((GetKeyState(Key) & 0x8000) != 0) class CClientRect : public CRect { public: CClientRect(HWND hWnd) { ::GetClientRect(hWnd, this); }; CClientRect(const CWindow *pWnd) { ::GetClientRect(pWnd->m_hWnd, this); }; }; class CWindowRect : public CRect { public: CWindowRect(HWND hWnd) { ::GetWindowRect(hWnd, this); }; CWindowRect(const CWindow *pWnd) { ::GetWindowRect(pWnd->m_hWnd, this); }; }; HLSCOLOR RGB2HLS(COLORREF rgb) { unsigned char minval = min(GetRValue(rgb), min(GetGValue(rgb), GetBValue(rgb))); unsigned char maxval = max(GetRValue(rgb), max(GetGValue(rgb), GetBValue(rgb))); float mdiff = float(maxval) - float(minval); float msum = float(maxval) + float(minval); float luminance = msum / 510.0f; float saturation = 0.0f; float hue = 0.0f; if (maxval != minval) { float rnorm = (maxval - GetRValue(rgb)) / mdiff; float gnorm = (maxval - GetGValue(rgb)) / mdiff; float bnorm = (maxval - GetBValue(rgb)) / mdiff; saturation = (luminance <= 0.5f) ? (mdiff / msum) : (mdiff / (510.0f - msum)); if (GetRValue(rgb) == maxval) hue = 60.0f * (6.0f + bnorm - gnorm); if (GetGValue(rgb) == maxval) hue = 60.0f * (2.0f + rnorm - bnorm); if (GetBValue(rgb) == maxval) hue = 60.0f * (4.0f + gnorm - rnorm); if (hue > 360.0f) hue = hue - 360.0f; } return HLS((hue * 255) / 360, luminance * 255, saturation * 255); } static BYTE _ToRGB(float rm1, float rm2, float rh) { if (rh > 360.0f) rh -= 360.0f; else if (rh < 0.0f) rh += 360.0f; if (rh < 60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f; else if (rh < 180.0f) rm1 = rm2; else if (rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f; return (BYTE)(rm1 * 255); } COLORREF HLS2RGB(HLSCOLOR hls) { float hue = ((int)HLS_H(hls) * 360) / 255.0f; float luminance = HLS_L(hls) / 255.0f; float saturation = HLS_S(hls) / 255.0f; if (saturation == 0.0f) { return RGB(HLS_L(hls), HLS_L(hls), HLS_L(hls)); } float rm1, rm2; if (luminance <= 0.5f) rm2 = luminance + luminance * saturation; else rm2 = luminance + saturation - luminance * saturation; rm1 = 2.0f * luminance - rm2; BYTE red = _ToRGB(rm1, rm2, hue + 120.0f); BYTE green = _ToRGB(rm1, rm2, hue); BYTE blue = _ToRGB(rm1, rm2, hue - 120.0f); return RGB(red, green, blue); } COLORREF HLS_TRANSFORM(COLORREF rgb, int percent_L, int percent_S) { HLSCOLOR hls = RGB2HLS(rgb); BYTE h = HLS_H(hls); BYTE l = HLS_L(hls); BYTE s = HLS_S(hls); if (percent_L > 0) { l = BYTE(l + ((255 - l) * percent_L) / 100); } else if (percent_L < 0) { l = BYTE((l * (100 + percent_L)) / 100); } if (percent_S > 0) { s = BYTE(s + ((255 - s) * percent_S) / 100); } else if (percent_S < 0) { s = BYTE((s * (100 + percent_S)) / 100); } return HLS2RGB(HLS(h, l, s)); } CBufferDC::CBufferDC(HDC hDestDC, const CRect &rcPaint) : m_hDestDC(hDestDC) { if (rcPaint.IsRectEmpty()) { ::GetClipBox(m_hDestDC, m_rect); } else { m_rect = rcPaint; } Attach(::CreateCompatibleDC(m_hDestDC)); m_bitmap.Attach( ::CreateCompatibleBitmap(m_hDestDC, m_rect.right, m_rect.bottom)); m_hOldBitmap = ::SelectObject(m_hDC, m_bitmap); if (m_rect.top > 0) { ExcludeClipRect(0, 0, m_rect.right, m_rect.top); } if (m_rect.left > 0) { ExcludeClipRect(0, m_rect.top, m_rect.left, m_rect.bottom); } } CBufferDC::~CBufferDC() { ::BitBlt(m_hDestDC, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), m_hDC, m_rect.left, m_rect.top, SRCCOPY); ::SelectObject(m_hDC, m_hOldBitmap); } CPenDC::CPenDC(HDC hDC, COLORREF crColor) : m_hDC(hDC) { m_pen.CreatePen(PS_SOLID, 1, crColor); m_hOldPen = (HPEN)::SelectObject(m_hDC, m_pen); } CPenDC::~CPenDC() { ::SelectObject(m_hDC, m_hOldPen); } void CPenDC::Color(COLORREF crColor) { ::SelectObject(m_hDC, m_hOldPen); m_pen.DeleteObject(); m_pen.CreatePen(PS_SOLID, 1, crColor); m_hOldPen = (HPEN)::SelectObject(m_hDC, m_pen); } COLORREF CPenDC::Color() const { LOGPEN logPen; ((CPenDC *)this)->m_pen.GetLogPen(&logPen); return logPen.lopnColor; } CBrushDC::CBrushDC(HDC hDC, COLORREF crColor) : m_hDC(hDC) { if (crColor == CLR_NONE) m_brush.Attach((HBRUSH)::GetStockObject(NULL_BRUSH)); else m_brush.CreateSolidBrush(crColor); m_hOldBrush = (HBRUSH)::SelectObject(m_hDC, m_brush); } CBrushDC::~CBrushDC() { ::SelectObject(m_hDC, m_hOldBrush); } void CBrushDC::Color(COLORREF crColor) { ::SelectObject(m_hDC, m_hOldBrush); m_brush.DeleteObject(); if (crColor == CLR_NONE) m_brush.Attach((HBRUSH)::GetStockObject(NULL_BRUSH)); else m_brush.CreateSolidBrush(crColor); m_hOldBrush = (HBRUSH)::SelectObject(m_hDC, m_brush); } COLORREF CBrushDC::Color() const { LOGBRUSH logBrush; ((CBrushDC *)this)->m_brush.GetLogBrush(&logBrush); return logBrush.lbColor; } CBoldDC::CBoldDC(HDC hDC, bool bBold) : m_hDC(hDC), m_hDefFont(NULL) { LOGFONT lf; CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT)).GetLogFont(&lf); if ((bBold && lf.lfWeight != FW_BOLD) || (!bBold && lf.lfWeight == FW_BOLD)) { lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL; m_fontBold.CreateFontIndirect(&lf); m_hDefFont = (HFONT)::SelectObject(m_hDC, m_fontBold); } } CBoldDC::~CBoldDC() { if (m_hDefFont != NULL) { ::SelectObject(m_hDC, m_hDefFont); } } ================================================ FILE: src/DirectUI/Draw.h ================================================ #pragma once typedef DWORD HLSCOLOR; #define HLS(h, l, s) \ ((HLSCOLOR)(((BYTE)(h) | ((WORD)((BYTE)(l)) << 8)) | \ (((DWORD)(BYTE)(s)) << 16))) #define HLS_H(hls) ((BYTE)(hls)) #define HLS_L(hls) ((BYTE)(((WORD)(hls)) >> 8)) #define HLS_S(hls) ((BYTE)((hls) >> 16)) HLSCOLOR RGB2HLS(COLORREF rgb); COLORREF HLS2RGB(HLSCOLOR hls); COLORREF HLS_TRANSFORM(COLORREF rgb, int percent_L, int percent_S); class CBufferDC : public CDCHandle { HDC m_hDestDC; CBitmap m_bitmap; CRect m_rect; HGDIOBJ m_hOldBitmap; public: CBufferDC(HDC hDestDC, const CRect &rcPaint = CRect(0, 0, 0, 0)); ~CBufferDC(); }; class CPenDC { protected: CPen m_pen; HDC m_hDC; HPEN m_hOldPen; public: CPenDC(HDC hDC, COLORREF crColor = CLR_NONE); ~CPenDC(); void Color(COLORREF crColor); COLORREF Color() const; }; class CBrushDC { protected: CBrush m_brush; HDC m_hDC; HBRUSH m_hOldBrush; public: CBrushDC(HDC hDC, COLORREF crColor = CLR_NONE); ~CBrushDC(); void Color(COLORREF crColor); COLORREF Color() const; }; class CBoldDC { protected: CFont m_fontBold; HDC m_hDC; HFONT m_hDefFont; public: CBoldDC(HDC hDC, bool bBold); ~CBoldDC(); }; ================================================ FILE: src/DirectUI/EventHandler.h ================================================ #pragma once #include "../base/FastDelegate.h" using namespace fastdelegate; #define BIND(c, f) MakeDelegate(&c, &f) typedef FastDelegate0<> Delegate0; typedef FastDelegate1 Delegate1_string; typedef FastDelegate1 Delegate1_UINT; class EventHandler { public: EventHandler() {} EventHandler(Delegate0 func) : m_func_no_para(func) {} EventHandler(Delegate1_string func) : m_func_para_string(func) {} EventHandler(Delegate1_UINT func) : m_func_para_int(func) {} void Invoke() { if (m_func_no_para) { m_func_no_para(); } } void Invoke(LPCTSTR strPara) { if (m_func_para_string) { m_func_para_string(strPara); } } void Invoke(UINT nPara) { if (m_func_para_int) { m_func_para_int(nPara); } } public: Delegate0 m_func_no_para; Delegate1_string m_func_para_string; Delegate1_UINT m_func_para_int; }; ================================================ FILE: src/DirectUI/UpdateWindowBase.cpp ================================================ #include "StdAfx.h" #include "UpdateWindowBase.h" CUpdateWindowBase::CUpdateWindowBase() { m_hFuncInst = NULL; } CUpdateWindowBase::~CUpdateWindowBase() { if (m_hFuncInst) FreeLibrary(m_hFuncInst); } LRESULT CUpdateWindowBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { m_Blend.BlendOp = 0; m_Blend.BlendFlags = 0; m_Blend.AlphaFormat = 1; m_Blend.SourceConstantAlpha = 255; if (IsBits32()) { m_hFuncInst = LoadLibrary(_T("User32.DLL")); BOOL bRet = FALSE; if (m_hFuncInst) UpdateLayeredWindow = (UPDATELAYERWINDOWPTR)GetProcAddress( m_hFuncInst, "UpdateLayeredWindow"); else assert(0); PostMessage(MSG_UPDATE_WINDOW_INVALIDATE, 0, 100); } bHandled = FALSE; return 0; } LRESULT CUpdateWindowBase::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CPaintDC dc(m_hWnd); DrawBg(dc); OnDraw(dc); return 0; } LRESULT CUpdateWindowBase::UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { UpdateTransDisplay(lParam); return 0; } BOOL CUpdateWindowBase::UpdateTransDisplay(int Transparent) { if (!IsBits32()) { Invalidate(TRUE); return FALSE; } CRect rcWindow; GetWindowRect(rcWindow); POINT ptWinPos = {rcWindow.left, rcWindow.top}; HDC hdcTemp = GetDC(); HDC m_hdcMemory = CreateCompatibleDC(hdcTemp); HBITMAP hBitMap = CreateCompatibleBitmap(hdcTemp, rcWindow.Width(), rcWindow.Height()); SelectObject(m_hdcMemory, hBitMap); if (Transparent < 0 || Transparent > 100) Transparent = 100; m_Blend.SourceConstantAlpha = int(Transparent * 2.55); HDC hdcScreen = ::GetDC(m_hWnd); DrawBg(m_hdcMemory); OnDraw(m_hdcMemory); SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()}; POINT ptSrc = {0, 0}; DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE); if ((dwExStyle & 0x80000) != 0x80000) ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000); BOOL bRet = FALSE; bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow, m_hdcMemory, &ptSrc, 0, &m_Blend, 2); ::ReleaseDC(m_hWnd, hdcScreen); hdcScreen = NULL; ::ReleaseDC(m_hWnd, hdcTemp); hdcTemp = NULL; DeleteObject(hBitMap); DeleteDC(m_hdcMemory); m_hdcMemory = NULL; return bRet; } bool CUpdateWindowBase::IsBits32() { DEVMODE lpDevMode; BOOL Result = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode); if (Result) { if (lpDevMode.dmBitsPerPel == 32) return true; } return false; } ================================================ FILE: src/DirectUI/UpdateWindowBase.h ================================================ #pragma once #include #include #include "DUIDef.h" class __declspec(novtable) CUpdateWindowBase : public CWindowImpl { public: CUpdateWindowBase(); ~CUpdateWindowBase(); public: BEGIN_MSG_MAP_EX(CUpdateWindowBase) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(MSG_UPDATE_WINDOW_INVALIDATE, UpdateTranslate) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); protected: typedef BOOL(WINAPI *UPDATELAYERWINDOWPTR)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD); UPDATELAYERWINDOWPTR UpdateLayeredWindow; BLENDFUNCTION m_Blend; HINSTANCE m_hFuncInst; protected: BOOL UpdateTransDisplay(int Transparent); virtual void DrawBg(HDC hDC) = 0; virtual void OnDraw(HDC hDC) = 0; bool IsBits32(); }; ================================================ FILE: src/DirectUI/UpdateWindowBaseEx.cpp ================================================ #include "StdAfx.h" #include "UpdateWindowBaseEx.h" ================================================ FILE: src/DirectUI/UpdateWindowBaseEx.h ================================================ #pragma once #include #include #include "DUIDef.h" constexpr int TIMER_ID1 = 0x1110; constexpr int TIMER_ID2 = 0x1111; constexpr int COUNT_END_CONST = -3; template class __declspec(novtable) CUpdateWindowBaseEx : public CWindowImpl { public: CUpdateWindowBaseEx(); virtual ~CUpdateWindowBaseEx(); public: BEGIN_MSG_MAP_EX(CUpdateWindowBaseEx) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_TIMER, CUpdateWindowBaseEx_OnTimer) MESSAGE_HANDLER(MSG_UPDATE_WINDOW_INVALIDATE, UpdateTranslate) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() LRESULT CUpdateWindowBaseEx_OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); protected: typedef BOOL(WINAPI *UPDATELAYERWINDOWPTR)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD); UPDATELAYERWINDOWPTR UpdateLayeredWindow; BLENDFUNCTION m_Blend; HINSTANCE m_hFuncInst; public: BOOL UpdateTransDisplay(int Transparent); protected: BOOL UpdateTransDisplay2(int Transparent); BOOL UpdateTransDisplay3(int Transparent); virtual void DrawBg(HDC hDC) = 0; virtual void OnDraw(HDC hDC) = 0; virtual void IsWindowShowed() {} bool IsBits32(); public: void ClearOBJ(); CRect _CUpdateWindowBaseEx_WndRect_con; CRect _CUpdateWindowBaseEx_WndRect_var; BOOL _bCUpdateWindowBaseEx_TransShow; void TransShowWindow(int SW = SW_SHOWNORMAL); int _CUpdateWindowBaseEx_Count; void TransBeginShow(); void StretchRect(const RECT &i_rc, float percent, RECT &o_rc); void AnimateRect(const RECT &i_rc, int x, int y, RECT &o_rc); float _CUpdateWindowBaseEx_percent; void StretchShow(int, int); void StretchShowSim(int, int); HDC _hdcTemp; HDC _hdcMemory; HBITMAP _hBitMap; HGDIOBJ _oldOBJ; }; template CUpdateWindowBaseEx::CUpdateWindowBaseEx() : _CUpdateWindowBaseEx_WndRect_con(0, 0, 0, 0) { m_hFuncInst = NULL; _bCUpdateWindowBaseEx_TransShow = FALSE; _CUpdateWindowBaseEx_Count = 10; _CUpdateWindowBaseEx_percent = 0.0; _hdcTemp = NULL; _hdcMemory = NULL; _hBitMap = NULL; _oldOBJ = NULL; } template CUpdateWindowBaseEx::~CUpdateWindowBaseEx() { if (m_hFuncInst) FreeLibrary(m_hFuncInst); } template LRESULT CUpdateWindowBaseEx::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { m_Blend.BlendOp = 0; m_Blend.BlendFlags = 0; m_Blend.AlphaFormat = 1; m_Blend.SourceConstantAlpha = 255; if (IsBits32()) { m_hFuncInst = LoadLibrary(_T("User32.DLL")); BOOL bRet = FALSE; if (m_hFuncInst) UpdateLayeredWindow = (UPDATELAYERWINDOWPTR)GetProcAddress( m_hFuncInst, "UpdateLayeredWindow"); else assert(0); PostMessage(MSG_UPDATE_WINDOW_INVALIDATE, 0, 100); } bHandled = FALSE; return 0; } template LRESULT CUpdateWindowBaseEx::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CPaintDC dc(m_hWnd); DrawBg(dc); OnDraw(dc); return 0; } template LRESULT CUpdateWindowBaseEx::UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { UpdateTransDisplay(lParam); return 0; } template BOOL CUpdateWindowBaseEx::UpdateTransDisplay(int Transparent) { if (!IsBits32()) { Invalidate(TRUE); return FALSE; } if (_bCUpdateWindowBaseEx_TransShow) return FALSE; CRect rcWindow; GetWindowRect(&rcWindow); POINT ptWinPos = {rcWindow.left, rcWindow.top}; HDC hdcTemp = GetDC(); HDC m_hdcMemory = CreateCompatibleDC(hdcTemp); HBITMAP hBitMap = CreateCompatibleBitmap(hdcTemp, rcWindow.Width(), rcWindow.Height()); HGDIOBJ m_oldbj = SelectObject(m_hdcMemory, hBitMap); if (Transparent < 0 || Transparent > 100) Transparent = 100; m_Blend.SourceConstantAlpha = int(Transparent * 2.55); HDC hdcScreen = ::GetDC(m_hWnd); DrawBg(m_hdcMemory); OnDraw(m_hdcMemory); SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()}; POINT ptSrc = {0, 0}; DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE); if ((dwExStyle & 0x80000) != 0x80000) ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000); BOOL bRet = FALSE; bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow, m_hdcMemory, &ptSrc, 0, &m_Blend, 2); ::ReleaseDC(m_hWnd, hdcScreen); hdcScreen = NULL; ::ReleaseDC(m_hWnd, hdcTemp); SelectObject(m_hdcMemory, m_oldbj); DeleteObject(hBitMap); DeleteDC(m_hdcMemory); return bRet; } template bool CUpdateWindowBaseEx::IsBits32() { DEVMODE lpDevMode; BOOL Result = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode); if (Result) { if (lpDevMode.dmBitsPerPel == 32) return true; } return false; } template void CUpdateWindowBaseEx::StretchShow(int a, int b) { AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100 + a, -100 + a, _CUpdateWindowBaseEx_WndRect_var); SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_var, SWP_NOZORDER); UpdateTransDisplay2(b); } template void CUpdateWindowBaseEx::StretchShowSim(int a, int b) { AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100 + a, -100 + a, _CUpdateWindowBaseEx_WndRect_var); UpdateTransDisplay3(b); } template LRESULT CUpdateWindowBaseEx::CUpdateWindowBaseEx_OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (TIMER_ID1 == wParam) { --_CUpdateWindowBaseEx_Count; if (_CUpdateWindowBaseEx_Count < COUNT_END_CONST) { KillTimer(TIMER_ID1); _bCUpdateWindowBaseEx_TransShow = FALSE; return 0; } switch (_CUpdateWindowBaseEx_Count) { case 9: { StretchShowSim(6, 40); } break; case 8: { StretchShowSim(23, 45); } break; case 7: { StretchShowSim(51, 55); } break; case 6: { StretchShowSim(90, 60); } break; case 5: { KillTimer(TIMER_ID1); StretchShowSim(140, 65); SetTimer(TIMER_ID2, 30, NULL); } break; default: { KillTimer(TIMER_ID1); SetTimer(TIMER_ID2, 30, NULL); } } return 0; } if (wParam == TIMER_ID2) { --_CUpdateWindowBaseEx_Count; if (_bCUpdateWindowBaseEx_TransShow == FALSE) { KillTimer(TIMER_ID2); UpdateTransDisplay(100); ClearOBJ(); IsWindowShowed(); return 0; } if (_CUpdateWindowBaseEx_Count < COUNT_END_CONST) { _bCUpdateWindowBaseEx_TransShow = FALSE; return 0; } switch (_CUpdateWindowBaseEx_Count) { case 4: { StretchShow(126, 70); } break; case 3: { StretchShow(114, 75); } break; case 2: { StretchShow(106, 80); } break; case 1: { StretchShow(102, 90); } break; case 0: { SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_con, SWP_NOZORDER); UpdateTransDisplay(100); _bCUpdateWindowBaseEx_TransShow = FALSE; } break; default: { SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_con, SWP_NOZORDER); UpdateTransDisplay(100); _bCUpdateWindowBaseEx_TransShow = FALSE; } } return 0; } bHandled = FALSE; return 0; } template void CUpdateWindowBaseEx::TransBeginShow() { if (!IsBits32()) { _bCUpdateWindowBaseEx_TransShow = FALSE; return; } _bCUpdateWindowBaseEx_TransShow = TRUE; } template void CUpdateWindowBaseEx::StretchRect(/*_In_*/ const RECT &i_rc, float percent, /*_Out_*/ RECT &o_rc) { int x; int y; x = (i_rc.right - i_rc.left) * percent; y = (i_rc.bottom - i_rc.top) * percent; o_rc.left = i_rc.left + ((i_rc.right - i_rc.left) - x) / 2; o_rc.right = (o_rc.left + x); o_rc.top = i_rc.top + ((i_rc.bottom - i_rc.top) - y) / 2; o_rc.bottom = (o_rc.top + y); } template BOOL CUpdateWindowBaseEx::UpdateTransDisplay2(int Transparent) { CRect rcWindow; rcWindow = _CUpdateWindowBaseEx_WndRect_var; POINT ptWinPos = {rcWindow.left, rcWindow.top}; if (Transparent < 0 || Transparent > 100) Transparent = 100; m_Blend.SourceConstantAlpha = int(Transparent * 2.55); HDC hdcScreen = ::GetDC(m_hWnd); SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()}; HDC yyhdcTemp = GetDC(); HDC m_yyhdcMemory = CreateCompatibleDC(yyhdcTemp); HBITMAP yyhBitMap = CreateCompatibleBitmap( yyhdcTemp, _CUpdateWindowBaseEx_WndRect_var.Width(), _CUpdateWindowBaseEx_WndRect_var.Height()); HGDIOBJ m_oldbj2 = SelectObject(m_yyhdcMemory, yyhBitMap); ::StretchBlt(m_yyhdcMemory, 0, 0, sizeWindow.cx, sizeWindow.cy, _hdcMemory, 0, 0, _CUpdateWindowBaseEx_WndRect_con.Width(), _CUpdateWindowBaseEx_WndRect_con.Height(), SRCCOPY); POINT ptSrc = {0, 0}; DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE); if ((dwExStyle & 0x80000) != 0x80000) ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000); BOOL bRet = FALSE; bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow, m_yyhdcMemory, &ptSrc, 0, &m_Blend, 2); ::ReleaseDC(m_hWnd, hdcScreen); ::ReleaseDC(m_hWnd, yyhdcTemp); SelectObject(m_yyhdcMemory, m_oldbj2); DeleteDC(m_yyhdcMemory); DeleteObject(yyhBitMap); return bRet; } template BOOL CUpdateWindowBaseEx::UpdateTransDisplay3(int Transparent) { CRect rcWindow; rcWindow = _CUpdateWindowBaseEx_WndRect_con; POINT ptWinPos = {rcWindow.left - 20, rcWindow.top - 20}; if (Transparent < 0 || Transparent > 100) Transparent = 100; m_Blend.SourceConstantAlpha = int(Transparent * 2.55); HDC hdcScreen = ::GetDC(m_hWnd); SIZE sizeWindow = {rcWindow.Width() + 40, rcWindow.Height() + 40}; HDC yyhdcTemp = GetDC(); HDC m_yyhdcMemory = CreateCompatibleDC(yyhdcTemp); HBITMAP yyhBitMap = CreateCompatibleBitmap( yyhdcTemp, _CUpdateWindowBaseEx_WndRect_con.Width() + 40, _CUpdateWindowBaseEx_WndRect_con.Height() + 40); HGDIOBJ m_oldbj2 = SelectObject(m_yyhdcMemory, yyhBitMap); int delta_x = _CUpdateWindowBaseEx_WndRect_con.Width() + 40 - _CUpdateWindowBaseEx_WndRect_var.Width(); delta_x = delta_x / 2; int delta_y = _CUpdateWindowBaseEx_WndRect_con.Height() + 40 - _CUpdateWindowBaseEx_WndRect_var.Height(); delta_y = delta_y / 2; ::StretchBlt(m_yyhdcMemory, delta_x, delta_y, _CUpdateWindowBaseEx_WndRect_var.Width(), _CUpdateWindowBaseEx_WndRect_var.Height(), _hdcMemory, 0, 0, _CUpdateWindowBaseEx_WndRect_con.Width(), _CUpdateWindowBaseEx_WndRect_con.Height(), SRCCOPY); POINT ptSrc = {0, 0}; DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE); if ((dwExStyle & 0x80000) != 0x80000) ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000); BOOL bRet = FALSE; bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow, m_yyhdcMemory, &ptSrc, 0, &m_Blend, 2); ::ReleaseDC(m_hWnd, hdcScreen); ::ReleaseDC(m_hWnd, yyhdcTemp); SelectObject(m_yyhdcMemory, m_oldbj2); DeleteDC(m_yyhdcMemory); DeleteObject(yyhBitMap); return bRet; } template void CUpdateWindowBaseEx::ClearOBJ() { if (_hdcTemp && _hdcMemory) { ::ReleaseDC(m_hWnd, _hdcTemp); SelectObject(_hdcMemory, _oldOBJ); DeleteDC(_hdcMemory); DeleteObject(_hBitMap); _hdcTemp = NULL; _hdcMemory = NULL; _hBitMap = NULL; _oldOBJ = NULL; } } template void CUpdateWindowBaseEx::TransShowWindow(int SW) { if (_bCUpdateWindowBaseEx_TransShow) { ATLASSERT(_CUpdateWindowBaseEx_Count == 10); int cx, cy; cx = _CUpdateWindowBaseEx_WndRect_con.Width(); cy = _CUpdateWindowBaseEx_WndRect_con.Height(); if (cx >= 150 && cy >= 110) { MSG msg; while (::PeekMessage(&msg, m_hWnd, MSG_UPDATE_WINDOW_INVALIDATE, MSG_UPDATE_WINDOW_INVALIDATE, PM_REMOVE)) ; ((T *)this)->ChangeSize(cx, cy); if (!_hdcTemp) { _hdcTemp = GetDC(); } if (!_hdcMemory) { _hdcMemory = CreateCompatibleDC(_hdcTemp); } if (!_hBitMap) { _hBitMap = CreateCompatibleBitmap( _hdcTemp, _CUpdateWindowBaseEx_WndRect_con.Width(), _CUpdateWindowBaseEx_WndRect_con.Height()); } _oldOBJ = SelectObject(_hdcMemory, _hBitMap); DrawBg(_hdcMemory); OnDraw(_hdcMemory); AnimateRect(_CUpdateWindowBaseEx_WndRect_con, 40, 40, _CUpdateWindowBaseEx_WndRect_var); SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_var, SWP_NOZORDER); AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100, -100, _CUpdateWindowBaseEx_WndRect_var); UpdateTransDisplay3(35); ShowWindow(SW_SHOWNORMAL); _CUpdateWindowBaseEx_Count = 10; SetTimer(TIMER_ID1, 30, NULL); } else { _bCUpdateWindowBaseEx_TransShow = FALSE; ShowWindow(SW); } } else { ShowWindow(SW); } } template void CUpdateWindowBaseEx::AnimateRect(/*_In_*/ const RECT &i_rc, int x, int y, /*_Out_*/ RECT &o_rc) { y = x * (i_rc.bottom - i_rc.top) / (i_rc.bottom - i_rc.top); x = -x; o_rc.left = i_rc.left + x / 2; o_rc.right = (i_rc.right - x / 2); y = -y; o_rc.top = i_rc.top + y / 2; o_rc.bottom = (i_rc.bottom - y / 2); } ================================================ FILE: src/DownLoader/DownloadDelegate.cpp ================================================ #include "StdAfx.h" #include "DownloadDelegate.h" DownCompleteInfo::DownCompleteInfo(net::URLFetcher::ErrorType reason) : reason_(reason) {} ================================================ FILE: src/DownLoader/DownloadDelegate.h ================================================ #pragma once #include "../net/url_fetcher.h" struct DownCompleteInfo { explicit DownCompleteInfo(net::URLFetcher::ErrorType reason); net::URLFetcher::ErrorType reason_; union { DWORD file_totle_size_; struct { DWORD already_byte_infile_; DWORD endoffset_; DWORD original_begin_offset_; } mutDownParam; }; }; class FetchURLDelegate { public: virtual void FetchURLComplete(std::string res) = 0; }; class FetchFileDelegate { public: virtual void FetchFileComplete(bool status, DownCompleteInfo &info) = 0; virtual void FetchFileProgress(double cur) = 0; }; ================================================ FILE: src/DownLoader/fetcherurl.cpp ================================================ #include "StdAfx.h" #include "fetcherurl.h" using namespace net; CFetchUrl::CFetchUrl(FetchURLDelegate *delegate, std::string downurl) { assert(delegate); delegate_ = delegate; fetcher_ = URLFetcher::Create(URLFetcher::Params(downurl), this); } CFetchUrl::~CFetchUrl() { if (fetcher_.get()) fetcher_->Stop(); } void CFetchUrl::OnURLFetchComplete(const net::URLFetcher *source) { std::string content; if (source->status()) { content = const_cast(source)->data(); } if (delegate_) delegate_->FetchURLComplete(content); } ================================================ FILE: src/DownLoader/fetcherurl.h ================================================ #pragma once #include "../net/url_fetcher.h" #include "../base.h" #include "util/def.h" #include "DownloadDelegate.h" class CFetchUrl : public net::URLFetcher::URLFetcherDelegate { public: explicit CFetchUrl(FetchURLDelegate *delegate, std::string downurl); ~CFetchUrl(); virtual void OnURLFetchComplete(const net::URLFetcher *source) override; scoped_refptr fetcher_; private: FetchURLDelegate *delegate_; }; ================================================ FILE: src/DownLoader/fetchfile.cpp ================================================ #include "StdAfx.h" #include "fetchfile.h" using namespace net; CFetchFile::CFetchFile(FetchFileDelegate *delegate, std::string downurl, std::wstring downtopath) : retrycount_(0) { assert(delegate); delegate_ = delegate; fetcher_ = URLFetcher::Create(URLFetcher::Params(downurl, downtopath), this); } CFetchFile::~CFetchFile() { if (fetcher_.get()) fetcher_->Stop(); } void CFetchFile::OnURLFetchComplete(const net::URLFetcher *source) { if (delegate_) { DownCompleteInfo info(source->error_type_); delegate_->FetchFileComplete(source->status(), info); } } void CFetchFile::OnURLFetchDownloadProgress(const net::URLFetcher *source, double cur) { if (delegate_) delegate_->FetchFileProgress(cur); } ================================================ FILE: src/DownLoader/fetchfile.h ================================================ #pragma once #include "../net/url_fetcher.h" #include "../base.h" #include "util/def.h" #include "DownloadDelegate.h" class CFetchFile : public net::URLFetcher::URLFetcherDelegate { public: explicit CFetchFile(FetchFileDelegate *delegate, std::string downurl, std::wstring downtopath); ~CFetchFile(); virtual void OnURLFetchComplete(const net::URLFetcher *source) override; virtual void OnURLFetchDownloadProgress(const net::URLFetcher *source, double cur) override; scoped_refptr fetcher_; char retrycount_; private: FetchFileDelegate *delegate_; }; ================================================ FILE: src/Downloader.rc ================================================ // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS #include "resource.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // (壬й) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #pragma code_page(936) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE BEGIN "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""resource.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // XML // UIMAINWINDOW XML "res\\xml\\UIMainWindow.xml" UICANNOTDOWN XML "res\\xml\\UICannotDown.xml" UIAGREEMENT XML "res\\xml\\UIAgreement.xml" UICONTENT XML "res\\xml\\UIContent.xml" ENGUIMAINWINDOW XML "res\\xml\\EngUIMainWindow.xml" ENGUICANNOTDOWN XML "res\\xml\\EngUICannotDown.xml" ENGUIAGREEMENT XML "res\\xml\\EngUIAgreement.xml" ENGUICONTENT XML "res\\xml\\EngUIContent.xml" ///////////////////////////////////////////////////////////////////////////// // // 6000 // APP1 6000 "res\\png\\1.png" APP2 6000 "res\\png\\2.png" APP3 6000 "res\\png\\3.png" APP4 6000 "res\\png\\4.png" APP5 6000 "res\\png\\5.png" APP6 6000 "res\\png\\6.png" ABOUTDIALOG 6000 "res\\png\\AboutDlg.png" DLG_BTN_CLOSE 6000 "res\\png\\account_close.png" DLG_BTN_MIN 6000 "res\\png\\btn_min.png" DLG_BTN_INSTALL 6000 "res\\png\\dialog_btn_main.png" CHECK_BOX 6000 "res\\png\\checkbox.png" APPLOGO 6000 "res\\png\\logo.png" SELECTPATH 6000 "res\\png\\selctpath.png" BACKMAIN 6000 "res\\png\\backmain.png" EDIT_INSTALL_BACK 6000 "res\\png\\edit_install_back.png" LIGHTPOINT 6000 "res\\png\\lightpoint.png" ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "FileVersion", "1.0.0.0" VALUE "ProductVersion", "1.0.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // (壬й) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Ӣ() resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\App.ico" #endif // Ӣ() resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: src/Event/WaitableEvent.cc ================================================ #include "stdafx.h" #include "WaitableEvent.h" namespace base { WaitableEvent::WaitableEvent(bool manual_reset, bool signaled) : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) { assert(handle_); } WaitableEvent::WaitableEvent(HANDLE event_handle) : handle_(event_handle) { assert(handle_ != INVALID_HANDLE_VALUE); } HANDLE WaitableEvent::Release() { HANDLE rv = handle_; handle_ = NULL; return rv; } WaitableEvent::~WaitableEvent() { assert(handle_); CloseHandle(handle_); handle_ = NULL; } void WaitableEvent::Reset() { ResetEvent(handle_); } void WaitableEvent::Signal() { SetEvent(handle_); } void WaitableEvent::Wait() { DWORD result = WaitForSingleObject(handle_, INFINITE); } bool WaitableEvent::TimedWait(const TimeDelta &max_time) { double timeout = ceil(max_time.InMillisecondsF()); DWORD result = WaitForSingleObject(handle_, static_cast(timeout)); switch (result) { case WAIT_OBJECT_0: return true; case WAIT_TIMEOUT: return false; } assert(0); return false; } } // namespace base ================================================ FILE: src/Event/WaitableEvent.h ================================================ #pragma once #include #include #include #include "../time/time.h" namespace base { class TimeDelta; class WaitableEvent { public: WaitableEvent(bool manual_reset, bool initially_signaled); explicit WaitableEvent(HANDLE event_handle); HANDLE Release(); ~WaitableEvent(); void Reset(); void Signal(); void Wait(); bool TimedWait(const TimeDelta &max_time); HANDLE handle() const { return handle_; } private: HANDLE handle_; }; } // namespace base ================================================ FILE: src/Global.cpp ================================================ #include "stdafx.h" #include "util/system.h" #include "Global.h" /// /// Set the following string and then compile // Query zip download link std::string CGlobal::downloadurl_ = "http://127.0.0.1:5001/download-url"; // directory name std::string CGlobal::appDirName_ = "MyeXeAppDir"; // Exe file name such as eXeScope.exe or a relative path such as bin\\eXeScope.exe std::string CGlobal::appname_ = "eXeScope.exe"; // shortcut file name std::string CGlobal::shortcutname_ = "eXeScope"; // Link to open after installation std::string CGlobal::openurl_ = "https://github.com/sinajia/Downloader"; /// ITaskbarList4* CGlobal::pTaskbar_ = nullptr; CGlobal::CGlobal(): hUitlWnd_(NULL), lanId_(0), m_zh(false) { m_macAddress = SystemCommon::Device::GetTheFirstMac(); m_platform = Util::Base::GetOSVersion(); } CGlobal::~CGlobal() {} CGlobal global; ================================================ FILE: src/Global.h ================================================ #pragma once #include "util/util_tools.h" class CGlobal { public: // configuration value static std::string downloadurl_; static std::string appDirName_; static std::string appname_; static std::string shortcutname_; static std::string openurl_; CGlobal(); virtual ~CGlobal(); HWND hUitlWnd_ = NULL; LANGID lanId_; bool m_zh; std::string m_filedownurl; std::string m_downloadfileLen; std::string m_macAddress; std::string m_platform; std::wstring m_packPath; std::wstring m_strInstallPath; static ITaskbarList4* pTaskbar_; constexpr static TCHAR* szUtilityClassName_ = _T("AppInstallerWindow"); constexpr static TCHAR* szGlobalString_ = _T("65E6B66785CEC64B329"); constexpr static LONG UitlWndPrivacyCode_ = 0x746A04DE; }; extern CGlobal global; ================================================ FILE: src/Language/Language.cpp ================================================ #include "StdAfx.h" #include "../Global.h" #include "Language.h" namespace lan { Sentence AppLanguage::s_lanArr[] = { {L"Installing...Please wait!~", L"Server error, Try again!", L"Install directly", L"Disk space not enough", L"Downloading ... Please wait"}, }; DWORD AppLanguage::lanIndex_ = 0; void AppLanguage::SysLanguage() { global.lanId_ = GetSystemDefaultLangID(); switch (global.lanId_) { case 0x804: { global.m_zh = true; } break; default: break; } } } // namespace lan ================================================ FILE: src/Language/Language.h ================================================ #pragma once namespace lan { struct Sentence { LPCWSTR pstrInstalling; LPCWSTR pstrServiceError; LPCWSTR pstrRepair; LPCWSTR pstrDiskSpace; LPCWSTR pstrApkInstalling; }; class AppLanguage { public: static Sentence s_lanArr[]; static DWORD lanIndex_; static void SysLanguage(); }; } // namespace lan ================================================ FILE: src/LogAssist/LogAssist.cpp ================================================ #include "StdAfx.h" #include #include #include #include "LogAssist.h" #include "util/system.h" #pragma comment(lib, "shlwapi") applog::LogAssist DebugSet; namespace applog { base::LazyInstance log_entity_ = LAZY_INSTANCE_INITIALIZER; LogThread::LogThread() : thread_() {} LogThread::~LogThread() { if (thread_.IsRunning()) { thread_.Stop(); } } STRU_LOG_DATA::STRU_LOG_DATA() { mlDataLen = 0; ZeroMemory(&mszPrintBuff, sizeof(STRU_LOG_DATA::mszPrintBuff)); }; STRU_LOG_DATA &STRU_LOG_DATA::operator<<(char acCharVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 1) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 2, "%c", acCharVal); StringCchLengthA(lpWritePtr, 2, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(bool abBoolVal) { if (mlDataLen < DEF_MAX_BUFF_LEN - 5) { char *lpWritePtr = (mszPrintBuff) + mlDataLen; unsigned int len = 0; if (abBoolVal) { StringCchPrintfA(lpWritePtr, 6, "true"); StringCchLengthA(lpWritePtr, 6, &len); } else { StringCchPrintfA(lpWritePtr, 6, "%s", "false"); StringCchLengthA(lpWritePtr, 6, &len); } mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(short asShortVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 6) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 7, "%d", asShortVal); StringCchLengthA(lpWritePtr, 7, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(int aiIntVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 11) { char *lpWritePtr = (char *)mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 12, "%d", aiIntVal); StringCchLengthA(lpWritePtr, 12, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(unsigned int aiIntVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 11) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 12, "%u", aiIntVal); StringCchLengthA(lpWritePtr, 12, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(float afFloatVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 20) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 21, "%f", afFloatVal); StringCchLengthA(lpWritePtr, 21, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(double afdoubleVal) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 25) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 26, "%lf", afdoubleVal); StringCchLengthA(lpWritePtr, 26, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(__int64 aiInt64Val) { unsigned int len = 0; if (mlDataLen < DEF_MAX_BUFF_LEN - 20) { char *lpWritePtr = mszPrintBuff + mlDataLen; StringCchPrintfA(lpWritePtr, 21, "%I64d", aiInt64Val); StringCchLengthA(lpWritePtr, 21, &len); mlDataLen += len; } return *this; } STRU_LOG_DATA &STRU_LOG_DATA::operator<<(const char *apStrVal) { unsigned int len = 0; char *lpWritePtr = mszPrintBuff + mlDataLen; if (!apStrVal) { if (mlDataLen < DEF_MAX_BUFF_LEN - 4) { StringCchPrintfA(lpWritePtr, 5, "%s", "NULL"); StringCchLengthA(lpWritePtr, 5, &len); mlDataLen += len; } } else { int iLen = static_cast(strlen(apStrVal)); if (mlDataLen < DEF_MAX_BUFF_LEN - iLen) { StringCchPrintfA(lpWritePtr, iLen + 1, "%s", apStrVal); StringCchLengthA(lpWritePtr, iLen + 1, &len); mlDataLen += len; } else if (DEF_MAX_BUFF_LEN - mlDataLen > 1) { StringCchCopyA(lpWritePtr, DEF_MAX_BUFF_LEN - mlDataLen, apStrVal); mlDataLen += (DEF_MAX_BUFF_LEN - mlDataLen - 1); } } return *this; } LogAssist::LogAssist() : mbIsOpen(false), mbInitial(false), mnLogLevel(3), muTraceOptions(LogAssist::Timestamp | LogAssist::AppendToFile | LogAssist::FileAndLine | LogAssist::PrintThreadID) {} LogAssist::~LogAssist() {} void LogAssist::OpenLog(int anLogLevel, const tstring &strDirectory) { CHECK(strDirectory.length()); base::Threads::Get(base::Threads::UI) ->PostTask(base::Bind(base::Unretained(this), &LogAssist::InitDebug, anLogLevel, strDirectory)); } void LogAssist::CloseLog() { mbIsOpen = false; } void LogAssist::SetOptions(unsigned options) { base::Threads::Get(base::Threads::UI) ->PostTask(base::Bind(base::Unretained(this), &LogAssist::SetTraceOptions, options)); } void LogAssist::LogString(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent) { base::Threads::Get(base::Threads::UI) ->PostTask(base::Bind(base::Unretained(this), &LogAssist::PrintLogInUI, strFile, aiLine, aiLogLevel, strContent)); } std::string LogAssist::Print(const char *pFmt, ...) { char lstrPrintBuff[DEF_MAX_BUFF_LEN] = {0}; va_list argptr; va_start(argptr, pFmt); StringCchVPrintfA(lstrPrintBuff, ARRAYSIZE(lstrPrintBuff) - 1, pFmt, argptr); va_end(argptr); std::string strBuffer = lstrPrintBuff; return strBuffer; } void LogAssist::InitDebug(int anLogLevel, const tstring &strDirectory) { #ifdef NDEBUG return; #endif CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current()); if (0 == strDirectory.length()) { return; } if (mbInitial) { return; } char szVariable[100] = { 0 }; SetTraceLevel(anLogLevel); if (&log_entity_.Get()) { if (!log_entity_.Get().Thread().IsRunning()) { log_entity_.Get().Thread().set_thread_name("LogThread"); log_entity_.Get().Thread().StartWithOptions(base::Thread::Options()); } if (!log_entity_.Get().Thread().IsRunning()) { return; } mbInitial = true; mbIsOpen = true; log_entity_.Get().Thread().message_loop()->PostTask( base::Bind(base::Unretained(this), &LogAssist::InitLog, strDirectory)); } } void LogAssist::PrintLogInUI(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent) { if (!CanTrace(aiLogLevel) || !mbInitial) return; if (&log_entity_.Get()) { if (!log_entity_.Get().Thread().IsRunning() || !log_entity_.Get().Thread().message_loop()) return; log_entity_.Get().Thread().message_loop()->PostTask( base::Bind(base::Unretained(this), &LogAssist::DoPrintLog, strFile, aiLine, aiLogLevel, strContent)); } } void LogAssist::DoPrintLog(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent) { STRU_LOG_DATA loDebugData; OptionTrace(loDebugData, aiLogLevel); loDebugData << strContent.c_str(); char *lszSrcFile = PathFindFileNameA(strFile.c_str()); FileLineTrace(loDebugData, lszSrcFile, aiLine); EndTrace(loDebugData); } tstring LogAssist::CreateLogFile(LPCTSTR szDirectory) { tstring strReturn; tstring strFileName; tstring filename0; tstring filename1; FILETIME fileTime0 = {0}; FILETIME fileTime1 = {0}; TCHAR szAppData[MAX_PATH + 1] = {0}; GetModuleFileName(NULL, szAppData, MAX_PATH); strFileName = szAppData; strFileName = SystemCommon::FilePathHelper::GetPath(strFileName); PathCombine(szAppData, strFileName.c_str(), szDirectory); strFileName = szAppData; SystemCommon::FilePathHelper::CreateDir(strFileName.c_str()); if (PathFileExists(strFileName.c_str())) { int i = 0; for (; i < 2; ++i) { TCHAR lszFileName[MAX_PATH] = {0}; StringCchPrintf(lszFileName, MAX_PATH, _T("%d.log"), i); PathAppend(szAppData, lszFileName); tstring &filename = (0 == i) ? filename0 : filename1; filename = szAppData; HANDLE file = ::CreateFile(filename.c_str(), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (file != INVALID_HANDLE_VALUE) { FILETIME &filetime = i ? fileTime1 : fileTime0; GetFileTime(file, NULL, NULL, &filetime); CloseHandle(file); } long size = SystemCommon::FilePathHelper::GetFileSize(szAppData); if (size < DEF_MAX_FILE_SIZE) { strReturn = filename; break; } PathRemoveFileSpec(szAppData); } if (2 == i) { strReturn = (CompareFileTime(&fileTime0, &fileTime1) > 0) ? filename1 : filename0; DeleteFile(strReturn.c_str()); } } return strReturn; } void LogAssist::InitLog(const tstring &strDirectory) { mszLogFileName = CreateLogFile(strDirectory.c_str()); } void LogAssist::SetTraceLevel(int aiTraceLevel) { mnLogLevel = aiTraceLevel; } void LogAssist::SetTraceOptions(unsigned options) { muTraceOptions = options; } unsigned LogAssist::GetTraceOptions(void) { return muTraceOptions; } bool LogAssist::CanTrace(int aiLogLevel) { return mbIsOpen && (aiLogLevel <= mnLogLevel); } void LogAssist::OptionTrace(STRU_LOG_DATA &astruDebugData, int aiLogLevel) { astruDebugData.mlDataLen = 0; if (muTraceOptions & Timestamp) { SYSTEMTIME loSystemTime; GetLocalTime(&loSystemTime); char lszTraceBuff[MAX_PATH] = {0}; StringCchPrintfA(lszTraceBuff, ARRAYSIZE(lszTraceBuff) - 1, "%d.%d.%d %02d:%02d:%02d:%03d ", loSystemTime.wYear, loSystemTime.wMonth, loSystemTime.wDay, loSystemTime.wHour, loSystemTime.wMinute, loSystemTime.wSecond, loSystemTime.wMilliseconds); astruDebugData << lszTraceBuff; } if (muTraceOptions & LogLevel) { astruDebugData << aiLogLevel << ' '; } return; } void LogAssist::TraceFormat(STRU_LOG_DATA &astruDebugData, const char *pFmt, ...) { char szTempContent[DEF_MAX_BUFF_LEN] = {0}; va_list argptr; va_start(argptr, pFmt); int liLen = StringCchVPrintfA(szTempContent, ARRAYSIZE(szTempContent) - 1, pFmt, argptr); va_end(argptr); astruDebugData << szTempContent; } void LogAssist::FileLineTrace(STRU_LOG_DATA &astruDebugData, char *apSrcFile, int aiSrcLine) { if (muTraceOptions & FileAndLine) { astruDebugData << " " << apSrcFile << "[" << aiSrcLine << "]"; } return; } void LogAssist::EndTrace(STRU_LOG_DATA &astruDebugData) { try { astruDebugData.mszPrintBuff[astruDebugData.mlDataLen] = '\n'; if (muTraceOptions & PrintToConsole) { printf("%s", astruDebugData.mszPrintBuff); } if ((muTraceOptions & AppendToFile) && mszLogFileName.length()) { FILE *lfpTraceFile = NULL; lfpTraceFile = _tfopen(mszLogFileName.c_str(), _T("a")); if (NULL != lfpTraceFile) { fprintf(lfpTraceFile, "%s", astruDebugData.mszPrintBuff); fclose(lfpTraceFile); } } } catch (...) { } } } // namespace applog ================================================ FILE: src/LogAssist/LogAssist.h ================================================ #pragma once #include #include #include #include #include "../base/macros.h" #include "../base.h" #define FORMAT(x) applog::LogAssist::Print##x #define INIT_LOG(obj, szDirectory) obj.OpenLog(3, szDirectory); #define PRT_LOG(obj, alevel, y) obj.LogString(__FILE__, __LINE__, alevel, FORMAT(y)); #define PRT_LOG3(obj, y) PRT_LOG(obj, 3, y) namespace applog { constexpr int DEF_MAX_BUFF_LEN = 2048; constexpr int DEF_MAX_FILE_SIZE = 1024 * 1024 * 2; class STRU_LOG_DATA { public: STRU_LOG_DATA(); STRU_LOG_DATA &operator<<(char acCharVal); STRU_LOG_DATA &operator<<(bool abBoolVal); STRU_LOG_DATA &operator<<(short asShortVal); STRU_LOG_DATA &operator<<(int aiIntVal); STRU_LOG_DATA &operator<<(unsigned int aiIntVal); STRU_LOG_DATA &operator<<(float afFloatVal); STRU_LOG_DATA &operator<<(double afdoubleVal); STRU_LOG_DATA &operator<<(__int64 aiInt64Val); STRU_LOG_DATA &operator<<(const char *apStrVal); char mszPrintBuff[DEF_MAX_BUFF_LEN + sizeof(short)]; int mlDataLen = 0; }; class LogThread { public: base::Thread &Thread() { return thread_; } DISALLOW_COPY_AND_ASSIGN(LogThread); private: friend class base::LazyInstance; friend class base::DefaultLazyInstanceTraits; LogThread(); ~LogThread(); base::Thread thread_; }; class LogAssist { public: LogAssist(); ~LogAssist(); enum Options { Timestamp = 1, LogLevel = 2, FileAndLine = 4, AppendToFile = 8, PrintToConsole = 16, PrintThreadID = 32 }; public: void OpenLog(int anLogLevel, const tstring &strDirectory); void CloseLog(); void SetOptions(unsigned options); void LogString(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent); static std::string Print(const char *pFmt, ...); private: void DoPrintLog(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent); void PrintLogInUI(const std::string &strFile, int aiLine, int aiLogLevel, const std::string &strContent); void InitDebug(int anLogLevel, const tstring &strDirectory); void InitLog(const tstring &strDirectory); bool CanTrace(int aiLogLevel); void SetTraceLevel(int aiTraceLevel); void SetTraceOptions(unsigned options); unsigned GetTraceOptions(void); void OptionTrace(STRU_LOG_DATA &astruDebugData, int aiLogLevel); void TraceFormat(STRU_LOG_DATA &astruDebugData, const char *pFmt, ...); void FileLineTrace(STRU_LOG_DATA &astruDebugData, char *apSrcFile, int aiSrcLine); void EndTrace(STRU_LOG_DATA &astruDebugData); static tstring CreateLogFile(LPCTSTR szDirectory); private: tstring mszLogFileName; unsigned muTraceOptions; long mnLogLevel = 3; bool mbIsOpen = false; bool mbInitial = false; }; extern base::LazyInstance log_entity_; } // namespace applog extern applog::LogAssist DebugSet; ================================================ FILE: src/Main.cpp ================================================ #include "stdafx.h" #include "util/base.h" #include "util/util_tools.h" #include "util/system.h" #include "Global.h" #include "Language/Language.h" #include "LogAssist/LogAssist.h" #include "UI/UtilityWindow.h" HINSTANCE _hInstance = nullptr; CAppModule _Module; UINT WM_TASKBARBUTTONCREATED = 0x1000; static HRESULT Initialize(); static HRESULT UnInitialize(); base::LazyInstance io_thread_ LAZY_INSTANCE_INITIALIZER; base::LazyInstance file_thread_ LAZY_INSTANCE_INITIALIZER; void InstallCommonThread() { if (!file_thread_.Get().IsRunning()) { file_thread_.Get().set_thread_name("file_thread"); file_thread_.Get().StartWithOptions(base::Thread::Options()); base::Threads::Set(base::Threads::FILE, file_thread_.Get().message_loop()); } if (!io_thread_.Get().IsRunning()) { io_thread_.Get().set_thread_name("io_thread"); io_thread_.Get().StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO)); base::Threads::Set(base::Threads::IO, io_thread_.Get().message_loop()); } } void InitGlobalPath() { if (Util::Base::GetAccurateOSVersion() <= WINDOWS_2003) global.m_strInstallPath = L"C:\\Program Files"; else { global.m_strInstallPath = SystemCommon::FilePathHelper::GetAssignPath(CSIDL_APPDATA, FALSE); } global.m_packPath = SystemCommon::FilePathHelper::GetAssignPath(CSIDL_LOCAL_APPDATA, TRUE); } void UnstallCommonThread() { io_thread_.Get().Stop(); file_thread_.Get().Stop(); applog::log_entity_.Get().Thread().Stop(); } int Run(int nCmdShow = SW_SHOWDEFAULT) { InstallCommonThread(); InitGlobalPath(); std::auto_ptr message_loop; message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI)); message_loop->set_thread_name("ui_thread"); base::Threads::Set(Threads::UI, message_loop.get()); INIT_LOG(DebugSet, _T("LOGINIT\\")) PRT_LOG3(DebugSet, ("sys lang: %d", global.lanId_)); do { TCHAR szPath[MAX_PATH + 1] = {0}; GetModuleFileName(NULL, szPath, MAX_PATH); TCHAR szFileVersion[200] = {0}; SystemCommon::FileVersionHelper::GetFileVersion(szPath, szFileVersion, 200); std::string verNum = Util::Base::WChar2Ansi(szFileVersion); PRT_LOG3(DebugSet, ("app started %s", verNum.c_str())) } while (false); if (!CUtilityWindow::GetInstance().Initialize()) { goto RETURN; } message_loop->Run(); CUtilityWindow::GetInstance().UnInitialize(); RETURN: UnstallCommonThread(); return TRUE; } void CheckIsRunning() { HWND hWnd = ::FindWindow(CGlobal::szUtilityClassName_, CGlobal::szGlobalString_); if (hWnd && ::IsWindow(hWnd) && GetWindowLongPtr(hWnd, GWLP_USERDATA) == CGlobal::UitlWndPrivacyCode_) { ::PostMessage(hWnd, WM_IS_EXIST, 0, 0); ExitProcess(0); } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { CheckIsRunning(); base::AtExitManager atmgr; _hInstance = hInstance; WM_TASKBARBUTTONCREATED = ::RegisterWindowMessage(L"TaskbarButtonCreated"); HRESULT hRes = S_OK; BOOL bSuccess = AtlInitCommonControls(ICC_BAR_CLASSES); ::DefWindowProc(NULL, 0, 0, 0L); int nRet = -1; if (S_OK == Initialize()) { hRes = _Module.Init(NULL, hInstance); ATLASSERT(SUCCEEDED(hRes)); nRet = Run(nCmdShow); _Module.Term(); } UnInitialize(); return nRet; } HRESULT Initialize() { LPCTSTR lpCommandLine = GetCommandLine(); int nArgs = 0; LPTSTR *lpArgList = CommandLineToArgvW(lpCommandLine, &nArgs); LPCTSTR lpParaVal = nullptr; TCHAR szUrl[MAX_URL_LEN + 1] = {0}; lan::AppLanguage::SysLanguage(); return S_OK; } HRESULT UnInitialize() { return S_OK; } ================================================ FILE: src/StdAfx.cpp ================================================ #include "StdAfx.h" #pragma comment(lib, "netapi32.lib") #pragma comment(lib, "version.lib") #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "gdiplus.lib") #pragma comment(lib, "strsafe.lib") void TrackMouseLeave(HWND hWnd) { TRACKMOUSEEVENT tme; memset(&tme, 0, sizeof(tme)); tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; tme.dwHoverTime = 0; TrackMouseEvent(&tme); } ================================================ FILE: src/StdAfx.h ================================================ #pragma once #pragma warning(disable: 4302) #pragma warning(disable: 4244) #define WIN32_LEAN_AND_MEAN #define _CRT_SECURE_NO_WARNINGS #define WINVER 0x0501 #define _WIN32_WINNT 0x0501 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern CAppModule _Module; extern HINSTANCE _hInstance; #ifndef tstring #ifdef _UNICODE #define tstring std::wstring #else #define tstring std::string #endif #endif #define SIZEOF(A) (sizeof(A) / sizeof((A)[0])) #ifndef MAX_URL_LEN #define MAX_URL_LEN INTERNET_MAX_URL_LENGTH #endif #include "util/base.h" #define MAX_WINDOW_WIDTH 800 #define MAX_WINDOW_HEIGHT 600 ================================================ FILE: src/UI/FrameShowState.cpp ================================================ #include "StdAfx.h" #include "FrameShowState.h" ShowState::ShowState() : bPending_(false), step_(APP1), degree_(DETEN) {} ================================================ FILE: src/UI/FrameShowState.h ================================================ #pragma once class ShowState { public: explicit ShowState(); enum PngType { PNG_BEGIN = 0, APP1, APP2, APP3, APP4, APP5, APP6, }; enum TransDegree { DETEN = 20, DEFIF = 50, DESIX = 100, DESEVN = 150, DEEIGHT = 180, DENIGHT = 220, DEALL = 255, }; bool bPending_; PngType step_; DWORD degree_; }; ================================================ FILE: src/UI/UIAgreement.cpp ================================================ #include "stdafx.h" #include "util/util_tools.h" #include "../base/Thread.h" #include "../base/WeakPtr.h" #include "../base/WrapperObj.h" #include "../base/common_threads.h" #include "../base/lazy_instance.h" #include "../Global.h" #include "UIAgreement.h" static constexpr int BEGINSCROLL = 0x101; static constexpr int SCROLLING = 0x102; static constexpr int HEIGHT = 300; static constexpr int ENHEIGHT = 400; CUIContents::CUIContents() : _parent(NULL), _scrollDelta(0) {} CUIContents::~CUIContents() { ATLTRACE("delete CUIContents\n"); } void CUIContents::OnWheel(WPARAM wParam) { const int zDelta = (int)(short)HIWORD(wParam); const int height = global.m_zh ? HEIGHT : ENHEIGHT; if (zDelta < 0) { _scrollDelta += 20; if (_scrollDelta > height) { _scrollDelta = height; } } if (zDelta > 0) { _scrollDelta -= 20; if (_scrollDelta < 0) { _scrollDelta = 0; } } tstring strID = _T("id_static_tip2"); CBaseElementCtl *pEle = _elementManager.Search(strID); if (pEle) { static_cast(pEle)->_scrollDelta = _scrollDelta; RaiseInvalidate(TRUE); } } LRESULT CUIContents::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { const int height = global.m_zh ? HEIGHT : ENHEIGHT; if (wParam == BEGINSCROLL) { KillTimer(BEGINSCROLL); SetTimer(SCROLLING, 100, NULL); } if (wParam == SCROLLING) { _scrollDelta += 4; if (_scrollDelta > height) { KillTimer(SCROLLING); } else { tstring strID = _T("id_static_tip2"); CBaseElementCtl *pEle = _elementManager.Search(strID); if (pEle) { static_cast(pEle)->_scrollDelta = _scrollDelta; RaiseInvalidate(TRUE); } } } return S_OK; } LRESULT CUIContents::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (_parent && ::IsWindow(_parent)) { ::PostMessage(_parent, WM_CLOSE, 0, 0); } return S_OK; } void CUIContents::CreateWnd(HWND hWnd) { _parent = hWnd; std::wstring strXMLSource; switch (global.lanId_) { case 0x804: { strXMLSource = L"UICONTENT"; } break; default: strXMLSource = L"ENGUICONTENT"; } CTransWindow::DUICreate(hWnd, strXMLSource.c_str()); ::ShowWindow(m_hWnd, SW_SHOW); } void CUIContents::OnFinalMessage(HWND) { _elementManager.Dispose(); delete this; } void CUIContents::OnLoad() { RECT rc; ::GetWindowRect(_parent, &rc); rc.left += 20; rc.top += 47; SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE); } void CUIContents::OnLoaded() { SetTimer(BEGINSCROLL, 600, NULL); } CUIAgreement::CUIAgreement() : _obj(NULL) {} CUIAgreement::~CUIAgreement() {} void CUIAgreement::CreateWnd(HWND hpWnd) { std::wstring strXMLSource; switch (global.lanId_) { case 0x804: { strXMLSource = L"UIAGREEMENT"; } break; default: strXMLSource = L"ENGUIAGREEMENT"; } CTransWindow::DUICreate(hpWnd, strXMLSource.c_str()); } void CUIAgreement::DestroyWnd() { _elementManager.Dispose(); DestroyWindow(); } LRESULT CUIAgreement::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { CTransWindow::OnLButtonDown(uMsg, wParam, lParam, bHandled); PostMessage(WM_CLOSE, 0, 0); return S_OK; } void CUIAgreement::OnLoad() { _obj = new CUIContents(); _obj->CreateWnd(m_hWnd); } void CUIAgreement::OnLoaded() { SetFocus(); } void CUIAgreement::OnExit() { _elementManager.Dispose(); DestroyWnd(); (static_cast( base::MessageLoop::LayerLoop::Back()->pump_win())) ->Quit(); } void CUIAgreement::OnFinalMessage(HWND) { m_hWnd = NULL; } void CUIAgreement::DrawBorder(CDCHandle dc) { DUI_Rect wndRect; GetClientRect(&wndRect); HDC hDC = dc.m_hDC; BITMAP bmpFrameData; GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData); if (_bmpFrame) { CGDIResource::GetInstance().GDI_DrawImageStretch( hDC, _bmpFrame, wndRect, DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 210, _rcFrameCorner); } } LRESULT CUIAgreement::OnWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (_obj && ::IsWindow(_obj->m_hWnd)) { _obj->OnWheel(wParam); } return S_OK; } ================================================ FILE: src/UI/UICannotDown.cpp ================================================ #include "stdafx.h" #include "util/util_tools.h" #include "../Global.h" #include "../base/Thread.h" #include "../base/WeakPtr.h" #include "../base/WrapperObj.h" #include "../base/common_threads.h" #include "../base/lazy_instance.h" #include "UICannotDown.h" CUIUpDate::CUIUpDate() : infostyle_(QUIT) {} CUIUpDate::~CUIUpDate() {} void CUIUpDate::CreateWnd(HWND hpWnd) { std::wstring strXMLSource; switch (global.lanId_) { case 0x804: { strXMLSource = L"UICANNOTDOWN"; } break; default: strXMLSource = L"ENGUICANNOTDOWN"; } CTransWindow::DUICreate(hpWnd, strXMLSource.c_str()); } void CUIUpDate::DestroyWnd() { _elementManager.Dispose(); DestroyWindow(); } void CUIUpDate::OnLoad() { tstring strID = _T("id_btn_close"); CBaseElementCtl *pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnCancal)); } strID = _T("id_btn_ok"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnYes)); } strID = _T("id_btn_cancal"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnCancal)); } strID = _T("id_btn_quit"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnYes)); } if (infostyle_ == QUIT) { strID = _T("id_btn_quit"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_static_tip2"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } } else if (infostyle_ == CHECKSYSTEM) { strID = _T("id_btn_ok"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_btn_cancal"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_static_tip1"); pEle = _elementManager.Search(strID); if (pEle) pEle->SetVisible(FALSE); strID = _T("id_btn_close"); pEle = _elementManager.Search(strID); if (pEle) pEle->SetVisible(FALSE); } } void CUIUpDate::OnLoaded() {} void CUIUpDate::OnExit() { _elementManager.Dispose(); DestroyWnd(); (static_cast( base::MessageLoop::LayerLoop::Back()->pump_win())) ->Quit(); } void CUIUpDate::OnFinalMessage(HWND) { m_hWnd = NULL; } void CUIUpDate::OnYes() { _bOK = TRUE; PostMessage(WM_CLOSE, 0, 0); } void CUIUpDate::OnCancal() { _bOK = FALSE; PostMessage(WM_CLOSE, 0, 0); } void CUIUpDate::DrawBorder(CDCHandle dc) { CTransWindow::DrawBorder(dc); { HBITMAP hBitMap = NULL; hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APPLOGO"), PNG); if (hBitMap) { BITMAP bmpFrameData; GetObject(hBitMap, sizeof(bmpFrameData), &bmpFrameData); DUI_Rect rRect(22, 20, 22 + bmpFrameData.bmWidth, 20 + bmpFrameData.bmHeight); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } } void CUIUpDate::SetCustomTitle(std::wstring &title) { tstring strID = _T("id_static_tip2"); CBaseElementCtl *pEle = _elementManager.Search(strID); if (pEle) { pEle->SetTitle(title); } } ================================================ FILE: src/UI/UIMainWindowEx.cpp ================================================ #include "stdafx.h" #include #include #include #include "jsoncpp/json/json.h" #include "util/util_tools.h" #include "util/system.h" #include "../base/Thread.h" #include "../base/common_threads.h" #include "../Global.h" #include "../LogAssist/LogAssist.h" #include "../Language/Language.h" #include "../Util/UtilApi.h" #include "UtilityWindow.h" #include "UICannotDown.h" #include "UIAgreement.h" #include "UIMainWindowEx.h" #define PELEMENT (pEle = _elementManager.Search(strID)) CUIMainWindowEx::CUIMainWindowEx(): instep_(BEFOREDOWN), installtype_(DEFAULT), downloadway_(SINGLE), showstate_(), time_download_(0), time_install_(0), b_user_quit_(false), window_showing_(true), is_pack_complete_(false), f_down_process_(0.0), urldownloader_(this, global.downloadurl_), filedownloader_(this, global.downloadurl_, global.m_packPath) {} CUIMainWindowEx::~CUIMainWindowEx() { } LRESULT CUIMainWindowEx::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (wParam != SC_MAXIMIZE) { bHandled = FALSE; } if (wParam == SC_RESTORE) { RaiseInvalidate(TRUE); } if (SC_CLOSE == wParam) { if (instep_ < INSTALLING) { CUIUpDate obj; obj.CreateWnd(m_hWnd); if (obj.DoModal()) { DownLoadingAUserQuit(); b_user_quit_ = true; } else { bHandled = TRUE; base::Threads::Get(Threads::UI) ->PostTask(Bind(this, &CUIMainWindowEx::DoInstall)); } } else if (instep_ == INSTALLING) { bHandled = TRUE; ShakeWindow(); } else { bHandled = TRUE; base::Threads::Get(Threads::UI) ->PostTask(Bind(this, &CUIMainWindowEx::OnInstallComplete)); } } return 0; } LRESULT CUIMainWindowEx::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { if (bshaking_ || _bCUpdateWindowBaseEx_TransShow) { bHandled = TRUE; return S_OK; } RECT rect; GetWindowRect(&rect); int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); DUI_Point pt(x, y); ScreenToClient(&pt); if (_elementManager.MouseOnElement(pt)) return HTCLIENT; UINT nFlags = 0; _elementManager.OnMouseMove(nFlags, pt); int nTop = 0; int nLeft = 0; int nRight = 0; int nBottom = 0; if (IsZoomed()) { if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; return HTCLIENT; } if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (_bSupportChangeSize) { if (x >= rect.left && x <= rect.left + nLeft) { if (y < rect.top + nTop) return HTTOPLEFT; else if (y > rect.bottom - nBottom) return HTBOTTOMLEFT; return HTLEFT; } if (x <= rect.right && x >= rect.right - nRight) { if (y < rect.top + nTop) return HTTOPRIGHT; else if (y > rect.bottom - nBottom) return HTBOTTOMRIGHT; return HTRIGHT; } if (y >= rect.top && y <= rect.top + nTop) return HTTOP; if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight)) return HTCAPTION; if (y <= rect.bottom && y >= rect.bottom - nBottom) { return HTBOTTOM; } } return HTCLIENT; } LRESULT CUIMainWindowEx::OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { CBaseElementCtl* pEle = NULL; tstring strID; strID = _T("id_panel_userdef"); pEle = _elementManager.Search(strID); if (pEle && pEle->GetVisible()) { } else return 0; strID = _T("id_edit_installpath"); pEle = _elementManager.Search(strID); if (!pEle) return 0; std::wstring title = pEle->GetTitle(); std::wregex p( L"^[a-zA-Z]:\\\\{1}(?:[^/:*?\"<>|])*[^./:*?\"<>|]{1}$|[a-zA-Z]:\\\\"); bool ism = std::regex_match(title, p); BOOL tipshow = FALSE; if (ism) { if (!(-1 == title.find(L"\\\\") && -1 == title.find(L".\\") && -1 == title.find(L"\\."))) { tipshow = TRUE; } } else { tipshow = TRUE; } strID = _T("id_static_patherror"); pEle = _elementManager.Search(strID); if (pEle) pEle->SetVisible(tipshow); strID = _T("id_btn_installnow"); PELEMENT; if (pEle) { ((CButtonCtl*)pEle)->Enable(!tipshow); } return 0; } LRESULT CUIMainWindowEx::OnTaskBarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (CGlobal::pTaskbar_) return S_OK; if (S_OK == ::CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&CGlobal::pTaskbar_))) { CGlobal::pTaskbar_->HrInit(); CGlobal::pTaskbar_->SetProgressState(m_hWnd, TBPF_NORMAL); } return S_OK; } HWND CUIMainWindowEx::CreateWnd(HWND hParent, const WCHAR *wstr) { CTransWindowEx::DUICreate(hParent, wstr); TransBeginShow(); TransShowWindow(); return m_hWnd; } void CUIMainWindowEx::DestroyWnd() { if (::IsWindow(m_hWnd)) { DestroyWindow(); } } void CUIMainWindowEx::RestoreWindow() { if (::IsIconic(m_hWnd)) ::ShowWindow(m_hWnd, SW_RESTORE); RaiseInvalidate(); } void CUIMainWindowEx::OnLoad() { CBaseElementCtl *pEle = NULL; tstring strID; strID = _T("id_close"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnClose)); } strID = _T("id_install"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnInstall)); } strID = _T("id_checkbox"); pEle = _elementManager.Search(strID); if (pEle) { ((CCheckBoxCtl *)pEle)->SetCheck(TRUE); pEle->RegisterLButtonDownEvent(BIND(*this, CUIMainWindowEx::OnCheck)); } strID = _T("id_openurl"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnAgreement)); } strID = _T("id_userinstall"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnSelected)); } strID = _T("id_btn_min"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnMin)); } strID = _T("id_panel_userdef"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_btn_backmain"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnBackMain)); } strID = _T("id_btn_installdir"); pEle = _elementManager.Search(strID); if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OpenInstallDir)); } strID = _T("id_checkbox_shortcut"); pEle = _elementManager.Search(strID); if (pEle) { ((CCheckBoxCtl *)pEle)->SetCheck(TRUE); } strID = _T("id_checkbox_easymenu"); pEle = _elementManager.Search(strID); if (pEle) ((CCheckBoxCtl *)pEle)->SetCheck(TRUE); strID = _T("id_checkbox_autorun"); pEle = _elementManager.Search(strID); if (pEle) ((CCheckBoxCtl *)pEle)->SetCheck(FALSE); strID = _T("id_edit_installpath"); PELEMENT; if (pEle) pEle->SetTitle(global.m_strInstallPath); strID = _T("id_btn_installnow"); pEle = _elementManager.Search(strID); PELEMENT; if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnInstallSelected)); } strID = _T("id_panel_download"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_panel_complete"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_btn_usenow"); PELEMENT; if (pEle) { pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnUseNow)); } strID = _T("id_btn_complete"); PELEMENT; if (pEle) { pEle->RegisterLButtonUpEvent( BIND(*this, CUIMainWindowEx::OnInstallComplete)); } strID = _T("id_static_tryshutdown"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } } void CUIMainWindowEx::OnLoaded() {} void CUIMainWindowEx::IsWindowShowed() { window_showing_ = false; if (CheckCanInstall()) { base::Threads::Get(base::Threads::FILE) ->PostTask(base::Bind(this, &CUIMainWindowEx::FileInit)); base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::Rotational), base::TimeDelta::FromMilliseconds(1000)); } else { CUIUpDate obj; obj.infostyle_ = CUIUpDate::CHECKSYSTEM; obj.CreateWnd(m_hWnd); obj.DoModal(); PostMessage(WM_CLOSE, 0, 0); } } void CUIMainWindowEx::StartShake() { tstring strID; CBaseElementCtl* pEle = NULL; strID = _T("id_static_tryshutdown"); PELEMENT; if (pEle) { pEle->SetVisible(TRUE); } } void CUIMainWindowEx::Shaked() { tstring strID; CBaseElementCtl* pEle = NULL; strID = _T("id_static_tryshutdown"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } } void CUIMainWindowEx::DrawBorder(CDCHandle dc) { CTransWindowEx::DrawBorder(dc); if (showstate_.bPending_) { HBITMAP hBitMap = NULL; switch (showstate_.step_) { case ShowState::APP1: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP6"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP1"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; case ShowState::APP2: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP1"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP2"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; case ShowState::APP3: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP2"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP3"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; case ShowState::APP4: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP3"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP4"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; case ShowState::APP5: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP4"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP5"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; case ShowState::APP6: { DUI_Rect rRect(6, 6, 486, 246); hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP5"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP6"), PNG); if (hBitMap) { HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage( hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_); } } break; default: break; } } else { HBITMAP hBitMap = NULL; switch (showstate_.step_) { case ShowState::APP1: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP1"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; case ShowState::APP2: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP2"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; case ShowState::APP3: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP3"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; case ShowState::APP4: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP4"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; case ShowState::APP5: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP5"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; case ShowState::APP6: { hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APP6"), PNG); if (hBitMap) { DUI_Rect rRect(6, 6, 486, 246); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } break; default: break; } } HBITMAP hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T("APPLOGO"), PNG); if (hBitMap) { BITMAP bmpFrameData; GetObject(hBitMap, sizeof(bmpFrameData), &bmpFrameData); DUI_Rect rRect(20 - 4, 20 - 6, 20 - 4 + bmpFrameData.bmWidth, 20 - 6 + bmpFrameData.bmHeight); HDC hDC = dc.m_hDC; CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect); } } void CUIMainWindowEx::FetchURLComplete(std::string res) { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); if (b_user_quit_) { return; } do { instep_ = DOWNLOADING; std::wstring errorNotice = lan::AppLanguage::s_lanArr[lan::AppLanguage::lanIndex_] .pstrServiceError; std::string fileurl; do { std::map map_token; bool bret = GetJsonTokenByDownLoadUrl(res, map_token); if (!bret) { CUIUpDate obj; obj.infostyle_ = CUIUpDate::NOTICE; obj.CreateWnd(m_hWnd); obj.SetCustomTitle(errorNotice); obj.DoModal(); PostMessage(WM_CLOSE, 0, 0); return; } std::map::iterator ite; ite = map_token.find(std::string("downloadUrl")); if (ite != map_token.end() && ite->second.length() && (0 == ite->second.find("http"))) { fileurl = ite->second; } else { CUIUpDate obj; obj.infostyle_ = CUIUpDate::NOTICE; obj.CreateWnd(m_hWnd); obj.SetCustomTitle(errorNotice); obj.DoModal(); PostMessage(WM_CLOSE, 0, 0); return; } } while (false); global.m_filedownurl = fileurl; break; } while (false); } void CUIMainWindowEx::FetchFileComplete(bool status, DownCompleteInfo& rest) { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); if (b_user_quit_) { return; } const net::URLFetcher::ErrorType reason = rest.reason_; if (!status) { if (reason == net::URLFetcher::DISK_NO_SPACE) { CUIUpDate obj; obj.infostyle_ = CUIUpDate::NOTICE; obj.CreateWnd(m_hWnd); obj.SetCustomTitle(std::wstring(L"Not enough disk space")); obj.DoModal(); base::Threads::Get(Threads::FILE) ->PostTask( Bind(this, &CUIMainWindowEx::ClearDownloads, global.m_packPath)); PostMessage(WM_CLOSE, 0, 0); } else { if (filedownloader_.retrycount_++ != static_cast(-1)) { base::Threads::Get(Threads::FILE) ->PostTask(Bind(this, &CUIMainWindowEx::ClearDownloads, global.m_packPath)); base::MessageLoop::current()->PostDelayedTask( Bind(this, &CUIMainWindowEx::RetryDownLoadAgain), base::TimeDelta::FromMilliseconds(1000)); } else { CUIUpDate obj; obj.infostyle_ = CUIUpDate::NOTICE; obj.CreateWnd(m_hWnd); obj.SetCustomTitle(std::wstring(L"Unable connect to server")); obj.DoModal(); base::Threads::Get(Threads::FILE) ->PostTask(Bind(this, &CUIMainWindowEx::ClearDownloads, global.m_packPath)); PostMessage(WM_CLOSE, 0, 0); } } return; } time_download_ = timeGetTime() - time_download_; is_pack_complete_ = true; if (IsWindowEnabled()) { instep_ = INSTALLING; DoInstall(); } } void CUIMainWindowEx::FetchFileProgress(double cur) { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); if (b_user_quit_) { return; } CBaseElementCtl* pEle = NULL; tstring strID; strID = _T("id_progress_download"); PELEMENT; if (pEle) { ((CProgressCtl*)pEle)->SetPos(cur * 0.8); } DWORD now = static_cast(100 * cur * 0.8); SetProgressTaskBar(now, 100); } void CUIMainWindowEx::DeletePack(const std::wstring& str_path) { SystemCommon::FilePathHelper::DeepDeleteFile(str_path); } void CUIMainWindowEx::OnMin() { ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); } void CUIMainWindowEx::OnClose() { if (instep_ < INSTALLING) { CUIUpDate obj; obj.CreateWnd(m_hWnd); if (obj.DoModal()) { DownLoadingAUserQuit(); b_user_quit_ = true; PostMessage(WM_CLOSE, 0, 0); } else { base::Threads::Get(Threads::UI) ->PostTask(Bind(this, &CUIMainWindowEx::DoInstall)); } } else if (instep_ == INSTALLING) { ShakeWindow(); } else { OnInstallComplete(); } } void CUIMainWindowEx::OnInstall() { if (window_showing_) return; tstring strID = _T("id_panel_main"); CBaseElementCtl *pEle = NULL; PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } installtype_ = DEFAULT; Ready2DownloadZip(); } void CUIMainWindowEx::OnInstallSelected() { tstring strID = _T("id_edit_installpath"); CBaseElementCtl *pEle = NULL; int deskcut = 1; int barcut = 1; int autorun = 1; pEle = _elementManager.Search(strID); if (pEle) { global.m_strInstallPath = pEle->GetTitle(); if (global.m_strInstallPath[global.m_strInstallPath.length() - 1] == L'\\') { std::wstring strtemp = global.m_strInstallPath.c_str(); strtemp[strtemp.length() - 1] = L'\0'; global.m_strInstallPath = strtemp.c_str(); } } strID = _T("id_checkbox_shortcut"); PELEMENT; if (pEle) { deskcut = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0; } strID = _T("id_checkbox_easymenu"); PELEMENT; if (pEle) { barcut = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0; } strID = _T("id_checkbox_autorun"); PELEMENT; if (pEle) { autorun = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0; } strID = _T("id_panel_userdef"); PELEMENT; if (!pEle) return; pEle->SetVisible(FALSE); installtype_ = SELECT; Ready2DownloadZip(); } void CUIMainWindowEx::OnAgreement() { CUIAgreement obj; obj.CreateWnd(m_hWnd); if (obj.DoModal()) { } } void CUIMainWindowEx::OnCheck() { if (window_showing_) return; bool bCheck = false; tstring strID = _T("id_checkbox"); CBaseElementCtl* pEle = _elementManager.Search(strID); if (pEle) { bCheck = ((CCheckBoxCtl*)pEle)->GetCheck(); } strID = _T("id_install"); pEle = _elementManager.Search(strID); if (pEle) { if (bCheck) { ((CButtonCtl*)pEle)->Enable(TRUE); } else { ((CButtonCtl*)pEle)->Enable(FALSE); } } strID = _T("id_userinstall"); pEle = _elementManager.Search(strID); if (pEle) { if (bCheck) { ((CButtonCtl*)pEle)->Enable(TRUE); } else { ((CButtonCtl*)pEle)->Enable(FALSE); } } } void CUIMainWindowEx::OpenInstallDir() { BROWSEINFO bi; bi.hwndOwner = this->GetHost(); bi.pidlRoot = NULL; bi.pszDisplayName = NULL; bi.lpszTitle = TEXT("Please select a folder"); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; bi.lpfn = NULL; bi.lParam = 0; bi.iImage = 0; LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if (pidl == NULL) { return; } WCHAR szPath[MAX_PATH + 1] = {0}; if (!SHGetPathFromIDListW(pidl, szPath)) { return; } tstring strID; strID = _T("id_edit_installpath"); CBaseElementCtl *pEle = _elementManager.Search(strID); if (pEle) { std::wstring strPath = szPath; static_cast(pEle)->SetTitle(strPath); } strID = _T("id_static_patherror"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_btn_installnow"); PELEMENT; if (pEle) { static_cast(pEle)->Enable(TRUE); } } void CUIMainWindowEx::OnSelected() { if (window_showing_) return; CBaseElementCtl *pEle = NULL; tstring strID; strID = _T("id_panel_main"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 472, SWP_NOZORDER | SWP_NOMOVE); ChangeSize(492, 472); strID = _T("id_panel_userdef"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(TRUE); if (GetPathEditError()) ; else { strID = _T("id_static_patherror"); pEle = _elementManager.Search(strID); if (pEle) pEle->SetVisible(FALSE); } } } void CUIMainWindowEx::OnBackMain() { CBaseElementCtl *pEle = NULL; tstring strID; strID = _T("id_panel_userdef"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(FALSE); } ChangeSize(492, 402); strID = _T("id_panel_main"); pEle = _elementManager.Search(strID); if (pEle) { pEle->SetVisible(TRUE); } ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 402, SWP_NOZORDER | SWP_NOMOVE); } void CUIMainWindowEx::OnUseNow() { b_user_quit_ = true; std::wstring app = global.m_strInstallPath + L"\\" + Util::Base::s2ws(global.appname_); STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; WCHAR szProcessCmd[MAX_PATH + 1 + MAX_URL_LEN + MAX_PATH] = { 0 }; _snwprintf(szProcessCmd, MAX_PATH + MAX_URL_LEN + MAX_PATH, L"\"%s\"", app.c_str()); do { std::wstring wstrtmp = szProcessCmd; std::string stemstr = Util::Base::ws2s(wstrtmp); } while (false); bool ProcessCreated = true; do { if (!SystemCommon::OS::CreateLowIntegrityProcess(szProcessCmd)) { ProcessCreated = false; break; } } while (false); if (false == ProcessCreated) { CreateProcessW(NULL, szProcessCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); } PostMessage(WM_CLOSE, 0, 0); } void CUIMainWindowEx::OnInstallComplete() { b_user_quit_ = true; PostMessage(WM_CLOSE, 0, 0); } void CUIMainWindowEx::CreateShortCut(LPCTSTR szExePath, const ShortCutType Stype) { ::CoInitialize(NULL); IShellLink* psl; LPITEMIDLIST pidl; LPMALLOC pShellMalloc; std::wstring strDesktopPath; std::wstring strStartMenuPath; const int nFolder[2] = { CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU }; if (SUCCEEDED(SHGetMalloc(&pShellMalloc))) { TCHAR Path[MAX_PATH + 1]; for (int i = 0; i < 2; ++i) { if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, nFolder[i], &pidl))) { if (SHGetPathFromIDList(pidl, Path)) { if (i == 0) strDesktopPath = Path; else strStartMenuPath = Path; } pShellMalloc->Free(pidl); } } pShellMalloc->Release(); } std::wstring str; switch (Stype) { case DESK: { str = strDesktopPath; } break; case STARTMENU: { str = strStartMenuPath; } break; case TASKBAR: { std::wstring strTaskBarPath = SystemCommon::FilePathHelper::GetAssignPath(CSIDL_APPDATA, TRUE); strTaskBarPath += L"\\Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar"; str = strTaskBarPath; } break; default: { return; } break; } str += _T("\\"); str += Util::Base::s2ws(global.shortcutname_); str += _T(".lnk"); do { HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); if (SUCCEEDED(hr)) { IPersistFile* ppf; psl->SetPath(szExePath); psl->SetArguments(_T("")); psl->SetShowCmd(SW_SHOW); psl->SetIconLocation(szExePath, 0); if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) { if (SUCCEEDED(ppf->Save(str.c_str(), TRUE))) ; ppf->Release(); } psl->Release(); } } while (false); ::CoUninitialize(); } void CUIMainWindowEx::SetProgressTaskBar(DWORD now, DWORD total) { if (CGlobal::pTaskbar_) { CGlobal::pTaskbar_->SetProgressValue(m_hWnd, now, total); } } void CUIMainWindowEx::Rotational() { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); do { if (showstate_.bPending_ == false) { showstate_.bPending_ = true; switch (showstate_.step_) { case ShowState::APP1: { showstate_.step_ = ShowState::APP2; } break; case ShowState::APP2: { showstate_.step_ = ShowState::APP3; } break; case ShowState::APP3: { showstate_.step_ = ShowState::APP4; } break; case ShowState::APP4: { showstate_.step_ = ShowState::APP5; } break; case ShowState::APP5: { showstate_.step_ = ShowState::APP6; } break; case ShowState::APP6: { showstate_.step_ = ShowState::APP1; } break; default: break; } showstate_.degree_ = ShowState::DETEN; break; } if (showstate_.degree_ == ShowState::DEALL) { showstate_.bPending_ = false; RaiseInvalidate(TRUE); base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::Rotational), base::TimeDelta::FromMilliseconds(4000)); return; } switch (showstate_.degree_) { case ShowState::DETEN: { showstate_.degree_ = ShowState::DEFIF; } break; case ShowState::DEFIF: { showstate_.degree_ = ShowState::DESIX; } break; case ShowState::DESIX: { showstate_.degree_ = ShowState::DESEVN; } break; case ShowState::DESEVN: { showstate_.degree_ = ShowState::DEEIGHT; } break; case ShowState::DEEIGHT: { showstate_.degree_ = ShowState::DENIGHT; } break; case ShowState::DENIGHT: { showstate_.degree_ = ShowState::DEALL; } break; case ShowState::DEALL: { } break; default: break; } } while (false); RaiseInvalidate(TRUE); base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::Rotational), base::TimeDelta::FromMilliseconds(100)); } void CUIMainWindowEx::Ready2DownloadZip() { CBaseElementCtl *pEle = NULL; tstring strID; ChangeSize(492, 402); ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 402, SWP_NOZORDER | SWP_NOMOVE); strID = _T("id_panel_download"); PELEMENT; if (pEle) { pEle->SetVisible(TRUE); } if (global.m_filedownurl.empty()) { base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::CheckIFTureWillDownLoad), base::TimeDelta::FromMilliseconds(200)); } else { CombineRealInstallPath(); DownLoadingFileUrl(); } } void CUIMainWindowEx::ClearDownloads(const std::wstring str_path) { CUIMainWindowEx::DeletePack(str_path); } void CUIMainWindowEx::FileInit() { CHECK(base::MessageLoop::current() == base::Threads::Get(base::Threads::FILE)); global.m_packPath += L"\\AppInsPackFileDir\\"; SystemCommon::FilePathHelper::ForceCreateDir(global.m_packPath.c_str()); global.m_packPath += L"AppPackZip"; global.m_packPath += Util::Base::longtocharw(time(nullptr)); base::Threads::Get(Threads::UI) ->PostTask(base::Bind(this, &CUIMainWindowEx::QueryDownLoadUrl)); } void CUIMainWindowEx::QueryDownLoadUrl() { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); global.downloadurl_ = global.downloadurl_ + std::string("?version=") + Util::Base::ws2s( SystemCommon::FileVersionHelper::GetFileVersion(_hInstance)) + std::string("&mac_address=") + global.m_macAddress + std::string("&platform=") + global.m_platform; urldownloader_.fetcher_->set_download_url(global.downloadurl_); urldownloader_.fetcher_->Start(); } void CUIMainWindowEx::DoInstall() { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); if (is_pack_complete_ && IsWindowEnabled()) { instep_ = INSTALLING; CBaseElementCtl* pEle = NULL; tstring strID; strID = _T("id_static_downing"); PELEMENT; if (pEle) { std::wstring strTitle = lan::AppLanguage::s_lanArr[lan::AppLanguage::lanIndex_] .pstrInstalling; pEle->SetTitle(strTitle); pEle->RaiseInvalidate(TRUE); } strID = _T("id_static_downing_size"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); pEle->RaiseInvalidate(TRUE); } InstallIng(); } } void CUIMainWindowEx::InstallIng() { if (base::MessageLoop::current() != base::Threads::Get(Threads::FILE)) { base::Threads::Get(Threads::FILE) ->PostTask(base::Bind(this, &CUIMainWindowEx::InstallIng)); return; } do { bool bIs = false; std::wstring exename = Util::Base::s2ws(global.appname_); exename = SystemCommon::FilePathHelper::GetFileName(exename); DWORD dwPid = SystemCommon::OS::ProcesstoPid(exename.c_str()); if (dwPid) { char szArgs[50] = { 0 }; _snprintf_s(szArgs, 50, _TRUNCATE, "TASKKILL /F /PID %u", dwPid); system(szArgs); bIs = true; } if (bIs) { Sleep(100); } } while (false); time_install_ = timeGetTime(); BOOL res = SystemCommon::FilePathHelper::UnzipFileToPath(global.m_packPath.c_str(), global.m_strInstallPath.c_str()); base::Threads::Get(Threads::UI) ->PostTask(base::Bind(this, &CUIMainWindowEx::UnZipComplete, res)); } void CUIMainWindowEx::CheckIFTureWillDownLoad() { if (b_user_quit_) { return; } if (global.m_filedownurl.empty()) { base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::CheckIFTureWillDownLoad), base::TimeDelta::FromMilliseconds(200)); } else { CombineRealInstallPath(); DownLoadingFileUrl(); } } void CUIMainWindowEx::DownLoadingAUserQuit() { CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current()); urldownloader_.fetcher_->Stop(); filedownloader_.fetcher_->Stop(); } void CUIMainWindowEx::CombineRealInstallPath() { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); global.m_strInstallPath = global.m_strInstallPath + L"\\" + Util::Base::s2ws(CGlobal::appDirName_); base::Threads::Get(Threads::FILE) ->PostTask(base::Bind(this, &CUIMainWindowEx::ForceCreateInstallPath, global.m_strInstallPath)); } void CUIMainWindowEx::ForceCreateInstallPath(std::wstring path) { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::FILE)); path += L"\\"; SystemCommon::FilePathHelper::ForceCreateDir(path.c_str()); } bool CUIMainWindowEx::CheckCanInstall() { const DWORD c_memsize = 200; const DWORD c_freeharddisk = 1000; const DWORD c_cpu_type = PROCESSOR_INTEL_486; SYSTEM_INFO si; GetSystemInfo(&si); DWORD cpu_type = si.dwProcessorType; DWORD cpu_core_num = si.dwNumberOfProcessors; MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); GlobalMemoryStatusEx(&statex); DWORD memsize = (DWORDLONG)statex.ullTotalPhys / (1000 * 1000); ULARGE_INTEGER uli_free_bytes_available; ULARGE_INTEGER uli_total_bytes; ULARGE_INTEGER uli_total_free_bytes; GetDiskFreeSpaceExW(global.m_packPath.c_str(), &uli_free_bytes_available, &uli_total_bytes, &uli_total_free_bytes); DWORD freedisksize = uli_total_free_bytes.QuadPart / (1024 * 1024); if (memsize >= c_memsize && cpu_type >= c_cpu_type && freedisksize >= c_freeharddisk && cpu_core_num >= 2) return true; else return false; } void CUIMainWindowEx::RetryDownLoadAgain() { if (b_user_quit_) { return; } global.m_packPath = SystemCommon::FilePathHelper::GetPath(global.m_packPath); global.m_packPath += L"AppPackZip"; global.m_packPath += Util::Base::longtocharw(time(NULL)); filedownloader_.fetcher_ = net::URLFetcher::Create( net::URLFetcher::Params(global.m_filedownurl, global.m_packPath), &filedownloader_); filedownloader_.fetcher_->Start(); } bool CUIMainWindowEx::GetPathEditError() { CBaseElementCtl* pEle = NULL; tstring strID; strID = _T("id_edit_installpath"); pEle = _elementManager.Search(strID); if (!pEle) return false; std::wstring title = pEle->GetTitle(); std::wregex p( L"^[a-zA-Z]:\\\\{1}(?:[^/:*?\"<>|])*[^./:*?\"<>|]{1}$|[a-zA-Z]:\\\\"); bool ism = std::regex_match(title, p); bool tipshow = false; if (ism) { if (!(-1 == title.find(L"\\\\") && -1 == title.find(L".\\") && -1 == title.find(L"\\."))) { tipshow = true; } } else { tipshow = true; } return tipshow; } void CUIMainWindowEx::DownLoadingFileUrl() { if (UNKNOW == downloadway_) { base::MessageLoop::current()->PostDelayedTask( base::Bind(this, &CUIMainWindowEx::DownLoadingFileUrl), base::TimeDelta::FromMilliseconds(200)); return; } time_download_ = timeGetTime(); if (downloadway_ == SINGLE) { filedownloader_.fetcher_->set_download_url(global.m_filedownurl); filedownloader_.fetcher_->set_file_loadpath(global.m_packPath); filedownloader_.fetcher_->Start(); } } void CUIMainWindowEx::UnZipComplete(BOOL res) { CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); time_install_ = timeGetTime() - time_install_; if (FALSE == res) { base::MessageLoop::current()->PostQuitTask( base::Bind(CUIMainWindowEx::DeletePack, global.m_packPath)); CUIUpDate obj; obj.infostyle_ = CUIUpDate::NOTICE; obj.CreateWnd(m_hWnd); obj.SetCustomTitle(std::wstring(L"File is occupied")); obj.DoModal(); PostMessage(WM_CLOSE, 0, 0); return; } CBaseElementCtl* pEle = NULL; tstring strID; strID = _T("id_progress_download"); PELEMENT; if (pEle) { ((CProgressCtl*)pEle)->SetPos((0.95)); SetProgressTaskBar(95, 100); } strID = _T("id_panel_download"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } strID = _T("id_panel_complete"); PELEMENT; if (pEle) { pEle->SetVisible(TRUE); } if (CGlobal::pTaskbar_) { CGlobal::pTaskbar_->SetProgressState(m_hWnd, TBPF_NOPROGRESS); } strID = _T("id_static_tryshutdown"); PELEMENT; if (pEle) { pEle->SetVisible(FALSE); } std::wstring app_path = global.m_strInstallPath + L"\\" + Util::Base::s2ws(global.appname_); strID = _T("id_checkbox_shortcut"); PELEMENT; if (pEle) { if (((CCheckBoxCtl*)pEle)->GetCheck()) { CreateShortCut(app_path.c_str(), DESK); } } strID = _T("id_checkbox_autorun"); PELEMENT; if (pEle) { if (((CCheckBoxCtl*)pEle)->GetCheck()) { const std::wstring appName = Util::Base::s2ws(global.appDirName_); std::wstring regKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; if (SystemCommon::OS::IsWow64()) { SystemCommon::OS::SetRegValue(HKEY_CURRENT_USER, regKey.c_str(), appName.c_str(), app_path); } else { SystemCommon::OS::SetRegValue(HKEY_CURRENT_USER, regKey.c_str(), appName.c_str(), app_path); } } } if (Util::Base::GetAccurateOSVersion() >= WINDOWS_7) { strID = _T("id_checkbox_easymenu"); PELEMENT; if (pEle) { if (((CCheckBoxCtl*)pEle)->GetCheck()) { CreateShortCut(app_path.c_str(), TASKBAR); } } } //start memu CreateShortCut(app_path.c_str(), STARTMENU); instep_ = INSTALLED; if (CGlobal::openurl_.length() > 0) { ShellExecuteA(NULL, "open", CGlobal::openurl_.c_str(), NULL, NULL, SW_SHOWNORMAL); } } bool CUIMainWindowEx::GetJsonTokenByDownLoadUrl( const std::string &res, std::map &map_token) { if (res.length() == 0 || res[0] == 0) return false; Json::Features features = Json::Features::strictMode(); Json::Reader reader(features); Json::Value root; bool parsingSuccessful = false; parsingSuccessful = reader.parse(res, root, true); if (parsingSuccessful && root.isObject()) { Json::Value::Members keys = root.getMemberNames(); Json::Value::Members::iterator it = keys.begin(); std::string strItem; for (; it != keys.end(); ++it) { Json::Value valDefault(""); std::string &strKey = *it; Json::Value item = root.get(strKey, valDefault); strItem = "downloadUrl"; if (strKey == strItem) { if (item.isString()) { map_token.insert(make_pair(strItem, item.asString())); } continue; } } return true; } return false; } ================================================ FILE: src/UI/UIMainWindowEx.h ================================================ #pragma once #include "util/def.h" #include "../DirectUI/DUITransWindowEx.h" #include "../DownLoader/DownloadDelegate.h" #include "../DownLoader/fetcherurl.h" #include "../DownLoader/fetchfile.h" #include "../Event/WaitableEvent.h" #include "../base/MessageLoop.h" #include "../base/MessagePumpWin.h" #include "../base/macros.h" #include "../base/notification_observer.h" #include "../base/notification_registrar.h" #include "FrameShowState.h" class CUIMainWindowEx : public CTransWindowEx, public base::RefCountedThreadSafe, public FetchURLDelegate, public FetchFileDelegate { public: enum InstallStep { BEFOREDOWN = 0, DOWNLOADING, INSTALLING, INSTALLED, }; enum ShortCutType { SHORTCUTBEGIN = 0, DESK, STARTMENU, TASKBAR, }; enum UserInstallType { DEFAULT = 0, SELECT, }; enum DownLoadWay { UNKNOW = 0, SINGLE, MULTI, }; enum DownLoadFail { NO_SPACE = 0, CONNECT_ERROR, }; BEGIN_MSG_MAP(CUIMainWindowEx) MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) CHAIN_MSG_MAP(CTransWindowEx) MESSAGE_HANDLER(WM_TASKBARBUTTONCREATED, OnTaskBarCreated) END_MSG_MAP() CUIMainWindowEx(); virtual ~CUIMainWindowEx(); LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) override; virtual LRESULT OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) override; LRESULT OnTaskBarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); HWND CreateWnd(HWND hParent, const WCHAR* wstr); void DestroyWnd(); void RestoreWindow(); virtual void OnLoad() override; virtual void OnLoaded() override; virtual void OnExit() override { _elementManager.Dispose(); DestroyWnd(); ::PostQuitMessage(0); } virtual void IsWindowShowed() override; virtual void StartShake() override; virtual void Shaked() override; virtual void DrawBorder(CDCHandle dc) override; virtual void FetchURLComplete(std::string res) override; virtual void FetchFileComplete(bool status, DownCompleteInfo &rest) override; virtual void FetchFileProgress(double cur) override; private: static void DeletePack(const std::wstring& str_path); void OnMin(); void OnClose(); void OnInstall(); void OnInstallSelected(); void OnAgreement(); void OnCheck(); void OpenInstallDir(); void OnSelected(); void OnBackMain(); void OnUseNow(); void OnInstallComplete(); void CreateShortCut(LPCTSTR strPath, const ShortCutType Stype = DESK); void SetProgressTaskBar(DWORD now, DWORD total); void Rotational(); void Ready2DownloadZip(); void ClearDownloads(const std::wstring str_path); void FileInit(); void QueryDownLoadUrl(); void DoInstall(); void InstallIng(); void CheckIFTureWillDownLoad(); void DownLoadingAUserQuit(); void CombineRealInstallPath(); void ForceCreateInstallPath(std::wstring path); bool CheckCanInstall(); void RetryDownLoadAgain(); bool GetPathEditError(); void DownLoadingFileUrl(); void UnZipComplete(BOOL res); bool GetJsonTokenByDownLoadUrl(const std::string &res, std::map &map_token); CFetchUrl urldownloader_; CFetchFile filedownloader_; InstallStep instep_; UserInstallType installtype_; DownLoadWay downloadway_; ShowState showstate_; DWORD time_download_; DWORD time_install_; bool b_user_quit_; bool window_showing_; bool is_pack_complete_; double f_down_process_; }; ================================================ FILE: src/UI/UtilityWindow.cpp ================================================ #include "StdAfx.h" #include "UtilityWindow.h" CUtilityWindow::CUtilityWindow() {} CUtilityWindow::~CUtilityWindow() {} CUtilityWindow& CUtilityWindow::GetInstance() { static CUtilityWindow* pThis = new CUtilityWindow(); return *pThis; } BOOL CUtilityWindow::Initialize() { CGDIResource::GetInstance().Initialize(_T("")); RECT rcPos = {0, 0, 1, 1}; HWND hwnd = NULL; hwnd = Create(HWND_MESSAGE, rcPos, CGlobal::szGlobalString_, WS_POPUP); if (!hwnd) return FALSE; SetWindowLongPtr(GWLP_USERDATA, CGlobal::UitlWndPrivacyCode_); return TRUE; } void CUtilityWindow::UnInitialize() { DestroyWindow(); pUIMainWindow_ = NULL; CGDIResource::GetInstance().Dispose(); CGDIResource::GetInstance().UnInitialize(); } LRESULT CUtilityWindow::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) { global.hUitlWnd_ = m_hWnd; pUIMainWindow_ = new CUIMainWindowEx(); if (NULL == pUIMainWindow_.get()) { return -1; } std::wstring strXMLSource; switch (global.lanId_) { case 0x804: { strXMLSource = L"UIMAINWINDOW"; } break; default: strXMLSource = L"ENGUIMAINWINDOW"; } if (!pUIMainWindow_->CreateWnd(NULL, strXMLSource.c_str())) { ATLTRACE(_T("Main window creation failed!\n")); return -1; } return 0; } LRESULT CUtilityWindow::OnDelGdi(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { HWND hwnd = (HWND)lParam; if (::IsWindow(hwnd)) { ::DestroyWindow(hwnd); } return 0; } LRESULT CUtilityWindow::OnRestore(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/) { pUIMainWindow_->RestoreWindow(); return 0; } ================================================ FILE: src/UI/UtilityWindow.h ================================================ #pragma once #include #include #include "util/def.h" #include "../Util/UtilApi.h" #include "../base/ref_counted.h" #include "../Global.h" #include "UIMainWindowEx.h" class CUtilityWindow : public CWindowImpl { public: DECLARE_WND_CLASS(CGlobal::szUtilityClassName_) CUtilityWindow(); virtual ~CUtilityWindow(); BEGIN_MSG_MAP(CUtilityWindow) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_DEL_GDI_OBJ, OnDelGdi) MESSAGE_HANDLER(WM_IS_EXIST, OnRestore) END_MSG_MAP() static CUtilityWindow &GetInstance(); BOOL Initialize(); void UnInitialize(); private: LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/); LRESULT OnDelGdi(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnRestore(UINT, WPARAM, LPARAM, BOOL &); scoped_refptr pUIMainWindow_; }; ================================================ FILE: src/Util/UtilApi.cpp ================================================ #include "stdafx.h" #include #include #include #include #include #include "util/base.h" #include "util/util_tools.h" #include "UtilApi.h" #pragma comment(lib, "winmm.lib") namespace Util { namespace Tools { int GetTextWidth(HWND hWnd, LPCTSTR lpszText, HFONT hFont) { CPaintDC dc(hWnd); HFONT hOldFont = dc.SelectFont(hFont); ::SetBkMode(dc.m_hDC, TRANSPARENT); CSize szText; ::GetTextExtentPoint32(dc.m_hDC, lpszText, lstrlen(lpszText), &szText); dc.SelectFont(hOldFont); return szText.cx; } int GetStringMd5(LPCTSTR lpSrc, TCHAR *lpDest, DWORD dwSize) { char *pBuf = new char[MAX_PATH]; memset(pBuf, 0, MAX_PATH * sizeof(char)); USES_CONVERSION; StringCchCopyA(pBuf, MAX_PATH, T2A(lpSrc)); MD5 md5((BYTE *)pBuf, strlen(pBuf)); string strMd5 = md5.toString(); StringCchCopyA(pBuf, MAX_PATH, strMd5.c_str()); StringCchCopy(lpDest, dwSize, A2T(pBuf)); delete[] pBuf; return strMd5.size(); } int GetStringMd5A(const char *lpSrc, char *lpDest, DWORD dwSize) { char *pBuf = new char[MAX_PATH]; memset(pBuf, 0, MAX_PATH * sizeof(char)); StringCchCopyA(pBuf, MAX_PATH, (lpSrc)); MD5 md5((BYTE *)pBuf, strlen(pBuf)); string strMd5 = md5.toString(); StringCchCopyA(pBuf, MAX_PATH, strMd5.c_str()); StringCchCopyA(lpDest, dwSize, (pBuf)); delete[] pBuf; return strMd5.size(); } BOOL IsWin7() { return Util::Base::GetAccurateOSVersion() >= WINDOWS_VISTA_NO_SP ? TRUE : FALSE; } } // namespace Tools } // namespace Util ================================================ FILE: src/Util/UtilApi.h ================================================ #pragma once namespace Util { namespace Tools { int GetTextWidth(HWND hWnd, LPCTSTR lpszText, HFONT hFont); int GetStringMd5(LPCTSTR lpSrc, TCHAR *lpDest, DWORD dwSize); int GetStringMd5A(const char *lpSrc, char *lpDest, DWORD dwSize); BOOL IsWin7(); } // namespace Tools } // namespace Util ================================================ FILE: src/base/FastDelegate.h ================================================ // FastDelegate.h // Efficient delegates in C++ that generate only two lines of asm code! // Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp // // - Don Clugston, Mar 2004. // Major contributions were made by Jody Hagins. // History: // 24-Apr-04 1.0 * Submitted to CodeProject. // 28-Apr-04 1.1 * Prevent most unsafe uses of evil static function hack. // * Improved syntax for horrible_cast (thanks Paul Bludov). // * Tested on Metrowerks MWCC and Intel ICL (IA32) // * Compiled, but not run, on Comeau C++ and Intel Itanium // ICL. // 27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5 // * Now works on /clr "managed C++" code on VC7, VC7.1 // * Comeau C++ now compiles without warnings. // * Prevent the virtual inheritance case from being used on // VC6 and earlier, which generate incorrect code. // * Improved warning and error messages. Non-standard hacks // now have compile-time checks to make them safer. // * implicit_cast used instead of static_cast in many cases. // * If calling a const member function, a const class pointer // can be used. // * MakeDelegate() global helper function added to simplify // pass-by-value. // * Added fastdelegate.clear() // 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in // templates) 30-Oct-04 1.3 * Support for (non-void) return values. // * No more workarounds in client code! // MSVC and Intel now use a clever hack invented by John // Dlugosz: // - The FASTDELEGATEDECLARE workaround is no longer // necessary. // - No more warning messages for VC6 // * Less use of macros. Error messages should be more // comprehensible. // * Added include guards // * Added FastDelegate::empty() to test if invocation is safe // (Thanks Neville Franks). // * Now tested on VS 2005 Express Beta, PGI C++ // 24-Dec-04 1.4 * Added DelegateMemento, to allow collections of disparate // delegates. // * <,>,<=,>= comparison operators to allow storage in ordered // containers. // * Substantial reduction of code size, especially the // 'Closure' class. // * Standardised all the compiler-specific workarounds. // * MFP conversion now works for CodePlay (but not yet supported // in the full code). // * Now compiles without warnings on _any_ supported compiler, // including BCC 5.5.1 // * New syntax: FastDelegate< int (char *, double) >. // 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent // to .empty(). (Thanks elfric). // * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64 // and Itanium. // 30-Mar-05 1.5 * Safebool idiom: "if (dg)" is now equivalent to "if // (!dg.empty())" // * Fully supported by CodePlay VectorC // * Bugfix for Metrowerks: empty() was buggy because a valid MFP // can be 0 on MWCC! // * More optimal assignment,== and != operators for static // function pointers. #pragma once #include // to allow <,> comparisons //////////////////////////////////////////////////////////////////////////////// // Configuration options // //////////////////////////////////////////////////////////////////////////////// // Uncomment the following #define for optimally-sized delegates. // In this case, the generated asm code is almost identical to the code you'd // get if the compiler had native support for delegates. It will not work on // systems where sizeof(dataptr) < sizeof(codeptr). Thus, it will not work for // DOS compilers using the medium model. It will also probably fail on some DSP // systems. #define FASTDELEGATE_USESTATICFUNCTIONHACK // Uncomment the next line to allow function declarator syntax. // It is automatically enabled for those compilers where it is known to work. // #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX //////////////////////////////////////////////////////////////////////////////// // Compiler identification for workarounds // //////////////////////////////////////////////////////////////////////////////// // Compiler identification. It's not easy to identify Visual C++ because // many vendors fraudulently define Microsoft's identifiers. #if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) && \ !defined(__ICL) && !defined(__BORLANDC__) #define FASTDLGT_ISMSVC #if (_MSC_VER < 1300) // Many workarounds are required for VC6. #define FASTDLGT_VC6 #pragma warning(disable : 4786) // disable this ridiculous warning #endif #endif // Does the compiler uses Microsoft's member function pointer structure? // If so, it needs special treatment. // Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's // identifier, _MSC_VER. We need to filter Metrowerks out. #if defined(_MSC_VER) && !defined(__MWERKS__) #define FASTDLGT_MICROSOFT_MFP #if !defined(__VECTOR_C) // CodePlay doesn't have the __single/multi/virtual_inheritance keywords #define FASTDLGT_HASINHERITANCE_KEYWORDS #endif #endif // Does it allow function declarator syntax? The following compilers are known // to work: #if defined(FASTDLGT_ISMSVC) && (_MSC_VER >= 1310) // VC 7.1 #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX #endif // Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use. #if defined(__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__) #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX #endif // It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on // earlier ones too. #if defined(__MWERKS__) #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX #endif #ifdef __GNUC__ // Workaround GCC bug #8271 // At present, GCC doesn't recognize constness of MFPs in templates #define FASTDELEGATE_GCC_BUG_8271 #endif //////////////////////////////////////////////////////////////////////////////// // General tricks used in this code // // (a) Error messages are generated by typdefing an array of negative size to // generate compile-time errors. // (b) Warning messages on MSVC are generated by declaring unused variables, and // enabling the "variable XXX is never used" warning. // (c) Unions are used in a few compiler-specific cases to perform illegal // casts. (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's // cast to // (char *) first to ensure that the correct number of *bytes* are added. // //////////////////////////////////////////////////////////////////////////////// // Helper templates // //////////////////////////////////////////////////////////////////////////////// namespace fastdelegate { namespace detail { // we'll hide the implementation details in a nested // namespace. // implicit_cast< > // I believe this was originally going to be in the C++ standard but // was left out by accident. It's even milder than static_cast. // I use it instead of static_cast<> to emphasize that I'm not doing // anything nasty. // Usage is identical to static_cast<> template inline OutputClass implicit_cast(InputClass input) { return input; } // horrible_cast< > // This is truly evil. It completely subverts C++'s type system, allowing you // to cast from any class to any other class. Technically, using a union // to perform the cast is undefined behaviour (even in C). But we can see if // it is OK by checking that the union is the same size as each of its members. // horrible_cast<> should only be used for compiler-specific workarounds. // Usage is identical to reinterpret_cast<>. // This union is declared outside the horrible_cast because BCC 5.5.1 // can't inline a function with a nested class, and gives a warning. template union horrible_union { OutputClass out; InputClass in; }; template inline OutputClass horrible_cast(const InputClass input) { horrible_union u; // Cause a compile-time error if in, out and u are not the same size. // If the compile fails here, it means the compiler has peculiar // unions which would prevent the cast from working. typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass) == sizeof(u) && sizeof(InputClass) == sizeof(OutputClass) ? 1 : -1]; u.in = input; return u.out; } //////////////////////////////////////////////////////////////////////////////// // Workarounds // //////////////////////////////////////////////////////////////////////////////// // Backwards compatibility: This macro used to be necessary in the virtual // inheritance case for Intel and Microsoft. Now it just forward-declares the // class. #define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME; // Prevent use of the static function hack with the DOS medium model. #ifdef __MEDIUM__ #undef FASTDELEGATE_USESTATICFUNCTIONHACK #endif // DefaultVoid - a workaround for 'void' templates in VC6. // // (1) VC6 and earlier do not allow 'void' as a default template argument. // (2) They also doesn't allow you to return 'void' from a function. // // Workaround for (1): Declare a dummy type 'DefaultVoid' which we use // when we'd like to use 'void'. We convert it into 'void' and back // using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>. // Workaround for (2): On VC6, the code for calling a void function is // identical to the code for calling a non-void function in which the // return value is never used, provided the return value is returned // in the EAX register, rather than on the stack. // This is true for most fundamental types such as int, enum, void *. // Const void * is the safest option since it doesn't participate // in any automatic conversions. But on a 16-bit compiler it might // cause extra code to be generated, so we disable it for all compilers // except for VC6 (and VC5). #ifdef FASTDLGT_VC6 // VC6 workaround typedef const void *DefaultVoid; #else // On any other compiler, just use a normal void. typedef void DefaultVoid; #endif // Translate from 'DefaultVoid' to 'void'. // Everything else is unchanged template struct DefaultVoidToVoid { typedef T type; }; template <> struct DefaultVoidToVoid { typedef void type; }; // Translate from 'void' into 'DefaultVoid' // Everything else is unchanged template struct VoidToDefaultVoid { typedef T type; }; template <> struct VoidToDefaultVoid { typedef DefaultVoid type; }; //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 1: // // Conversion of member function pointer to a standard form // //////////////////////////////////////////////////////////////////////////////// // GenericClass is a fake class, ONLY used to provide a type. // It is vitally important that it is never defined, so that the compiler // doesn't think it can optimize the invocation. For example, Borland generates // simpler code if it knows the class only uses single inheritance. // Compilers using Microsoft's structure need to be treated as a special case. #ifdef FASTDLGT_MICROSOFT_MFP #ifdef FASTDLGT_HASINHERITANCE_KEYWORDS // For Microsoft and Intel, we want to ensure that it's the most efficient type // of MFP (4 bytes), even when the /vmg option is used. Declaring an empty class // would give 16 byte pointers in this case.... class __single_inheritance GenericClass; #endif // ...but for Codeplay, an empty class *always* gives 4 byte pointers. // If compiled with the /clr option ("managed C++"), the JIT compiler thinks // it needs to load GenericClass before it can call any of its functions, // (compiles OK but crashes at runtime!), so we need to declare an // empty class to make it happy. // Codeplay and VC4 can't cope with the unknown_inheritance case either. class GenericClass {}; #else class GenericClass; #endif // The size of a single inheritance member function pointer. const int SINGLE_MEMFUNCPTR_SIZE = sizeof(void(GenericClass::*)()); // SimplifyMemFunc< >::Convert() // // A template function that converts an arbitrary member function pointer // into the simplest possible form of member function pointer, using a // supplied 'this' pointer. // According to the standard, this can be done legally with reinterpret_cast<>. // For (non-standard) compilers which use member function pointers which vary // in size // depending on the class, we need to use knowledge of the internal // structure of a member function pointer, as used by the compiler. Template // specialization is used to distinguish between the sizes. Because some // compilers don't support partial // template specialisation, I use full specialisation of a wrapper struct. // general case -- don't know how to convert it. Force a compile failure template struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { // Unsupported member function type -- force a compile failure. // (it's illegal to have a array with negative size). typedef char ERROR_Unsupported_member_function_pointer_on_this_compiler[N - 100]; return 0; } }; // For compilers where all member func ptrs are the same size, everything goes // here. For non-standard compilers, only single_inheritance classes go here. template <> struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { #if defined __DMC__ // Digital Mars doesn't allow you to cast between abitrary PMF's, // even though the standard says you can. The 32-bit compiler lets you // static_cast through an int, but the DOS compiler doesn't. bound_func = horrible_cast(function_to_bind); #else bound_func = reinterpret_cast(function_to_bind); #endif return reinterpret_cast(pthis); } }; //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 1b: // // Workarounds for Microsoft and Intel // //////////////////////////////////////////////////////////////////////////////// // Compilers with member function pointers which violate the standard (MSVC, // Intel, Codeplay), need to be treated as a special case. #ifdef FASTDLGT_MICROSOFT_MFP // We use unions to perform horrible_casts. I would like to use #pragma // pack(push, 1) at the start of each function for extra safety, but VC6 seems // to ICE intermittently if you do this inside a template. // __multiple_inheritance classes go here // Nasty hack for Microsoft and Intel (IA32 and Itanium) template <> struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { // We need to use a horrible_cast to do this conversion. // In MSVC, a multiple inheritance member pointer is internally defined as: union { XFuncType func; struct { GenericMemFuncType funcaddress; // points to the actual member function int delta; // #BYTES to be added to the 'this' pointer } s; } u; // Check that the horrible_cast will work typedef int ERROR_CantUsehorrible_cast [sizeof(function_to_bind) == sizeof(u.s) ? 1 : -1]; u.func = function_to_bind; bound_func = u.s.funcaddress; return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta); } }; // virtual inheritance is a real nuisance. It's inefficient and complicated. // On MSVC and Intel, there isn't enough information in the pointer itself to // enable conversion to a closure pointer. Earlier versions of this code didn't // work for all cases, and generated a compile-time error instead. // But a very clever hack invented by John M. Dlugosz solves this problem. // My code is somewhat different to his: I have no asm code, and I make no // assumptions about the calling convention that is used. // In VC++ and ICL, a virtual_inheritance member pointer // is internally defined as: struct MicrosoftVirtualMFP { void (GenericClass::*codeptr)(); // points to the actual member function int delta; // #bytes to be added to the 'this' pointer int vtable_index; // or 0 if no virtual inheritance }; // The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the // m_codeptr member is *always* called, regardless of the values of the other // members. (This is *not* true for other compilers, eg GCC, which obtain the // function address from the vtable if a virtual function is being called). // Dlugosz's trick is to make the codeptr point to a probe function which // returns the 'this' pointer that was used. // Define a generic class that uses virtual inheritance. // It has a trival member function that returns the value of the 'this' pointer. struct GenericVirtualClass : virtual public GenericClass { typedef GenericVirtualClass *(GenericVirtualClass::*ProbePtrType)(); GenericVirtualClass *GetThis() { return this; } }; // __virtual_inheritance classes go here template <> struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { union { XFuncType func; GenericClass *(X::*ProbeFunc)(); MicrosoftVirtualMFP s; } u; u.func = function_to_bind; bound_func = reinterpret_cast(u.s.codeptr); union { GenericVirtualClass::ProbePtrType virtfunc; MicrosoftVirtualMFP s; } u2; // Check that the horrible_cast<>s will work typedef int ERROR_CantUsehorrible_cast[sizeof(function_to_bind) == sizeof(u.s) && sizeof(function_to_bind) == sizeof(u.ProbeFunc) && sizeof(u2.virtfunc) == sizeof(u2.s) ? 1 : -1]; // Unfortunately, taking the address of a MF prevents it from being inlined, // so this next line can't be completely optimised away by the compiler. u2.virtfunc = &GenericVirtualClass::GetThis; u.s.codeptr = u2.s.codeptr; return (pthis->*u.ProbeFunc)(); } }; #if (_MSC_VER < 1300) // Nasty hack for Microsoft Visual C++ 6.0 // unknown_inheritance classes go here // There is a compiler bug in MSVC6 which generates incorrect code in this // case!! template <> struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { // There is an apalling but obscure compiler bug in MSVC6 and earlier: // vtable_index and 'vtordisp' are always set to 0 in the // unknown_inheritance case! // This means that an incorrect function could be called!!! // Compiling with the /vmg option leads to potentially incorrect code. // This is probably the reason that the IDE has a user interface for // specifying the /vmg option, but it is disabled - you can only specify // /vmg on the command line. In VC1.5 and earlier, the compiler would ICE if // it ever encountered this situation. It is OK to use the /vmg option if // /vmm or /vms is specified. // Fortunately, the wrong function is only called in very obscure cases. // It only occurs when a derived class overrides a virtual function declared // in a virtual base class, and the member function // points to the *Derived* version of that function. The problem can be // completely averted in 100% of cases by using the *Base class* for the // member fpointer. Ie, if you use the base class as an interface, you'll // stay out of trouble. // Occasionally, you might want to point directly to a derived class // function that isn't an override of a base class. In this case, both // vtable_index and 'vtordisp' are zero, but a virtual_inheritance pointer // will be generated. We can generate correct code in this case. To prevent // an incorrect call from ever being made, on MSVC6 we generate a warning, // and call a function to make the program crash instantly. typedef char ERROR_VC6CompilerBug[-100]; return 0; } }; #else // Nasty hack for Microsoft and Intel (IA32 and Itanium) // unknown_inheritance classes go here // This is probably the ugliest bit of code I've ever written. Look at the // casts! There is a compiler bug in MSVC6 which prevents it from using this // code. template <> struct SimplifyMemFunc { template inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind, GenericMemFuncType &bound_func) { // The member function pointer is 16 bytes long. We can't use a normal cast, // but we can use a union to do the conversion. union { XFuncType func; // In VC++ and ICL, an unknown_inheritance member pointer // is internally defined as: struct { GenericMemFuncType m_funcaddress; // points to the actual member function int delta; // #bytes to be added to the 'this' pointer int vtordisp; // #bytes to add to 'this' to find the vtable int vtable_index; // or 0 if no virtual inheritance } s; } u; // Check that the horrible_cast will work typedef int ERROR_CantUsehorrible_cast[sizeof(XFuncType) == sizeof(u.s) ? 1 : -1]; u.func = function_to_bind; bound_func = u.s.funcaddress; int virtual_delta = 0; if (u.s.vtable_index) { // Virtual inheritance is used // First, get to the vtable. // It is 'vtordisp' bytes from the start of the class. const int *vtable = *reinterpret_cast( reinterpret_cast(pthis) + u.s.vtordisp); // 'vtable_index' tells us where in the table we should be looking. virtual_delta = u.s.vtordisp + *reinterpret_cast( reinterpret_cast(vtable) + u.s.vtable_index); } // The int at 'virtual_delta' gives us the amount to add to 'this'. // Finally we can add the three components together. Phew! return reinterpret_cast(reinterpret_cast(pthis) + u.s.delta + virtual_delta); }; }; #endif // MSVC 7 and greater #endif // MS/Intel hacks } // namespace detail //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 2: // // Define the delegate storage, and cope with static functions // //////////////////////////////////////////////////////////////////////////////// // DelegateMemento -- an opaque structure which can hold an arbitary delegate. // It knows nothing about the calling convention or number of arguments used by // the function pointed to. // It supplies comparison operators so that it can be stored in STL collections. // It cannot be set to anything other than null, nor invoked directly: // it must be converted to a specific delegate. // Implementation: // There are two possible implementations: the Safe method and the Evil method. // DelegateMemento - Safe version // // This implementation is standard-compliant, but a bit tricky. // A static function pointer is stored inside the class. // Here are the valid values: // +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+ // | 0 | 0 | 0 | Empty | // | !=0 |(dontcare)| Invoker | Static function| // | 0 | !=0 | !=0* | Method call | // +--------------------+----------+------------+----------------+ // * For Metrowerks, this can be 0. (first virtual function in a // single_inheritance class). // When stored stored inside a specific delegate, the 'dontcare' entries are // replaced with a reference to the delegate itself. This complicates the = and // == operators for the delegate class. // DelegateMemento - Evil version // // For compilers where data pointers are at least as big as code pointers, it is // possible to store the function pointer in the this pointer, using another // horrible_cast. In this case the DelegateMemento implementation is simple: // +--pThis --+-- pMemFunc-+-- Meaning---------------------+ // | 0 | 0 | Empty | // | !=0 | !=0* | Static function or method call| // +----------+------------+-------------------------------+ // * For Metrowerks, this can be 0. (first virtual function in a // single_inheritance class). // Note that the Sun C++ and MSVC documentation explicitly state that they // support static_cast between void * and function pointers. class DelegateMemento { protected: // the data is protected, not private, because many // compilers have problems with template friends. typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP. detail::GenericClass *m_pthis; GenericMemFuncType m_pFunction; #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) typedef void (*GenericFuncPtr)(); // arbitrary code pointer GenericFuncPtr m_pStaticFunction; #endif public: #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0){}; void clear() { m_pthis = 0; m_pFunction = 0; m_pStaticFunction = 0; } #else DelegateMemento() : m_pthis(0), m_pFunction(0){}; void clear() { m_pthis = 0; m_pFunction = 0; } #endif public: #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) inline bool IsEqual(const DelegateMemento &x) const { // We have to cope with the static function pointers as a special case if (m_pFunction != x.m_pFunction) return false; // the static function ptrs must either both be equal, or both be 0. if (m_pStaticFunction != x.m_pStaticFunction) return false; if (m_pStaticFunction != 0) return m_pthis == x.m_pthis; else return true; } #else // Evil Method inline bool IsEqual(const DelegateMemento &x) const { return m_pthis == x.m_pthis && m_pFunction == x.m_pFunction; } #endif // Provide a strict weak ordering for DelegateMementos. inline bool IsLess(const DelegateMemento &right) const { // deal with static function pointers first #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) if (m_pStaticFunction != 0 || right.m_pStaticFunction != 0) return m_pStaticFunction < right.m_pStaticFunction; #endif if (m_pthis != right.m_pthis) return m_pthis < right.m_pthis; // There are no ordering operators for member function pointers, // but we can fake one by comparing each byte. The resulting ordering is // arbitrary (and compiler-dependent), but it permits storage in ordered STL // containers. return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0; } // BUGFIX (Mar 2005): // We can't just compare m_pFunction because on Metrowerks, // m_pFunction can be zero even if the delegate is not empty! inline bool operator!() const // Is it bound to anything? { return m_pthis == 0 && m_pFunction == 0; } inline bool empty() const // Is it bound to anything? { return m_pthis == 0 && m_pFunction == 0; } public: DelegateMemento &operator=(const DelegateMemento &right) { SetMementoFrom(right); return *this; } inline bool operator<(const DelegateMemento &right) { return IsLess(right); } inline bool operator>(const DelegateMemento &right) { return right.IsLess(*this); } DelegateMemento(const DelegateMemento &right) : m_pFunction(right.m_pFunction), m_pthis(right.m_pthis) #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) , m_pStaticFunction(right.m_pStaticFunction) #endif { } protected: void SetMementoFrom(const DelegateMemento &right) { m_pFunction = right.m_pFunction; m_pthis = right.m_pthis; #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) m_pStaticFunction = right.m_pStaticFunction; #endif } }; // ClosurePtr<> // // A private wrapper class that adds function signatures to DelegateMemento. // It's the class that does most of the actual work. // The signatures are specified by: // GenericMemFunc: must be a type of GenericClass member function pointer. // StaticFuncPtr: must be a type of function pointer with the same signature // as GenericMemFunc. // UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6 // where it never returns void (returns DefaultVoid instead). // An outer class, FastDelegateN<>, handles the invoking and creates the // necessary typedefs. // This class does everything else. namespace detail { template class ClosurePtr : public DelegateMemento { public: // These functions are for setting the delegate to a member function. // Here's the clever bit: we convert an arbitrary member function into a // standard form. XMemFunc should be a member function of class X, but I can't // enforce that here. It needs to be enforced by the wrapper class. template inline void bindmemfunc(X *pthis, XMemFunc function_to_bind) { m_pthis = SimplifyMemFunc::Convert( pthis, function_to_bind, m_pFunction); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) m_pStaticFunction = 0; #endif } // For const member functions, we only need a const class pointer. // Since we know that the member function is const, it's safe to // remove the const qualifier from the 'this' pointer with a const_cast. // VC6 has problems if we just overload 'bindmemfunc', so we give it a // different name. template inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) { m_pthis = SimplifyMemFunc::Convert( const_cast(pthis), function_to_bind, m_pFunction); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) m_pStaticFunction = 0; #endif } #ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness // of MFPs in templates template inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) { bindconstmemfunc(pthis, function_to_bind); #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) m_pStaticFunction = 0; #endif } #endif // These functions are required for invoking the stored function inline GenericClass *GetClosureThis() const { return m_pthis; } inline GenericMemFunc GetClosureMemPtr() const { return reinterpret_cast(m_pFunction); } // There are a few ways of dealing with static function pointers. // There's a standard-compliant, but tricky method. // There's also a straightforward hack, that won't work on DOS compilers using // the medium memory model. It's so evil that I can't recommend it, but I've // implemented it anyway because it produces very nice asm code. #if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) // ClosurePtr<> - Safe version // // This implementation is standard-compliant, but a bit tricky. // I store the function pointer inside the class, and the delegate then // points to itself. Whenever the delegate is copied, these self-references // must be transformed, and this complicates the = and == operators. public: // The next two functions are for operator ==, =, and the copy constructor. // We may need to convert the m_pthis pointers, so that // they remain as self-references. template inline void CopyFrom(DerivedClass *pParent, const DelegateMemento &x) { SetMementoFrom(x); if (m_pStaticFunction != 0) { // transform self references... m_pthis = reinterpret_cast(pParent); } } // For static functions, the 'static_function_invoker' class in the parent // will be called. The parent then needs to call GetStaticFunction() to find // out the actual function to invoke. template inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, StaticFuncPtr function_to_bind) { if (function_to_bind == 0) { // cope with assignment to 0 m_pFunction = 0; } else { bindmemfunc(pParent, static_function_invoker); } m_pStaticFunction = reinterpret_cast(function_to_bind); } inline UnvoidStaticFuncPtr GetStaticFunction() const { return reinterpret_cast(m_pStaticFunction); } #else // ClosurePtr<> - Evil version // // For compilers where data pointers are at least as big as code pointers, it // is possible to store the function pointer in the this pointer, using // another horrible_cast. Invocation isn't any faster, but it saves 4 bytes, // and speeds up comparison and assignment. If C++ provided direct language // support for delegates, they would produce asm code that was almost // identical to this. Note that the Sun C++ and MSVC documentation explicitly // state that they support static_cast between void * and function pointers. template inline void CopyFrom(DerivedClass *pParent, const DelegateMemento &right) { SetMementoFrom(right); } // For static functions, the 'static_function_invoker' class in the parent // will be called. The parent then needs to call GetStaticFunction() to find // out the actual function to invoke. // ******** EVIL, EVIL CODE! ******* template inline void bindstaticfunc(DerivedClass *pParent, ParentInvokerSig static_function_invoker, StaticFuncPtr function_to_bind) { if (function_to_bind == 0) { // cope with assignment to 0 m_pFunction = 0; } else { // We'll be ignoring the 'this' pointer, but we need to make sure we pass // a valid value to bindmemfunc(). bindmemfunc(pParent, static_function_invoker); } // WARNING! Evil hack. We store the function in the 'this' pointer! // Ensure that there's a compilation failure if function pointers // and data pointers have different sizes. // If you get this error, you need to #undef // FASTDELEGATE_USESTATICFUNCTIONHACK. typedef int ERROR_CantUseEvilMethod [sizeof(GenericClass *) == sizeof(function_to_bind) ? 1 : -1]; m_pthis = horrible_cast(function_to_bind); // MSVC, SunC++ and DMC accept the following (non-standard) code: // m_pthis = static_cast(static_cast(function_to_bind)); // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead // of long // m_pthis = reinterpret_cast(reinterpret_cast(function_to_bind)); } // ******** EVIL, EVIL CODE! ******* // This function will be called with an invalid 'this' pointer!! // We're just returning the 'this' pointer, converted into // a function pointer! inline UnvoidStaticFuncPtr GetStaticFunction() const { // Ensure that there's a compilation failure if function pointers // and data pointers have different sizes. // If you get this error, you need to #undef // FASTDELEGATE_USESTATICFUNCTIONHACK. typedef int ERROR_CantUseEvilMethod [sizeof(UnvoidStaticFuncPtr) == sizeof(this) ? 1 : -1]; return horrible_cast(this); } #endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK) // Does the closure contain this static function? inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr) { if (funcptr == 0) return empty(); // For the Evil method, if it doesn't actually contain a static function, // this will return an arbitrary value that is not equal to any valid // function pointer. else return funcptr == reinterpret_cast(GetStaticFunction()); } }; } // namespace detail //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 3: // // Wrapper classes to ensure type safety // //////////////////////////////////////////////////////////////////////////////// // Once we have the member function conversion templates, it's easy to make the // wrapper classes. So that they will work with as many compilers as possible, // the classes are of the form // FastDelegate3 // They can cope with any combination of parameters. The max number of // parameters allowed is 8, but it is trivial to increase this limit. Note that // we need to treat const member functions seperately. All this class does is to // enforce type safety, and invoke the delegate with the correct list of // parameters. // Because of the weird rule about the class of derived member function // pointers, you sometimes need to apply a downcast to the 'this' pointer. This // is the reason for the use of "implicit_cast(pthis)" in the code below. If // CDerivedClass is derived from CBaseClass, but doesn't override // SimpleVirtualFunction, without this trick you'd need to write: // MyDelegate(static_cast(&d), // &CDerivedClass::SimpleVirtualFunction); // but with the trick you can write // MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction); // RetType is the type the compiler uses in compiling the template. For VC6, // it cannot be void. DesiredRetType is the real type which is returned from // all of the functions. It can be void. // Implicit conversion to "bool" is achieved using the safe_bool idiom, // using member data pointers (MDP). This allows "if (dg)..." syntax // Because some compilers (eg codeplay) don't have a unique value for a zero // MDP, an extra padding member is added to the SafeBool struct. // Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so // in that case the static function constructor is not made explicit; this // allows "if (dg==0) ..." to compile. // default template class Function { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(); typedef RetType (*UnvoidStaticFunctionPtr)(); typedef RetType (detail::GenericClass::*GenericMemFn)(); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef Function type; // Construction and comparison functions Function() { clear(); } Function(const Function &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const Function &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const Function &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const Function &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const Function &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const Function &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template Function(Y *pthis, DesiredRetType (X::*function_to_bind)()) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)()) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template Function(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion Function(DesiredRetType (*function_to_bind)()) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)()) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)()) { m_Closure.bindstaticfunc(this, &Function::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()() const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction() const { // bugfix remove p1 return (*(m_Closure.GetStaticFunction()))(); } }; // N=0 template class FastDelegate0 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(); typedef RetType (*UnvoidStaticFunctionPtr)(); typedef RetType (detail::GenericClass::*GenericMemFn)(); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate0 type; // Construction and comparison functions FastDelegate0() { clear(); } FastDelegate0(const FastDelegate0 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate0 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate0 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate0 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate0 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate0 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate0(Y *pthis, DesiredRetType (X::*function_to_bind)()) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)()) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate0(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate0(DesiredRetType (*function_to_bind)()) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)()) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)()) { m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()() const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction() const { return (*(m_Closure.GetStaticFunction()))(); } }; // N=1 template class FastDelegate1 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate1 type; // Construction and comparison functions FastDelegate1() { clear(); } FastDelegate1(const FastDelegate1 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate1 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate1 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate1 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate1 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate1 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate1(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate1(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1)) { m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1) const { return (*(m_Closure.GetStaticFunction()))(p1); } }; // N=2 template class FastDelegate2 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate2 type; // Construction and comparison functions FastDelegate2() { clear(); } FastDelegate2(const FastDelegate2 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate2 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate2 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate2 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate2 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate2 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate2(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate2(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) { m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2) const { return (*(m_Closure.GetStaticFunction()))(p1, p2); } }; // N=3 template class FastDelegate3 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate3 type; // Construction and comparison functions FastDelegate3() { clear(); } FastDelegate3(const FastDelegate3 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate3 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate3 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate3 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate3 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate3 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate3(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate3(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) { m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2, p3); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3); } }; // N=4 template class FastDelegate4 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate4 type; // Construction and comparison functions FastDelegate4() { clear(); } FastDelegate4(const FastDelegate4 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate4 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate4 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate4 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate4 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate4 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate4(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate4(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))( p1, p2, p3, p4); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4); } }; // N=5 template class FastDelegate5 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate5 type; // Construction and comparison functions FastDelegate5() { clear(); } FastDelegate5(const FastDelegate5 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate5 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate5 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate5 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate5 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate5 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate5(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate5(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))( p1, p2, p3, p4, p5); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5); } }; // N=6 template class FastDelegate6 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate6 type; // Construction and comparison functions FastDelegate6() { clear(); } FastDelegate6(const FastDelegate6 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate6 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate6 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate6 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate6 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate6 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate6(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate6(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))( p1, p2, p3, p4, p5, p6); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6); } }; // N=7 template class FastDelegate7 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate7 type; // Construction and comparison functions FastDelegate7() { clear(); } FastDelegate7(const FastDelegate7 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate7 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate7 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate7 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate7 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate7 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate7(Y *pthis, DesiredRetType (X::*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate7(const Y *pthis, DesiredRetType (X::*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))( p1, p2, p3, p4, p5, p6, p7); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7); } }; // N=8 template class FastDelegate8 { private: typedef typename detail::DefaultVoidToVoid::type DesiredRetType; typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8); typedef detail::ClosurePtr ClosureType; ClosureType m_Closure; public: // Typedefs to aid generic programming typedef FastDelegate8 type; // Construction and comparison functions FastDelegate8() { clear(); } FastDelegate8(const FastDelegate8 &x) { m_Closure.CopyFrom(this, x.m_Closure); } void operator=(const FastDelegate8 &x) { m_Closure.CopyFrom(this, x.m_Closure); } bool operator==(const FastDelegate8 &x) const { return m_Closure.IsEqual(x.m_Closure); } bool operator!=(const FastDelegate8 &x) const { return !m_Closure.IsEqual(x.m_Closure); } bool operator<(const FastDelegate8 &x) const { return m_Closure.IsLess(x.m_Closure); } bool operator>(const FastDelegate8 &x) const { return x.m_Closure.IsLess(m_Closure); } // Binding to non-const member functions template FastDelegate8(Y *pthis, DesiredRetType (X::*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)( Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { m_Closure.bindmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Binding to const member functions. template FastDelegate8(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } template inline void bind(const Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { m_Closure.bindconstmemfunc(detail::implicit_cast(pthis), function_to_bind); } // Static functions. We convert them into a member function call. // This constructor also provides implicit conversion FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { bind(function_to_bind); } // for efficiency, prevent creation of a temporary void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { bind(function_to_bind); } inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction, function_to_bind); } // Invoke the delegate RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const { return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))( p1, p2, p3, p4, p5, p6, p7, p8); } // Implicit conversion to "bool" using the safe_bool idiom private: typedef struct SafeBoolStruct { int a_data_pointer_to_this_is_0_on_buggy_compilers; StaticFunctionPtr m_nonzero; } UselessTypedef; typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type; public: operator unspecified_bool_type() const { return empty() ? 0 : &SafeBoolStruct::m_nonzero; } // necessary to allow ==0 to work despite the safe_bool idiom inline bool operator==(StaticFunctionPtr funcptr) { return m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!=(StaticFunctionPtr funcptr) { return !m_Closure.IsEqualToStaticFuncPtr(funcptr); } inline bool operator!() const { // Is it bound to anything? return !m_Closure; } inline bool empty() const { return !m_Closure; } void clear() { m_Closure.clear(); } // Conversion to and from the DelegateMemento storage class const DelegateMemento &GetMemento() { return m_Closure; } void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); } private: // Invoker for static functions RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const { return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8); } }; //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 4: // // FastDelegate<> class (Original author: Jody Hagins) // Allows boost::function style syntax like: // FastDelegate< double (int, long) > // instead of: // FastDelegate2< int, long, double > // //////////////////////////////////////////////////////////////////////////////// #ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX // Declare FastDelegate as a class template. It will be specialized // later for all number of arguments. template class FastDelegate; // N=0 // Specialization to allow use of // FastDelegate< R ( ) > // instead of // FastDelegate0 < R > template class FastDelegate // Inherit from FastDelegate0 so that it can be treated just like a // FastDelegate0 : public FastDelegate0 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate0 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)()) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)() const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)()) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=1 // Specialization to allow use of // FastDelegate< R ( Param1 ) > // instead of // FastDelegate1 < Param1, R > template class FastDelegate // Inherit from FastDelegate1 so that it can be treated just like a // FastDelegate1 : public FastDelegate1 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate1 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=2 // Specialization to allow use of // FastDelegate< R ( Param1, Param2 ) > // instead of // FastDelegate2 < Param1, Param2, R > template class FastDelegate // Inherit from FastDelegate2 so that it can be treated just like a // FastDelegate2 : public FastDelegate2 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate2 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=3 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3 ) > // instead of // FastDelegate3 < Param1, Param2, Param3, R > template class FastDelegate // Inherit from FastDelegate3 so that it can be treated just like a // FastDelegate3 : public FastDelegate3 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate3 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=4 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3, Param4 ) > // instead of // FastDelegate4 < Param1, Param2, Param3, Param4, R > template class FastDelegate // Inherit from FastDelegate4 so that it can be treated just like a // FastDelegate4 : public FastDelegate4 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate4 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=5 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) > // instead of // FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R > template class FastDelegate // Inherit from FastDelegate5 so that it can be treated just like a // FastDelegate5 : public FastDelegate5 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate5 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=6 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) > // instead of // FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R > template class FastDelegate // Inherit from FastDelegate6 so that it can be treated just like a // FastDelegate6 : public FastDelegate6 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate6 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=7 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) > // instead of // FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R > template class FastDelegate // Inherit from FastDelegate7 so that it can be treated just like a // FastDelegate7 : public FastDelegate7 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate7 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; // N=8 // Specialization to allow use of // FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7, // Param8 ) > instead of FastDelegate8 < Param1, Param2, Param3, Param4, // Param5, Param6, Param7, Param8, R > template class FastDelegate // Inherit from FastDelegate8 so that it can be treated just like a // FastDelegate8 : public FastDelegate8 { public: // Make using the base type a bit easier via typedef. typedef FastDelegate8 BaseType; // Allow users access to the specific type of this delegate. typedef FastDelegate SelfType; // Mimic the base class constructors. FastDelegate() : BaseType() {} template FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) : BaseType(pthis, function_to_bind) {} template FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) : BaseType(pthis, function_to_bind) {} FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) : BaseType(function_to_bind) {} void operator=(const BaseType &x) { *static_cast(this) = x; } }; #endif // FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX //////////////////////////////////////////////////////////////////////////////// // Fast Delegates, part 5: // // MakeDelegate() helper function // // MakeDelegate(&x, &X::func) returns a fastdelegate of the type // necessary for calling x.func() with the correct number of // arguments. This makes it possible to eliminate many typedefs from // user code. // //////////////////////////////////////////////////////////////////////////////// // Also declare overloads of a MakeDelegate() global function to // reduce the need for typedefs. // We need seperate overloads for const and non-const member functions. // Also, because of the weird rule about the class of derived member function // pointers, implicit downcasts may need to be applied later to the 'this' // pointer. That's why two classes (X and Y) appear in the definitions. Y must // be implicitly castable to X. // Workaround for VC6. VC6 needs void return types converted into DefaultVoid. // GCC 3.2 and later won't compile this unless it's preceded by 'typename', // but VC6 doesn't allow 'typename' in this context. // So, I have to use a macro. #ifdef FASTDLGT_VC6 #define FASTDLGT_RETTYPE detail::VoidToDefaultVoid::type #else #define FASTDLGT_RETTYPE RetType #endif // N=0 template FastDelegate0 MakeDelegate(Y *x, RetType (X::*func)()) { return FastDelegate0(x, func); } template FastDelegate0 MakeDelegate(Y *x, RetType (X::*func)() const) { return FastDelegate0(x, func); } // N=1 template FastDelegate1 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1)) { return FastDelegate1(x, func); } template FastDelegate1 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1) const) { return FastDelegate1(x, func); } // N=2 template FastDelegate2 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2)) { return FastDelegate2(x, func); } template FastDelegate2 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2) const) { return FastDelegate2(x, func); } // N=3 template FastDelegate3 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) { return FastDelegate3(x, func); } template FastDelegate3 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) { return FastDelegate3(x, func); } // N=4 template FastDelegate4 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) { return FastDelegate4(x, func); } template FastDelegate4 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const) { return FastDelegate4(x, func); } // N=5 template FastDelegate5 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5)) { return FastDelegate5(x, func); } template FastDelegate5 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5) const) { return FastDelegate5(x, func); } // N=6 template FastDelegate6 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6)) { return FastDelegate6(x, func); } template FastDelegate6 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6) const) { return FastDelegate6(x, func); } // N=7 template FastDelegate7 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7)) { return FastDelegate7(x, func); } template FastDelegate7 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7) const) { return FastDelegate7(x, func); } // N=8 template FastDelegate8 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8)) { return FastDelegate8(x, func); } template FastDelegate8 MakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5, Param6 p6, Param7 p7, Param8 p8) const) { return FastDelegate8(x, func); } // clean up after ourselves... #undef FASTDLGT_RETTYPE } // namespace fastdelegate ================================================ FILE: src/base/FastDelegateImpl.h ================================================ #pragma once #include #include "FastDelegate.h" #include "WeakPtr.h" using namespace base; namespace fastdelegate { #ifdef FASTDLGT_VC6 #define FASTDLGT_RETTYPE detail::VoidToDefaultVoid::type #else #define FASTDLGT_RETTYPE RetType #endif class __declspec(novtable) CCounter { public: virtual ~CCounter() {}; virtual unsigned AddRef() = 0; virtual unsigned ReleaseRef() = 0; static const int IniCounter = 1; }; template class __declspec(novtable) ExecDelegate : public CCounter { public: virtual RetType Run() = 0; virtual ~ExecDelegate() {} }; template class FunctionEntity0 : public ExecDelegate { public: FunctionEntity0(FASTDLGT_RETTYPE (*func_no_para)()) : _Ref(CCounter::IniCounter), m_func_no_para(func_no_para) {} virtual FASTDLGT_RETTYPE Run() { if (m_func_no_para) { return m_func_no_para(); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { delete this; return 0; } return _Ref; } protected: FASTDLGT_RETTYPE (*m_func_no_para)(); unsigned _Ref; }; template class FunctionEntity1 : public ExecDelegate { public: FunctionEntity1(FASTDLGT_RETTYPE (*func_1_para)(Param1), const P1 &p1) : _Ref(CCounter::IniCounter), m_func_1_para(func_1_para), _p1(p1) {} virtual FASTDLGT_RETTYPE Run() { if (m_func_1_para) { return m_func_1_para(_p1); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { delete this; return 0; } return _Ref; } protected: FASTDLGT_RETTYPE (*m_func_1_para)(Param1); P1 _p1; unsigned _Ref; }; template class FunctionEntity2 : public ExecDelegate { public: FunctionEntity2(FASTDLGT_RETTYPE (*func_2_para)(Param1, Param2), const P1 &p1, const P2 &p2) : _Ref(CCounter::IniCounter), m_func_2_para(func_2_para), _p1(p1), _p2(p2) {} virtual FASTDLGT_RETTYPE Run() { if (m_func_2_para) { return m_func_2_para(_p1, _p2); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { delete this; return 0; } return _Ref; } protected: FASTDLGT_RETTYPE (*m_func_2_para)(Param1, Param2); P1 _p1; P2 _p2; unsigned _Ref; }; template class FunctionEntity3 : public ExecDelegate { public: FunctionEntity3(FASTDLGT_RETTYPE (*func_3_para)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) : _Ref(CCounter::IniCounter), m_func_3_para(func_3_para), _p1(p1), _p2(p2), _p3(p3) {} virtual FASTDLGT_RETTYPE Run() { if (m_func_3_para) { return m_func_3_para(_p1, _p2, _p3); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { delete this; return 0; } return _Ref; } protected: FASTDLGT_RETTYPE (*m_func_3_para)(Param1, Param2, Param3); P1 _p1; P2 _p2; P3 _p3; unsigned _Ref; }; template class FunctionEntity4 : public ExecDelegate { public: FunctionEntity4(FASTDLGT_RETTYPE (*func_4_para)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) : _Ref(CCounter::IniCounter), m_func_4_para(func_4_para), _p1(p1), _p2(p2), _p3(p3), _p4(p4) {} virtual FASTDLGT_RETTYPE Run() { if (m_func_4_para) { return m_func_4_para(_p1, _p2, _p3, _p4); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { delete this; return 0; } return _Ref; } protected: FASTDLGT_RETTYPE (*m_func_4_para)(Param1, Param2, Param3, Param4); P1 _p1; P2 _p2; P3 _p3; P4 _p4; unsigned _Ref; }; template FunctionEntity0 * MakeFunctionEntity(FASTDLGT_RETTYPE (*func)()) { return (new FunctionEntity0(func)); } template inline FunctionEntity1 * MakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1), const P1 &p1) { return (new FunctionEntity1(func, p1)); } template inline FunctionEntity2 * MakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2), const P1 &p1, const P2 &p2) { return (new FunctionEntity2( func, p1, p2)); } template inline FunctionEntity3 * MakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { return ( new FunctionEntity3( func, p1, p2, p3)); } template inline FunctionEntity4 * MakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { return (FunctionEntity4(func, p1, p2, p3, p4)); } template class DelegateEntity0 : public ExecDelegate { public: DelegateEntity0(Y *that, const FastDelegate0 &func_no_para) : m_func_no_para(func_no_para), _Ref(CCounter::IniCounter) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_no_para) { return m_func_no_para(); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate0 m_func_no_para; unsigned _Ref; }; template class DelegateEntity1 : public ExecDelegate { public: DelegateEntity1(Y *that, const FastDelegate1 &func_1_para, const P1 &p1) : m_func_1_para(func_1_para), _Ref(CCounter::IniCounter), _p1(p1) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_1_para) { return m_func_1_para(_p1); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate1 m_func_1_para; unsigned _Ref; P1 _p1; }; template class DelegateEntity2 : public ExecDelegate { public: DelegateEntity2( Y *that, const FastDelegate2 &func_2_para, const P1 &p1, const P2 &p2) : m_func_2_para(func_2_para), _Ref(CCounter::IniCounter), _p1(p1), _p2(p2) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_2_para) { return m_func_2_para(_p1, _p2); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate2 m_func_2_para; unsigned _Ref; P1 _p1; P2 _p2; }; template class DelegateEntity3 : public ExecDelegate { public: DelegateEntity3(Y *that, const FastDelegate3 &func_3_para, const P1 &p1, const P2 &p2, const P3 &p3) : m_func_3_para(func_3_para), _Ref(CCounter::IniCounter), _p1(p1), _p2(p2), _p3(p3) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_3_para) { return m_func_3_para(_p1, _p2, _p3); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate3 m_func_3_para; unsigned _Ref; P1 _p1; P2 _p2; P3 _p3; }; template class DelegateEntity4 : public ExecDelegate { public: DelegateEntity4(Y *that, const FastDelegate4 &func_4_para, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) : m_func_4_para(func_4_para), _Ref(CCounter::IniCounter), _p1(p1), _p2(p2), _p3(p3), _p4(p4) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_4_para) { return m_func_4_para(_p1, _p2, _p3, _p4); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate4 m_func_4_para; unsigned _Ref; P1 _p1; P2 _p2; P3 _p3; P4 _p4; }; template class DelegateEntity5 : public ExecDelegate { public: DelegateEntity5(Y *that, const FastDelegate5 &func_5_para, const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) : m_func_5_para(func_5_para), _Ref(CCounter::IniCounter), _p1(p1), _p2(p2), _p3(p3), _p4(p4), _p5(p5) { _that.reset(that); if (_that.get()) { _that->AddRef(); } } virtual FASTDLGT_RETTYPE Run() { if (_that->IsWeakPtr()) { if (NULL == _that->get()) return FASTDLGT_RETTYPE(); } if (m_func_5_para) { return m_func_5_para(_p1, _p2, _p3, _p4, _p5); } return FASTDLGT_RETTYPE(); } virtual unsigned AddRef() { return ++_Ref; } virtual unsigned ReleaseRef() { --_Ref; assert(_Ref >= 0); if (0 == _Ref) { if (_that.get()) _that->Release(); delete this; return 0; } return _Ref; } protected: std::auto_ptr _that; FastDelegate5 m_func_5_para; unsigned _Ref; P1 _p1; P2 _p2; P3 _p3; P4 _p4; P5 _p5; }; template inline DelegateEntity0, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)()) { return (new DelegateEntity0, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate0((x), func))); } template inline DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)(Param1), const P1 &p1) { return ( new DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate1((x), func), p1)); } template inline DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2), const P1 &p1, const P2 &p2) { return (new DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate2((x), func), p1, p2)); } template inline DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { return (new DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate3((x), func), p1, p2, p3)); } template inline DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { return (new DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate4((x), func), p1, p2, p3, p4)); } template inline DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> * MakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2, Param3, Param4, Param5), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) { return ( new DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>( new NormalWrapper(x), FastDelegate5((x), func), p1, p2, p3, p4, p5)); } template inline DelegateEntity0, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)()) { return (new DelegateEntity0, FASTDLGT_RETTYPE>( x, FastDelegate0(x->get(), func))); } template inline DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)(Param1), const P1 &p1) { return (new DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE>( x, FastDelegate1(x->get(), func), p1)); } template inline DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)(Param1, Param2), const P1 &p1, const P2 &p2) { return (new DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE>( x, FastDelegate2(x->get(), func), p1, p2)); } template inline DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { return (new DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE>( x, FastDelegate3(x->get(), func), p1, p2, p3)); } template inline DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { return (new DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE>( x, FastDelegate4(x->get(), func), p1, p2, p3, p4)); } template inline DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> * MakeDelegateEntity(UnretainedWrapper *x, RetType (X::*func)(Param1, Param2, Param3, Param4, Param5), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) { return ( new DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>( x, FastDelegate5(x->get(), func), p1, p2, p3, p4, p5)); } template inline DelegateEntity0, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)()) { return (new DelegateEntity0, FASTDLGT_RETTYPE>( x, FastDelegate0(x->ptr_, func))); } template inline DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)(Param1), const P1 &p1) { return (new DelegateEntity1, Param1, P1, FASTDLGT_RETTYPE>( x, FastDelegate1(x->ptr_, func), p1)); } template inline DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)(Param1, Param2), const P1 &p1, const P2 &p2) { return (new DelegateEntity2, Param1, Param2, P1, P2, FASTDLGT_RETTYPE>( x, FastDelegate2(x->ptr_, func), p1, p2)); } template inline DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { return (new DelegateEntity3, Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE>( x, FastDelegate3(x->ptr_, func), p1, p2, p3)); } template inline DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { return (new DelegateEntity4, Param1, Param2, Param3, Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE>( x, FastDelegate4(x->ptr_, func), p1, p2, p3, p4)); } template inline DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> * MakeDelegateEntity(WeakPtr *x, RetType (X::*func)(Param1, Param2, Param3, Param4, Param5), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) { return (new DelegateEntity5, Param1, Param2, Param3, Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>( x, FastDelegate5( x->ptr_, func), p1, p2, p3, p4, p5)); } template class Task final : public base::RefCountedThreadSafe> { public: Task() : m_Func(NULL), m_Class(NULL) { ATLTRACE("new TASK\n"); } ~Task() { ATLTRACE("delete TASK\n"); if (m_Func) { m_Func->ReleaseRef(); } if (m_Class) { m_Class->ReleaseRef(); } } void SetFun(ExecDelegate *p) { m_Func = p; } void SetClass(ExecDelegate *p) { m_Class = p; } FASTDLGT_RETTYPE Run(); protected: ExecDelegate *m_Func; ExecDelegate *m_Class; friend class RefCountedThreadSafe>; }; template FASTDLGT_RETTYPE Task::Run() { if (m_Class) { return m_Class->Run(); } if (m_Func) { return m_Func->Run(); } return FASTDLGT_RETTYPE(); } #undef FASTDLGT_RETTYPE } // namespace fastdelegate namespace base { inline fastdelegate::Task *Bind(void (*func_no_para)()) { fastdelegate::Task *task = new fastdelegate::Task; task->SetFun(fastdelegate::MakeFunctionEntity(func_no_para)); return task; } template inline fastdelegate::Task *Bind(void (*func_1para)(Param1), const P1 &p1) { fastdelegate::Task *task = new fastdelegate::Task; task->SetFun(fastdelegate::MakeFunctionEntity(func_1para, p1)); return task; } template inline fastdelegate::Task *Bind(void (*func_2para)(Param1, Param2), const P1 &p1, const P2 &p2) { fastdelegate::Task *task = new fastdelegate::Task; task->SetFun(fastdelegate::MakeFunctionEntity(func_2para, p1, p2)); return task; } template inline fastdelegate::Task * Bind(void (*func_3para)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { fastdelegate::Task *task = new fastdelegate::Task; task->SetFun(fastdelegate::MakeFunctionEntity(func_3para, p1, p2, p3)); return task; } template inline fastdelegate::Task * Bind(void (*func_4para)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { fastdelegate::Task *task = new fastdelegate::Task; task->SetFun(fastdelegate::MakeFunctionEntity(func_4para, p1, p2, p3, p4)); return task; } template inline fastdelegate::Task *Bind(Y *obj, void (X::*func)()) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass(fastdelegate::MakeDelegateEntity(obj, func)); return task; } template inline fastdelegate::Task *Bind(Y *obj, void (X::*func)(Param1), const P1 &p1) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1)); return task; } template inline fastdelegate::Task *Bind(Y *obj, void (X::*func)(Param1, Param2), const P1 &p1, const P2 &p2) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2)); return task; } template inline fastdelegate::Task * Bind(Y *obj, void (X::*func)(Param1, Param2, Param3), const P1 &p1, const P2 &p2, const P3 &p3) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3)); return task; } template inline fastdelegate::Task * Bind(Y *obj, void (X::*func)(Param1, Param2, Param3, Param4), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3, p4)); return task; } template inline fastdelegate::Task * Bind(Y *obj, void (X::*func)(Param1, Param2, Param3, Param4, Param5), const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) { fastdelegate::Task *task = new fastdelegate::Task; task->SetClass( fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3, p4, p5)); return task; } } // namespace base ================================================ FILE: src/base/MessageLoop.cc ================================================ #include "StdAfx.h" #include "MessageLoop.h" namespace base { static base::ThreadLocalPointer tls_ptr; void MessageLoop::AddDestructionObserver( DestructionObserver *destruction_observer) { assert(this == current()); destruction_observers_.AddObserver(destruction_observer); } void MessageLoop::RemoveDestructionObserver( DestructionObserver *destruction_observer) { assert(this == current()); destruction_observers_.RemoveObserver(destruction_observer); } MessageLoop::MessageLoop(Type type) : type_(type), running_(false), recent_time_() /*,upLayer_(NULL)*/ { Init(); pump_.reset(CreateMessagePumpForType(type)); } MessageLoop *MessageLoop::current() { return tls_ptr.Get(); } void MessageLoop::Init() { assert(tls_ptr.Get() == NULL); tls_ptr.Set(this); } void MessageLoop::PostTask(fastdelegate::Task *task) { PostDelayedTask(task, TimeDelta()); } void MessageLoop::PostDelayedTask(fastdelegate::Task *task, TimeDelta delay) { assert(delay >= TimeDelta()); do { if (delay == TimeDelta()) { AppendTask(PendingTask(task)); break; } AppendTask(PendingTask(task, CalculateDelayedRuntime(delay))); } while (false); pump_->ScheduleWork(); } void MessageLoop::PostQuitTask(fastdelegate::Task *task) { AutoCritSecLock lock(m_cs, false); lock.Lock(); quitwork_queue_.push_back(PendingTask(task)); } void MessageLoop::Run() { running_ = true; pump_->Run(this); running_ = false; } void MessageLoop::Quit() { PostTask(Bind(Unretained(this), &MessageLoop::QuitInternal)); } bool MessageLoop::is_running() const { return running_; } MessagePump *MessageLoop::CreateMessagePumpForType(Type type) { if (MessageLoop::TYPE_UI == type) { return new MessagePumpForUI(); } if (MessageLoop::TYPE_IO == type) { return new MessagePumpForIO(); } if (MessageLoop::TYPE_DEFAULT == type) { return new MessagePumpDefault(); } return NULL; } void MessageLoop::AppendTask(PendingTask &task) { AutoCritSecLock lock(m_cs, false); lock.Lock(); incoming_queue_.push_back(task); } void MessageLoop::AddToDelayedWorkQueue(const PendingTask &pending_task) { delayed_work_queue_.push(pending_task); } void MessageLoop::QuitInternal() { pump_->Quit(); } MessageLoop::~MessageLoop() { assert(this == current()); // Clean up any unprocessed tasks DeletePendingTasks(); ReloadWorkQueue(); DeletePendingTasks(); // Let interested parties have one last shot at accessing this. FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, WillDestroyCurrentMessageLoop()); // OK, now make it so that no one can find us. tls_ptr.Set(NULL); ExeQuitQueue(); } void MessageLoop::ExeQuitQueue() { for (; !quitwork_queue_.empty();) { PendingTask pending_task = quitwork_queue_.pick_front(); RunPendingTask(pending_task); } } void MessageLoop::DeletePendingTasks() { size_t size = working_queue_.size(); for (size_t i = 0; i < size; ++i) { PendingTask pending_task = working_queue_.pick_front(); pending_task.Reset(); } while (!delayed_work_queue_.empty()) { PendingTask pending_task = delayed_work_queue_.top(); delayed_work_queue_.pop(); pending_task.Reset(); } } void MessageLoop::ReloadWorkQueue() { if (!working_queue_.empty()) return; AutoCritSecLock lock(m_cs, false); lock.Lock(); if (0 == incoming_queue_.size()) { } else { incoming_queue_.swap(working_queue_); } } bool MessageLoop::RunPendingTask(PendingTask &pending_task) { pending_task.Run(); return true; } TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { TimeTicks delayed_run_time = TimeTicks::Now() + delay; return delayed_run_time; } bool MessageLoop::DoWork() { for (;;) { ReloadWorkQueue(); if (working_queue_.empty()) break; // Execute oldest task. do { PendingTask pending_task = working_queue_.pick_front(); if (!pending_task.delayed_run_time_.is_null()) { AddToDelayedWorkQueue(pending_task); // If we changed the topmost task, then it is time to reschedule. if (delayed_work_queue_.top().Equals(pending_task)) pump_->ScheduleDelayedWork(pending_task.delayed_run_time_); } else { if (RunPendingTask(pending_task)) return true; } } while (!working_queue_.empty()); } // Nothing runned. return false; } bool MessageLoop::DoDelayedWork(TimeTicks *next_delayed_work_time) { if (delayed_work_queue_.empty()) { recent_time_ = *next_delayed_work_time = TimeTicks(); return false; } TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time_; if (next_run_time > recent_time_) { recent_time_ = TimeTicks::Now(); if (next_run_time > recent_time_) { *next_delayed_work_time = next_run_time; return false; } } PendingTask pending_task = delayed_work_queue_.top(); delayed_work_queue_.pop(); if (!delayed_work_queue_.empty()) { *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time_; } RunPendingTask(pending_task); return true; } bool MessageLoop::DoIdleWork() { return false; } MessagePumpWin *MessageLoop::pump_win() { return static_cast(pump_.get()); } // LayerLoop std::vector MessageLoop::LayerLoop::layer_; MessageLoop::LayerLoop::LayerLoop(Type type) { pump_.reset(new MessagePumpForUI(NULL, (MessagePumpForUI *)1)); } MessagePumpWin *MessageLoop::LayerLoop::pump_win() { return static_cast(pump_.get()); } bool MessageLoop::LayerLoop::DoWork() { return false; } bool MessageLoop::LayerLoop::DoDelayedWork(TimeTicks *next_delayed_work_time) { return false; } bool MessageLoop::LayerLoop::DoIdleWork() { return false; } void MessageLoop::LayerLoop::Run() { pump_->Run(NULL); } void MessageLoop::LayerLoop::PushBackLoop(LayerLoop *loop) { layer_.push_back(loop); } void MessageLoop::LayerLoop::PopBackLoop() { layer_.pop_back(); } MessageLoop::LayerLoop *MessageLoop::LayerLoop::Back() { LayerLoop *back = layer_.back(); return back; } } // namespace base ================================================ FILE: src/base/MessageLoop.h ================================================ #pragma once #include #include "../Event/WaitableEvent.h" #include "FastDelegateImpl.h" #include "PendingTask.h" #include "observer_list.h" #include "MessagePumpDefault.h" #include "MessagePumpWin.h" #include "thread_local.h" namespace base { class MessagePumpWin; class MessageLoop : public MessagePump::Delegate { public: enum Type { TYPE_DEFAULT, TYPE_UI, TYPE_IO, }; template class DeleteHelper { public: static void DoDelete(const void *object) { delete reinterpret_cast(object); } DISALLOW_COPY_AND_ASSIGN(DeleteHelper); }; class DestructionObserver { public: virtual void WillDestroyCurrentMessageLoop() = 0; protected: virtual ~DestructionObserver() {} }; void AddDestructionObserver(DestructionObserver *destruction_observer); // Remove a DestructionObserver. It is safe to call this method while a // DestructionObserver is receiving a notification callback. void RemoveDestructionObserver(DestructionObserver *destruction_observer); explicit MessageLoop(Type type = TYPE_DEFAULT); virtual ~MessageLoop(); // static static MessageLoop *current(); void PostTask(fastdelegate::Task *task); void PostDelayedTask(fastdelegate::Task *task, TimeDelta delay); void PostQuitTask(fastdelegate::Task *task); template void DeleteSoon(T *object) { TASK *task = build TASK; PostTask(MAKETASK_FUN1(task, DeleteHelper::DoDelete, object)); } void Run(); void Quit(); Type type() const { return type_; } // Optional call to connect the thread name with this loop. void set_thread_name(const std::string &thread_name) { if (thread_name_.empty()) thread_name_ = thread_name; } void reset_thread_name(const std::string &thread_name) { if (!thread_name_.empty()) thread_name_ = thread_name; } const std::string &thread_name() const { return thread_name_; } // Can only be called from the thread that owns the MessageLoop. bool is_running() const; // static static MessagePump *CreateMessagePumpForType(Type type); MessagePumpWin *pump_win(); private: void ExeQuitQueue(); void Init(); void AddToDelayedWorkQueue(const PendingTask &pending_task); TimeTicks CalculateDelayedRuntime(TimeDelta delay); void QuitInternal(); void DeletePendingTasks(); void ReloadWorkQueue(); bool RunPendingTask(PendingTask &pending_task); void AppendTask(PendingTask &task); // MessagePump::Delegate methods: virtual bool DoWork() override; virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) override; virtual bool DoIdleWork() override; bool running_; std::string thread_name_; Type type_; std::auto_ptr pump_; ObserverList destruction_observers_; TaskQueue incoming_queue_; TaskQueue working_queue_; TaskQueue quitwork_queue_; DelayedTaskQueue delayed_work_queue_; CriticalSection m_cs; TimeTicks recent_time_; public: class LayerLoop : public MessagePump::Delegate { public: explicit LayerLoop(Type type = TYPE_DEFAULT); void Run(); virtual bool DoWork() override; virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) override; virtual bool DoIdleWork() override; MessagePumpWin *pump_win(); std::auto_ptr pump_; static void PushBackLoop(LayerLoop *loop); static void PopBackLoop(); static LayerLoop *Back(); private: static std::vector layer_; }; }; } // namespace base ================================================ FILE: src/base/MessagePump.h ================================================ #pragma once #include "../time/time.h" namespace base { class __declspec(novtable) MessagePump { public: class __declspec(novtable) Delegate { public: // Called from within Run in response to ScheduleWork or when the message // pump would otherwise call DoDelayedWork. Returns true to indicate that // work was done. DoDelayedWork will still be called if DoWork returns // true, but DoIdleWork will not. virtual bool DoWork() = 0; // Called from within Run in response to ScheduleDelayedWork or when the // message pump would otherwise sleep waiting for more work. Returns true // to indicate that delayed work was done. DoIdleWork will not be called // if DoDelayedWork returns true. Upon return |next_delayed_work_time| // indicates the time when DoDelayedWork should be called again. If // |next_delayed_work_time| is null (per Time::is_null), then the queue of // future delayed work (timer events) is currently empty, and no additional // calls to this function need to be scheduled. virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) = 0; // Called from within Run just before the message pump goes to sleep. // Returns true to indicate that idle work was done. Returning false means // the pump will now wait. virtual bool DoIdleWork() = 0; }; virtual void Run(Delegate* delegate) = 0; // Quit immediately from the most recently entered run loop. This method may // only be used on the thread that called Run. virtual void Quit() = 0; // Schedule a DoWork callback to happen reasonably soon. Does nothing if a // DoWork callback is already scheduled. This method may be called from any // thread. Once this call is made, DoWork should not be "starved" at least // until it returns a value of false. virtual void ScheduleWork() = 0; // Schedule a DoDelayedWork callback to happen at the specified time, // cancelling any pending DoDelayedWork callback. This method may only be // used on the thread that called Run. virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0; }; }; //base ================================================ FILE: src/base/MessagePumpDefault.cc ================================================ #include "StdAfx.h" #include "MessagePumpDefault.h" namespace base { MessagePumpDefault::MessagePumpDefault() : keep_running_(true), event_(false, false) {} MessagePumpDefault::~MessagePumpDefault() {} void MessagePumpDefault::Run(Delegate *delegate) { for (;;) { bool did_work = delegate->DoWork(); if (false == keep_running_) break; did_work |= delegate->DoDelayedWork(&delayed_work_time_); if (false == keep_running_) break; if (did_work) continue; did_work = delegate->DoIdleWork(); if (false == keep_running_) break; if (did_work) continue; if (delayed_work_time_.is_null()) { event_.Wait(); } else { TimeDelta delay = delayed_work_time_ - TimeTicks::Now(); if (delay > TimeDelta()) { event_.TimedWait(delay); } else { // It looks like delayed_work_time_ indicates a time in the past, so we // need to call DoDelayedWork now. delayed_work_time_ = TimeTicks(); } } } keep_running_ = true; } void MessagePumpDefault::Quit() { keep_running_ = false; } void MessagePumpDefault::ScheduleWork() { event_.Signal(); } void MessagePumpDefault::ScheduleDelayedWork( const TimeTicks &delayed_work_time) { // We know that we can't be blocked on Wait right now since this method can // only be called on the same thread as Run, so we only need to update our // record of how long to sleep when we do sleep. delayed_work_time_ = delayed_work_time; } } // namespace base ================================================ FILE: src/base/MessagePumpDefault.h ================================================ #pragma once #include "../Event/WaitableEvent.h" #include "MessagePump.h" #include "macros.h" namespace base { class MessagePumpDefault : public MessagePump { public: MessagePumpDefault(); virtual ~MessagePumpDefault(); // MessagePump methods: virtual void Run(Delegate *delegate) override; virtual void Quit() override; virtual void ScheduleWork() override; virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override; private: // This flag is set to false when Run should return. bool keep_running_; // Used to sleep until there is more work to do. WaitableEvent event_; // The time at which we should call DoDelayedWork. TimeTicks delayed_work_time_; DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault); }; } // namespace base ================================================ FILE: src/base/MessagePumpWin.cc ================================================ #include "StdAfx.h" #include "stringprintf.h" #include "MessagePumpWin.h" namespace base { static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p"; static const int kMsgHaveWork = WM_USER + 1; HMODULE GetModuleFromAddress(void *address) { HMODULE instance = NULL; if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast(address), &instance)) { assert(0); } return instance; } // Win void MessagePumpWin::AddObserver(MessagePumpObserver *observer) { observers_.AddObserver(observer); } void MessagePumpWin::RemoveObserver(MessagePumpObserver *observer) { observers_.RemoveObserver(observer); } void MessagePumpWin::WillProcessMessage(const MSG &msg) { FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg)); } void MessagePumpWin::DidProcessMessage(const MSG &msg) { FOR_EACH_OBSERVER(MessagePumpObserver, observers_, DidProcessEvent(msg)); } void MessagePumpWin::Quit() { keep_running_ = false; } int MessagePumpWin::GetCurrentDelay() const { if (delayed_work_time_.is_null()) return -1; // Be careful here. TimeDelta has a precision of microseconds, but we want a // value in milliseconds. If there are 5.5ms left, should the delay be 5 or // 6? It should be 6 to avoid executing delayed work too early. double timeout = ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF()); // If this value is negative, then we need to run delayed work soon. int delay = static_cast(timeout); if (delay < 0) delay = 0; return delay; } // UI MessagePumpForUI::MessagePumpForUI(Delegate *delegate, MessagePumpForUI *upLayer) : atom_(0), message_hwnd_(NULL), delegate_(delegate), upLayer_(upLayer) { if (!upLayer_) InitMessageWnd(); } MessagePumpForUI::~MessagePumpForUI() { DestroyWindow(message_hwnd_); UnregisterClass(MAKEINTATOM(atom_), GetModuleFromAddress(&WndProcThunk)); } void MessagePumpForUI::Run(Delegate *delegate) { assert(delegate_ == NULL || delegate == delegate_); delegate_ = delegate; if (!upLayer_) { // for module dialog assert(delegate_); for (;;) { // If we do any work, we may create more messages etc., and more work may // possibly be waiting in another task group. When we (for example) // ProcessNextWindowsMessage(), there is a good chance there are still // more messages waiting. On the other hand, when any of these methods // return having done no work, then it is pretty unlikely that calling // them again quickly will find any work to do. Finally, if they all say // they had no work, then it is a good time to consider sleeping (waiting) // for more work. bool more_work_is_plausible = ProcessNextWindowsMessage(); if (!keep_running_) break; more_work_is_plausible |= delegate->DoWork(); if (!keep_running_) break; more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time_); if (!keep_running_) break; if (more_work_is_plausible) continue; more_work_is_plausible = delegate->DoIdleWork(); if (!keep_running_) break; if (more_work_is_plausible) continue; WaitForWork(); // Wait (sleep) until we have work to do again. } } else { assert(!delegate_); for (;;) { bool more_work_is_plausible = upLayer_->ProcessNextWindowsMessage(); if (!keep_running_) break; more_work_is_plausible |= upLayer_->PumpDelegate()->DoWork(); if (!keep_running_) break; more_work_is_plausible |= upLayer_->PumpDelegate()->DoDelayedWork(&delayed_work_time_); if (!keep_running_) break; if (more_work_is_plausible) continue; more_work_is_plausible = upLayer_->PumpDelegate()->DoIdleWork(); if (!keep_running_) break; if (more_work_is_plausible) continue; upLayer_->WaitForWork(); // Wait (sleep) until we have work to do again. } } keep_running_ = true; } void MessagePumpForUI::ScheduleWork() { if (InterlockedExchange(&have_work_, 1)) return; BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, (WPARAM)this, 0); if (ret) return; // There was room in the Window Message queue. InterlockedExchange(&have_work_, 0); } void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks &delayed_work_time) { delayed_work_time_ = delayed_work_time; int delay_msec = GetCurrentDelay(); assert(delay_msec >= 0); if (delay_msec < USER_TIMER_MINIMUM) delay_msec = USER_TIMER_MINIMUM; KillTimer(message_hwnd_, reinterpret_cast(this)); BOOL ret = SetTimer(message_hwnd_, reinterpret_cast(this), delay_msec, NULL); } void MessagePumpForUI::InitMessageWnd() { std::wstring class_name = base::StringPrintf(kWndClassFormat, this); HINSTANCE instance = GetModuleFromAddress(&WndProcThunk); WNDCLASSEX wc = {0}; wc.cbSize = sizeof(wc); wc.lpfnWndProc = WndProcThunk; wc.hInstance = instance; wc.lpszClassName = class_name.c_str(); atom_ = RegisterClassEx(&wc); assert(atom_); message_hwnd_ = ::CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0); assert(message_hwnd_); } bool MessagePumpForUI::ProcessMessageHelper(const MSG &msg) { if (WM_QUIT == msg.message) { // Repost the QUIT message so that it will be retrieved by the primary // GetMessage() loop. keep_running_ = false; PostQuitMessage(static_cast(msg.wParam)); return false; } WillProcessMessage(msg); TranslateMessage(&msg); DispatchMessage(&msg); DidProcessMessage(msg); return true; } bool MessagePumpForUI::ProcessNextWindowsMessage() { // If there are sent messages in the queue then PeekMessage internally // dispatches the message and returns false. We return true in this // case to ensure that the message loop peeks again instead of calling // MsgWaitForMultipleObjectsEx again. bool sent_messages_in_queue = false; DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); if (HIWORD(queue_status) & QS_SENDMESSAGE) sent_messages_in_queue = true; MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE) return ProcessMessageHelper(msg); return sent_messages_in_queue; } // static LRESULT CALLBACK MessagePumpForUI::WndProcThunk(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { switch (message) { case kMsgHaveWork: reinterpret_cast(wparam)->HandleWorkMessage(); break; case WM_TIMER: reinterpret_cast(wparam)->HandleTimerMessage(); break; } return DefWindowProc(hwnd, message, wparam, lparam); } void MessagePumpForUI::WaitForWork() { int delay = GetCurrentDelay(); if (delay < 0) // Negative value means no timers waiting. delay = INFINITE; DWORD result; result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, MWMO_INPUTAVAILABLE); if (WAIT_OBJECT_0 == result) { // A WM_* message is available. // If a parent child relationship exists between windows across threads // then their thread inputs are implicitly attached. // This causes the MsgWaitForMultipleObjectsEx API to return indicating // that messages are ready for processing (Specifically, mouse messages // intended for the child window may appear if the child window has // capture). // The subsequent PeekMessages call may fail to return any messages thus // causing us to enter a tight loop at times. // The WaitMessage call below is a workaround to give the child window // some time to process its input messages. MSG msg = {0}; DWORD queue_status = GetQueueStatus(QS_MOUSE); if (HIWORD(queue_status) & QS_MOUSE && !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { WaitMessage(); } return; } } void MessagePumpForUI::HandleWorkMessage() { InterlockedExchange(&have_work_, 0); delegate_->DoWork(); } void MessagePumpForUI::HandleTimerMessage() { KillTimer(message_hwnd_, reinterpret_cast(this)); delegate_->DoDelayedWork(&delayed_work_time_); if (!delayed_work_time_.is_null()) { ScheduleDelayedWork(delayed_work_time_); } } // IO MessagePumpForIO::MessagePumpForIO(Delegate *delegate) : delegate_(delegate) { port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0)); assert(port_.IsValid()); } MessagePumpForIO::~MessagePumpForIO() {} void MessagePumpForIO::Run(Delegate *delegate) { assert(delegate_ == NULL || delegate == delegate_); delegate_ = delegate; for (;;) { bool more_work_is_plausible = delegate->DoWork(); if (!keep_running_) break; more_work_is_plausible |= WaitForIOCompletion(0, NULL); if (!keep_running_) break; more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time_); if (!keep_running_) break; if (more_work_is_plausible) continue; more_work_is_plausible = delegate->DoIdleWork(); if (!keep_running_) break; if (more_work_is_plausible) continue; WaitForWork(); } } void MessagePumpForIO::ScheduleWork() { if (InterlockedExchange(&have_work_, 1)) return; // Someone else continued the pumping. BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0, reinterpret_cast(this), reinterpret_cast(this)); if (ret) return; InterlockedExchange(&have_work_, 0); } void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks &delayed_work_time) { delayed_work_time_ = delayed_work_time; } void MessagePumpForIO::Quit() { keep_running_ = false; } void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, IOHandler *handler) { ULONG_PTR key = HandlerToKey(handler, true); HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 0); assert(port_.Get() == port); } bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler *filter) { IOItem item; if (!GetIOItem(timeout, &item)) return false; if (ProcessInternalIOItem(item)) return true; assert(item.context->handler == item.handler); item.handler->OnIOCompleted(item.context, item.bytes_transfered, item.error); return true; } void MessagePumpForIO::WaitForWork() { int timeout = GetCurrentDelay(); if (timeout < 0) { timeout = INFINITE; } WaitForIOCompletion(timeout, NULL); } bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem *item) { memset(item, 0, sizeof(*item)); ULONG_PTR key = NULL; OVERLAPPED *overlapped = NULL; if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key, &overlapped, timeout)) { if (!overlapped) return false; // Nothing in the queue. item->error = GetLastError(); item->bytes_transfered = 0; } item->handler = KeyToHandler(key, &item->has_valid_io_context); item->context = reinterpret_cast(overlapped); return true; } bool MessagePumpForIO::ProcessInternalIOItem(const IOItem &item) { if (this == reinterpret_cast(item.context) && this == reinterpret_cast(item.handler)) { // This is our internal completion. assert(!item.bytes_transfered); InterlockedExchange(&have_work_, 0); return true; } return false; } // static ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler *handler, bool has_valid_io_context) { ULONG_PTR key = reinterpret_cast(handler); // |IOHandler| is at least pointer-size aligned, so the lowest two bits are // always cleared. We use the lowest bit to distinguish completion keys with // and without the associated |IOContext|. assert((key & 1) == 0); // Mark the completion key as context-less. if (!has_valid_io_context) key = key | 1; return key; } // static MessagePumpForIO::IOHandler * MessagePumpForIO::KeyToHandler(ULONG_PTR key, bool *has_valid_io_context) { *has_valid_io_context = ((key & 1) == 0); return reinterpret_cast(key & ~static_cast(1)); } } // namespace base ================================================ FILE: src/base/MessagePumpWin.h ================================================ #pragma once #include #include "MessagePump.h" #include "macros.h" #include "observer_list.h" #include "scoped_handle.h" namespace base { class MessagePumpWin : public MessagePump { public: class __declspec(novtable) MessagePumpObserver { public: // This method is called before processing a NativeEvent. If the // method returns EVENT_HANDLED, it indicates the event has already // been handled, so the event is not processed any farther. If the // method returns EVENT_CONTINUE, the event dispatching proceeds as // normal. virtual void WillProcessEvent(const MSG &event) = 0; // This method is called after processing a message. This method // will not be called if WillProcessEvent returns EVENT_HANDLED. virtual void DidProcessEvent(const MSG &event) = 0; protected: virtual ~MessagePumpObserver() {} }; MessagePumpWin() : keep_running_(true), have_work_(0) {} virtual ~MessagePumpWin() {} // Add an Observer, which will start receiving notifications immediately. void AddObserver(MessagePumpObserver *observer); // Remove an Observer. It is safe to call this method while an Observer is // receiving a notification callback. void RemoveObserver(MessagePumpObserver *observer); // Give a chance to code processing additional messages to notify the // message loop observers that another message has been processed. void WillProcessMessage(const MSG &msg); void DidProcessMessage(const MSG &msg); // MessagePump method: virtual void Quit() override; virtual HANDLE io_port() { return NULL; } protected: int GetCurrentDelay() const; ObserverList observers_; TimeTicks delayed_work_time_; bool keep_running_; long have_work_; }; class MessagePumpForUI : public MessagePumpWin { public: MessagePumpForUI(Delegate *delegate = NULL, MessagePumpForUI *upLayer = NULL); virtual ~MessagePumpForUI(); // MessagePump methods: virtual void Run(Delegate *delegate) override; virtual void ScheduleWork() override; virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override; Delegate *PumpDelegate() { return delegate_; } bool ProcessNextWindowsMessage(); void WaitForWork(); void upPumpLayer(MessagePumpForUI *upLayer) { upLayer_ = upLayer; } private: static LRESULT CALLBACK WndProcThunk(HWND window_handle, UINT message, WPARAM wparam, LPARAM lparam); void InitMessageWnd(); bool ProcessMessageHelper(const MSG &msg); void HandleWorkMessage(); void HandleTimerMessage(); // Atom representing the registered window class. ATOM atom_; // A hidden message-only window. HWND message_hwnd_; Delegate *delegate_; MessagePumpForUI *upLayer_; DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI); }; class MessagePumpForIO : public MessagePumpWin { public: struct IOContext; class IOHandler { public: virtual ~IOHandler() {} virtual void OnIOCompleted(IOContext *context, DWORD bytes_transfered, DWORD error) = 0; }; struct IOContext { OVERLAPPED overlapped; IOHandler *handler; }; MessagePumpForIO(Delegate *delegate = NULL); ~MessagePumpForIO(); // MessagePump methods: virtual void Run(Delegate *delegate) override; virtual void Quit() override; virtual void ScheduleWork() override; virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override; void RegisterIOHandler(HANDLE file_handle, IOHandler *handler); virtual HANDLE io_port() override { return port_.Get(); } private: struct IOItem { IOHandler *handler; IOContext *context; DWORD bytes_transfered; DWORD error; // In some cases |context| can be a non-pointer value casted to a pointer. // |has_valid_io_context| is true if |context| is a valid IOContext // pointer, and false otherwise. bool has_valid_io_context; }; bool WaitForIOCompletion(DWORD timeout, IOHandler *filter); void WaitForWork(); bool GetIOItem(DWORD timeout, IOItem *item); bool ProcessInternalIOItem(const IOItem &item); // static // Converts an IOHandler pointer to a completion port key. // |has_valid_io_context| specifies whether completion packets posted to // |handler| will have valid OVERLAPPED pointers. static ULONG_PTR HandlerToKey(IOHandler *handler, bool has_valid_io_context); // Converts a completion port key to an IOHandler pointer. static IOHandler *KeyToHandler(ULONG_PTR key, bool *has_valid_io_context); std::list cmpleted_io_; ScopedWinHandle port_; Delegate *delegate_; }; } // namespace base ================================================ FILE: src/base/PendingTask.cpp ================================================ #include "StdAfx.h" #include "PendingTask.h" namespace base { PendingTask::PendingTask() : task_(NULL), sequence_num_(0) {} PendingTask::PendingTask(fastdelegate::Task *task) : task_(task), sequence_num_(0) {} PendingTask::PendingTask(fastdelegate::Task *task, const TimeTicks delayed_run_time) : task_(task), delayed_run_time_(delayed_run_time), sequence_num_(0) {} PendingTask::~PendingTask() {} bool PendingTask::is_null() const { return NULL == task_.get(); } void PendingTask::Reset() { task_ = NULL; } bool PendingTask::Equals(const PendingTask &other) const { return task_.get() == other.task_.get(); } void PendingTask::Run() { if (task_.get()) { task_->Run(); } } bool PendingTask::operator<(const PendingTask &other) const { // Since the top of a priority queue is defined as the "greatest" element, we // need to invert the comparison here. We want the smaller time to be at the // top of the heap. if (delayed_run_time_ < other.delayed_run_time_) return false; if (delayed_run_time_ > other.delayed_run_time_) return true; // If the times happen to match, then we use the sequence number to decide. // Compare the difference to support integer roll-over. return (sequence_num_ > other.sequence_num_); } // task queue namespace taskqueue { bool queue::empty() { return _val.empty(); } int queue::size() { return _val.size(); } void queue::push_back(const PendingTask &val) { val.sequence_num_ = ++sequence_num_; _val.push_back(val); } PendingTask queue::pick_front() { assert(_val.size()); PendingTask o = _val.front(); _val.pop_front(); return o; } PendingTask queue::front() { assert(_val.size()); return _val.front(); } void queue::swap(taskqueue::queue &val) { _val.swap(val._val); } } // namespace taskqueue } // namespace base ================================================ FILE: src/base/PendingTask.h ================================================ #pragma once #include #include #include "../time/time.h" #include "FastDelegateImpl.h" #include "ref_counted.h" namespace base { class PendingTask { public: explicit PendingTask(); explicit PendingTask(fastdelegate::Task *task); explicit PendingTask(fastdelegate::Task *task, const TimeTicks delayed_run_time); ~PendingTask(); bool is_null() const; void Reset(); bool Equals(const PendingTask &other) const; void Run(); // Used to support sorting. bool operator<(const PendingTask &other) const; // The time when the task should be run. base::TimeTicks delayed_run_time_; // Secondary sort key for run time. mutable unsigned int sequence_num_; private: scoped_refptr > task_; }; namespace taskqueue { class queue { public: queue() : sequence_num_(0) { _val.clear(); } ~queue() { _val.clear(); } bool empty(); int size(); void push_back(const PendingTask &task); //_val.empty() is false PendingTask pick_front(); PendingTask front(); void swap(queue &val); private: std::list _val; unsigned int sequence_num_; }; } // end namespace taskqueue typedef std::priority_queue DelayedTaskQueue; typedef taskqueue::queue TaskQueue; } // namespace base ================================================ FILE: src/base/Thread.cc ================================================ #include "StdAfx.h" #include "Thread.h" namespace base { unsigned int __stdcall ThreadFunc(void *params); Thread::Options::Options() : message_loop_type_(MessageLoop::TYPE_DEFAULT), stack_size_(0) {} Thread::Options::Options(MessageLoop::Type type, size_t size) : message_loop_type_(type), stack_size_(size) {} Thread::Thread() : com_status_(NONE), started_(false), stopping_(false), running_(false), thread_(NULL), message_loop_(NULL), thread_id_(kInvalidThreadId), startup_data_(NULL), thread_context_(NULL) {} Thread::Thread(const char *name) : com_status_(NONE), started_(false), stopping_(false), running_(false), thread_(NULL), message_loop_(NULL), name_(name), thread_id_(kInvalidThreadId), startup_data_(NULL), thread_context_(NULL) { } Thread::~Thread() { Stop(); } bool Thread::StartWithOptions(const Options &options) { assert(!message_loop_); StartupData startup_data(options); startup_data_ = &startup_data; if (!CreateThreadInternal(options.stack_size_, this, &thread_)) { startup_data_ = NULL; return false; } startup_data.event_.Wait(); startup_data_ = NULL; started_ = true; assert(message_loop_); return true; } bool Thread::CreateThreadInternal(size_t stack_size, Thread *thread, HANDLE *out_thread_handle) { unsigned int flags = 0; if (stack_size > 0) flags = STACK_SIZE_PARAM_IS_A_RESERVATION; Thread::ThreadParams *params = new Thread::ThreadParams; params->thread_ = thread; HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, stack_size, ThreadFunc, params, flags, NULL); if (NULL == thread_handle) { delete params; return false; } if (out_thread_handle) { *out_thread_handle = thread_handle; } else { CloseHandle(thread_handle); } return true; } void Thread::ThreadMain() { std::auto_ptr message_loop; message_loop.reset( new MessageLoop(startup_data_->options_.message_loop_type_)); assert(message_loop.get()); thread_id_ = GetCurrentThreadId(); message_loop->set_thread_name(name_); message_loop_ = message_loop.get(); std::auto_ptr com_initializer; if (com_status_ != NONE) { com_initializer.reset((com_status_ == STA) ? new ScopedCOMInitializer() : new ScopedCOMInitializer(MTA)); } running_ = true; startup_data_->event_.Signal(); Run(message_loop_); running_ = false; // Let the thread do extra cleanup. CleanUp(); com_initializer.reset(); message_loop_ = NULL; } void Thread::Run(MessageLoop *message_loop) { message_loop->Run(); } bool Thread::IsRunning() const { return running_; } void Thread::SetPriority(ThreadPriority priority) { switch (priority) { case kThreadPriority_Normal: ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL); break; case kThreadPriority_RealtimeAudio: ::SetThreadPriority(thread_, THREAD_PRIORITY_TIME_CRITICAL); break; default: break; } } void Thread::Stop() { if (!started_) return; if (stopping_ || !message_loop_) return; stopping_ = true; message_loop_->Quit(); HANDLE thread_handle = thread_; DWORD result = WaitForSingleObject(thread_handle, INFINITE); if (result != WAIT_OBJECT_0) { assert(0); } CloseHandle(thread_handle); assert(!message_loop_); started_ = false; stopping_ = false; } bool Thread::set_thread_name(std::string name) { if (name_.empty()) { name_ = name; return true; } return false; } } // namespace base namespace base { unsigned int __stdcall ThreadFunc(void *params) { Thread::ThreadParams *thread_params = static_cast(params); base::Thread *thread = thread_params->thread_; delete thread_params; thread->ThreadMain(); return NULL; } } // namespace base ================================================ FILE: src/base/Thread.h ================================================ #pragma once #include #include "../Event/WaitableEvent.h" #include "MessageLoop.h" namespace base { class Thread final { public: typedef bool (*ThreadContextInit)(void *); static const DWORD kInvalidThreadId = 0; class Options { public: Options(); Options(MessageLoop::Type type, size_t size = 0); size_t stack_size_; MessageLoop::Type message_loop_type_; }; enum ThreadPriority { kThreadPriority_Normal, // Suitable for low-latency, glitch-resistant audio. kThreadPriority_RealtimeAudio, // Suitable for threads which generate data for the display (at ~60Hz). kThreadPriority_Display, // Suitable for threads that shouldn't disrupt high priority work. kThreadPriority_Background }; enum ComStatus { NONE, STA, MTA, }; class ScopedCOMInitializer { public: ScopedCOMInitializer() : thread_id_(Thread::kInvalidThreadId) { Initialize(COINIT_APARTMENTTHREADED); } explicit ScopedCOMInitializer(ComStatus mta) : thread_id_(Thread::kInvalidThreadId) { Initialize(COINIT_MULTITHREADED); } ~ScopedCOMInitializer() { assert(GetCurrentThreadId() == thread_id_); CoUninitialize(); } private: void Initialize(COINIT init) { thread_id_ = GetCurrentThreadId(); CoInitializeEx(NULL, init); } // tid DWORD thread_id_; }; class StartupData { public: const Options &options_; WaitableEvent event_; explicit StartupData(const Options &options) : options_(options), event_(false, false) {} }; class ThreadParams { public: Thread *thread_; }; explicit Thread(); explicit Thread(const char *name); virtual ~Thread(); bool StartWithOptions(const Options &options); void Stop(); MessageLoop *message_loop() const { return message_loop_; } const std::string &thread_name() const { return name_; } bool set_thread_name(std::string name); HANDLE thread_handle() { return thread_; } DWORD thread_id() { return thread_id_; } bool IsRunning() const; void SetPriority(ThreadPriority priority); void init_com_with_mta(bool use_mta) { assert(!started_); com_status_ = use_mta ? MTA : STA; } virtual void ThreadMain(); // static static bool CreateThreadInternal(size_t stack_size, Thread *thread, HANDLE *out_thread_handle); protected: virtual void CleanUp() {} private: void Run(MessageLoop *message_loop); MessageLoop *message_loop_; HANDLE thread_; std::string name_; DWORD thread_id_; // Whether we successfully started the thread. bool started_; // If true, we're in the middle of stopping, and shouldn't access // |message_loop_|. It may non-NULL and invalid. bool stopping_; // True while inside of Run(). bool running_; ComStatus com_status_; StartupData *startup_data_; ThreadContextInit thread_context_; DISALLOW_COPY_AND_ASSIGN(Thread); }; } // namespace base ================================================ FILE: src/base/WeakPtr.cc ================================================ #include "StdAfx.h" #include "WeakPtr.h" namespace base { WeakReference::Flag::~Flag() {} WeakReference::WeakReference() {} WeakReference::WeakReference(const Flag *flag) : flag_(flag) {} WeakReference::~WeakReference() {} bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); } WeakReferenceOwner::WeakReferenceOwner() {} WeakReferenceOwner::~WeakReferenceOwner() { Invalidate(); } WeakReference WeakReferenceOwner::GetRef() const { // If we hold the last reference to the Flag then create a new one. if (!HasRefs()) flag_ = new WeakReference::Flag(); return WeakReference(flag_.get()); } void WeakReferenceOwner::Invalidate() { if (flag_.get()) { flag_->Invalidate(); flag_ = NULL; } } } // end namespace base ================================================ FILE: src/base/WeakPtr.h ================================================ #pragma once #include "macros.h" #include "WrapperObj.h" #include "ref_counted.h" namespace base { class WeakReference { public: // Although Flag is bound to a specific thread, it may be deleted from another // via base::WeakPtr::~WeakPtr(). class Flag : public RefCountedThreadSafe { public: Flag() : is_valid_(true) {} void Invalidate() { is_valid_ = false; } bool IsValid() const { return is_valid_; } private: friend class base::RefCountedThreadSafe; ~Flag(); bool is_valid_; }; WeakReference(); explicit WeakReference(const Flag *flag); ~WeakReference(); bool is_valid() const; private: scoped_refptr flag_; }; class WeakReferenceOwner { public: WeakReferenceOwner(); ~WeakReferenceOwner(); WeakReference GetRef() const; bool HasRefs() const { return flag_.get() && !flag_->HasOneRef(); } void Invalidate(); private: mutable scoped_refptr flag_; }; template class WeakPtr : public ObjWrapper { public: WeakPtr() : ptr_(NULL) {} explicit WeakPtr(WeakReference &ref, T *o); T *get() const override { return ref_.is_valid() ? ptr_ : NULL; } void AddRef() const override {} void Release() const override {} bool IsWeakPtr() const override; T &operator*() const { assert(get() != NULL); return *get(); } T *operator->() const { assert(get() != NULL); return get(); } WeakReference ref_; T *ptr_; }; template WeakPtr::WeakPtr(WeakReference &ref, T *o) : ref_(ref), ptr_(o) {} template bool WeakPtr::IsWeakPtr() const { return true; } // A class may extend from SupportsWeakPtr to let others take weak pointers to // it. This avoids the class itself implementing boilerplate to dispense weak // pointers. However, since SupportsWeakPtr's destructor won't invalidate // weak pointers to the class until after the derived class' members have been // destroyed, its use can lead to subtle use-after-destroy issues. template class SupportsWeakPtr { public: SupportsWeakPtr() {} // for posttask WeakPtr *BldWeakPtr() { return new WeakPtr(weak_reference_owner_.GetRef(), static_cast(this)); } WeakPtr AsWeakPtr() { return WeakPtr(weak_reference_owner_.GetRef(), static_cast(this)); } protected: ~SupportsWeakPtr() {} private: WeakReferenceOwner weak_reference_owner_; DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr); }; } // end namespace base ================================================ FILE: src/base/WrapperObj.h ================================================ #pragma once // weakprt // ref count // Unretained namespace base { template class __declspec(novtable) ObjWrapper { public: virtual T *get() const = 0; virtual void AddRef() const = 0; virtual void Release() const = 0; virtual bool IsWeakPtr() const = 0; }; template class NormalWrapper : public ObjWrapper { public: explicit NormalWrapper(T *o) : ptr_(o) {} virtual T *get() const override { return ptr_; } virtual void AddRef() const override { ptr_->AddRef(); } virtual void Release() const override { ptr_->Release(); } virtual bool IsWeakPtr() const override { return false; } private: T *ptr_; }; template class UnretainedWrapper : public ObjWrapper { public: explicit UnretainedWrapper(T *o) : ptr_(o) {} T *get() const override { return ptr_; } void AddRef() const override {} void Release() const override {} bool IsWeakPtr() const override { return false; } private: T *ptr_; }; template static inline UnretainedWrapper *Unretained(T *o) { return new UnretainedWrapper(o); } } // namespace base ================================================ FILE: src/base/aligned_memory.h ================================================ #ifndef BASE_MEMORY_ALIGNED_MEMORY_H_ #define BASE_MEMORY_ALIGNED_MEMORY_H_ #include namespace base { // AlignedMemory is specialized for all supported alignments. // Make sure we get a compiler error if someone uses an unsupported alignment. template struct AlignedMemory {}; #define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \ template class AlignedMemory { \ public: \ __declspec(align(byte_alignment)) unsigned char data_[Size]; \ void *void_data() { return static_cast(data_); } \ const void *void_data() const { return static_cast(data_); } \ template Type *data_as() { \ return static_cast(void_data()); \ } \ template const Type *data_as() const { \ return static_cast(void_data()); \ } \ \ private: \ void *operator new(size_t); \ void operator delete(void *); \ } // Specialization for all alignments is required because MSVC (as of VS 2008) // does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param). // Greater than 4096 alignment is not supported by some compilers, so 4096 is // the maximum specified here. BASE_DECL_ALIGNED_MEMORY(1); BASE_DECL_ALIGNED_MEMORY(2); BASE_DECL_ALIGNED_MEMORY(4); BASE_DECL_ALIGNED_MEMORY(8); BASE_DECL_ALIGNED_MEMORY(16); BASE_DECL_ALIGNED_MEMORY(32); BASE_DECL_ALIGNED_MEMORY(64); BASE_DECL_ALIGNED_MEMORY(128); BASE_DECL_ALIGNED_MEMORY(256); BASE_DECL_ALIGNED_MEMORY(512); BASE_DECL_ALIGNED_MEMORY(1024); BASE_DECL_ALIGNED_MEMORY(2048); BASE_DECL_ALIGNED_MEMORY(4096); } // namespace base #endif // BASE_MEMORY_ALIGNED_MEMORY_H_ ================================================ FILE: src/base/at_exist.cc ================================================ #include "StdAfx.h" #include "at_exist.h" namespace base { static AtExitManager *g_top_manager = nullptr; AtExitManager::AtExitManager() { g_top_manager = this; } AtExitManager::~AtExitManager() { assert(this == g_top_manager); ProcessCallbacksNow(); g_top_manager = nullptr; } // static void AtExitManager::RegisterCallback(AtExitCallbackType func, void *param) { assert(func); RegisterTask(base::Bind(func, param)); } // static void AtExitManager::RegisterTask(fastdelegate::Task *task) { if (!g_top_manager) { assert(0); return; } AutoCritSecLock lock(g_top_manager->m_cs, false); lock.Lock(); g_top_manager->stack_.push(task); } // static void AtExitManager::ProcessCallbacksNow() { if (!g_top_manager) { assert(0); return; } AutoCritSecLock lock(g_top_manager->m_cs, false); lock.Lock(); while (!g_top_manager->stack_.empty()) { std::auto_ptr> task(g_top_manager->stack_.top()); task->Run(); g_top_manager->stack_.pop(); } } } // namespace base ================================================ FILE: src/base/at_exist.h ================================================ #pragma once #include #include #include "FastDelegateImpl.h" namespace base { class AtExitManager { public: typedef void (*AtExitCallbackType)(void *); AtExitManager(); // The dtor calls all the registered callbacks. Do not try to register more // callbacks after this point. ~AtExitManager(); static void RegisterCallback(AtExitCallbackType func, void *param); // Registers the specified task to be called at exit. static void RegisterTask(fastdelegate::Task *task); // Calls the functions registered with RegisterCallback in LIFO order. It // is possible to register new callbacks after calling this function. static void ProcessCallbacksNow(); private: CriticalSection m_cs; std::stack *> stack_; DISALLOW_COPY_AND_ASSIGN(AtExitManager); }; } // namespace base ================================================ FILE: src/base/common_threads.cc ================================================ #include "StdAfx.h" #include "common_threads.h" namespace base { MessageLoop *Threads::threads_[Threads::COUNT] = { 0 }; MessageLoop *Threads::Get(ThreadType type) { return Threads::threads_[type]; } void Threads::Set(ThreadType type, MessageLoop *loop) { assert(type < Threads::COUNT && !Threads::threads_[type]); Threads::threads_[type] = loop; } } // namespace base ================================================ FILE: src/base/common_threads.h ================================================ #pragma once #include "MessageLoop.h" namespace base { class MessageLoop; class Threads { public: enum ThreadType { UI = 0, IO, FILE, DB, COUNT, }; static MessageLoop *Get(ThreadType type); static void Set(ThreadType type, MessageLoop *loop); private: static MessageLoop *threads_[COUNT]; }; } // namespace base ================================================ FILE: src/base/lazy_instance.cc ================================================ #include "StdAfx.h" #include "lazy_instance.h" namespace base { void CompleteLazyInstance(intptr_t *state, intptr_t new_instance, void *lazy_instance, void (*dtor)(void *)) { *state = new_instance; // Make sure that the lazily instantiated object will get destroyed at exit. if (dtor) AtExitManager::RegisterCallback(dtor, lazy_instance); } } // namespace base ================================================ FILE: src/base/lazy_instance.h ================================================ #pragma once #include "aligned_memory.h" #include "at_exist.h" #define LAZY_INSTANCE_INITIALIZER { 0 } namespace base { void CompleteLazyInstance(intptr_t *state, intptr_t new_instance, void *lazy_instance, void (*dtor)(void *)); template struct DefaultLazyInstanceTraits { static Type *New(void *instance) { return new (instance) Type(); } static void Delete(Type *instance) { // Explicitly call the destructor. instance->~Type(); } }; template > class LazyInstance { public: // Do not define a destructor, as doing so makes LazyInstance a // non-POD-struct. We don't want that because then a static initializer will // be created to register the (empty) destructor with atexit() under MSVC, for // example. We handle destruction of the contained Type class explicitly via // the OnExit member function, where needed. // ~LazyInstance() {} Type &Get() { return *Pointer(); } Type *Pointer() { // We will hopefully have fast access when the instance is already created. // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating // at most once, the load is taken out of NeedsInstance() as a fast-path. // The load has acquire memory ordering as a thread which sees // private_instance_ > creating needs to acquire visibility over // the associated data (private_buf_). Pairing Release_Store is in // CompleteLazyInstance(). intptr_t value = private_instance_; if (!value) { // Create the instance in the space provided by |private_buf_|. value = reinterpret_cast(Traits::New(private_buf_.void_data())); CompleteLazyInstance(&private_instance_, value, this, OnExit); } return instance(); } bool operator==(Type *p) { switch private_instance_ { case 0: return p == NULL; default: return p == instance(); } } // Effectively private: member data is only public to allow the linker to // statically initialize it and to maintain a POD class. DO NOT USE FROM // OUTSIDE THIS CLASS. intptr_t private_instance_; // Preallocated space for the Type instance. base::AlignedMemory private_buf_; private: Type *instance() { return reinterpret_cast(private_instance_); } // Adapter function for use with AtExit. This should be called single // threaded, so don't synchronize across threads. // Calling OnExit while the instance is in use by other threads is a mistake. static void OnExit(void *lazy_instance) { LazyInstance *me = reinterpret_cast *>(lazy_instance); Traits::Delete(me->instance()); me->private_instance_ = 0; } }; } // namespace base ================================================ FILE: src/base/macros.h ================================================ #pragma once #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName &); \ TypeName(const TypeName &&); \ void operator=(const TypeName&); #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName(); \ DISALLOW_COPY_AND_ASSIGN(TypeName) template char (&ArraySizeHelper(T (&array)[N]))[N]; #define arraysize(array) (sizeof(ArraySizeHelper(array))) #if defined(COMPILER_GCC) #define GG_VA_COPY(a, b) (va_copy(a, b)) #elif defined(COMPILER_MSVC) #define GG_VA_COPY(a, b) (a = b) #endif #define DCHECK_GE(a, b) assert((a) >= (b)); #define DCHECK_LE(a, b) assert((a) <= (b)); #define DCHECK_NE(a, b) assert((a) != (b)); #define DCHECK_EQ(a, b) assert((a) == (b)); #define CHECK(x) assert(x); ================================================ FILE: src/base/notification_details.h ================================================ #pragma once namespace base { // Do not declare a NotificationDetails directly--use either // "Details(detailsclasspointer)" or // NotificationService::NoDetails(). class NotificationDetails { public: NotificationDetails() : ptr_(NULL) {} NotificationDetails(const NotificationDetails &other) : ptr_(other.ptr_) {} ~NotificationDetails() {} // NotificationDetails can be used as the index for a map; this method // returns the pointer to the current details as an identifier, for use as a // map index. uintptr_t map_key() const { return reinterpret_cast(ptr_); } bool operator!=(const NotificationDetails &other) const { return ptr_ != other.ptr_; } bool operator==(const NotificationDetails &other) const { return ptr_ == other.ptr_; } protected: explicit NotificationDetails(const void *ptr) : ptr_(ptr) {} // Declaring this const allows Details to be used with both T = Foo and // T = const Foo. const void *ptr_; }; template class Details : public NotificationDetails { public: // TODO(erg): Our code hard relies on implicit conversion Details(T *ptr) : NotificationDetails(ptr) {} // NOLINT Details(const NotificationDetails &other) // NOLINT : NotificationDetails(other) {} T *operator->() const { return ptr(); } // The casts here allow this to compile with both T = Foo and T = const Foo. T *ptr() const { return static_cast(const_cast(ptr_)); } }; } // namespace base ================================================ FILE: src/base/notification_observer.h ================================================ #pragma once namespace base { class NotificationDetails; class NotificationSource; // This is the base class for notification observers. When a matching // notification is posted to the notification service, Observe is called. class NotificationObserver { public: virtual void Observe(int type, const NotificationSource &source, const NotificationDetails &details) = 0; protected: virtual ~NotificationObserver() {} }; } // namespace base ================================================ FILE: src/base/notification_registrar.cc ================================================ #include "StdAfx.h" #include "notification_registrar.h" namespace base { struct NotificationRegistrar::Record { bool operator==(const Record &other) const; NotificationObserver *observer; int type; NotificationSource source; }; bool NotificationRegistrar::Record::operator==(const Record &other) const { return observer == other.observer && type == other.type && source == other.source; } NotificationRegistrar::NotificationRegistrar() { // Force the NotificationService to be constructed (if it isn't already). // This ensures the NotificationService will be registered on the // AtExitManager before any objects which access it via NotificationRegistrar. // This in turn means it will be destroyed after these objects, so they will // never try to access the NotificationService after it's been destroyed. NotificationService::current(); } NotificationRegistrar::~NotificationRegistrar() { RemoveAll(); } void NotificationRegistrar::Add(NotificationObserver *observer, int type, const NotificationSource &source) { Record record = {observer, type, source}; registered_.push_back(record); NotificationService::current()->AddObserver(observer, type, source); } void NotificationRegistrar::Remove(NotificationObserver *observer, int type, const NotificationSource &source) { Record record = {observer, type, source}; RecordVector::iterator found = std::find(registered_.begin(), registered_.end(), record); if (found == registered_.end()) { assert(0); //"Trying to remove unregistered observer of type " return; } registered_.erase(found); // This can be NULL if our owner outlives the NotificationService, e.g. if our // owner is a Singleton. NotificationService *service = NotificationService::current(); if (service) service->RemoveObserver(observer, type, source); } void NotificationRegistrar::RemoveAll() { // Early-exit if no registrations, to avoid calling // NotificationService::current. If we've constructed an object with a // NotificationRegistrar member, but haven't actually used the notification // service, and we reach prgram exit, then calling current() below could try // to initialize the service's lazy TLS pointer during exit, which throws // wrenches at things. if (registered_.empty()) return; // This can be NULL if our owner outlives the NotificationService, e.g. if our // owner is a Singleton. NotificationService *service = NotificationService::current(); if (service) { for (size_t i = 0; i < registered_.size(); i++) { service->RemoveObserver(registered_[i].observer, registered_[i].type, registered_[i].source); } } registered_.clear(); } bool NotificationRegistrar::IsEmpty() const { return registered_.empty(); } bool NotificationRegistrar::IsRegistered(NotificationObserver *observer, int type, const NotificationSource &source) { Record record = {observer, type, source}; return std::find(registered_.begin(), registered_.end(), record) != registered_.end(); } } // namespace base ================================================ FILE: src/base/notification_registrar.h ================================================ #pragma once #include #include #include "macros.h" #include "notification_observer.h" #include "notification_service.h" #include "observer_list.h" namespace base { class NotificationObserver; class NotificationSource; // Aids in registering for notifications and ensures that all registered // notifications are unregistered when the class is destroyed. // // The intended use is that you make a NotificationRegistrar member in your // class and use it to register your notifications instead of going through the // notification service directly. It will automatically unregister them for // you. class NotificationRegistrar { public: // This class must not be derived from (we don't have a virtual destructor so // it won't work). Instead, use it as a member in your class. NotificationRegistrar(); ~NotificationRegistrar(); // Wrappers around NotificationService::[Add|Remove]Observer. void Add(NotificationObserver *observer, int type, const NotificationSource &source); void Remove(NotificationObserver *observer, int type, const NotificationSource &source); // Unregisters all notifications. void RemoveAll(); // Returns true if no notifications are registered. bool IsEmpty() const; // Returns true if there is already a registered notification with the // specified details. bool IsRegistered(NotificationObserver *observer, int type, const NotificationSource &source); private: struct Record; // We keep registered notifications in a simple vector. This means we'll do // brute-force searches when removing them individually, but individual // removal is uncommon, and there will typically only be a couple of // notifications anyway. typedef std::vector RecordVector; // Lists all notifications we're currently registered for. RecordVector registered_; DISALLOW_COPY_AND_ASSIGN(NotificationRegistrar); }; } // namespace base ================================================ FILE: src/base/notification_service.cc ================================================ #include "StdAfx.h" #include "lazy_instance.h" #include "notification_observer.h" #include "notification_types.h" #include "notification_service.h" namespace base { namespace { base::LazyInstance lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER; } // namespace NotificationService *NotificationService::current() { return lazy_tls_ptr.Pointer(); } NotificationService::~NotificationService() { for (int i = 0; i < static_cast(observer_counts_.size()); i++) { if (observer_counts_[i] > 0) { //"notification observer(s) leaked " assert(0); } } for (int i = 0; i < static_cast(observers_.size()); i++) { NotificationSourceMap omap = observers_[i]; for (NotificationSourceMap::iterator it = omap.begin(); it != omap.end(); ++it) delete it->second; } } void NotificationService::Notify(int type, const NotificationSource &source, const NotificationDetails &details) { // There's no particular reason for the order in which the different // classes of observers get notified here. // Notify observers of all types and all sources if (HasKey(observers_[NOTIFICATION_ALL], AllSources()) && source != AllSources()) { FOR_EACH_OBSERVER(NotificationObserver, *observers_[NOTIFICATION_ALL][AllSources().map_key()], Observe(type, source, details)); } // Notify observers of all types and the given source if (HasKey(observers_[NOTIFICATION_ALL], source)) { FOR_EACH_OBSERVER(NotificationObserver, *observers_[NOTIFICATION_ALL][source.map_key()], Observe(type, source, details)); } // Notify observers of the given type and all sources if (HasKey(observers_[type], AllSources()) && source != AllSources()) { FOR_EACH_OBSERVER(NotificationObserver, *observers_[type][AllSources().map_key()], Observe(type, source, details)); } // Notify observers of the given type and the given source if (HasKey(observers_[type], source)) { FOR_EACH_OBSERVER(NotificationObserver, *observers_[type][source.map_key()], Observe(type, source, details)); } } // static bool NotificationService::HasKey(const NotificationSourceMap &map, const NotificationSource &source) { return map.find(source.map_key()) != map.end(); } void NotificationService::AddObserver(NotificationObserver *observer, int type, const NotificationSource &source) { // We have gotten some crashes where the observer pointer is NULL. The problem // is that this happens when we actually execute a notification, so have no // way of knowing who the bad observer was. We want to know when this happens // in release mode so we know what code to blame the crash on (since this is // guaranteed to crash later). assert(observer); NotificationObserverList *observer_list; if (HasKey(observers_[type], source)) { observer_list = observers_[type][source.map_key()]; } else { observer_list = new NotificationObserverList; observers_[type][source.map_key()] = observer_list; } observer_list->AddObserver(observer); ++observer_counts_[type]; } void NotificationService::RemoveObserver(NotificationObserver *observer, int type, const NotificationSource &source) { // This is a very serious bug. An object is most likely being deleted on // the wrong thread, and as a result another thread's NotificationServiceImpl // has its deleted pointer in its map. A garbge object will be called in the // future. // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or // other variants as the trait on the object. assert(HasKey(observers_[type], source)); NotificationObserverList *observer_list = observers_[type][source.map_key()]; if (observer_list) { observer_list->RemoveObserver(observer); if (!observer_list->size()) { observers_[type].erase(source.map_key()); delete observer_list; } --observer_counts_[type]; } } } // namespace base ================================================ FILE: src/base/notification_service.h ================================================ #pragma once #include #include "macros.h" #include "observer_list.h" #include "notification_details.h" #include "notification_source.h" namespace base { class NotificationObserver; class NotificationRegistrar; class NotificationService { public: // static static NotificationService *current(); virtual ~NotificationService(); NotificationService() {} // Synchronously posts a notification to all interested observers. // Source is a reference to a NotificationSource object representing // the object originating the notification (can be // NotificationService::AllSources(), in which case // only observers interested in all sources will be notified). // Details is a reference to an object containing additional data about // the notification. If no additional data is needed, NoDetails() is used. // There is no particular order in which the observers will be notified. void Notify(int type, const NotificationSource &source, const NotificationDetails &details); // Returns a NotificationSource that represents all notification sources // (for the purpose of registering an observer for events from all sources). static Source AllSources() { return Source(NULL); } // Returns a NotificationDetails object that represents a lack of details // associated with a notification. (This is effectively a null pointer.) static Details NoDetails() { return Details(NULL); } private: friend class NotificationRegistrar; typedef ObserverList NotificationObserverList; typedef std::map NotificationSourceMap; typedef std::map NotificationObserverMap; typedef std::map NotificationObserverCount; // Convenience function to determine whether a source has a // NotificationObserverList in the given map; static bool HasKey(const NotificationSourceMap &map, const NotificationSource &source); // NOTE: Rather than using this directly, you should use a // NotificationRegistrar. // // Registers a NotificationObserver to be called whenever a matching // notification is posted. Observer is a pointer to an object subclassing // NotificationObserver to be notified when an event matching the other two // parameters is posted to this service. Type is the type of events to be // notified about (or NOTIFICATION_ALL to receive events of all // types). // Source is a NotificationSource object (created using // "Source(pointer)"), if this observer only wants to // receive events from that object, or NotificationService::AllSources() // to receive events from all sources. // // A given observer can be registered only once for each combination of // type and source. If the same object is registered more than once, // it must be removed for each of those combinations of type and source later. // // The caller retains ownership of the object pointed to by observer. void AddObserver(NotificationObserver *observer, int type, const NotificationSource &source); // NOTE: Rather than using this directly, you should use a // NotificationRegistrar. // // Removes the object pointed to by observer from receiving notifications // that match type and source. If no object matching the parameters is // currently registered, this method is a no-op. void RemoveObserver(NotificationObserver *observer, int type, const NotificationSource &source); // Keeps track of the observers for each type of notification. // Until we get a prohibitively large number of notification types, // a simple array is probably the fastest way to dispatch. NotificationObserverMap observers_; // Used to check to see that AddObserver and RemoveObserver calls are // balanced. NotificationObserverCount observer_counts_; static NotificationService *server_; DISALLOW_COPY_AND_ASSIGN(NotificationService); }; } // namespace base ================================================ FILE: src/base/notification_source.h ================================================ #pragma once namespace base { // Do not declare a NotificationSource directly--use either // "Source(sourceclasspointer)" or // NotificationService::AllSources(). class NotificationSource { public: NotificationSource(const NotificationSource &other) : ptr_(other.ptr_) {} ~NotificationSource() {} // NotificationSource can be used as the index for a map; this method // returns the pointer to the current source as an identifier, for use as a // map index. uintptr_t map_key() const { return reinterpret_cast(ptr_); } bool operator!=(const NotificationSource &other) const { return ptr_ != other.ptr_; } bool operator==(const NotificationSource &other) const { return ptr_ == other.ptr_; } protected: explicit NotificationSource(const void *ptr) : ptr_(ptr) {} // Declaring this const allows Source to be used with both T = Foo and // T = const Foo. const void *ptr_; }; template class Source : public NotificationSource { public: // TODO(erg): Our code hard relies on implicit conversion Source(const T *ptr) : NotificationSource(ptr) {} // NOLINT Source(const NotificationSource &other) // NOLINT : NotificationSource(other) {} T *operator->() const { return ptr(); } // The casts here allow this to compile with both T = Foo and T = const Foo. T *ptr() const { return static_cast(const_cast(ptr_)); } }; } // namespace base ================================================ FILE: src/base/notification_types.h ================================================ #pragma once namespace base { enum NotificationType { NOTIFICATION_START = 0, // Special signal value to represent an interest in all notifications. // Not valid when posting a notification. NOTIFICATION_ALL = NOTIFICATION_START, // Add your code here // Custom notifications used by the embedder should start from here. NOTIFICATION_END, }; } // namespace base ================================================ FILE: src/base/observer_list.h ================================================ #pragma once #include "WeakPtr.h" #include #include #include namespace base { template class ObserverListBase : public base::SupportsWeakPtr> { public: ObserverListBase() : remov_count_(0) {} // An iterator class that can be used to access the list of observers. See // also the FOR_EACH_OBSERVER macro defined below. class Iterator { public: Iterator(ObserverListBase &list) : index_(0) { list_ = list.AsWeakPtr(); } ~Iterator() { if (list_.get()) list_->Compact(); } ObserverType *GetNext() { if (!list_.get()) return NULL; ListType &observers = list_->observers_; // Advance if the current element is null size_t max_index = observers.size(); while (index_ < max_index && !observers[index_]) ++index_; return index_ < max_index ? observers[index_++] : NULL; } private: base::WeakPtr> list_; size_t index_; }; // Add an observer to the list. An observer should not be added to // the same list more than once. void AddObserver(ObserverType *obs) { if (std::find(observers_.begin(), observers_.end(), obs) != observers_.end()) { assert(0); return; } observers_.push_back(obs); } // Remove an observer from the list if it is in the list. void RemoveObserver(ObserverType *obs) { typename ListType::iterator it = std::find(observers_.begin(), observers_.end(), obs); if (it != observers_.end()) { *it = NULL; } ++remov_count_; if (remov_count_ > 128) { remov_count_ = 0; Compact(); } } bool HasObserver(ObserverType *observer) const { for (size_t i = 0; i < observers_.size(); ++i) { if (observers_[i] == observer) return true; } return false; } void Clear() { observers_.clear(); } size_t size() const { return observers_.size(); } protected: void Compact() { observers_.erase(std::remove(observers_.begin(), observers_.end(), static_cast(NULL)), observers_.end()); } private: typedef std::vector ListType; ListType observers_; int remov_count_; friend class ObserverListBase::Iterator; DISALLOW_COPY_AND_ASSIGN(ObserverListBase); }; template class ObserverList : public ObserverListBase { public: ObserverList() {} ~ObserverList() { // When check_empty is true, assert that the list is empty on destruction. if (check_empty) { ObserverListBase::Compact(); } } bool might_have_observers() const { return ObserverListBase::size() != 0; } }; #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ do { \ if ((observer_list).might_have_observers()) { \ ObserverListBase::Iterator it_inside_observer_macro( \ observer_list); \ ObserverType *obs; \ while ((obs = it_inside_observer_macro.GetNext()) != NULL) \ obs->func; \ } \ } while (0) } // namespace base ================================================ FILE: src/base/ref_counted.cc ================================================ // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "StdAfx.h" #include "ref_counted.h" namespace base { namespace subtle { RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {} RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {} void RefCountedThreadSafeBase::AddRef() const { InterlockedExchangeAdd(reinterpret_cast(&ref_count_), static_cast(1)); } bool RefCountedThreadSafeBase::Release() const { if (0 == (InterlockedExchangeAdd(reinterpret_cast(&ref_count_), static_cast(-1)) - 1)) { return true; } return false; } bool RefCountedThreadSafeBase::HasOneRef() const { return (ref_count_ == 1); } } // namespace subtle } // namespace base ================================================ FILE: src/base/ref_counted.h ================================================ #pragma once #include #include "macros.h" namespace base { namespace subtle { class RefCountedBase { public: bool HasOneRef() const { return ref_count_ == 1; } protected: RefCountedBase() : ref_count_(0) {} ~RefCountedBase() {} void AddRef() const { ++ref_count_; } // Returns true if the object should self-delete. bool Release() const { if (--ref_count_ == 0) { return true; } return false; } private: mutable int ref_count_; DISALLOW_COPY_AND_ASSIGN(RefCountedBase); }; class RefCountedThreadSafeBase { public: bool HasOneRef() const; protected: RefCountedThreadSafeBase(); ~RefCountedThreadSafeBase(); void AddRef() const; // Returns true if the object should self-delete. bool Release() const; private: mutable int ref_count_; DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); }; } // namespace subtle template class RefCounted : public subtle::RefCountedBase { public: RefCounted() {} void AddRef() const { subtle::RefCountedBase::AddRef(); } void Release() const { if (subtle::RefCountedBase::Release()) { delete static_cast(this); } } protected: ~RefCounted() {} private: DISALLOW_COPY_AND_ASSIGN(RefCounted); }; // Forward declaration. template class RefCountedThreadSafe; // Default traits for RefCountedThreadSafe. Deletes the object when its ref // count reaches 0. Overload to delete it on a different thread etc. template struct DefaultRefCountedThreadSafeTraits { static void Destruct(const T *x) { // Delete through RefCountedThreadSafe to make child classes only need to be // friend with RefCountedThreadSafe instead of this struct, which is an // implementation detail. RefCountedThreadSafe::DeleteInternal( x); } }; // // A thread-safe variant of RefCounted // // class MyFoo : public base::RefCountedThreadSafe { // ... // }; // // If you're using the default trait, then you should add compile time // asserts that no one else is deleting your object. i.e. // private: // friend class base::RefCountedThreadSafe; // ~MyFoo(); template > class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { public: RefCountedThreadSafe() {} void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); } void Release() const { if (subtle::RefCountedThreadSafeBase::Release()) { Traits::Destruct(static_cast(this)); } } protected: ~RefCountedThreadSafe() {} private: friend struct DefaultRefCountedThreadSafeTraits; static void DeleteInternal(const T *x) { delete x; } DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); }; // // A thread-safe wrapper for some piece of data so we can place other // things in scoped_refptrs<>. // template class RefCountedData : public base::RefCountedThreadSafe> { public: RefCountedData() : data() {} RefCountedData(const T &in_value) : data(in_value) {} T data; private: friend class base::RefCountedThreadSafe>; ~RefCountedData() {} }; } // namespace base // // A smart pointer class for reference counted objects. Use this class instead // of calling AddRef and Release manually on a reference counted object to // avoid common memory leaks caused by forgetting to Release an object // reference. Sample usage: // // class MyFoo : public RefCounted { // ... // }; // // void some_function() { // scoped_refptr foo = new MyFoo(); // foo->Method(param); // // |foo| is released when this function returns // } // // void some_other_function() { // scoped_refptr foo = new MyFoo(); // ... // foo = NULL; // explicitly releases |foo| // ... // if (foo) // foo->Method(param); // } // // The above examples show how scoped_refptr acts like a pointer to T. // Given two scoped_refptr classes, it is also possible to exchange // references between the two objects, like so: // // { // scoped_refptr a = new MyFoo(); // scoped_refptr b; // // b.swap(a); // // now, |b| references the MyFoo object, and |a| references NULL. // } // // To make both |a| and |b| in the above example reference the same MyFoo // object, simply use the assignment operator: // // { // scoped_refptr a = new MyFoo(); // scoped_refptr b; // // b = a; // // now, |a| and |b| each own a reference to the same MyFoo object. // } // template class scoped_refptr { public: typedef T element_type; scoped_refptr() : ptr_(NULL) {} scoped_refptr(T *p) : ptr_(p) { if (ptr_) ptr_->AddRef(); } scoped_refptr(const scoped_refptr &r) : ptr_(r.ptr_) { if (ptr_) ptr_->AddRef(); } template scoped_refptr(const scoped_refptr &r) : ptr_(r.get()) { if (ptr_) ptr_->AddRef(); } ~scoped_refptr() { if (ptr_) ptr_->Release(); } T *get() const { return ptr_; } // Allow scoped_refptr to be used in boolean expression // and comparison operations. operator T *() const { return ptr_; } T *operator->() const { assert(ptr_ != NULL); return ptr_; } scoped_refptr &operator=(T *p) { // AddRef first so that self assignment should work if (p) p->AddRef(); T *old_ptr = ptr_; ptr_ = p; if (old_ptr) old_ptr->Release(); return *this; } scoped_refptr &operator=(const scoped_refptr &r) { return *this = r.ptr_; } template scoped_refptr &operator=(const scoped_refptr &r) { return *this = r.get(); } void swap(T **pp) { T *p = ptr_; ptr_ = *pp; *pp = p; } void swap(scoped_refptr &r) { swap(&r.ptr_); } protected: T *ptr_; }; // Handy utility for creating a scoped_refptr out of a T* explicitly without // having to retype all the template arguments template scoped_refptr make_scoped_refptr(T *t) { return scoped_refptr(t); } ================================================ FILE: src/base/scoped_handle.h ================================================ #pragma once #include #include "macros.h" namespace base { class HandleTraits { public: typedef HANDLE Handle; // Closes the handle. static bool CloseHandle(HANDLE handle) { return ::CloseHandle(handle) != FALSE; } // Returns true if the handle value is valid. static bool IsHandleValid(HANDLE handle) { return handle != NULL && handle != INVALID_HANDLE_VALUE; } // Returns NULL handle value. static HANDLE NullHandle() { return NULL; } private: DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits); }; template class ScopedWinHandle { public: typedef typename Traits::Handle Handle; ScopedWinHandle() : handle_(Traits::NullHandle()) {} explicit ScopedWinHandle(Handle handle) : handle_(Traits::NullHandle()) { Set(handle); } ScopedWinHandle &operator=(ScopedWinHandle &other) { if (handle_ != other.handle_ && IsValid()) { Close(); } handle_ = other.Release(); return *this; } ScopedWinHandle(ScopedWinHandle &other) { handle_ = other.Release(); } ~ScopedWinHandle() { Close(); } bool IsValid() const { return Traits::IsHandleValid(handle_); } void Set(Handle handle) { if (handle_ != handle) { Close(); } handle_ = handle; } Handle Get() const { return handle_; } operator Handle() { return handle_; } void Close() { if (Traits::IsHandleValid(handle_)) { if (!Traits::CloseHandle(handle_)) { assert(0); } handle_ = Traits::NullHandle(); } } Handle Release() { Handle tmp = handle_; handle_ = Traits::NullHandle(); return tmp; } private: Handle handle_; }; } // namespace base ================================================ FILE: src/base/string_util_win.h ================================================ #pragma once #include #include #include namespace base { inline int vsnprintf(char *buffer, size_t size, const char *format, ::va_list arguments) { int length = _vsprintf_p(buffer, size, format, arguments); if (length < 0) { if (size > 0) buffer[0] = 0; return _vscprintf_p(format, arguments); } return length; } inline int vswprintf(wchar_t *buffer, size_t size, const wchar_t *format, ::va_list arguments) { int length = _vswprintf_p(buffer, size, format, arguments); if (length < 0) { if (size > 0) buffer[0] = 0; return _vscwprintf_p(format, arguments); } return length; } } // namespace base ================================================ FILE: src/base/stringprintf.cc ================================================ #include "StdAfx.h" #include "stringprintf.h" #include "macros.h" namespace base { inline int vsnprintfT(char *buffer, size_t buf_size, const char *format, ::va_list argptr) { return base::vsnprintf(buffer, buf_size, format, argptr); } inline int vsnprintfT(wchar_t *buffer, size_t buf_size, const wchar_t *format, ::va_list argptr) { return base::vswprintf(buffer, buf_size, format, argptr); } template static void StringAppendVT(StringType *dst, const typename StringType::value_type *format, ::va_list ap) { // First try with a small fixed size buffer. // This buffer size should be kept in sync with StringUtilTest.GrowBoundary // and StringUtilTest.StringPrintfBounds. typename StringType::value_type stack_buf[1024]; va_list ap_copy; GG_VA_COPY(ap_copy, ap); int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy); va_end(ap_copy); if (result >= 0 && result < static_cast(arraysize(stack_buf))) { // It fit. dst->append(stack_buf, result); return; } // Repeatedly increase buffer size until it fits. int mem_length = arraysize(stack_buf); while (true) { if (result < 0) { { return; } // Try doubling the buffer size. mem_length *= 2; } else { // We need exactly "result + 1" characters. mem_length = result + 1; } if (mem_length > 32 * 1024 * 1024) { // That should be plenty, don't try anything larger. This protects // against huge allocations when using vsnprintfT implementations that // return -1 for reasons other than overflow without setting errno. return; } std::vector mem_buf(mem_length); // NOTE: You can only use a va_list once. Since we're in a while loop, we // need to make a new copy each time so we don't use up the original. GG_VA_COPY(ap_copy, ap); result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); va_end(ap_copy); if ((result >= 0) && (result < mem_length)) { // It fit. dst->append(&mem_buf[0], result); return; } } } std::string StringPrintf(const char *format, ...) { ::va_list ap; va_start(ap, format); std::string result; StringAppendV(&result, format, ap); va_end(ap); return result; } std::wstring StringPrintf(const wchar_t *format, ...) { ::va_list ap; va_start(ap, format); std::wstring result; StringAppendV(&result, format, ap); va_end(ap); return result; } void StringAppendV(std::string *dst, const char *format, ::va_list ap) { StringAppendVT(dst, format, ap); } void StringAppendV(std::wstring *dst, const wchar_t *format, ::va_list ap) { StringAppendVT(dst, format, ap); } } // namespace base ================================================ FILE: src/base/stringprintf.h ================================================ #pragma once #include "string_util_win.h" namespace base { std::string StringPrintf(const char *format, ...); std::wstring StringPrintf(const wchar_t *format, ...); void StringAppendV(std::string *dst, const char *format, ::va_list ap); void StringAppendV(std::wstring *dst, const wchar_t *format, ::va_list ap); } // namespace base ================================================ FILE: src/base/thread_local.cc ================================================ #include "StdAfx.h" ================================================ FILE: src/base/thread_local.h ================================================ #pragma once #include "macros.h" namespace base { template class ThreadLocalPointer { public: ThreadLocalPointer() { slot_ = TlsAlloc(); assert(slot_ != TLS_OUT_OF_INDEXES); } ~ThreadLocalPointer() { if (!TlsFree(slot_)) { assert(0); } } Type *Get() { return static_cast(TlsGetValue(slot_)); } void Set(Type *ptr) { if (!TlsSetValue(slot_, const_cast(static_cast(ptr)))) { assert(0); } } private: DWORD slot_; DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer); }; } // namespace base ================================================ FILE: src/base.h ================================================ #pragma once #include "util/util_tools.h" #include "Event/WaitableEvent.h" #include "base/Thread.h" #include "base/WeakPtr.h" #include "base/aligned_memory.h" #include "base/at_exist.h" #include "base/common_threads.h" #include "base/lazy_instance.h" #include "base/notification_registrar.h" ================================================ FILE: src/net/url_fetcher.cc ================================================ #include "StdAfx.h" #include "../base.h" #include "../LogAssist/LogAssist.h" #include "util/system.h" #include "url_fetcher.h" namespace net { #define DEFAULT_WININET_TIMEOUT (20 * 1000) #define USER_AGENT \ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0;)" #define DEFAULT_CONNECT_RETRYS 2 static DWORD WINAPI ThreadProc(LPVOID lpParameter); bool SetTimeout(HINTERNET &hConnect, ULONG uTimeoutSec = DEFAULT_WININET_TIMEOUT) { uTimeoutSec *= 2; bool bret = false; do { if (!::InternetSetOption(hConnect, INTERNET_OPTION_SEND_TIMEOUT, &uTimeoutSec, sizeof(uTimeoutSec))) break; if (!::InternetSetOption(hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &uTimeoutSec, sizeof(uTimeoutSec))) break; uTimeoutSec /= 2; if (!::InternetSetOption(hConnect, INTERNET_OPTION_CONNECT_TIMEOUT, &uTimeoutSec, sizeof(uTimeoutSec))) break; ULONG uRetrys = DEFAULT_CONNECT_RETRYS; if (!::InternetSetOption(hConnect, INTERNET_OPTION_CONNECT_RETRIES, &uRetrys, sizeof(uRetrys))) break; bret = true; } while (false); if (!bret) { PRT_LOG3(DebugSet, ("***failed***")) } return bret; } URLFetcher *URLFetcher::Create(const Params ¶ms, URLFetcherDelegate *delegate) { return (new URLFetcher(params, delegate)); } URLFetcher::Params::Params(const std::string& url) : url_(url), type_(STRING), beginwoffset_(0), endoffset_(0) {} URLFetcher::Params::Params(const std::string &url, std::wstring file_name) : url_(url), name_(file_name), type_(FILE), beginwoffset_(0), endoffset_(0) {} URLFetcher::Params::Params(const std::string &url, DownType type) : url_(url), type_(type), beginwoffset_(0), endoffset_(0) {} void URLFetcher::URLFetcherDelegate::OnURLFetchDownloadProgress( const URLFetcher *source, double cur) {} URLFetcher::URLFetcherDelegate::~URLFetcherDelegate() {} URLFetcher::URLFetcher(const Params ¶ms, URLFetcherDelegate *delegate) : download_url_(params.url_), type_(params.type_), download_file_name_(params.name_), delegate_(delegate), input_state_(this), fdownloadprogress_(0.0), status_(false), event_(true, false), quit_status_(false), beginwoffset_(params.beginwoffset_), endoffset_(params.endoffset_), file_totle_len_(0), support_breakpoint_(true), error_type_(ERROR_NO), already_byteinfile_(0), orginal_begin_offset_(0) { assert(download_url_.length()); io_port_ = base::Threads::Get(Threads::IO)->pump_win()->io_port(); assert(io_port_); } URLFetcher::~URLFetcher() { if (type_ == DownType::FILE && download_file_name_.length()) { SystemCommon::FilePathHelper::DeepDeleteFile(download_file_name_); } } void URLFetcher::Start() { assert(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); base::Threads::Get(Threads::IO) ->PostTask(Bind(this, &URLFetcher::StartInternal)); } void URLFetcher::Stop() { assert(base::MessageLoop::current() == base::Threads::Get(Threads::UI)); delegate_ = nullptr; quit_status_ = true; } void URLFetcher::WillDestroyCurrentMessageLoop() { quit_status_ = true; event_.Wait(); Release(); } void URLFetcher::OnIOCompleted(base::MessagePumpForIO::IOContext* context, DWORD bytes_transfered, DWORD error) { base::Threads::Get(Threads::IO)->RemoveDestructionObserver(this); if (delegate_) { base::Threads::Get(Threads::UI) ->PostTask(Bind(this, &URLFetcher::FetchComplete)); } Release(); } void URLFetcher::FetchComplete() { if (delegate_) { delegate_->OnURLFetchComplete(this); } } void URLFetcher::FetchDownloadProgress(double cur) { fdownloadprogress_ = cur; if (delegate_) { delegate_->OnURLFetchDownloadProgress(this, fdownloadprogress_); } } void URLFetcher::StartInternal() { AddRef(); AddRef(); base::Threads::Get(Threads::IO)->AddDestructionObserver(this); if (!QueueUserWorkItem(ThreadProc, this, WT_EXECUTEDEFAULT)) { Release(); base::Threads::Get(Threads::IO)->RemoveDestructionObserver(this); status_ = false; base::Threads::Get(Threads::UI) ->PostTask(Bind(this, &URLFetcher::FetchComplete)); Release(); return; } } void URLFetcher::StopInternal() { } DWORD WINAPI ThreadProc(LPVOID lpParameter) { URLFetcher *const url_fetcher = reinterpret_cast(lpParameter); bool bResult = false; const std::string &url = url_fetcher->durl(); switch (url_fetcher->type()) { case URLFetcher::STRING: { std::string &contents = url_fetcher->data(); HINTERNET hSession = ::InternetOpenA( USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession) { SetTimeout(hSession); HINTERNET hRequest = ::InternetOpenUrlA(hSession, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, NULL); if (hRequest) { TCHAR szBuffer[256] = {0}; DWORD dwSize = _countof(szBuffer); if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize, NULL) && _tcscmp(szBuffer, _T("200")) == 0) { for (;;) { if (url_fetcher->quit_status()) { break; } char btBuffer[1024 + 1] = {0}; DWORD dwFileLength = 0; if (!::InternetReadFile(hRequest, btBuffer, 1024, &dwFileLength)) { break; } if (dwFileLength == 0) { bResult = true; break; } btBuffer[dwFileLength] = NULL; contents += btBuffer; } } ::InternetCloseHandle(hRequest); } ::InternetCloseHandle(hSession); } } break; case URLFetcher::FILE: { HINTERNET hSession = ::InternetOpenA( USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession) { SetTimeout(hSession); HINTERNET hRequest = ::InternetOpenUrlA(hSession, url.c_str(), NULL, 0, 0, NULL); if (hRequest) { TCHAR szBuffer[256] = {0}; DWORD dwSize = _countof(szBuffer); DWORD dwContentLength = -1; DWORD dwAlreadyReadLen = 0; if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize, NULL) && _tcscmp(szBuffer, _T("200")) == 0) { dwSize = sizeof(dwContentLength); BOOL issucc = HttpQueryInfo( hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLength, &dwSize, NULL); if (!issucc || -1 == dwContentLength) { url_fetcher->error_type_ = URLFetcher::ERROR_SERV; ::InternetCloseHandle(hRequest); ::InternetCloseHandle(hSession); break; } std::wstring filepath = url_fetcher->download_file_name(); HANDLE hFile = ::CreateFileW(filepath.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { do { SetFilePointer(hFile, dwContentLength, NULL, FILE_BEGIN); if (SetEndOfFile(hFile) == FALSE) { url_fetcher->error_type_ = URLFetcher::DISK_NO_SPACE; break; } SetFilePointer(hFile, 0, NULL, FILE_BEGIN); DWORD dwSizePost = 0; for (;;) { if (url_fetcher->quit_status()) { break; } char btBuffer[1024 * 8 + 1] = {0}; DWORD dwFileLength = 0; if (!::InternetReadFile(hRequest, btBuffer, 1024 * 8, &dwFileLength)) { break; } dwAlreadyReadLen += dwFileLength; dwSizePost += dwFileLength; if (dwFileLength == 0) { base::Threads::Get(Threads::UI) ->PostTask(Bind(url_fetcher, &URLFetcher::FetchDownloadProgress, 1.0)); bResult = true; break; } DWORD dwWriteLength = 0; ::WriteFile(hFile, btBuffer, dwFileLength, &dwWriteLength, NULL); url_fetcher->already_byteinfile_ += dwFileLength; if (dwSizePost > 1024 * 8) { dwSizePost = 0; double cur = static_cast(dwAlreadyReadLen) / dwContentLength; base::Threads::Get(Threads::UI) ->PostTask(Bind(url_fetcher, &URLFetcher::FetchDownloadProgress, cur)); } } } while (false); ::CloseHandle(hFile); } } ::InternetCloseHandle(hRequest); } ::InternetCloseHandle(hSession); } } break; case URLFetcher::TEST_BREAKPOINT_SUPPORT: { if (!url_fetcher->support_breakpoint_) { url_fetcher->error_type_ = URLFetcher::NOT_SUPPORT_BREAKPOINT; break; } HINTERNET hSession = NULL; hSession = ::InternetOpenA(USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession) { SetTimeout(hSession); char vheaders[200] = {0}; DWORD dwZero = 0; _snprintf_s(vheaders, 200, _TRUNCATE, "Range:bytes=%u-\r\n", dwZero); HINTERNET hRequest = ::InternetOpenUrlA(hSession, url.c_str(), vheaders, -1L, 0, NULL); if (hRequest) { TCHAR szBuffer[256] = {0}; DWORD dwSize = _countof(szBuffer); if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize, NULL) && _tcscmp(szBuffer, _T("206")) == 0) { DWORD dwContentLength = -1; DWORD dwSize = sizeof(dwContentLength); BOOL issucc = HttpQueryInfo( hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLength, &dwSize, NULL); if (FALSE == issucc || -1 == dwContentLength) { url_fetcher->error_type_ = URLFetcher::ERROR_SERV; ::InternetCloseHandle(hRequest); ::InternetCloseHandle(hSession); break; } url_fetcher->file_totle_len_ = dwContentLength; bResult = true; } else { url_fetcher->support_breakpoint_ = false; } ::InternetCloseHandle(hRequest); } ::InternetCloseHandle(hSession); } } break; default: assert(0); break; } url_fetcher->set_status(bResult); PostQueuedCompletionStatus( url_fetcher->io_port(), (url_fetcher->type() == URLFetcher::STRING) ? url_fetcher->data().length() : 0, reinterpret_cast( static_cast(url_fetcher)), &url_fetcher->state().context.overlapped); url_fetcher->event().Signal(); url_fetcher->Release(); return 0; } } // namespace net ================================================ FILE: src/net/url_fetcher.h ================================================ #pragma once #include "../Event/WaitableEvent.h" #include "../base/MessageLoop.h" #include "../base/MessagePumpWin.h" #include "../base/macros.h" #include "../base/notification_observer.h" #include "../base/notification_registrar.h" namespace net { class URLFetcher : public base::MessagePumpForIO::IOHandler, public base::MessageLoop::DestructionObserver, public base::RefCountedThreadSafe { public: class URLFetcherDelegate { public: virtual void OnURLFetchComplete(const URLFetcher *source) = 0; virtual void OnURLFetchDownloadProgress(const URLFetcher *source, double cur); virtual ~URLFetcherDelegate(); }; enum ErrorType { ERROR_NO, DISK_NO_SPACE, FILE_NO_EXIST, NOT_SUPPORT_BREAKPOINT, ERROR_SERV, }; enum DownType { STRING, FILE, TEST_BREAKPOINT_SUPPORT, }; struct Params { explicit Params(const std::string& url); explicit Params(const std::string &url, std::wstring file_name); explicit Params(const std::string &url, DownType type); std::string url_; std::wstring name_; DownType type_; DWORD beginwoffset_; DWORD endoffset_; }; struct State { explicit State(URLFetcher *fetcher) { context.handler = fetcher; } ~State() {} base::MessagePumpForIO::IOContext context; }; static URLFetcher *Create(const Params ¶ms, URLFetcherDelegate *delegate); ~URLFetcher(); void Start(); void Stop(); virtual void WillDestroyCurrentMessageLoop() override; virtual void OnIOCompleted(base::MessagePumpForIO::IOContext *context, DWORD bytes_transfered, DWORD error) override; void FetchComplete(); void FetchDownloadProgress(double cur); void set_download_url(const std::string &url) { download_url_ = url; } void set_file_loadpath(const std::wstring &path) { download_file_name_ = path; } void set_status(const bool status) { status_ = status; } bool status() const { return status_; } bool quit_status() { return quit_status_; } std::string& data() { return data_; } const std::string& durl() { return download_url_; } const std::wstring& download_file_name() { return download_file_name_; } HANDLE io_port() { return io_port_; } base::WaitableEvent& event() { return event_; } State &state() { return input_state_; } DownType type() { return type_; } private: explicit URLFetcher(const Params ¶ms, URLFetcherDelegate *delegate); void StartInternal(); void StopInternal(); bool status_; bool quit_status_; std::string data_; std::string download_url_; std::wstring download_file_name_; HANDLE io_port_; State input_state_; DownType type_; URLFetcherDelegate *delegate_; base::WaitableEvent event_; public: ErrorType error_type_; double fdownloadprogress_; bool support_breakpoint_; DWORD already_byteinfile_; DWORD file_totle_len_; DWORD beginwoffset_; DWORD endoffset_; DWORD orginal_begin_offset_; }; } // namespace net ================================================ FILE: src/res/xml/EngUIAgreement.xml ================================================  ================================================ FILE: src/res/xml/EngUICannotDown.xml ================================================