[
  {
    "path": ".gitignore",
    "content": "# Compiled Static libraries\n\n.vs/\n0utPut/\nDebug/\nRelease/\n\n*.aps\n*.vcxproj.user\n*.vcproj.user\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) <year> <copyright holders>\n\n996 License Version 1.0 (Draft)\n\nPermission 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:\n\n1. The individual or the legal entity must conspicuously display, without modification, this License on each redistributed or derivative copy of the Licensed Work.\n\n2. 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.\n\n3. 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.\n\nTHE 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.\n"
  },
  {
    "path": "Microsoft_VC++2022.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.7.34031.279\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Downloader\", \"src\\App.vcxproj\", \"{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Debug|x86.Build.0 = Debug|Win32\n\t\t{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Release|x86.ActiveCfg = Release|Win32\n\t\t{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {8F0590AF-8B95-4D3A-B92B-2D153EA34AB5}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README-zh.md",
    "content": "# 当必火🔥——Windows 平台的下载器\n\n🚀 当必火🔥——让程序下载和安装变得简单！\n\n![](./assets/20240525104340.png)\n\n## 特点:\n\n- Windows C++ 原生代码（std:c++14）\n- 超小体积——Release 版本只有 400kb 左右\n- 使用 WTL，不依赖其他库\n- 只需修改一个文件，就可以编译成自己的下载器\n- 自绘界面，对懂 C++ 的高度可定制\n- 下载一个 Zip 文件，解压然后安装到指定目录，并创建桌面快捷方式\n\n## 编译\n\nVisual Studio 2022\n\n## 使用:\n\n代码上，只需改一个 cpp 文件，重新编译即可。\n\n编辑 src/Global.cpp。如果用 VC++ 打开，查看 Source Files/Global.cpp。\n\n```c++\n/// <configuration>\n/// Set the following string and then compile\n\n// Query zip download link\nstd::string CGlobal::downloadurl_ = \"http://127.0.0.1:5001/download-url\";\n// directory name\nstd::string CGlobal::appDirName_ = \"MyeXeAppDir\";\n// Exe file name such as eXeScope.exe or a relative path such as bin\\\\eXeScope.exe\nstd::string CGlobal::appname_ = \"eXeScope.exe\";\n// shortcut file name\nstd::string CGlobal::shortcutname_ = \"eXeScope\";\n// Link to open after installation\nstd::string CGlobal::openurl_ = \"https://github.com/sinajia/Downloader\";\n\n/// </configuration>\n```\n\n需要修改上面五个变量。它们代表的意义如下：\n\ndownloadurl_，Get 请求地址。获取真正的 Zip 文件地址。\n\nappDirName_，代表程序安装的文件夹的名称，这个文件夹由本下载器自动创建。\n\nappname_，exe 文件的名称。例如 eXeScope.exe 或者 bin\\\\eXeScope.exe。\n\nshortcutname_，桌面快捷方式的名称。\n\nopenurl_，可选。安装过程中，自动调用系统默认浏览器打开的网址，可以是空字符串\"\"。如果为空字符串，则没有打开动作。\n\n使用本下载器，需要有一个服务器端，必须实现上述的 Get 请求。以下代码是用 node.js 写的示例代码：\n\n```js\nconst express = require('express')\nconst app = express()\n\napp.get('/download-url', (req, res) => {\n  res.json({\n    downloadUrl: 'http://xxxx.com/zipfile.zip',\n  })\n})\n\nconst server = require('http').createServer(app)\n\nserver.listen(5001, '0.0.0.0', function (err) {\n  console.log('running')\n})\n```\n\n本下载器会自动解析这个 Get 请求返回的 Json 字符串。字段 downloadUrl 是必须的，表示真正的 Zip 文件的地址。Zip 文件就是程序的压缩包。\n\n关于程序压缩包，可以参看 example\\eXeScope.zip。\n\n你还应该替换 App.ico，这个文件在 src\\res。将 App.ico 替换为你自己程序的 ico 文件。当然，文件名必须还是 App.ico。\n\n除此之外，你需要将 src\\res\\png 里面 1.png, 2.png, 3.png, 4.png, 5.png, 6.png 替换一下。这六张 png 图片是六张轮播图，替换成自己的。要求图片尺寸都是 480 × 240，png 格式。\n\n做完这些，重新编译，然后启动！\n\n## Star 一下\n\n本程序的创作耗费了很多精力，请动动发财的小手点个 Star ~~~///(^v^)\\\\\\~~~\n\n## 赞助\n\n本程序的创作耗费了我很多时间和精力，如果也帮到了你，请动动发财的小手，支持一下，让我更有动力更新 ❤️\n\nUSDT(TRC20)\n\nTYWsj6oBb1zqkhMvYhXBuFYJD21dVWzXFL\n"
  },
  {
    "path": "README.md",
    "content": "# Win32 Native Downloader\n\n🚀 A fast, tiny, native win32 downloader & installer for Windows platform.\n\n![](./assets/20240525104340.png)\n\n[中文介绍](./README-zh.md)\n\n## Features:\n\n- Pure C++ (std:c++14).\n- Tiny, the release version is only 414kb.\n- Without any other dependencies.\n- Just modify a little, very easy to use.\n- Very beautiful UI framework, highly customizable.\n- Download a zip file and install it to the specified directory.\n\n## Compile and Build\n\nVisual Studio 2022\n\n## How to use:\n\nYou only need to modify one file and recompile it to get a customized downloader.\n\nEdit file src/Global.cpp (Source Files/Global.cpp in VC++).\n\n```c++\n/// <configuration>\n/// Set the following string and then compile\n\n// Query zip download link\nstd::string CGlobal::downloadurl_ = \"http://127.0.0.1:5001/download-url\";\n// directory name\nstd::string CGlobal::appDirName_ = \"MyeXeAppDir\";\n// Exe file name such as eXeScope.exe or a relative path such as bin\\\\eXeScope.exe\nstd::string CGlobal::appname_ = \"eXeScope.exe\";\n// shortcut file name\nstd::string CGlobal::shortcutname_ = \"eXeScope\";\n// Link to open after installation\nstd::string CGlobal::openurl_ = \"https://github.com/sinajia/Downloader\";\n\n/// </configuration>\n```\n\nYou should modify the values of the above five variables.\n\nThe 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.\n\nHere is an example of a server side (Node.js)\n\n```js\nconst express = require('express')\nconst app = express()\n\napp.get('/download-url', (req, res) => {\n  res.json({\n    downloadUrl: 'http://xxxx.com/zipfile.zip',\n  })\n})\n\nconst server = require('http').createServer(app)\n\nserver.listen(5001, '0.0.0.0', function (err) {\n  console.log('running')\n})\n```\n\n\"downloadUrl\" is the real installation package link. `The package must be a zip file.`\n\nYou 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.\n\nIf you have done the above, please recompile it. Start now !\n\n## Support\n\nHelp support the development and maintenance of the software ❤️\n\nUSDT(TRC20)\n\nTYWsj6oBb1zqkhMvYhXBuFYJD21dVWzXFL\n"
  },
  {
    "path": "WTL/atlapp.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLAPP_H__\n#define __ATLAPP_H__\n\n#pragma once\n\n#ifndef __cplusplus\n\t#error WTL requires C++ compilation (use a .cpp suffix)\n#endif\n\n#ifndef __ATLBASE_H__\n\t#error atlapp.h requires atlbase.h to be included first\n#endif\n\n#ifndef _WIN32_WCE\n  #if (WINVER < 0x0400)\n\t#error WTL requires Windows version 4.0 or higher\n  #endif\n\n  #if (_WIN32_IE < 0x0300)\n\t#error WTL requires IE version 3.0 or higher\n  #endif\n#endif\n\n#ifdef _ATL_NO_COMMODULE\n\t#error WTL requires that _ATL_NO_COMMODULE is not defined\n#endif\n\n#if (_ATL_VER >= 0x0900) && defined(_ATL_MIN_CRT)\n\t#error _ATL_MIN_CRT is not supported with ATL 9.0 and higher\n#endif\n\n#if defined(_WIN32_WCE) && defined(_ATL_MIN_CRT)\n\t#pragma message(\"Warning: WTL for Windows CE doesn't use _ATL_MIN_CRT\")\n#endif\n\n#include <limits.h>\n#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE)\n  #include <process.h>\t// for _beginthreadex\n#endif\n\n#if (_ATL_VER < 0x0800) && !defined(_DEBUG)\n  #include <stdio.h>\n#endif\n\n#include <commctrl.h>\n#ifndef _WIN32_WCE\n  #pragma comment(lib, \"comctl32.lib\")\n#endif\n\n#if defined(_SYSINFOAPI_H_) && defined(NOT_BUILD_WINDOWS_DEPRECATE) && (_WIN32_WINNT >= 0x0501)\n  #include <VersionHelpers.h>\n#endif\n\n#ifndef _WIN32_WCE\n  #include \"atlres.h\"\n#else // CE specific\n  #include \"atlresce.h\"\n#endif // _WIN32_WCE\n\n// We need to disable this warning because of template class arguments\n#pragma warning(disable: 4127)\n\n#if (_ATL_VER >= 0x0900) && !defined(_SECURE_ATL)\n  #define _SECURE_ATL\t1\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// WTL version number\n\n#define _WTL_VER\t0x0910\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CMessageFilter\n// CIdleHandler\n// CMessageLoop\n//\n// CAppModule\n// CServerAppModule\n//\n// CRegKeyEx\n//\n// Global functions:\n//   AtlGetDefaultGuiFont()\n//   AtlCreateControlFont()\n//   AtlCreateBoldFont()\n//   AtlInitCommonControls()\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global support for Windows CE\n\n#ifdef _WIN32_WCE\n\n#ifndef SW_SHOWDEFAULT\n  #define SW_SHOWDEFAULT\tSW_SHOWNORMAL\n#endif // !SW_SHOWDEFAULT\n\n// These get's OR-ed in a constant and will have no effect.\n// Defining them reduces the number of #ifdefs required for CE.\n#define LR_DEFAULTSIZE      0\n#define LR_LOADFROMFILE     0\n\n#ifndef SM_CXCURSOR\n  #define SM_CXCURSOR             13\n#endif\n#ifndef SM_CYCURSOR\n  #define SM_CYCURSOR             14\n#endif\n\ninline BOOL IsMenu(HMENU hMenu)\n{\n\tMENUITEMINFO mii = { sizeof(MENUITEMINFO) };\n\t::SetLastError(0);\n\tBOOL bRet = ::GetMenuItemInfo(hMenu, 0, TRUE, &mii);\n\tif(!bRet)\n\t\tbRet = (::GetLastError() != ERROR_INVALID_MENU_HANDLE) ? TRUE : FALSE;\n\treturn bRet;\n}\n\n#if (_WIN32_WCE >= 410)\nextern \"C\" void WINAPI ListView_SetItemSpacing(HWND hwndLV, int iHeight);\n#endif // (_WIN32_WCE >= 410)\n\ninline int MulDiv(IN int nNumber, IN int nNumerator, IN int nDenominator)\n{\n\t__int64 multiple = nNumber * nNumerator;\n\treturn static_cast<int>(multiple / nDenominator);\n}\n\n#if (_ATL_VER >= 0x0800)\n\n#ifndef _WTL_KEEP_WS_OVERLAPPEDWINDOW\n  #ifdef WS_OVERLAPPEDWINDOW\n    #undef WS_OVERLAPPEDWINDOW\n    #define WS_OVERLAPPEDWINDOW\t0\n  #endif // WS_OVERLAPPEDWINDOW\n#endif // !_WTL_KEEP_WS_OVERLAPPEDWINDOW\n\n#ifndef RDW_FRAME\n  #define RDW_FRAME\t0\n#endif // !RDW_FRAME\n\n#ifndef WM_WINDOWPOSCHANGING\n  #define WM_WINDOWPOSCHANGING\t0\n#endif // !WM_WINDOWPOSCHANGING\n\n#define FreeResource(x)\n#define UnlockResource(x)\n\nnamespace ATL\n{\n  inline HRESULT CComModule::RegisterClassObjects(DWORD /*dwClsContext*/, DWORD /*dwFlags*/) throw()\n  { return E_NOTIMPL; }\n  inline HRESULT CComModule::RevokeClassObjects() throw()\n  { return E_NOTIMPL; }\n}; // namespace ATL\n\n#ifndef lstrlenW\n  #define lstrlenW\t(int)ATL::lstrlenW\n#endif // lstrlenW\n\ninline int WINAPI lstrlenA(LPCSTR lpszString)\n{ return ATL::lstrlenA(lpszString); }\n\n#ifdef lstrcpyn\n  #undef lstrcpyn\n  #define lstrcpyn\tATL::lstrcpynW\n#endif // lstrcpyn\n\n#ifndef SetWindowLongPtrW\n  inline LONG_PTR tmp_SetWindowLongPtrW( HWND hWnd, int nIndex, LONG_PTR dwNewLong )\n  {\n\treturn( ::SetWindowLongW( hWnd, nIndex, LONG( dwNewLong ) ) );\n  }\n  #define SetWindowLongPtrW tmp_SetWindowLongPtrW\n#endif\n\n#ifndef GetWindowLongPtrW\n  inline LONG_PTR tmp_GetWindowLongPtrW( HWND hWnd, int nIndex )\n  {\n\treturn( ::GetWindowLongW( hWnd, nIndex ) );\n  }\n  #define GetWindowLongPtrW tmp_GetWindowLongPtrW\n#endif\n\n#ifndef LongToPtr\n  #define LongToPtr(x) ((void*)x)\n#endif\n\n#ifndef PtrToInt\n  #define PtrToInt( p ) ((INT)(INT_PTR) (p) )\n#endif\n\n#else // !(_ATL_VER >= 0x0800)\n\n#ifdef lstrlenW\n  #undef lstrlenW\n  #define lstrlenW (int)::wcslen\n#endif // lstrlenW\n\n#define lstrlenA (int)strlen\n\n#ifndef lstrcpyn\n  inline LPTSTR lstrcpyn(LPTSTR lpstrDest, LPCTSTR lpstrSrc, int nLength)\n  {\n\tif(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0)\n\t\treturn NULL;\n\tint nLen = __min(lstrlen(lpstrSrc), nLength - 1);\n\tLPTSTR lpstrRet = (LPTSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(TCHAR));\n\tlpstrDest[nLen] = 0;\n\treturn lpstrRet;\n  }\n#endif // !lstrcpyn\n\n#ifndef lstrcpynW\n  inline LPWSTR lstrcpynW(LPWSTR lpstrDest, LPCWSTR lpstrSrc, int nLength)\n  {\n\treturn lstrcpyn(lpstrDest, lpstrSrc, nLength);   // WinCE is Unicode only\n  }\n#endif // !lstrcpynW\n\n#ifndef lstrcpynA\n  inline LPSTR lstrcpynA(LPSTR lpstrDest, LPCSTR lpstrSrc, int nLength)\n  {\n\tif(lpstrDest == NULL || lpstrSrc == NULL || nLength <= 0)\n\t\treturn NULL;\n\tint nLen = __min(lstrlenA(lpstrSrc), nLength - 1);\n\tLPSTR lpstrRet = (LPSTR)memcpy(lpstrDest, lpstrSrc, nLen * sizeof(char));\n\tlpstrDest[nLen] = 0;\n\treturn lpstrRet;\n  }\n#endif // !lstrcpyn\n\n#ifdef TrackPopupMenu\n  #undef TrackPopupMenu\n#endif // TrackPopupMenu\n\n#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \\\nstatic CWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic CWndClassInfo wc = \\\n\t{ \\\n\t\t{ style, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \\\n\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\") \\\n\t}; \\\n\treturn wc; \\\n}\n\n#ifndef _MAX_FNAME\n  #define _MAX_FNAME\t_MAX_PATH\n#endif // _MAX_FNAME\n\n#if (_WIN32_WCE < 400)\n  #define MAKEINTATOM(i)  (LPTSTR)((ULONG_PTR)((WORD)(i)))\n#endif // (_WIN32_WCE < 400)\n\n#if (_WIN32_WCE < 410)\n  #define WHEEL_PAGESCROLL                (UINT_MAX)\n  #define WHEEL_DELTA                     120\n#endif // (_WIN32_WCE < 410)\n\n#ifdef DrawIcon\n  #undef DrawIcon\n#endif\n\n#ifndef VARCMP_LT\n  #define VARCMP_LT   0\n#endif\n#ifndef VARCMP_EQ\n  #define VARCMP_EQ   1\n#endif\n#ifndef VARCMP_GT\n  #define VARCMP_GT   2\n#endif\n#ifndef VARCMP_NULL\n  #define VARCMP_NULL 3\n#endif\n\n#ifndef RDW_ALLCHILDREN\n  #define RDW_ALLCHILDREN   0\n#endif\n\n#endif // !(_ATL_VER >= 0x0800)\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global support for using original VC++ 6.0 headers with WTL\n\n#if (_MSC_VER < 1300) && !defined(_WIN32_WCE)\n  #ifndef REG_QWORD\n    #define REG_QWORD\t11\n  #endif\n\n  #ifndef BS_PUSHBOX\n    #define BS_PUSHBOX\t0x0000000AL\n  #endif\n\n  struct __declspec(uuid(\"000214e6-0000-0000-c000-000000000046\")) IShellFolder;\n  struct __declspec(uuid(\"000214f9-0000-0000-c000-000000000046\")) IShellLinkW;\n  struct __declspec(uuid(\"000214ee-0000-0000-c000-000000000046\")) IShellLinkA;\n#endif // (_MSC_VER < 1300) && !defined(_WIN32_WCE)\n\n#ifndef _ATL_NO_OLD_HEADERS_WIN64\n#if !defined(_WIN64) && (_ATL_VER < 0x0700)\n\n  #ifndef PSM_INSERTPAGE\n    #define PSM_INSERTPAGE          (WM_USER + 119)\n  #endif // !PSM_INSERTPAGE\n\n  #ifndef GetClassLongPtr\n    #define GetClassLongPtrA   GetClassLongA\n    #define GetClassLongPtrW   GetClassLongW\n    #ifdef UNICODE\n      #define GetClassLongPtr  GetClassLongPtrW\n    #else\n      #define GetClassLongPtr  GetClassLongPtrA\n    #endif // !UNICODE\n  #endif // !GetClassLongPtr\n\n  #ifndef GCLP_HICONSM\n    #define GCLP_HICONSM        (-34)\n  #endif // !GCLP_HICONSM\n\n  #ifndef GetWindowLongPtr\n    #define GetWindowLongPtrA   GetWindowLongA\n    #define GetWindowLongPtrW   GetWindowLongW\n    #ifdef UNICODE\n      #define GetWindowLongPtr  GetWindowLongPtrW\n    #else\n      #define GetWindowLongPtr  GetWindowLongPtrA\n    #endif // !UNICODE\n  #endif // !GetWindowLongPtr\n\n  #ifndef SetWindowLongPtr\n    #define SetWindowLongPtrA   SetWindowLongA\n    #define SetWindowLongPtrW   SetWindowLongW\n    #ifdef UNICODE\n      #define SetWindowLongPtr  SetWindowLongPtrW\n    #else\n      #define SetWindowLongPtr  SetWindowLongPtrA\n    #endif // !UNICODE\n  #endif // !SetWindowLongPtr\n\n  #ifndef GWLP_WNDPROC\n    #define GWLP_WNDPROC        (-4)\n  #endif\n  #ifndef GWLP_HINSTANCE\n    #define GWLP_HINSTANCE      (-6)\n  #endif\n  #ifndef GWLP_HWNDPARENT\n    #define GWLP_HWNDPARENT     (-8)\n  #endif\n  #ifndef GWLP_USERDATA\n    #define GWLP_USERDATA       (-21)\n  #endif\n  #ifndef GWLP_ID\n    #define GWLP_ID             (-12)\n  #endif\n\n  #ifndef DWLP_MSGRESULT\n    #define DWLP_MSGRESULT  0\n  #endif\n\n  typedef long LONG_PTR;\n  typedef unsigned long ULONG_PTR;\n  typedef ULONG_PTR DWORD_PTR;\n\n  #ifndef HandleToUlong\n    #define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) )\n  #endif\n  #ifndef HandleToLong\n    #define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )\n  #endif\n  #ifndef LongToHandle\n    #define LongToHandle( h) ((HANDLE)(LONG_PTR) (h))\n  #endif\n  #ifndef PtrToUlong\n    #define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )\n  #endif\n  #ifndef PtrToLong\n    #define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )\n  #endif\n  #ifndef PtrToUint\n    #define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )\n  #endif\n  #ifndef PtrToInt\n    #define PtrToInt( p ) ((INT)(INT_PTR) (p) )\n  #endif\n  #ifndef PtrToUshort\n    #define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )\n  #endif\n  #ifndef PtrToShort\n    #define PtrToShort( p ) ((short)(LONG_PTR)(p) )\n  #endif\n  #ifndef IntToPtr\n    #define IntToPtr( i )    ((VOID *)(INT_PTR)((int)i))\n  #endif\n  #ifndef UIntToPtr\n    #define UIntToPtr( ui )  ((VOID *)(UINT_PTR)((unsigned int)ui))\n  #endif\n  #ifndef LongToPtr\n    #define LongToPtr( l )   ((VOID *)(LONG_PTR)((long)l))\n  #endif\n  #ifndef ULongToPtr\n    #define ULongToPtr( ul )  ((VOID *)(ULONG_PTR)((unsigned long)ul))\n  #endif\n\n#endif // !defined(_WIN64) && (_ATL_VER < 0x0700)\n#endif // !_ATL_NO_OLD_HEADERS_WIN64\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global support for using original VC++ 7.x headers with WTL\n\n#if (_MSC_VER >= 1300) && (_MSC_VER < 1400)\n\n  #ifndef BS_PUSHBOX\n    #define BS_PUSHBOX\t0x0000000AL\n  #endif\n\n  #pragma warning(disable: 4244)   // conversion from 'type1' to 'type2', possible loss of data\n\n#endif // (_MSC_VER >= 1300) && (_MSC_VER < 1400)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global support for old SDK headers\n\n#ifndef BTNS_BUTTON\n  #define BTNS_BUTTON\tTBSTYLE_BUTTON\n#endif\n\n#ifndef BTNS_SEP\n  #define BTNS_SEP\tTBSTYLE_SEP\n#endif\n\n#ifndef BTNS_CHECK\n  #define BTNS_CHECK\tTBSTYLE_CHECK\n#endif\n\n#ifndef BTNS_GROUP\n  #define BTNS_GROUP\tTBSTYLE_GROUP\n#endif\n\n#ifndef BTNS_CHECKGROUP\n  #define BTNS_CHECKGROUP\tTBSTYLE_CHECKGROUP\n#endif\n\n#if (_WIN32_IE >= 0x0300)\n  #ifndef BTNS_DROPDOWN\n    #define BTNS_DROPDOWN\tTBSTYLE_DROPDOWN\n  #endif\n#endif\n\n#if (_WIN32_IE >= 0x0400)\n  #ifndef BTNS_AUTOSIZE\n    #define BTNS_AUTOSIZE\tTBSTYLE_AUTOSIZE\n  #endif\n\n  #ifndef BTNS_NOPREFIX\n    #define BTNS_NOPREFIX\tTBSTYLE_NOPREFIX\n  #endif\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global support for SecureHelper functions\n\n#ifndef _TRUNCATE\n  #define _TRUNCATE ((size_t)-1)\n#endif\n\n#ifndef _ERRCODE_DEFINED\n  #define _ERRCODE_DEFINED\n  typedef int errno_t;\n#endif\n\n#ifndef _SECURECRT_ERRCODE_VALUES_DEFINED\n  #define _SECURECRT_ERRCODE_VALUES_DEFINED\n  #define EINVAL          22\n  #define STRUNCATE       80\n#endif\n\n#ifndef _countof\n  #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Miscellaneous global support\n\n// define useful macros from winuser.h\n#ifndef IS_INTRESOURCE\n  #define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)\n#endif // IS_INTRESOURCE\n\n// protect template members from windowsx.h macros\n#ifdef _INC_WINDOWSX\n  #undef SubclassWindow\n#endif // _INC_WINDOWSX\n\n// define useful macros from windowsx.h\n#ifndef GET_X_LPARAM\n  #define GET_X_LPARAM(lParam)\t((int)(short)LOWORD(lParam))\n#endif\n#ifndef GET_Y_LPARAM\n  #define GET_Y_LPARAM(lParam)\t((int)(short)HIWORD(lParam))\n#endif\n\n// Dummy structs for compiling with /CLR\n#if (_MSC_VER >= 1300) && defined(_MANAGED)\n  __if_not_exists(_IMAGELIST::_IMAGELIST) { struct _IMAGELIST { }; }\n  __if_not_exists(_TREEITEM::_TREEITEM) { struct _TREEITEM { }; }\n  __if_not_exists(_PSP::_PSP) { struct _PSP { }; }\n#endif\n\n// Define ATLVERIFY macro for ATL3\n#if (_ATL_VER < 0x0700)\n  #ifndef ATLVERIFY\n    #ifdef _DEBUG\n      #define ATLVERIFY(expr) ATLASSERT(expr)\n    #else\n      #define ATLVERIFY(expr) (expr)\n    #endif // DEBUG\n  #endif // ATLVERIFY\n#endif // (_ATL_VER < 0x0700)\n\n// Forward declaration for ATL3 and ATL11 fix\n#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE)\n  namespace ATL { HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); };\n#endif\n\n#ifndef WM_MOUSEHWHEEL\n  #define WM_MOUSEHWHEEL                  0x020E\n#endif\n\n\nnamespace WTL\n{\n\n#if (_ATL_VER >= 0x0700)\n  DECLARE_TRACE_CATEGORY(atlTraceUI);\n  #ifdef _DEBUG\n    __declspec(selectany) ATL::CTraceCategory atlTraceUI(_T(\"atlTraceUI\"));\n  #endif // _DEBUG\n#else // !(_ATL_VER >= 0x0700)\n  enum wtlTraceFlags\n  {\n\tatlTraceUI = 0x10000000\n  };\n#endif // !(_ATL_VER >= 0x0700)\n\n// Windows version helper\ninline bool AtlIsOldWindows()\n{\n#ifdef _versionhelpers_H_INCLUDED_\n\treturn !::IsWindowsVersionOrGreater(4, 90, 0);\n#else // !_versionhelpers_H_INCLUDED_\nOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\tBOOL bRet = ::GetVersionEx(&ovi);\n\treturn (!bRet || !((ovi.dwMajorVersion >= 5) || (ovi.dwMajorVersion == 4 && ovi.dwMinorVersion >= 90)));\n#endif // _versionhelpers_H_INCLUDED_\n}\n\n// Default GUI font helper - \"MS Shell Dlg\" stock font\ninline HFONT AtlGetDefaultGuiFont()\n{\n#ifndef _WIN32_WCE\n\treturn (HFONT)::GetStockObject(DEFAULT_GUI_FONT);\n#else // CE specific\n\treturn (HFONT)::GetStockObject(SYSTEM_FONT);\n#endif // _WIN32_WCE\n}\n\n// Control font helper - default font for controls not in a dialog\n// (NOTE: Caller owns the font, and should destroy it when it's no longer needed)\ninline HFONT AtlCreateControlFont()\n{\n#ifndef _WIN32_WCE\n\tLOGFONT lf = { 0 };\n\tATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);\n\tHFONT hFont = ::CreateFontIndirect(&lf);\n\tATLASSERT(hFont != NULL);\n\treturn hFont;\n#else // CE specific\n\treturn (HFONT)::GetStockObject(SYSTEM_FONT);\n#endif // _WIN32_WCE\n}\n\n// Bold font helper\n// (NOTE: Caller owns the font, and should destroy it when it's no longer needed)\ninline HFONT AtlCreateBoldFont(HFONT hFont = NULL)\n{\n\tLOGFONT lf = { 0 };\n#ifndef _WIN32_WCE\n\tif(hFont == NULL)\n\t\tATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);\n\telse\n\t\tATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT));\n#else // CE specific\n\tif(hFont == NULL)\n\t\thFont = (HFONT)::GetStockObject(SYSTEM_FONT);\n\tATLVERIFY(::GetObject(hFont, sizeof(LOGFONT), &lf) == sizeof(LOGFONT));\n#endif // _WIN32_WCE\n\tlf.lfWeight = FW_BOLD;\n\tHFONT hFontBold =  ::CreateFontIndirect(&lf);\n\tATLASSERT(hFontBold != NULL);\n\treturn hFontBold;\n}\n\n// Common Controls initialization helper\ninline BOOL AtlInitCommonControls(DWORD dwFlags)\n{\n\tINITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX), dwFlags };\n\tBOOL bRet = ::InitCommonControlsEx(&iccx);\n\tATLASSERT(bRet);\n\treturn bRet;\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// RunTimeHelper - helper functions for Windows version and structure sizes\n\n// Not for Windows CE\n#if defined(_WIN32_WCE) && !defined(_WTL_NO_RUNTIME_STRUCT_SIZE)\n  #define _WTL_NO_RUNTIME_STRUCT_SIZE\n#endif\n\n#ifndef _WTL_NO_RUNTIME_STRUCT_SIZE\n\n#ifndef _SIZEOF_STRUCT\n  #define _SIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))\n#endif\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE)\n  #define REBARBANDINFO_V6_SIZE   _SIZEOF_STRUCT(REBARBANDINFO, cxHeader)\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(REBARBANDINFO_V6_SIZE)\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE)\n  #define LVGROUP_V5_SIZE   _SIZEOF_STRUCT(LVGROUP, uAlign)\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVGROUP_V5_SIZE)\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE)\n  #define LVTILEINFO_V5_SIZE   _SIZEOF_STRUCT(LVTILEINFO, puColumns)\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(LVTILEINFO_V5_SIZE)\n\n#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE)\n  #define MCHITTESTINFO_V1_SIZE   _SIZEOF_STRUCT(MCHITTESTINFO, st)\n#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN) && !defined(MCHITTESTINFO_V1_SIZE)\n\n#if !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE)\n  #define NONCLIENTMETRICS_V1_SIZE   _SIZEOF_STRUCT(NONCLIENTMETRICS, lfMessageFont)\n#endif // !defined(_WIN32_WCE) && (WINVER >= 0x0600) && !defined(NONCLIENTMETRICS_V1_SIZE)\n\n#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE)\n  #define TTTOOLINFO_V2_SIZE   _SIZEOF_STRUCT(TTTOOLINFO, lParam)\n#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0501) && !defined(TTTOOLINFO_V2_SIZE)\n\n#endif // !_WTL_NO_RUNTIME_STRUCT_SIZE\n\nnamespace RunTimeHelper\n{\n#ifndef _WIN32_WCE\n\tinline bool IsCommCtrl6()\n\t{\n\t\tDWORD dwMajor = 0, dwMinor = 0;\n\t\tHRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);\n\t\treturn (SUCCEEDED(hRet) && (dwMajor >= 6));\n\t}\n\n\tinline bool IsVista()\n\t{\n#ifdef _versionhelpers_H_INCLUDED_\n\t\treturn ::IsWindowsVistaOrGreater();\n#else // !_versionhelpers_H_INCLUDED_\n\t\tOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\t\tBOOL bRet = ::GetVersionEx(&ovi);\n\t\treturn ((bRet != FALSE) && (ovi.dwMajorVersion >= 6));\n#endif // _versionhelpers_H_INCLUDED_\n\t}\n\n\tinline bool IsThemeAvailable()\n\t{\n\t\tbool bRet = false;\n\n\t\tif(IsCommCtrl6())\n\t\t{\n\t\t\tHMODULE hThemeDLL = ::LoadLibrary(_T(\"uxtheme.dll\"));\n\t\t\tif(hThemeDLL != NULL)\n\t\t\t{\n\t\t\t\ttypedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)();\n\t\t\t\tPFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, \"IsThemeActive\");\n\t\t\t\tATLASSERT(pfnIsThemeActive != NULL);\n\t\t\t\tbRet = (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE);\n\t\t\t\tif(bRet)\n\t\t\t\t{\n\t\t\t\t\ttypedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)();\n\t\t\t\t\tPFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, \"IsAppThemed\");\n\t\t\t\t\tATLASSERT(pfnIsAppThemed != NULL);\n\t\t\t\t\tbRet = (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE);\n\t\t\t\t}\n\n\t\t\t\t::FreeLibrary(hThemeDLL);\n\t\t\t}\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tinline bool IsWin7()\n\t{\n#ifdef _versionhelpers_H_INCLUDED_\n\t\treturn ::IsWindows7OrGreater();\n#else // !_versionhelpers_H_INCLUDED_\n\t\tOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\t\tBOOL bRet = ::GetVersionEx(&ovi);\n\t\treturn ((bRet != FALSE) && (ovi.dwMajorVersion == 6) && (ovi.dwMinorVersion >= 1));\n#endif // _versionhelpers_H_INCLUDED_\n\t}\n\n\tinline bool IsRibbonUIAvailable()\n\t{\n\t\tstatic INT iRibbonUI = -1;\n\n#if defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)\n\t\tif (iRibbonUI == -1)\n\t\t{\n\t\t\tHMODULE hRibbonDLL = ::LoadLibrary(_T(\"propsys.dll\"));\n\t\t\tif (hRibbonDLL != NULL)\n\t\t\t{\n\t\t\t\tconst GUID CLSID_UIRibbonFramework = { 0x926749fa, 0x2615, 0x4987, { 0x88, 0x45, 0xc3, 0x3e, 0x65, 0xf2, 0xb9, 0x57 } };\n\t\t\t\t// block - create instance\n\t\t\t\t{\n\t\t\t\t\tATL::CComPtr<IUnknown> pIUIFramework;\n\t\t\t\t\tiRibbonUI = SUCCEEDED(pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework)) ? 1 : 0;\n\t\t\t\t}\n\t\t\t\t::FreeLibrary(hRibbonDLL);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tiRibbonUI = 0;\n\t\t\t}\n\t\t}\n#endif // defined(NTDDI_WIN7) && (NTDDI_VERSION >= NTDDI_WIN7)\n\n\t\treturn (iRibbonUI == 1);\n\t}\n\n#endif // !_WIN32_WCE\n\n\tinline UINT SizeOf_REBARBANDINFO()\n\t{\n\t\tUINT uSize = sizeof(REBARBANDINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!(IsVista() && IsCommCtrl6()))\n\t\t\tuSize = REBARBANDINFO_V6_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn uSize;\n\t}\n\n#if (_WIN32_WINNT >= 0x501)\n  \tinline UINT SizeOf_LVGROUP()\n\t{\n\t\tUINT uSize = sizeof(LVGROUP);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tuSize = LVGROUP_V5_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn uSize;\n\t}\n\n\tinline UINT SizeOf_LVTILEINFO()\n\t{\n\t\tUINT uSize = sizeof(LVTILEINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tuSize = LVTILEINFO_V5_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn uSize;\n\t}\n#endif // (_WIN32_WINNT >= 0x501)\n\n\tinline UINT SizeOf_MCHITTESTINFO()\n\t{\n\t\tUINT uSize = sizeof(MCHITTESTINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\t\tif(!(IsVista() && IsCommCtrl6()))\n\t\t\tuSize = MCHITTESTINFO_V1_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\t\treturn uSize;\n\t}\n\n#ifndef _WIN32_WCE\n\tinline UINT SizeOf_NONCLIENTMETRICS()\n\t{\n\t\tUINT uSize = sizeof(NONCLIENTMETRICS);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tuSize = NONCLIENTMETRICS_V1_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)\n\t\treturn uSize;\n\t}\n\n\tinline UINT SizeOf_TOOLINFO()\n\t{\n\t\tUINT uSize = sizeof(TOOLINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501)\n\t\tif(!IsVista())\n\t\t\tuSize = TTTOOLINFO_V2_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501)\n\t\treturn uSize;\n\t}\n#endif // !_WIN32_WCE\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// ModuleHelper - helper functions for ATL3 and ATL7 module classes\n\nnamespace ModuleHelper\n{\n\tinline HINSTANCE GetModuleInstance()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\treturn ATL::_AtlBaseModule.GetModuleInstance();\n#else // !(_ATL_VER >= 0x0700)\n\t\treturn ATL::_pModule->GetModuleInstance();\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n\n\tinline HINSTANCE GetResourceInstance()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\treturn ATL::_AtlBaseModule.GetResourceInstance();\n#else // !(_ATL_VER >= 0x0700)\n\t\treturn ATL::_pModule->GetResourceInstance();\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n\n\tinline void AddCreateWndData(ATL::_AtlCreateWndData* pData, void* pObject)\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\tATL::_AtlWinModule.AddCreateWndData(pData, pObject);\n#else // !(_ATL_VER >= 0x0700)\n\t\tATL::_pModule->AddCreateWndData(pData, pObject);\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n\n\tinline void* ExtractCreateWndData()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\treturn ATL::_AtlWinModule.ExtractCreateWndData();\n#else // !(_ATL_VER >= 0x0700)\n\t\treturn ATL::_pModule->ExtractCreateWndData();\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// SecureHelper - helper functions for VS2005 secure CRT\n\nnamespace SecureHelper\n{\n\tinline void strcpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::strcpy_s(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tif(cchDest > (size_t)lstrlenA(lpstrSrc))\n\t\t\tATLVERIFY(lstrcpyA(lpstrDest, lpstrSrc) != NULL);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline void strcpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::wcscpy_s(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tif(cchDest > (size_t)lstrlenW(lpstrSrc))\n\t\t\tATLVERIFY(lstrcpyW(lpstrDest, lpstrSrc) != NULL);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline void strcpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc)\n\t{\n#ifdef _UNICODE\n\t\tstrcpyW_x(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tstrcpyA_x(lpstrDest, cchDest, lpstrSrc);\n#endif\n\t}\n\n\tinline errno_t strncpyA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc, size_t cchCount)\n\t{\n#if _SECURE_ATL\n\t\treturn ATL::Checked::strncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount);\n#else\n\t\terrno_t nRet = 0;\n\t\tif(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL)\n\t\t{\n\t\t\tnRet = EINVAL;\n\t\t}\n\t\telse if(cchCount == _TRUNCATE)\n\t\t{\n\t\t\tcchCount = __min(cchDest - 1, size_t(lstrlenA(lpstrSrc)));\n\t\t\tnRet = STRUNCATE;\n\t\t}\n\t\telse if(cchDest <= cchCount)\n\t\t{\n\t\t\tlpstrDest[0] = 0;\n\t\t\tnRet = EINVAL;\n\t\t}\n\t\tif(nRet == 0 || nRet == STRUNCATE)\n\t\t\tnRet = (lstrcpynA(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL;\n\t\tATLASSERT(nRet == 0 || nRet == STRUNCATE);\n\t\treturn nRet;\n#endif\n\t}\n\n\tinline errno_t strncpyW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc, size_t cchCount)\n\t{\n#if _SECURE_ATL\n\t\treturn ATL::Checked::wcsncpy_s(lpstrDest, cchDest, lpstrSrc, cchCount);\n#else\n\t\terrno_t nRet = 0;\n\t\tif(lpstrDest == NULL || cchDest == 0 || lpstrSrc == NULL)\n\t\t{\n\t\t\tnRet = EINVAL;\n\t\t}\n\t\telse if(cchCount == _TRUNCATE)\n\t\t{\n\t\t\tcchCount = __min(cchDest - 1, size_t(lstrlenW(lpstrSrc)));\n\t\t\tnRet = STRUNCATE;\n\t\t}\n\t\telse if(cchDest <= cchCount)\n\t\t{\n\t\t\tlpstrDest[0] = 0;\n\t\t\tnRet = EINVAL;\n\t\t}\n\t\tif(nRet == 0 || nRet == STRUNCATE)\n\t\t\tnRet = (lstrcpynW(lpstrDest, lpstrSrc, (int)cchCount + 1) != NULL) ? nRet : EINVAL;\n\t\tATLASSERT(nRet == 0 || nRet == STRUNCATE);\n\t\treturn nRet;\n#endif\n\t}\n\n\tinline errno_t strncpy_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc, size_t cchCount)\n\t{\n#ifdef _UNICODE\n\t\treturn strncpyW_x(lpstrDest, cchDest, lpstrSrc, cchCount);\n#else\n\t\treturn strncpyA_x(lpstrDest, cchDest, lpstrSrc, cchCount);\n#endif\n\t}\n\n\tinline void strcatA_x(char* lpstrDest, size_t cchDest, const char* lpstrSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::strcat_s(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tif(cchDest > (size_t)lstrlenA(lpstrSrc))\n\t\t\tATLVERIFY(lstrcatA(lpstrDest, lpstrSrc) != NULL);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline void strcatW_x(wchar_t* lpstrDest, size_t cchDest, const wchar_t* lpstrSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::wcscat_s(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tif(cchDest > (size_t)lstrlenW(lpstrSrc))\n\t\t\tATLVERIFY(lstrcatW(lpstrDest, lpstrSrc) != NULL);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline void strcat_x(LPTSTR lpstrDest, size_t cchDest, LPCTSTR lpstrSrc)\n\t{\n#ifdef _UNICODE\n\t\tstrcatW_x(lpstrDest, cchDest, lpstrSrc);\n#else\n\t\tstrcatA_x(lpstrDest, cchDest, lpstrSrc);\n#endif\n\t}\n\n\tinline void memcpy_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::memcpy_s(pDest, cbDest, pSrc, cbSrc);\n#else\n\t\tif(cbDest >= cbSrc)\n\t\t\tmemcpy(pDest, pSrc, cbSrc);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline void memmove_x(void* pDest, size_t cbDest, const void* pSrc, size_t cbSrc)\n\t{\n#if _SECURE_ATL\n\t\tATL::Checked::memmove_s(pDest, cbDest, pSrc, cbSrc);\n#else\n\t\tif(cbDest >= cbSrc)\n\t\t\tmemmove(pDest, pSrc, cbSrc);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n#endif\n\t}\n\n\tinline int vsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args)\n\t{\n#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)\n\t\treturn _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args);\n#else\n\t\tcchBuff;   // Avoid unused argument warning\n  #pragma warning(push)\n  #pragma warning(disable: 4996)\n\t\treturn _vstprintf(lpstrBuff, lpstrFormat, args);\n  #pragma warning(pop)\n#endif\n\t}\n\n\tinline int wvsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, va_list args)\n\t{\n#if _SECURE_ATL && !defined(_ATL_MIN_CRT) && !defined(_WIN32_WCE)\n\t\treturn _vstprintf_s(lpstrBuff, cchBuff, lpstrFormat, args);\n#else\n\t\tcchBuff;   // Avoid unused argument warning\n\t\treturn ::wvsprintf(lpstrBuff, lpstrFormat, args);\n#endif\n\t}\n\n\tinline int sprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...)\n\t{\n\t\tva_list args;\n\t\tva_start(args, lpstrFormat);\n\t\tint nRes = vsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args);\n\t\tva_end(args);\n\t\treturn nRes;\n\t}\n\n\tinline int wsprintf_x(LPTSTR lpstrBuff, size_t cchBuff, LPCTSTR lpstrFormat, ...)\n\t{\n\t\tva_list args;\n\t\tva_start(args, lpstrFormat);\n\t\tint nRes = wvsprintf_x(lpstrBuff, cchBuff, lpstrFormat, args);\n\t\tva_end(args);\n\t\treturn nRes;\n\t}\n}; // namespace SecureHelper\n\n\n///////////////////////////////////////////////////////////////////////////////\n// MinCrtHelper - helper functions for using _ATL_MIN_CRT\n\nnamespace MinCrtHelper\n{\n\tinline int _isspace(TCHAR ch)\n\t{\n#ifndef _ATL_MIN_CRT\n\t\treturn _istspace(ch);\n#else // _ATL_MIN_CRT\n\t\tWORD type = 0;\n\t\t::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);\n\t\treturn (type & C1_SPACE) == C1_SPACE;\n#endif // _ATL_MIN_CRT\n\t}\n\n\tinline int _isdigit(TCHAR ch)\n\t{\n#ifndef _ATL_MIN_CRT\n\t\treturn _istdigit(ch);\n#else // _ATL_MIN_CRT\n\t\tWORD type = 0;\n\t\t::GetStringTypeEx(::GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);\n\t\treturn (type & C1_DIGIT) == C1_DIGIT;\n#endif // _ATL_MIN_CRT\n\t}\n\n\tinline int _atoi(LPCTSTR str)\n\t{\n#ifndef _ATL_MIN_CRT\n\t\treturn _ttoi(str);\n#else // _ATL_MIN_CRT\n\t\twhile(_isspace(*str) != 0)\n\t\t\t++str;\n\n\t\tTCHAR ch = *str++;\n\t\tTCHAR sign = ch;   // save sign indication\n\t\tif(ch == _T('-') || ch == _T('+'))\n\t\t\tch = *str++;   // skip sign\n\n\t\tint total = 0;\n\t\twhile(_isdigit(ch) != 0)\n\t\t{\n\t\t\ttotal = 10 * total + (ch - '0');   // accumulate digit\n\t\t\tch = *str++;        // get next char\n\t\t}\n\n\t\treturn (sign == '-') ? -total : total;   // return result, negated if necessary\n#endif // _ATL_MIN_CRT\n\t}\n\n\tinline LPCTSTR _strrchr(LPCTSTR str, TCHAR ch)\n\t{\n#ifndef _ATL_MIN_CRT\n\t\treturn _tcsrchr(str, ch);\n#else // _ATL_MIN_CRT\n\t\tLPCTSTR lpsz = NULL;\n\t\twhile(*str != 0)\n\t\t{\n\t\t\tif(*str == ch)\n\t\t\t\tlpsz = str;\n\t\t\tstr = ::CharNext(str);\n\t\t}\n\t\treturn lpsz;\n#endif // _ATL_MIN_CRT\n\t}\n\n\tinline LPTSTR _strrchr(LPTSTR str, TCHAR ch)\n\t{\n#ifndef _ATL_MIN_CRT\n\t\treturn _tcsrchr(str, ch);\n#else // _ATL_MIN_CRT\n\t\tLPTSTR lpsz = NULL;\n\t\twhile(*str != 0)\n\t\t{\n\t\t\tif(*str == ch)\n\t\t\t\tlpsz = str;\n\t\t\tstr = ::CharNext(str);\n\t\t}\n\t\treturn lpsz;\n#endif // _ATL_MIN_CRT\n\t}\n}; // namespace MinCrtHelper\n\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericWndClass - generic window class usable for subclassing\n\n// Use in dialog templates to specify a placeholder to be subclassed\n// Specify as a custom control with class name WTL_GenericWindow\n// Call Rregister() before creating dialog (for example, in WinMain)\nnamespace GenericWndClass\n{\n\tinline LPCTSTR GetName()\n\t{\n\t\treturn _T(\"WTL_GenericWindow\");\n\t}\n\n\tinline ATOM Register()\n\t{\n#ifndef _WIN32_WCE\n\t\tWNDCLASSEX wc = { sizeof(WNDCLASSEX) };\n#else\n\t\tWNDCLASS wc = { 0 };\n#endif\n\t\twc.lpfnWndProc = ::DefWindowProc;\n\t\twc.hInstance = ModuleHelper::GetModuleInstance();\n\t\twc.hCursor = ::LoadCursor(NULL, IDC_ARROW);\n\t\twc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\n\t\twc.lpszClassName = GetName();\n#ifndef _WIN32_WCE\n\t\tATOM atom = ::RegisterClassEx(&wc);\n#else\n\t\tATOM atom = ::RegisterClass(&wc);\n#endif\n\t\tATLASSERT(atom != 0);\n\t\treturn atom;\n\t}\n\n\tinline BOOL Unregister()   // only needed for DLLs or tmp use\n\t{\n\t\treturn ::UnregisterClass(GetName(), ModuleHelper::GetModuleInstance());\n\t}\n}; // namespace GenericWndClass\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMessageFilter - Interface for message filter support\n\nclass CMessageFilter\n{\npublic:\n\tvirtual BOOL PreTranslateMessage(MSG* pMsg) = 0;\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CIdleHandler - Interface for idle processing\n\nclass CIdleHandler\n{\npublic:\n\tvirtual BOOL OnIdle() = 0;\n};\n\n#ifndef _ATL_NO_OLD_NAMES\n  // for compatilibility with old names only\n  typedef CIdleHandler CUpdateUIObject;\n  #define DoUpdate OnIdle\n#endif // !_ATL_NO_OLD_NAMES\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMessageLoop - message loop implementation\n\nclass CMessageLoop\n{\npublic:\n\tATL::CSimpleArray<CMessageFilter*> m_aMsgFilter;\n\tATL::CSimpleArray<CIdleHandler*> m_aIdleHandler;\n\tMSG m_msg;\n\n// Message filter operations\n\tBOOL AddMessageFilter(CMessageFilter* pMessageFilter)\n\t{\n\t\treturn m_aMsgFilter.Add(pMessageFilter);\n\t}\n\n\tBOOL RemoveMessageFilter(CMessageFilter* pMessageFilter)\n\t{\n\t\treturn m_aMsgFilter.Remove(pMessageFilter);\n\t}\n\n// Idle handler operations\n\tBOOL AddIdleHandler(CIdleHandler* pIdleHandler)\n\t{\n\t\treturn m_aIdleHandler.Add(pIdleHandler);\n\t}\n\n\tBOOL RemoveIdleHandler(CIdleHandler* pIdleHandler)\n\t{\n\t\treturn m_aIdleHandler.Remove(pIdleHandler);\n\t}\n\n#ifndef _ATL_NO_OLD_NAMES\n\t// for compatilibility with old names only\n\tBOOL AddUpdateUI(CIdleHandler* pIdleHandler)\n\t{\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CUpdateUIObject and AddUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\\n\"));\n\t\treturn AddIdleHandler(pIdleHandler);\n\t}\n\n\tBOOL RemoveUpdateUI(CIdleHandler* pIdleHandler)\n\t{\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CUpdateUIObject and RemoveUpdateUI are deprecated. Please change your code to use CIdleHandler and OnIdle\\n\"));\n\t\treturn RemoveIdleHandler(pIdleHandler);\n\t}\n#endif // !_ATL_NO_OLD_NAMES\n\n// message loop\n\tint Run()\n\t{\n\t\tBOOL bDoIdle = TRUE;\n\t\tint nIdleCount = 0;\n\t\tBOOL bRet;\n\n\t\tfor(;;)\n\t\t{\n\t\t\twhile(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))\n\t\t\t{\n\t\t\t\tif(!OnIdle(nIdleCount++))\n\t\t\t\t\tbDoIdle = FALSE;\n\t\t\t}\n\n\t\t\tbRet = ::GetMessage(&m_msg, NULL, 0, 0);\n\n\t\t\tif(bRet == -1)\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"::GetMessage returned -1 (error)\\n\"));\n\t\t\t\tcontinue;   // error, don't process\n\t\t\t}\n\t\t\telse if(!bRet)\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CMessageLoop::Run - exiting\\n\"));\n\t\t\t\tbreak;   // WM_QUIT, exit message loop\n\t\t\t}\n\n\t\t\tif(!PreTranslateMessage(&m_msg))\n\t\t\t{\n\t\t\t\t::TranslateMessage(&m_msg);\n\t\t\t\t::DispatchMessage(&m_msg);\n\t\t\t}\n\n\t\t\tif(IsIdleMessage(&m_msg))\n\t\t\t{\n\t\t\t\tbDoIdle = TRUE;\n\t\t\t\tnIdleCount = 0;\n\t\t\t}\n\t\t}\n\n\t\treturn (int)m_msg.wParam;\n\t}\n\n\tstatic BOOL IsIdleMessage(MSG* pMsg)\n\t{\n\t\t// These messages should NOT cause idle processing\n\t\tswitch(pMsg->message)\n\t\t{\n\t\tcase WM_MOUSEMOVE:\n#ifndef _WIN32_WCE\n\t\tcase WM_NCMOUSEMOVE:\n#endif // !_WIN32_WCE\n\t\tcase WM_PAINT:\n\t\tcase 0x0118:\t// WM_SYSTIMER (caret blink)\n\t\t\treturn FALSE;\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n// Overrideables\n\t// Override to change message filtering\n\tvirtual BOOL PreTranslateMessage(MSG* pMsg)\n\t{\n\t\t// loop backwards\n\t\tfor(int i = m_aMsgFilter.GetSize() - 1; i >= 0; i--)\n\t\t{\n\t\t\tCMessageFilter* pMessageFilter = m_aMsgFilter[i];\n\t\t\tif(pMessageFilter != NULL && pMessageFilter->PreTranslateMessage(pMsg))\n\t\t\t\treturn TRUE;\n\t\t}\n\t\treturn FALSE;   // not translated\n\t}\n\n\t// override to change idle processing\n\tvirtual BOOL OnIdle(int /*nIdleCount*/)\n\t{\n\t\tfor(int i = 0; i < m_aIdleHandler.GetSize(); i++)\n\t\t{\n\t\t\tCIdleHandler* pIdleHandler = m_aIdleHandler[i];\n\t\t\tif(pIdleHandler != NULL)\n\t\t\t\tpIdleHandler->OnIdle();\n\t\t}\n\t\treturn FALSE;   // don't continue\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CStaticDataInitCriticalSectionLock and CWindowCreateCriticalSectionLock\n// internal classes to manage critical sections for both ATL3 and ATL7\n\nclass CStaticDataInitCriticalSectionLock\n{\npublic:\n#if (_ATL_VER >= 0x0700)\n\tATL::CComCritSecLock<ATL::CComCriticalSection> m_cslock;\n\n\tCStaticDataInitCriticalSectionLock() : m_cslock(ATL::_pAtlModule->m_csStaticDataInitAndTypeInfo, false)\n\t{ }\n#endif // (_ATL_VER >= 0x0700)\n\n\tHRESULT Lock()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\treturn m_cslock.Lock();\n#else // !(_ATL_VER >= 0x0700)\n\t\t::EnterCriticalSection(&ATL::_pModule->m_csStaticDataInit);\n\t\treturn S_OK;\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n\n\tvoid Unlock()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\tm_cslock.Unlock();\n#else // !(_ATL_VER >= 0x0700)\n\t\t::LeaveCriticalSection(&ATL::_pModule->m_csStaticDataInit);\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n};\n\n\nclass CWindowCreateCriticalSectionLock\n{\npublic:\n#if (_ATL_VER >= 0x0700)\n\tATL::CComCritSecLock<ATL::CComCriticalSection> m_cslock;\n\n\tCWindowCreateCriticalSectionLock() : m_cslock(ATL::_AtlWinModule.m_csWindowCreate, false)\n\t{ }\n#endif // (_ATL_VER >= 0x0700)\n\n\tHRESULT Lock()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\treturn m_cslock.Lock();\n#else // !(_ATL_VER >= 0x0700)\n\t\t::EnterCriticalSection(&ATL::_pModule->m_csWindowCreate);\n\t\treturn S_OK;\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n\n\tvoid Unlock()\n\t{\n#if (_ATL_VER >= 0x0700)\n\t\tm_cslock.Unlock();\n#else // !(_ATL_VER >= 0x0700)\n\t\t::LeaveCriticalSection(&ATL::_pModule->m_csWindowCreate);\n#endif // !(_ATL_VER >= 0x0700)\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTempBuffer - helper class for stack allocations for ATL3\n\n#ifndef _WTL_STACK_ALLOC_THRESHOLD\n  #define _WTL_STACK_ALLOC_THRESHOLD   512\n#endif\n\n#if (_ATL_VER >= 0x0700)\n\nusing ATL::CTempBuffer;\n\n#else // !(_ATL_VER >= 0x0700)\n\n#ifndef SIZE_MAX\n  #ifdef _WIN64 \n    #define SIZE_MAX _UI64_MAX\n  #else\n    #define SIZE_MAX UINT_MAX\n  #endif\n#endif\n\n#pragma warning(push)\n#pragma warning(disable: 4284)   // warning for operator ->\n\ntemplate<typename T, int t_nFixedBytes = 128>\nclass CTempBuffer\n{\npublic:\n\tCTempBuffer() : m_p(NULL)\n\t{\n\t}\n\n\tCTempBuffer(size_t nElements) : m_p(NULL)\n\t{\n\t\tAllocate(nElements);\n\t}\n\n\t~CTempBuffer()\n\t{\n\t\tif(m_p != reinterpret_cast<T*>(m_abFixedBuffer))\n\t\t\tfree(m_p);\n\t}\n\n\toperator T*() const\n\t{\n\t\treturn m_p;\n\t}\n\n\tT* operator ->() const\n\t{\n\t\tATLASSERT(m_p != NULL);\n\t\treturn m_p;\n\t}\n\n\tT* Allocate(size_t nElements)\n\t{\n\t\tATLASSERT(nElements <= (SIZE_MAX / sizeof(T)));\n\t\treturn AllocateBytes(nElements * sizeof(T));\n\t}\n\n\tT* AllocateBytes(size_t nBytes)\n\t{\n\t\tATLASSERT(m_p == NULL);\n\t\tif(nBytes > t_nFixedBytes)\n\t\t\tm_p = static_cast<T*>(malloc(nBytes));\n\t\telse\n\t\t\tm_p = reinterpret_cast<T*>(m_abFixedBuffer);\n\n\t\treturn m_p;\n\t}\n\nprivate:\n\tT* m_p;\n\tBYTE m_abFixedBuffer[t_nFixedBytes];\n};\n\n#pragma warning(pop)\n\n#endif // !(_ATL_VER >= 0x0700)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppModule - module class for an application\n\nclass CAppModule : public ATL::CComModule\n{\npublic:\n\tDWORD m_dwMainThreadID;\n\tATL::CSimpleMap<DWORD, CMessageLoop*>* m_pMsgLoopMap;\n\tATL::CSimpleArray<HWND>* m_pSettingChangeNotify;\n\n// Overrides of CComModule::Init and Term\n\tHRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL)\n\t{\n\t\tHRESULT hRet = CComModule::Init(pObjMap, hInstance, pLibID);\n\t\tif(FAILED(hRet))\n\t\t\treturn hRet;\n\n\t\tm_dwMainThreadID = ::GetCurrentThreadId();\n\t\ttypedef ATL::CSimpleMap<DWORD, CMessageLoop*>   _mapClass;\n\t\tm_pMsgLoopMap = NULL;\n\t\tATLTRY(m_pMsgLoopMap = new _mapClass);\n\t\tif(m_pMsgLoopMap == NULL)\n\t\t\treturn E_OUTOFMEMORY;\n\t\tm_pSettingChangeNotify = NULL;\n\n\t\treturn hRet;\n\t}\n\n\tvoid Term()\n\t{\n\t\tTermSettingChangeNotify();\n\t\tdelete m_pMsgLoopMap;\n\t\tCComModule::Term();\n\t}\n\n// Message loop map methods\n\tBOOL AddMessageLoop(CMessageLoop* pMsgLoop)\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::AddMessageLoop.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tATLASSERT(pMsgLoop != NULL);\n\t\tATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL);   // not in map yet\n\n\t\tBOOL bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop);\n\n\t\tlock.Unlock();\n\n\t\treturn bRet;\n\t}\n\n\tBOOL RemoveMessageLoop()\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::RemoveMessageLoop.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tBOOL bRet = m_pMsgLoopMap->Remove(::GetCurrentThreadId());\n\n\t\tlock.Unlock();\n\n\t\treturn bRet;\n\t}\n\n\tCMessageLoop* GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::GetMessageLoop.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn NULL;\n\t\t}\n\n\t\tCMessageLoop* pLoop =  m_pMsgLoopMap->Lookup(dwThreadID);\n\n\t\tlock.Unlock();\n\n\t\treturn pLoop;\n\t}\n\n// Setting change notify methods\n\t// Note: Call this from the main thread for MSDI apps\n\tBOOL InitSettingChangeNotify(DLGPROC pfnDlgProc = _SettingChangeDlgProc)\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::InitSettingChangeNotify.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tif(m_pSettingChangeNotify == NULL)\n\t\t{\n\t\t\ttypedef ATL::CSimpleArray<HWND>   _notifyClass;\n\t\t\tATLTRY(m_pSettingChangeNotify = new _notifyClass);\n\t\t\tATLASSERT(m_pSettingChangeNotify != NULL);\n\t\t}\n\n\t\tBOOL bRet = (m_pSettingChangeNotify != NULL);\n\t\tif(bRet && m_pSettingChangeNotify->GetSize() == 0)\n\t\t{\n\t\t\t// init everything\n\t\t\t_ATL_EMPTY_DLGTEMPLATE templ;\n\t\t\tHWND hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL, pfnDlgProc);\n\t\t\tATLASSERT(::IsWindow(hNtfWnd));\n\t\t\tif(::IsWindow(hNtfWnd))\n\t\t\t{\n// need conditional code because types don't match in winuser.h\n#ifdef _WIN64\n\t\t\t\t::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);\n#else\n\t\t\t\t::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));\n#endif\n\t\t\t\tbRet = m_pSettingChangeNotify->Add(hNtfWnd);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbRet = FALSE;\n\t\t\t}\n\t\t}\n\n\t\tlock.Unlock();\n\n\t\treturn bRet;\n\t}\n\n\tvoid TermSettingChangeNotify()\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::TermSettingChangeNotify.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn;\n\t\t}\n\n\t\tif(m_pSettingChangeNotify != NULL && m_pSettingChangeNotify->GetSize() > 0)\n\t\t\t::DestroyWindow((*m_pSettingChangeNotify)[0]);\n\t\tdelete m_pSettingChangeNotify;\n\t\tm_pSettingChangeNotify = NULL;\n\n\t\tlock.Unlock();\n\t}\n\n\tBOOL AddSettingChangeNotify(HWND hWnd)\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::AddSettingChangeNotify.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tBOOL bRet = FALSE;\n\t\tif(InitSettingChangeNotify() != FALSE)\n\t\t\tbRet = m_pSettingChangeNotify->Add(hWnd);\n\n\t\tlock.Unlock();\n\n\t\treturn bRet;\n\t}\n\n\tBOOL RemoveSettingChangeNotify(HWND hWnd)\n\t{\n\t\tCStaticDataInitCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CAppModule::RemoveSettingChangeNotify.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tBOOL bRet = FALSE;\n\t\tif(m_pSettingChangeNotify != NULL)\n\t\t\tbRet = m_pSettingChangeNotify->Remove(hWnd);\n\n\t\tlock.Unlock();\n\n\t\treturn bRet;\n\t}\n\n// Implementation - setting change notify dialog template and dialog procedure\n\tstruct _ATL_EMPTY_DLGTEMPLATE : DLGTEMPLATE\n\t{\n\t\t_ATL_EMPTY_DLGTEMPLATE()\n\t\t{\n\t\t\tmemset(this, 0, sizeof(_ATL_EMPTY_DLGTEMPLATE));\n\t\t\tstyle = WS_POPUP;\n\t\t}\n\t\tWORD wMenu, wClass, wTitle;\n\t};\n\n#ifdef _WIN64\n\tstatic INT_PTR CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n#else\n\tstatic BOOL CALLBACK _SettingChangeDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n#endif\n\t{\n\t\tif(uMsg == WM_SETTINGCHANGE)\n\t\t{\n// need conditional code because types don't match in winuser.h\n#ifdef _WIN64\n\t\t\tCAppModule* pModule = (CAppModule*)::GetWindowLongPtr(hWnd, GWLP_USERDATA);\n#else\n\t\t\tCAppModule* pModule = (CAppModule*)LongToPtr(::GetWindowLongPtr(hWnd, GWLP_USERDATA));\n#endif\n\t\t\tATLASSERT(pModule != NULL);\n\t\t\tATLASSERT(pModule->m_pSettingChangeNotify != NULL);\n\t\t\tconst UINT uTimeout = 1500;   // ms\n\t\t\tfor(int i = 1; i < pModule->m_pSettingChangeNotify->GetSize(); i++)\n\t\t\t{\n#if !defined(_WIN32_WCE)\n\t\t\t\t::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_ABORTIFHUNG, uTimeout, NULL);\n#elif(_WIN32_WCE >= 400) // CE specific\n\t\t\t\t::SendMessageTimeout((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam, SMTO_NORMAL, uTimeout, NULL);\n#else // _WIN32_WCE < 400 specific\n\t\t\t\tuTimeout;\n\t\t\t\t::SendMessage((*pModule->m_pSettingChangeNotify)[i], uMsg, wParam, lParam);\n#endif\n\t\t\t}\n\t\t\treturn TRUE;\n\t\t}\n\t\treturn FALSE;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CServerAppModule - module class for a COM server application\n\nclass CServerAppModule : public CAppModule\n{\npublic:\n\tHANDLE m_hEventShutdown;\n\tbool m_bActivity;\n\tDWORD m_dwTimeOut;\n\tDWORD m_dwPause;\n\n// Override of CAppModule::Init\n\tHRESULT Init(ATL::_ATL_OBJMAP_ENTRY* pObjMap, HINSTANCE hInstance, const GUID* pLibID = NULL)\n\t{\n\t\tm_dwTimeOut = 5000;\n\t\tm_dwPause = 1000;\n\t\treturn CAppModule::Init(pObjMap, hInstance, pLibID);\n\t}\n\n\tvoid Term()\n\t{\n\t\tif(m_hEventShutdown != NULL && ::CloseHandle(m_hEventShutdown))\n\t\t\tm_hEventShutdown = NULL;\n\t\tCAppModule::Term();\n\t}\n\n// COM Server methods\n#if (_MSC_VER >= 1300)\n\tLONG Unlock() throw()\n#else\n\tLONG Unlock()\n#endif\n\t{\n\t\tLONG lRet = CComModule::Unlock();\n\t\tif(lRet == 0)\n\t\t{\n\t\t\tm_bActivity = true;\n\t\t\t::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tvoid MonitorShutdown()\n\t{\n\t\tfor(;;)\n\t\t{\n\t\t\t::WaitForSingleObject(m_hEventShutdown, INFINITE);\n\t\t\tDWORD dwWait = 0;\n\t\t\tdo\n\t\t\t{\n\t\t\t\tm_bActivity = false;\n\t\t\t\tdwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut);\n\t\t\t}\n\t\t\twhile(dwWait == WAIT_OBJECT_0);\n\t\t\t// timed out\n\t\t\tif(!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail\n\t\t\t{\n#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) && defined(_ATL_FREE_THREADED) && !defined(_WIN32_WCE)\n\t\t\t\t::CoSuspendClassObjects();\n\t\t\t\tif(!m_bActivity && m_nLockCnt == 0)\n#endif\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// This handle should be valid now. If it isn't, \n\t\t// check if _Module.Term was called first (it shouldn't)\n\t\tif(::CloseHandle(m_hEventShutdown))\n\t\t\tm_hEventShutdown = NULL;\n\t\t::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0);\n\t}\n\n\tbool StartMonitor()\n\t{\n\t\tm_hEventShutdown = ::CreateEvent(NULL, false, false, NULL);\n\t\tif(m_hEventShutdown == NULL)\n\t\t\treturn false;\n\t\tDWORD dwThreadID = 0;\n#if !defined(_ATL_MIN_CRT) && defined(_MT) && !defined(_WIN32_WCE)\n\t\tHANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))MonitorProc, this, 0, (UINT*)&dwThreadID);\n#else\n\t\tHANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);\n#endif\n\t\tbool bRet = (hThread != NULL);\n\t\tif(bRet)\n\t\t\t::CloseHandle(hThread);\n\t\treturn bRet;\n\t}\n\n\tstatic DWORD WINAPI MonitorProc(void* pv)\n\t{\n\t\tCServerAppModule* p = (CServerAppModule*)pv;\n\t\tp->MonitorShutdown();\n\t\treturn 0;\n\t}\n\n#if (_ATL_VER < 0x0700)\n\t// search for an occurence of string p2 in string p1\n\tstatic LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)\n\t{\n\t\twhile(p1 != NULL && *p1 != NULL)\n\t\t{\n\t\t\tLPCTSTR p = p2;\n\t\t\twhile(p != NULL && *p != NULL)\n\t\t\t{\n\t\t\t\tif(*p1 == *p)\n\t\t\t\t\treturn ::CharNext(p1);\n\t\t\t\tp = ::CharNext(p);\n\t\t\t}\n\t\t\tp1 = ::CharNext(p1);\n\t\t}\n\t\treturn NULL;\n\t}\n#endif // (_ATL_VER < 0x0700)\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRegKeyEx - adds type-specific methods to ATL3 CRegKey\n\n#if (_ATL_VER < 0x0700)\n\nclass CRegKeyEx : public ATL::CRegKey\n{\npublic:\n// Constructors and operators\n\tCRegKeyEx(HKEY hKey = NULL)\n\t{\n\t\tm_hKey = hKey;\n\t}\n\n\tCRegKeyEx(CRegKeyEx& key)\n\t{\n\t\tAttach(key.Detach());\n\t}\n\n\tCRegKeyEx& operator =(CRegKeyEx& key)\n\t{\n\t\tClose();\n\t\tAttach(key.Detach());\n\t\treturn *this;\n\t}\n\n// Methods\n\tLONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast<const BYTE*>(pValue), nBytes);\n\t}\n\n\tLONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\n\t\tOLECHAR szGUID[64] = { 0 };\n\t\t::StringFromGUID2(guidValue, szGUID, 64);\n\n\t\tUSES_CONVERSION;\n\t\tLPCTSTR lpstr = OLE2CT(szGUID);\n#ifndef _UNICODE\n\t\tif(lpstr == NULL) \n\t\t\treturn E_OUTOFMEMORY;\n#endif\t\n\t\treturn SetStringValue(pszValueName, lpstr);\n\t}\n\n\tLONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast<const BYTE*>(pValue), nBytes);\n\t}\n\n\tLONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast<const BYTE*>(&dwValue), sizeof(DWORD));\n\t}\n\n#ifndef _WIN32_WCE\n\tLONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast<const BYTE*>(&qwValue), sizeof(ULONGLONG));\n\t}\n#endif\n\n\tLONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\tif(pszValue == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn ERROR_INVALID_DATA;\n\t\t}\n\t\tATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ));\n\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast<const BYTE*>(pszValue), (lstrlen(pszValue) + 1) * sizeof(TCHAR));\n\t}\n\n\tLONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\tif(pszValue == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn ERROR_INVALID_DATA;\n\t\t}\n\n\t\tULONG nBytes = 0;\n\t\tULONG nLength = 0;\n\t\tLPCTSTR pszTemp = pszValue;\n\t\tdo\n\t\t{\n\t\t\tnLength = lstrlen(pszTemp) + 1;\n\t\t\tpszTemp += nLength;\n\t\t\tnBytes += nLength * sizeof(TCHAR);\n\t\t} while (nLength != 1);\n\n\t\treturn ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast<const BYTE*>(pszValue), nBytes);\n\t}\n\n\tLONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\treturn ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast<LPBYTE>(pData), pnBytes);\n\t}\n\n\tLONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\n\t\tguidValue = GUID_NULL;\n\n\t\tTCHAR szGUID[64] = { 0 };\n\t\tULONG nCount = 64;\n\t\tLONG lRes = QueryStringValue(pszValueName, szGUID, &nCount);\n\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t\treturn lRes;\n\n\t\tif(szGUID[0] != _T('{'))\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\tUSES_CONVERSION;\n\t\tLPOLESTR lpstr = T2OLE(szGUID);\n#ifndef _UNICODE\n\t\tif(lpstr == NULL) \n\t\t\treturn E_OUTOFMEMORY;\n#endif\t\n\t\t\n\t\tHRESULT hr = ::CLSIDFromString(lpstr, &guidValue);\n\t\tif (FAILED(hr))\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\treturn ERROR_SUCCESS;\n\t}\n\n\tLONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes)\n\t{\n\t\tATLASSERT(pnBytes != NULL);\n\t\tATLASSERT(m_hKey != NULL);\n\n\t\tDWORD dwType = 0;\n\t\tLONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pValue), pnBytes);\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t\treturn lRes;\n\t\tif (dwType != REG_BINARY)\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\treturn ERROR_SUCCESS;\n\t}\n\n\tLONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\n\t\tULONG nBytes = sizeof(DWORD);\n\t\tDWORD dwType = 0;\n\t\tLONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(&dwValue), &nBytes);\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t\treturn lRes;\n\t\tif (dwType != REG_DWORD)\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\treturn ERROR_SUCCESS;\n\t}\n\n#ifndef _WIN32_WCE\n\tLONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\n\t\tULONG nBytes = sizeof(ULONGLONG);\n\t\tDWORD dwType = 0;\n\t\tLONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(&qwValue), &nBytes);\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t\treturn lRes;\n\t\tif (dwType != REG_QWORD)\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\treturn ERROR_SUCCESS;\n\t}\n#endif\n\n\tLONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\tATLASSERT(pnChars != NULL);\n\n\t\tULONG nBytes = (*pnChars) * sizeof(TCHAR);\n\t\tDWORD dwType = 0;\n\t\t*pnChars = 0;\n\t\tLONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pszValue), &nBytes);\n\t\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t{\n\t\t\treturn lRes;\n\t\t}\n\n\t\tif(dwType != REG_SZ && dwType != REG_EXPAND_SZ)\n\t\t{\n\t\t\treturn ERROR_INVALID_DATA;\n\t\t}\n\n\t\tif (pszValue != NULL)\n\t\t{\n\t\t\tif(nBytes != 0)\n\t\t\t{\n\t\t\t\tif ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0))\n\t\t\t\t\treturn ERROR_INVALID_DATA;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpszValue[0] = _T('\\0');\n\t\t\t}\n\t\t}\n\n\t\t*pnChars = nBytes / sizeof(TCHAR);\n\n\t\treturn ERROR_SUCCESS;\n\t}\n\n\tLONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars)\n\t{\n\t\tATLASSERT(m_hKey != NULL);\n\t\tATLASSERT(pnChars != NULL);\n\n\t\tif (pszValue != NULL && *pnChars < 2)\n\t\t\treturn ERROR_INSUFFICIENT_BUFFER;\n\t\t\n\t\tULONG nBytes = (*pnChars) * sizeof(TCHAR);\n\t\tDWORD dwType = 0;\n\t\t*pnChars = 0;\n\t\tLONG lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast<LPBYTE>(pszValue), &nBytes);\n\t\tif (lRes != ERROR_SUCCESS)\n\t\t\treturn lRes;\n\t\tif (dwType != REG_MULTI_SZ)\n\t\t\treturn ERROR_INVALID_DATA;\n\t\tif (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)))\n\t\t\treturn ERROR_INVALID_DATA;\n\n\t\t*pnChars = nBytes / sizeof(TCHAR);\n\n\t\treturn ERROR_SUCCESS;\n\t}\n};\n\n#else // !(_ATL_VER < 0x0700)\n\ntypedef ATL::CRegKey CRegKeyEx;\n\n#endif // !(_ATL_VER < 0x0700)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CString forward reference (enables CString use in atluser.h and atlgdi.h)\n\n#if defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING)\n  #define _WTL_USE_CSTRING\n#endif // defined(_WTL_FORWARD_DECLARE_CSTRING) && !defined(_WTL_USE_CSTRING)\n\n#ifdef _WTL_USE_CSTRING\n  class CString;   // forward declaration (include atlmisc.h for the whole class)\n#endif // _WTL_USE_CSTRING\n\n// CString namespace\n#ifndef _CSTRING_NS\n  #ifdef __ATLSTR_H__\n    #define _CSTRING_NS\tATL\n  #else\n    #define _CSTRING_NS\tWTL\n  #endif\n#endif // _CSTRING_NS\n\n// Type classes namespace\n#ifndef _WTYPES_NS\n  #ifdef __ATLTYPES_H__\n    #define _WTYPES_NS\n  #else\n    #define _WTYPES_NS\tWTL\n  #endif\n#endif // _WTYPES_NS\n\n}; // namespace WTL\n\n\n///////////////////////////////////////////////////////////////////////////////\n// General DLL version helpers\n// (ATL3: excluded from atlbase.h if _ATL_DLL is defined; ATL11: removed)\n\n#if (((_ATL_VER < 0x0700) && defined(_ATL_DLL)) || (_ATL_VER >= 0x0B00)) && !defined(_WIN32_WCE)\n\nnamespace ATL\n{\n\ninline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo)\n{\n\tATLASSERT(pDllVersionInfo != NULL);\n\tif(pDllVersionInfo == NULL)\n\t\treturn E_INVALIDARG;\n\n\t// We must get this function explicitly because some DLLs don't implement it.\n\tDLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, \"DllGetVersion\");\n\tif(pfnDllGetVersion == NULL)\n\t\treturn E_NOTIMPL;\n\n\treturn (*pfnDllGetVersion)(pDllVersionInfo);\n}\n\ninline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo)\n{\n\tHINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName);\n\tif(hInstDLL == NULL)\n\t\treturn E_FAIL;\n\tHRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo);\n\t::FreeLibrary(hInstDLL);\n\treturn hRet;\n}\n\n// Common Control Versions:\n//   Win95/WinNT 4.0    maj=4 min=00\n//   IE 3.x     maj=4 min=70\n//   IE 4.0     maj=4 min=71\ninline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)\n{\n\tATLASSERT(pdwMajor != NULL && pdwMinor != NULL);\n\tif(pdwMajor == NULL || pdwMinor == NULL)\n\t\treturn E_INVALIDARG;\n\n\tDLLVERSIONINFO dvi;\n\t::ZeroMemory(&dvi, sizeof(dvi));\n\tdvi.cbSize = sizeof(dvi);\n\tHRESULT hRet = AtlGetDllVersion(_T(\"comctl32.dll\"), &dvi);\n\n\tif(SUCCEEDED(hRet))\n\t{\n\t\t*pdwMajor = dvi.dwMajorVersion;\n\t\t*pdwMinor = dvi.dwMinorVersion;\n\t}\n\telse if(hRet == E_NOTIMPL)\n\t{\n\t\t// If DllGetVersion is not there, then the DLL is a version\n\t\t// previous to the one shipped with IE 3.x\n\t\t*pdwMajor = 4;\n\t\t*pdwMinor = 0;\n\t\thRet = S_OK;\n\t}\n\n\treturn hRet;\n}\n\n// Shell Versions:\n//   Win95/WinNT 4.0                    maj=4 min=00\n//   IE 3.x, IE 4.0 without Web Integrated Desktop  maj=4 min=00\n//   IE 4.0 with Web Integrated Desktop         maj=4 min=71\n//   IE 4.01 with Web Integrated Desktop        maj=4 min=72\ninline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor)\n{\n\tATLASSERT(pdwMajor != NULL && pdwMinor != NULL);\n\tif(pdwMajor == NULL || pdwMinor == NULL)\n\t\treturn E_INVALIDARG;\n\n\tDLLVERSIONINFO dvi;\n\t::ZeroMemory(&dvi, sizeof(dvi));\n\tdvi.cbSize = sizeof(dvi);\n\tHRESULT hRet = AtlGetDllVersion(_T(\"shell32.dll\"), &dvi);\n\n\tif(SUCCEEDED(hRet))\n\t{\n\t\t*pdwMajor = dvi.dwMajorVersion;\n\t\t*pdwMinor = dvi.dwMinorVersion;\n\t}\n\telse if(hRet == E_NOTIMPL)\n\t{\n\t\t// If DllGetVersion is not there, then the DLL is a version\n\t\t// previous to the one shipped with IE 4.x\n\t\t*pdwMajor = 4;\n\t\t*pdwMinor = 0;\n\t\thRet = S_OK;\n\t}\n\n\treturn hRet;\n}\n\n}; // namespace ATL\n\n#endif // (_ATL_VER < 0x0700) && defined(_ATL_DLL) && !defined(_WIN32_WCE)\n\n\n// These are always included\n#include \"atlwinx.h\"\n#include \"atluser.h\"\n#include \"atlgdi.h\"\n\n#ifndef _WTL_NO_AUTOMATIC_NAMESPACE\nusing namespace WTL;\n#endif // !_WTL_NO_AUTOMATIC_NAMESPACE\n\n#endif // __ATLAPP_H__\n"
  },
  {
    "path": "WTL/atlcrack.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLCRACK_H__\n#define __ATLCRACK_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlcrack.h requires atlapp.h to be included first\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Message map macro for cracked handlers\n\n// Note about message maps with cracked handlers:\n// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX.\n// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl derived classes,\n// but must use BEGIN_MSG_MAP_EX for classes that don't derive from CWindowImpl/CDialogImpl.\n\n#define BEGIN_MSG_MAP_EX(theClass) \\\npublic: \\\n\tBOOL m_bMsgHandled; \\\n\t/* \"handled\" management for cracked handlers */ \\\n\tBOOL IsMsgHandled() const \\\n\t{ \\\n\t\treturn m_bMsgHandled; \\\n\t} \\\n\tvoid SetMsgHandled(BOOL bHandled) \\\n\t{ \\\n\t\tm_bMsgHandled = bHandled; \\\n\t} \\\n\tBOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) \\\n\t{ \\\n\t\tBOOL bOldMsgHandled = m_bMsgHandled; \\\n\t\tBOOL bRet = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \\\n\t\tm_bMsgHandled = bOldMsgHandled; \\\n\t\treturn bRet; \\\n\t} \\\n\tBOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \\\n\t{ \\\n\t\tBOOL bHandled = TRUE; \\\n\t\t(hWnd); \\\n\t\t(uMsg); \\\n\t\t(wParam); \\\n\t\t(lParam); \\\n\t\t(lResult); \\\n\t\t(bHandled); \\\n\t\tswitch(dwMsgMapID) \\\n\t\t{ \\\n\t\tcase 0:\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Standard Windows message macros\n\n// int OnCreate(LPCREATESTRUCT lpCreateStruct)\n#define MSG_WM_CREATE(func) \\\n\tif (uMsg == WM_CREATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((LPCREATESTRUCT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)\n#define MSG_WM_INITDIALOG(func) \\\n\tif (uMsg == WM_INITDIALOG) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct)\n#define MSG_WM_COPYDATA(func) \\\n\tif (uMsg == WM_COPYDATA) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDestroy()\n#define MSG_WM_DESTROY(func) \\\n\tif (uMsg == WM_DESTROY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMove(CPoint ptPos)\n#define MSG_WM_MOVE(func) \\\n\tif (uMsg == WM_MOVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSize(UINT nType, CSize size)\n#define MSG_WM_SIZE(func) \\\n\tif (uMsg == WM_SIZE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther)\n#define MSG_WM_ACTIVATE(func) \\\n\tif (uMsg == WM_ACTIVATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSetFocus(CWindow wndOld)\n#define MSG_WM_SETFOCUS(func) \\\n\tif (uMsg == WM_SETFOCUS) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnKillFocus(CWindow wndFocus)\n#define MSG_WM_KILLFOCUS(func) \\\n\tif (uMsg == WM_KILLFOCUS) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnEnable(BOOL bEnable)\n#define MSG_WM_ENABLE(func) \\\n\tif (uMsg == WM_ENABLE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPaint(CDCHandle dc)\n#define MSG_WM_PAINT(func) \\\n\tif (uMsg == WM_PAINT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HDC)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnClose()\n#define MSG_WM_CLOSE(func) \\\n\tif (uMsg == WM_CLOSE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff)\n#define MSG_WM_QUERYENDSESSION(func) \\\n\tif (uMsg == WM_QUERYENDSESSION) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnQueryOpen()\n#define MSG_WM_QUERYOPEN(func) \\\n\tif (uMsg == WM_QUERYOPEN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnEraseBkgnd(CDCHandle dc)\n#define MSG_WM_ERASEBKGND(func) \\\n\tif (uMsg == WM_ERASEBKGND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysColorChange()\n#define MSG_WM_SYSCOLORCHANGE(func) \\\n\tif (uMsg == WM_SYSCOLORCHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnEndSession(BOOL bEnding, UINT uLogOff)\n#define MSG_WM_ENDSESSION(func) \\\n\tif (uMsg == WM_ENDSESSION) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam, (UINT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnShowWindow(BOOL bShow, UINT nStatus)\n#define MSG_WM_SHOWWINDOW(func) \\\n\tif (uMsg == WM_SHOWWINDOW) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam, (int)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit)\n#define MSG_WM_CTLCOLOREDIT(func) \\\n\tif (uMsg == WM_CTLCOLOREDIT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox)\n#define MSG_WM_CTLCOLORLISTBOX(func) \\\n\tif (uMsg == WM_CTLCOLORLISTBOX) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button)\n#define MSG_WM_CTLCOLORBTN(func) \\\n\tif (uMsg == WM_CTLCOLORBTN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd)\n#define MSG_WM_CTLCOLORDLG(func) \\\n\tif (uMsg == WM_CTLCOLORDLG) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)\n#define MSG_WM_CTLCOLORSCROLLBAR(func) \\\n\tif (uMsg == WM_CTLCOLORSCROLLBAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic)\n#define MSG_WM_CTLCOLORSTATIC(func) \\\n\tif (uMsg == WM_CTLCOLORSTATIC) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection)\n#define MSG_WM_SETTINGCHANGE(func) \\\n\tif (uMsg == WM_SETTINGCHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPCTSTR)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDevModeChange(LPCTSTR lpDeviceName)\n#define MSG_WM_DEVMODECHANGE(func) \\\n\tif (uMsg == WM_DEVMODECHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((LPCTSTR)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnActivateApp(BOOL bActive, DWORD dwThreadID)\n#define MSG_WM_ACTIVATEAPP(func) \\\n\tif (uMsg == WM_ACTIVATEAPP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam, (DWORD)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnFontChange()\n#define MSG_WM_FONTCHANGE(func) \\\n\tif (uMsg == WM_FONTCHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnTimeChange()\n#define MSG_WM_TIMECHANGE(func) \\\n\tif (uMsg == WM_TIMECHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCancelMode()\n#define MSG_WM_CANCELMODE(func) \\\n\tif (uMsg == WM_CANCELMODE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message)\n#define MSG_WM_SETCURSOR(func) \\\n\tif (uMsg == WM_SETCURSOR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message)\n#define MSG_WM_MOUSEACTIVATE(func) \\\n\tif (uMsg == WM_MOUSEACTIVATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnChildActivate()\n#define MSG_WM_CHILDACTIVATE(func) \\\n\tif (uMsg == WM_CHILDACTIVATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI)\n#define MSG_WM_GETMINMAXINFO(func) \\\n\tif (uMsg == WM_GETMINMAXINFO) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((LPMINMAXINFO)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnIconEraseBkgnd(CDCHandle dc)\n#define MSG_WM_ICONERASEBKGND(func) \\\n\tif (uMsg == WM_ICONERASEBKGND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HDC)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSpoolerStatus(UINT nStatus, UINT nJobs)\n#define MSG_WM_SPOOLERSTATUS(func) \\\n\tif (uMsg == WM_SPOOLERSTATUS) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (UINT)LOWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)\n#define MSG_WM_DRAWITEM(func) \\\n\tif (uMsg == WM_DRAWITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)\n#define MSG_WM_MEASUREITEM(func) \\\n\tif (uMsg == WM_MEASUREITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)\n#define MSG_WM_DELETEITEM(func) \\\n\tif (uMsg == WM_DELETEITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n//int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox)\n#define MSG_WM_CHARTOITEM(func) \\\n\tif (uMsg == WM_CHARTOITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)\n#define MSG_WM_VKEYTOITEM(func) \\\n\tif (uMsg == WM_VKEYTOITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HCURSOR OnQueryDragIcon()\n#define MSG_WM_QUERYDRAGICON(func) \\\n\tif (uMsg == WM_QUERYDRAGICON) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)\n#define MSG_WM_COMPAREITEM(func) \\\n\tif (uMsg == WM_COMPAREITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCompacting(UINT nCpuTime)\n#define MSG_WM_COMPACTING(func) \\\n\tif (uMsg == WM_COMPACTING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct)\n#define MSG_WM_NCCREATE(func) \\\n\tif (uMsg == WM_NCCREATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((LPCREATESTRUCT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcDestroy()\n#define MSG_WM_NCDESTROY(func) \\\n\tif (uMsg == WM_NCDESTROY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam)\n#define MSG_WM_NCCALCSIZE(func) \\\n\tif (uMsg == WM_NCCALCSIZE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((BOOL)wParam, lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// UINT OnNcHitTest(CPoint point)\n#define MSG_WM_NCHITTEST(func) \\\n\tif (uMsg == WM_NCHITTEST) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(_WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcPaint(CRgnHandle rgn)\n#define MSG_WM_NCPAINT(func) \\\n\tif (uMsg == WM_NCPAINT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HRGN)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnNcActivate(BOOL bActive)\n#define MSG_WM_NCACTIVATE(func) \\\n\tif (uMsg == WM_NCACTIVATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((BOOL)wParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// UINT OnGetDlgCode(LPMSG lpMsg)\n#define MSG_WM_GETDLGCODE(func) \\\n\tif (uMsg == WM_GETDLGCODE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((LPMSG)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcMouseMove(UINT nHitTest, CPoint point)\n#define MSG_WM_NCMOUSEMOVE(func) \\\n\tif (uMsg == WM_NCMOUSEMOVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcLButtonDown(UINT nHitTest, CPoint point)\n#define MSG_WM_NCLBUTTONDOWN(func) \\\n\tif (uMsg == WM_NCLBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcLButtonUp(UINT nHitTest, CPoint point)\n#define MSG_WM_NCLBUTTONUP(func) \\\n\tif (uMsg == WM_NCLBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcLButtonDblClk(UINT nHitTest, CPoint point)\n#define MSG_WM_NCLBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_NCLBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcRButtonDown(UINT nHitTest, CPoint point)\n#define MSG_WM_NCRBUTTONDOWN(func) \\\n\tif (uMsg == WM_NCRBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcRButtonUp(UINT nHitTest, CPoint point)\n#define MSG_WM_NCRBUTTONUP(func) \\\n\tif (uMsg == WM_NCRBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcRButtonDblClk(UINT nHitTest, CPoint point)\n#define MSG_WM_NCRBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_NCRBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcMButtonDown(UINT nHitTest, CPoint point)\n#define MSG_WM_NCMBUTTONDOWN(func) \\\n\tif (uMsg == WM_NCMBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcMButtonUp(UINT nHitTest, CPoint point)\n#define MSG_WM_NCMBUTTONUP(func) \\\n\tif (uMsg == WM_NCMBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNcMButtonDblClk(UINT nHitTest, CPoint point)\n#define MSG_WM_NCMBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_NCMBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_KEYDOWN(func) \\\n\tif (uMsg == WM_KEYDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_KEYUP(func) \\\n\tif (uMsg == WM_KEYUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_CHAR(func) \\\n\tif (uMsg == WM_CHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_DEADCHAR(func) \\\n\tif (uMsg == WM_DEADCHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_SYSKEYDOWN(func) \\\n\tif (uMsg == WM_SYSKEYDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_SYSKEYUP(func) \\\n\tif (uMsg == WM_SYSKEYUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_SYSCHAR(func) \\\n\tif (uMsg == WM_SYSCHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_SYSDEADCHAR(func) \\\n\tif (uMsg == WM_SYSDEADCHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSysCommand(UINT nID, CPoint point)\n#define MSG_WM_SYSCOMMAND(func) \\\n\tif (uMsg == WM_SYSCOMMAND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnTCard(UINT idAction, DWORD dwActionData)\n#define MSG_WM_TCARD(func) \\\n\tif (uMsg == WM_TCARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (DWORD)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnTimer(UINT_PTR nIDEvent)\n#define MSG_WM_TIMER(func) \\\n\tif (uMsg == WM_TIMER) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT_PTR)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)\n#define MSG_WM_HSCROLL(func) \\\n\tif (uMsg == WM_HSCROLL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)\n#define MSG_WM_VSCROLL(func) \\\n\tif (uMsg == WM_VSCROLL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnInitMenu(CMenuHandle menu)\n#define MSG_WM_INITMENU(func) \\\n\tif (uMsg == WM_INITMENU) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HMENU)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnInitMenuPopup(CMenuHandle menuPopup, UINT nIndex, BOOL bSysMenu)\n#define MSG_WM_INITMENUPOPUP(func) \\\n\tif (uMsg == WM_INITMENUPOPUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenuHandle menu)\n#define MSG_WM_MENUSELECT(func) \\\n\tif (uMsg == WM_MENUSELECT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenuHandle menu)\n#define MSG_WM_MENUCHAR(func) \\\n\tif (uMsg == WM_MENUCHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh)\n#define MSG_WM_NOTIFY(func) \\\n\tif (uMsg == WM_NOTIFY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnEnterIdle(UINT nWhy, CWindow wndWho)\n#define MSG_WM_ENTERIDLE(func) \\\n\tif (uMsg == WM_ENTERIDLE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMouseMove(UINT nFlags, CPoint point)\n#define MSG_WM_MOUSEMOVE(func) \\\n\tif (uMsg == WM_MOUSEMOVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)\n#define MSG_WM_MOUSEWHEEL(func) \\\n\tif (uMsg == WM_MOUSEWHEEL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnLButtonDown(UINT nFlags, CPoint point)\n#define MSG_WM_LBUTTONDOWN(func) \\\n\tif (uMsg == WM_LBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnLButtonUp(UINT nFlags, CPoint point)\n#define MSG_WM_LBUTTONUP(func) \\\n\tif (uMsg == WM_LBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnLButtonDblClk(UINT nFlags, CPoint point)\n#define MSG_WM_LBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_LBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRButtonDown(UINT nFlags, CPoint point)\n#define MSG_WM_RBUTTONDOWN(func) \\\n\tif (uMsg == WM_RBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRButtonUp(UINT nFlags, CPoint point)\n#define MSG_WM_RBUTTONUP(func) \\\n\tif (uMsg == WM_RBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRButtonDblClk(UINT nFlags, CPoint point)\n#define MSG_WM_RBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_RBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMButtonDown(UINT nFlags, CPoint point)\n#define MSG_WM_MBUTTONDOWN(func) \\\n\tif (uMsg == WM_MBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMButtonUp(UINT nFlags, CPoint point)\n#define MSG_WM_MBUTTONUP(func) \\\n\tif (uMsg == WM_MBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMButtonDblClk(UINT nFlags, CPoint point)\n#define MSG_WM_MBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_MBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam)\n#define MSG_WM_PARENTNOTIFY(func) \\\n\tif (uMsg == WM_PARENTNOTIFY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate)\n#define MSG_WM_MDIACTIVATE(func) \\\n\tif (uMsg == WM_MDIACTIVATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRenderFormat(UINT nFormat)\n#define MSG_WM_RENDERFORMAT(func) \\\n\tif (uMsg == WM_RENDERFORMAT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRenderAllFormats()\n#define MSG_WM_RENDERALLFORMATS(func) \\\n\tif (uMsg == WM_RENDERALLFORMATS) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDestroyClipboard()\n#define MSG_WM_DESTROYCLIPBOARD(func) \\\n\tif (uMsg == WM_DESTROYCLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDrawClipboard()\n#define MSG_WM_DRAWCLIPBOARD(func) \\\n\tif (uMsg == WM_DRAWCLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct)\n#define MSG_WM_PAINTCLIPBOARD(func) \\\n\tif (uMsg == WM_PAINTCLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \\\n\t\t::GlobalUnlock((HGLOBAL)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)\n#define MSG_WM_VSCROLLCLIPBOARD(func) \\\n\tif (uMsg == WM_VSCROLLCLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnContextMenu(CWindow wnd, CPoint point)\n#define MSG_WM_CONTEXTMENU(func) \\\n\tif (uMsg == WM_CONTEXTMENU) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect)\n#define MSG_WM_SIZECLIPBOARD(func) \\\n\tif (uMsg == WM_SIZECLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \\\n\t\t::GlobalUnlock((HGLOBAL)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString)\n#define MSG_WM_ASKCBFORMATNAME(func) \\\n\tif (uMsg == WM_ASKCBFORMATNAME) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPTSTR)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter)\n#define MSG_WM_CHANGECBCHAIN(func) \\\n\tif (uMsg == WM_CHANGECBCHAIN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)\n#define MSG_WM_HSCROLLCLIPBOARD(func) \\\n\tif (uMsg == WM_HSCROLLCLIPBOARD) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnQueryNewPalette()\n#define MSG_WM_QUERYNEWPALETTE(func) \\\n\tif (uMsg == WM_QUERYNEWPALETTE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPaletteChanged(CWindow wndFocus)\n#define MSG_WM_PALETTECHANGED(func) \\\n\tif (uMsg == WM_PALETTECHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPaletteIsChanging(CWindow wndPalChg)\n#define MSG_WM_PALETTEISCHANGING(func) \\\n\tif (uMsg == WM_PALETTEISCHANGING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDropFiles(HDROP hDropInfo)\n#define MSG_WM_DROPFILES(func) \\\n\tif (uMsg == WM_DROPFILES) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HDROP)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnWindowPosChanging(LPWINDOWPOS lpWndPos)\n#define MSG_WM_WINDOWPOSCHANGING(func) \\\n\tif (uMsg == WM_WINDOWPOSCHANGING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((LPWINDOWPOS)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnWindowPosChanged(LPWINDOWPOS lpWndPos)\n#define MSG_WM_WINDOWPOSCHANGED(func) \\\n\tif (uMsg == WM_WINDOWPOSCHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((LPWINDOWPOS)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnExitMenuLoop(BOOL fIsTrackPopupMenu)\n#define MSG_WM_EXITMENULOOP(func) \\\n\tif (uMsg == WM_EXITMENULOOP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu)\n#define MSG_WM_ENTERMENULOOP(func) \\\n\tif (uMsg == WM_ENTERMENULOOP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct)\n#define MSG_WM_STYLECHANGED(func) \\\n\tif (uMsg == WM_STYLECHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPSTYLESTRUCT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct)\n#define MSG_WM_STYLECHANGING(func) \\\n\tif (uMsg == WM_STYLECHANGING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPSTYLESTRUCT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSizing(UINT fwSide, LPRECT pRect)\n#define MSG_WM_SIZING(func) \\\n\tif (uMsg == WM_SIZING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPRECT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMoving(UINT fwSide, LPRECT pRect)\n#define MSG_WM_MOVING(func) \\\n\tif (uMsg == WM_MOVING) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPRECT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCaptureChanged(CWindow wnd)\n#define MSG_WM_CAPTURECHANGED(func) \\\n\tif (uMsg == WM_CAPTURECHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnDeviceChange(UINT nEventType, DWORD_PTR dwData)\n#define MSG_WM_DEVICECHANGE(func) \\\n\tif (uMsg == WM_DEVICECHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam, (DWORD_PTR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define MSG_WM_COMMAND(func) \\\n\tif (uMsg == WM_COMMAND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDisplayChange(UINT uBitsPerPixel, CSize sizeScreen)\n#define MSG_WM_DISPLAYCHANGE(func) \\\n\tif (uMsg == WM_DISPLAYCHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, _WTYPES_NS::CSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnEnterSizeMove()\n#define MSG_WM_ENTERSIZEMOVE(func) \\\n\tif (uMsg == WM_ENTERSIZEMOVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnExitSizeMove()\n#define MSG_WM_EXITSIZEMOVE(func) \\\n\tif (uMsg == WM_EXITSIZEMOVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HFONT OnGetFont()\n#define MSG_WM_GETFONT(func) \\\n\tif (uMsg == WM_GETFONT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnGetHotKey()\n#define MSG_WM_GETHOTKEY(func) \\\n\tif (uMsg == WM_GETHOTKEY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HICON OnGetIcon()\n#define MSG_WM_GETICON(func) \\\n\tif (uMsg == WM_GETICON) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnGetText(int cchTextMax, LPTSTR lpszText)\n#define MSG_WM_GETTEXT(func) \\\n\tif (uMsg == WM_GETTEXT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnGetTextLength()\n#define MSG_WM_GETTEXTLENGTH(func) \\\n\tif (uMsg == WM_GETTEXTLENGTH) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnHelp(LPHELPINFO lpHelpInfo)\n#define MSG_WM_HELP(func) \\\n\tif (uMsg == WM_HELP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((LPHELPINFO)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey)\n#define MSG_WM_HOTKEY(func) \\\n\tif (uMsg == WM_HOTKEY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout)\n#define MSG_WM_INPUTLANGCHANGE(func) \\\n\tif (uMsg == WM_INPUTLANGCHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((DWORD)wParam, (HKL)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout)\n#define MSG_WM_INPUTLANGCHANGEREQUEST(func) \\\n\tif (uMsg == WM_INPUTLANGCHANGEREQUEST) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam, (HKL)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus)\n#define MSG_WM_NEXTDLGCTL(func) \\\n\tif (uMsg == WM_NEXTDLGCTL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)LOWORD(lParam), wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu)\n#define MSG_WM_NEXTMENU(func) \\\n\tif (uMsg == WM_NEXTMENU) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)wParam, (LPMDINEXTMENU)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnNotifyFormat(CWindow wndFrom, int nCommand)\n#define MSG_WM_NOTIFYFORMAT(func) \\\n\tif (uMsg == WM_NOTIFYFORMAT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, (int)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD_PTR dwData)\n#define MSG_WM_POWERBROADCAST(func) \\\n\tif (uMsg == WM_POWERBROADCAST) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((DWORD)wParam, (DWORD_PTR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPrint(CDCHandle dc, UINT uFlags)\n#define MSG_WM_PRINT(func) \\\n\tif (uMsg == WM_PRINT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HDC)wParam, (UINT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPrintClient(CDCHandle dc, UINT uFlags)\n#define MSG_WM_PRINTCLIENT(func) \\\n\tif (uMsg == WM_PRINTCLIENT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HDC)wParam, (UINT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError)\n#define MSG_WM_RASDIALEVENT(func) \\\n\tif (uMsg == WM_RASDIALEVENT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((RASCONNSTATE)wParam, (DWORD)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSetFont(CFontHandle font, BOOL bRedraw)\n#define MSG_WM_SETFONT(func) \\\n\tif (uMsg == WM_SETFONT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((HFONT)wParam, (BOOL)LOWORD(lParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnSetHotKey(int nVirtKey, UINT uFlags)\n#define MSG_WM_SETHOTKEY(func) \\\n\tif (uMsg == WM_SETHOTKEY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), (UINT)HIBYTE(LOWORD(wParam))); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HICON OnSetIcon(UINT uType, HICON hIcon)\n#define MSG_WM_SETICON(func) \\\n\tif (uMsg == WM_SETICON) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnSetRedraw(BOOL bRedraw)\n#define MSG_WM_SETREDRAW(func) \\\n\tif (uMsg == WM_SETREDRAW) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((BOOL)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnSetText(LPCTSTR lpstrText)\n#define MSG_WM_SETTEXT(func) \\\n\tif (uMsg == WM_SETTEXT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((LPCTSTR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnUserChanged()\n#define MSG_WM_USERCHANGED(func) \\\n\tif (uMsg == WM_USERCHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// New NT4 & NT5 messages\n\n#if (_WIN32_WINNT >= 0x0400)\n\n// void OnMouseHover(WPARAM wParam, CPoint ptPos)\n#define MSG_WM_MOUSEHOVER(func) \\\n\tif (uMsg == WM_MOUSEHOVER) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(wParam, _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMouseLeave()\n#define MSG_WM_MOUSELEAVE(func) \\\n\tif (uMsg == WM_MOUSELEAVE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // _WIN32_WINNT >= 0x0400\n\n#if (WINVER >= 0x0500)\n\n// void OnMenuRButtonUp(WPARAM wParam, CMenuHandle menu)\n#define MSG_WM_MENURBUTTONUP(func) \\\n\tif (uMsg == WM_MENURBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(wParam, (HMENU)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnMenuDrag(WPARAM wParam, CMenuHandle menu)\n#define MSG_WM_MENUDRAG(func) \\\n\tif (uMsg == WM_MENUDRAG) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(wParam, (HMENU)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info)\n#define MSG_WM_MENUGETOBJECT(func) \\\n\tif (uMsg == WM_MENUGETOBJECT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((PMENUGETOBJECTINFO)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnUnInitMenuPopup(UINT nID, CMenuHandle menu)\n#define MSG_WM_UNINITMENUPOPUP(func) \\\n\tif (uMsg == WM_UNINITMENUPOPUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(lParam), (HMENU)wParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnMenuCommand(WPARAM nIndex, CMenuHandle menu)\n#define MSG_WM_MENUCOMMAND(func) \\\n\tif (uMsg == WM_MENUCOMMAND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(wParam, (HMENU)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // WINVER >= 0x0500\n\n#if (_WIN32_WINNT >= 0x0500)\n\n// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys)\n#define MSG_WM_APPCOMMAND(func) \\\n\tif (uMsg == WM_APPCOMMAND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HWND)wParam, GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam)); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos)\n#define MSG_WM_NCXBUTTONDOWN(func) \\\n\tif (uMsg == WM_NCXBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos)\n#define MSG_WM_NCXBUTTONUP(func) \\\n\tif (uMsg == WM_NCXBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos)\n#define MSG_WM_NCXBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_NCXBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_NCHITTEST_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos)\n#define MSG_WM_XBUTTONDOWN(func) \\\n\tif (uMsg == WM_XBUTTONDOWN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos)\n#define MSG_WM_XBUTTONUP(func) \\\n\tif (uMsg == WM_XBUTTONUP) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos)\n#define MSG_WM_XBUTTONDBLCLK(func) \\\n\tif (uMsg == WM_XBUTTONDBLCLK) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_XBUTTON_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnChangeUIState(WORD nAction, WORD nState)\n#define MSG_WM_CHANGEUISTATE(func) \\\n\tif (uMsg == WM_CHANGEUISTATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(LOWORD(wParam), HIWORD(wParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnUpdateUIState(WORD nAction, WORD nState)\n#define MSG_WM_UPDATEUISTATE(func) \\\n\tif (uMsg == WM_UPDATEUISTATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(LOWORD(wParam), HIWORD(wParam)); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnQueryUIState()\n#define MSG_WM_QUERYUISTATE(func) \\\n\tif (uMsg == WM_QUERYUISTATE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // (_WIN32_WINNT >= 0x0500)\n\n#if(_WIN32_WINNT >= 0x0501)\n\n// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput)\n#define MSG_WM_INPUT(func) \\\n\tif (uMsg == WM_INPUT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags)\n#define MSG_WM_UNICHAR(func) \\\n\tif (uMsg == WM_UNICHAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((TCHAR)wParam, (UINT)lParam & 0xFFFF, (UINT)((lParam & 0xFFFF0000) >> 16)); \\\n\t\tif(IsMsgHandled()) \\\n\t\t{ \\\n\t\t\tlResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \\\n\t\t\treturn TRUE; \\\n\t\t} \\\n\t}\n\n// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION nSessionID)\n#define MSG_WM_WTSSESSION_CHANGE(func) \\\n\tif (uMsg == WM_WTSSESSION_CHANGE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(wParam, (PWTSSESSION_NOTIFICATION)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnThemeChanged()\n#define MSG_WM_THEMECHANGED(func) \\\n\tif (uMsg == WM_THEMECHANGED) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // _WIN32_WINNT >= 0x0501\n\n#if (_WIN32_WINNT >= 0x0600)\n\n// BOOL OnMouseHWheel(UINT nFlags, short zDelta, CPoint pt)\n#define MSG_WM_MOUSEHWHEEL(func) \\\n\tif (uMsg == WM_MOUSEHWHEEL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (short)HIWORD(wParam), _WTYPES_NS::CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // (_WIN32_WINNT >= 0x0600)\n\n///////////////////////////////////////////////////////////////////////////////\n// ATL defined messages\n\n// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData)\n#define MSG_WM_FORWARDMSG(func) \\\n\tif (uMsg == WM_FORWARDMSG) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// Dialog specific messages\n\n// LRESULT OnDMGetDefID()\n#define MSG_DM_GETDEFID(func) \\\n\tif (uMsg == DM_GETDEFID) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDMSetDefID(UINT DefID)\n#define MSG_DM_SETDEFID(func) \\\n\tif (uMsg == DM_SETDEFID) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnDMReposition()\n#define MSG_DM_REPOSITION(func) \\\n\tif (uMsg == DM_REPOSITION) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// Reflected messages\n\n// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define MSG_OCM_COMMAND(func) \\\n\tif (uMsg == OCM_COMMAND) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh)\n#define MSG_OCM_NOTIFY(func) \\\n\tif (uMsg == OCM_NOTIFY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam)\n#define MSG_OCM_PARENTNOTIFY(func) \\\n\tif (uMsg == OCM_PARENTNOTIFY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)\n#define MSG_OCM_DRAWITEM(func) \\\n\tif (uMsg == OCM_DRAWITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)\n#define MSG_OCM_MEASUREITEM(func) \\\n\tif (uMsg == OCM_MEASUREITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)\n#define MSG_OCM_COMPAREITEM(func) \\\n\tif (uMsg == OCM_COMPAREITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)\n#define MSG_OCM_DELETEITEM(func) \\\n\tif (uMsg == OCM_DELETEITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \\\n\t\tlResult = TRUE; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)\n#define MSG_OCM_VKEYTOITEM(func) \\\n\tif (uMsg == OCM_VKEYTOITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n//int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox)\n#define MSG_OCM_CHARTOITEM(func) \\\n\tif (uMsg == OCM_CHARTOITEM) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)\n#define MSG_OCM_HSCROLL(func) \\\n\tif (uMsg == OCM_HSCROLL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)\n#define MSG_OCM_VSCROLL(func) \\\n\tif (uMsg == OCM_VSCROLL) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit)\n#define MSG_OCM_CTLCOLOREDIT(func) \\\n\tif (uMsg == OCM_CTLCOLOREDIT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox)\n#define MSG_OCM_CTLCOLORLISTBOX(func) \\\n\tif (uMsg == OCM_CTLCOLORLISTBOX) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button)\n#define MSG_OCM_CTLCOLORBTN(func) \\\n\tif (uMsg == OCM_CTLCOLORBTN) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd)\n#define MSG_OCM_CTLCOLORDLG(func) \\\n\tif (uMsg == OCM_CTLCOLORDLG) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)\n#define MSG_OCM_CTLCOLORSCROLLBAR(func) \\\n\tif (uMsg == OCM_CTLCOLORSCROLLBAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic)\n#define MSG_OCM_CTLCOLORSTATIC(func) \\\n\tif (uMsg == OCM_CTLCOLORSTATIC) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// Edit specific messages\n\n// void OnClear()\n#define MSG_WM_CLEAR(func) \\\n\tif (uMsg == WM_CLEAR) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCopy()\n#define MSG_WM_COPY(func) \\\n\tif (uMsg == WM_COPY) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCut()\n#define MSG_WM_CUT(func) \\\n\tif (uMsg == WM_CUT) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnPaste()\n#define MSG_WM_PASTE(func) \\\n\tif (uMsg == WM_PASTE) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnUndo()\n#define MSG_WM_UNDO(func) \\\n\tif (uMsg == WM_UNDO) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc(); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// Generic message handlers\n\n// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)\n#define MESSAGE_HANDLER_EX(msg, func) \\\n\tif(uMsg == msg) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(uMsg, wParam, lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)\n#define MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \\\n\tif(uMsg >= msgFirst && uMsg <= msgLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func(uMsg, wParam, lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// Commands and notifications\n\n// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define COMMAND_HANDLER_EX(id, code, func) \\\n\tif (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define COMMAND_ID_HANDLER_EX(id, func) \\\n\tif (uMsg == WM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define COMMAND_CODE_HANDLER_EX(code, func) \\\n\tif (uMsg == WM_COMMAND && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh)\n#define NOTIFY_HANDLER_EX(id, cd, func) \\\n\tif (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh)\n#define NOTIFY_ID_HANDLER_EX(id, func) \\\n\tif (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh)\n#define NOTIFY_CODE_HANDLER_EX(cd, func) \\\n\tif (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \\\n\tif(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \\\n\tif(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh)\n#define NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \\\n\tif(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh)\n#define NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \\\n\tif(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define REFLECTED_COMMAND_HANDLER_EX(id, code, func) \\\n\tif (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \\\n\tif (uMsg == OCM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \\\n\tif (uMsg == OCM_COMMAND && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh)\n#define REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \\\n\tif (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh)\n#define REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \\\n\tif (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh)\n#define REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \\\n\tif (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \\\n\tif(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)\n#define REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \\\n\tif(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tfunc((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \\\n\t\tlResult = 0; \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh)\n#define REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \\\n\tif(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh)\n#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \\\n\tif(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tSetMsgHandled(TRUE); \\\n\t\tlResult = func((LPNMHDR)lParam); \\\n\t\tif(IsMsgHandled()) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // __ATLCRACK_H__\n"
  },
  {
    "path": "WTL/atlctrls.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLCTRLS_H__\n#define __ATLCTRLS_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlctrls.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlctrls.h requires atlwin.h to be included first\n#endif\n\n#ifndef _WIN32_WCE\n  #include <richedit.h>\n  #include <richole.h>\n#elif defined(WIN32_PLATFORM_WFSP) && !defined(_WINUSERM_H_)\n  #include <winuserm.h>\n#endif // !_WIN32_WCE\n\n// protect template members from windowsx.h macros\n#ifdef _INC_WINDOWSX\n  #undef GetNextSibling\n  #undef GetPrevSibling\n#endif // _INC_WINDOWSX\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CStaticT<TBase> - CStatic\n// CButtonT<TBase> - CButton\n// CListBoxT<TBase> - CListBox\n// CComboBoxT<TBase> - CComboBox\n// CEditT<TBase> - CEdit\n// CEditCommands<T>\n// CScrollBarT<TBase> - CScrollBar\n//\n// CImageListT<t_bManaged> - CImageList, CImageListManaged\n// CListViewCtrlT<TBase> - CListViewCtrl\n// CTreeViewCtrlT<TBase> - CTreeViewCtrl\n// CTreeItemT<TBase> - CTreeItem\n// CTreeViewCtrlExT<TBase> - CTreeViewCtrlEx\n// CHeaderCtrlT<TBase> - CHeaderCtrl\n// CToolBarCtrlT<TBase> - CToolBarCtrl\n// CStatusBarCtrlT<TBase> - CStatusBarCtrl\n// CTabCtrlT<TBase> - CTabCtrl\n// CToolInfo\n// CToolTipCtrlT<TBase> - CToolTipCtrl\n// CTrackBarCtrlT<TBase> - CTrackBarCtrl\n// CUpDownCtrlT<TBase> - CUpDownCtrl\n// CProgressBarCtrlT<TBase> - CProgressBarCtrl\n// CHotKeyCtrlT<TBase> - CHotKeyCtrl\n// CAnimateCtrlT<TBase> - CAnimateCtrl\n// CRichEditCtrlT<TBase> - CRichEditCtrl\n// CRichEditCommands<T>\n// CDragListBoxT<TBase> - CDragListBox\n// CDragListNotifyImpl<T>\n// CReBarCtrlT<TBase> - CReBarCtrl\n// CComboBoxExT<TBase> - CComboBoxEx\n// CDateTimePickerCtrlT<TBase> - CDateTimePickerCtrl\n// CMonthCalendarCtrlT<TBase> - CMonthCalendarCtrl\n// CFlatScrollBarImpl<T>\n// CFlatScrollBarT<TBase> - CFlatScrollBar\n// CIPAddressCtrlT<TBase> - CIPAddressCtrl\n// CPagerCtrlT<TBase> - CPagerCtrl\n// CLinkCtrlT<TBase> - CLinkCtrl\n//\n// CCustomDraw<T>\n//\n// CCECommandBarCtrlT<TBase> - CCECommandBarCtrl\n// CCECommandBandsCtrlT<TBase> - CCECommandBandsCtrl\n\n\nnamespace WTL\n{\n\n// These are wrapper classes for Windows standard and common controls.\n// To implement a window based on a control, use following:\n// Example: Implementing a window based on a list box\n//\n// class CMyListBox : CWindowImpl<CMyListBox, CListBox>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyListBox)\n//          // put your message handler entries here\n//      END_MSG_MAP()\n// };\n\n\n\n// --- Standard Windows controls ---\n\n///////////////////////////////////////////////////////////////////////////////\n// CStatic - client side for a Windows STATIC control\n\ntemplate <class TBase>\nclass CStaticT : public TBase\n{\npublic:\n// Constructors\n\tCStaticT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCStaticT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"STATIC\");\n\t}\n\n#ifndef _WIN32_WCE\n\tHICON GetIcon() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, STM_GETICON, 0, 0L);\n\t}\n\n\tHICON SetIcon(HICON hIcon)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, STM_SETICON, (WPARAM)hIcon, 0L);\n\t}\n\n\tHENHMETAFILE GetEnhMetaFile() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HENHMETAFILE)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ENHMETAFILE, 0L);\n\t}\n\n\tHENHMETAFILE SetEnhMetaFile(HENHMETAFILE hMetaFile)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HENHMETAFILE)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ENHMETAFILE, (LPARAM)hMetaFile);\n\t}\n#else // CE specific\n\tHICON GetIcon() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_ICON, 0L);\n\t}\n\n\tHICON SetIcon(HICON hIcon)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);\n\t}\n#endif // _WIN32_WCE\n\n\tCBitmapHandle GetBitmap() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_BITMAP, 0L));\n\t}\n\n\tCBitmapHandle SetBitmap(HBITMAP hBitmap)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap));\n\t}\n\n\tHCURSOR GetCursor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HCURSOR)::SendMessage(m_hWnd, STM_GETIMAGE, IMAGE_CURSOR, 0L);\n\t}\n\n\tHCURSOR SetCursor(HCURSOR hCursor)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HCURSOR)::SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor);\n\t}\n};\n\ntypedef CStaticT<ATL::CWindow>   CStatic;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CButton - client side for a Windows BUTTON control\n\ntemplate <class TBase>\nclass CButtonT : public TBase\n{\npublic:\n// Constructors\n\tCButtonT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCButtonT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"BUTTON\");\n\t}\n\n\tUINT GetState() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0L);\n\t}\n\n\tvoid SetState(BOOL bHighlight)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0L);\n\t}\n\n\tint GetCheck() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0L);\n\t}\n\n\tvoid SetCheck(int nCheck)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0L);\n\t}\n\n\tUINT GetButtonStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::GetWindowLong(m_hWnd, GWL_STYLE) & 0xFFFF;\n\t}\n\n\tvoid SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw);\n\t}\n\n#ifndef _WIN32_WCE\n\tHICON GetIcon() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L);\n\t}\n\n\tHICON SetIcon(HICON hIcon)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);\n\t}\n\n\tCBitmapHandle GetBitmap() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L));\n\t}\n\n\tCBitmapHandle SetBitmap(HBITMAP hBitmap)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CBitmapHandle((HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap));\n\t}\n#endif // !_WIN32_WCE\n\n#if (_WIN32_WINNT >= 0x0501)\n\tBOOL GetIdealSize(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_GETIDEALSIZE, 0, (LPARAM)lpSize);\n\t}\n\n\tBOOL GetImageList(PBUTTON_IMAGELIST pButtonImagelist) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_GETIMAGELIST, 0, (LPARAM)pButtonImagelist);\n\t}\n\n\tBOOL SetImageList(PBUTTON_IMAGELIST pButtonImagelist)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_SETIMAGELIST, 0, (LPARAM)pButtonImagelist);\n\t}\n\n\tBOOL GetTextMargin(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_GETTEXTMARGIN, 0, (LPARAM)lpRect);\n\t}\n\n\tBOOL SetTextMargin(LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_SETTEXTMARGIN, 0, (LPARAM)lpRect);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (WINVER >= 0x0600)\n\tvoid SetDontClick(BOOL bDontClick)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, BM_SETDONTCLICK, (WPARAM)bDontClick, 0L);\n\t}\n#endif // (WINVER >= 0x0600)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tBOOL SetDropDownState(BOOL bDropDown)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_SETDROPDOWNSTATE, (WPARAM)bDropDown, 0L);\n\t}\n\n\tBOOL GetSplitInfo(PBUTTON_SPLITINFO pSplitInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_GETSPLITINFO, 0, (LPARAM)pSplitInfo);\n\t}\n\n\tBOOL SetSplitInfo(PBUTTON_SPLITINFO pSplitInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_SPLITBUTTON | BS_DEFSPLITBUTTON)) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_SETSPLITINFO, 0, (LPARAM)pSplitInfo);\n\t}\n\n\tint GetNoteLength() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, BCM_GETNOTELENGTH, 0, 0L);\n\t}\n\n\tBOOL GetNote(LPWSTR lpstrNoteText, int cchNoteText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_GETNOTE, cchNoteText, (LPARAM)lpstrNoteText);\n\t}\n\n\tBOOL SetNote(LPCWSTR lpstrNoteText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (BS_COMMANDLINK | BS_DEFCOMMANDLINK)) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, BCM_SETNOTE, 0, (LPARAM)lpstrNoteText);\n\t}\n\n\tLRESULT SetElevationRequiredState(BOOL bSet)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::SendMessage(m_hWnd, BCM_SETSHIELD, 0, (LPARAM)bSet);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tvoid Click()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, BM_CLICK, 0, 0L);\n\t}\n};\n\ntypedef CButtonT<ATL::CWindow>   CButton;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CListBox - client side for a Windows LISTBOX control\n\ntemplate <class TBase>\nclass CListBoxT : public TBase\n{\npublic:\n// Constructors\n\tCListBoxT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCListBoxT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"LISTBOX\");\n\t}\n\n\t// for entire listbox\n\tint GetCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETCOUNT, 0, 0L);\n\t}\n\n#ifndef _WIN32_WCE\n\tint SetCount(int cItems)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(((GetStyle() & LBS_NODATA) != 0) && ((GetStyle() & LBS_HASSTRINGS) == 0));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETCOUNT, cItems, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tint GetHorizontalExtent() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETHORIZONTALEXTENT, 0, 0L);\n\t}\n\n\tvoid SetHorizontalExtent(int cxExtent)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LB_SETHORIZONTALEXTENT, cxExtent, 0L);\n\t}\n\n\tint GetTopIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETTOPINDEX, 0, 0L);\n\t}\n\n\tint SetTopIndex(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETTOPINDEX, nIndex, 0L);\n\t}\n\n\tLCID GetLocale() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LCID)::SendMessage(m_hWnd, LB_GETLOCALE, 0, 0L);\n\t}\n\n\tLCID SetLocale(LCID nNewLocale)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LCID)::SendMessage(m_hWnd, LB_SETLOCALE, (WPARAM)nNewLocale, 0L);\n\t}\n\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\tDWORD GetListBoxInfo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if (_WIN32_WINNT >= 0x0501)\n\t\treturn (DWORD)::SendMessage(m_hWnd, LB_GETLISTBOXINFO, 0, 0L);\n#else // !(_WIN32_WINNT >= 0x0501)\n\t\treturn ::GetListBoxInfo(m_hWnd);\n#endif // !(_WIN32_WINNT >= 0x0501)\n\t}\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\n\t// for single-selection listboxes\n\tint GetCurSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L);\n\t}\n\n\tint SetCurSel(int nSelect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETCURSEL, nSelect, 0L);\n\t}\n\n\t// for multiple-selection listboxes\n\tint GetSel(int nIndex) const           // also works for single-selection\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETSEL, nIndex, 0L);\n\t}\n\n\tint SetSel(int nIndex, BOOL bSelect = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETSEL, bSelect, nIndex);\n\t}\n\n\tint GetSelCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETSELCOUNT, 0, 0L);\n\t}\n\n\tint GetSelItems(int nMaxItems, LPINT rgIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETSELITEMS, nMaxItems, (LPARAM)rgIndex);\n\t}\n\n\tint GetAnchorIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETANCHORINDEX, 0, 0L);\n\t}\n\n\tvoid SetAnchorIndex(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\t::SendMessage(m_hWnd, LB_SETANCHORINDEX, nIndex, 0L);\n\t}\n\n\tint GetCaretIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETCARETINDEX, 0, 0);\n\t}\n\n\tint SetCaretIndex(int nIndex, BOOL bScroll = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETCARETINDEX, nIndex, MAKELONG(bScroll, 0));\n\t}\n\n\t// for listbox items\n\tDWORD_PTR GetItemData(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD_PTR)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L);\n\t}\n\n\tint SetItemData(int nIndex, DWORD_PTR dwItemData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETITEMDATA, nIndex, (LPARAM)dwItemData);\n\t}\n\n\tvoid* GetItemDataPtr(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (void*)::SendMessage(m_hWnd, LB_GETITEMDATA, nIndex, 0L);\n\t}\n\n\tint SetItemDataPtr(int nIndex, void* pData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItemData(nIndex, (DWORD_PTR)pData);\n\t}\n\n\tint GetItemRect(int nIndex, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETITEMRECT, nIndex, (LPARAM)lpRect);\n\t}\n\n\tint GetText(int nIndex, LPTSTR lpszBuffer) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETTEXT, nIndex, (LPARAM)lpszBuffer);\n\t}\n\n#ifndef _ATL_NO_COM\n#ifdef _OLEAUTO_H_\n\tBOOL GetTextBSTR(int nIndex, BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\n\t\tint nLen = GetTextLen(nIndex);\n\t\tif(nLen == LB_ERR)\n\t\t\treturn FALSE;\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrText = buff.Allocate(nLen + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(GetText(nIndex, lpstrText) == LB_ERR)\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // _OLEAUTO_H_\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetText(int nIndex, _CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint cchLen = GetTextLen(nIndex);\n\t\tif(cchLen == LB_ERR)\n\t\t\treturn LB_ERR;\n\t\tint nRet = LB_ERR;\n\t\tLPTSTR lpstr = strText.GetBufferSetLength(cchLen);\n\t\tif(lpstr != NULL)\n\t\t{\n\t\t\tnRet = GetText(nIndex, lpstr);\n\t\t\tstrText.ReleaseBuffer();\n\t\t}\n\t\treturn nRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tint GetTextLen(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETTEXTLEN, nIndex, 0L);\n\t}\n\n\tint GetItemHeight(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_GETITEMHEIGHT, nIndex, 0L);\n\t}\n\n\tint SetItemHeight(int nIndex, UINT cyItemHeight)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0));\n\t}\n\n\t// Settable only attributes\n\tvoid SetColumnWidth(int cxWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LB_SETCOLUMNWIDTH, cxWidth, 0L);\n\t}\n\n\tBOOL SetTabStops(int nTabStops, LPINT rgTabStops)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);\n\t}\n\n\tBOOL SetTabStops()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 0, 0L);\n\t}\n\n\tBOOL SetTabStops(const int& cxEachStop)    // takes an 'int'\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LBS_USETABSTOPS) != 0);\n\t\treturn (BOOL)::SendMessage(m_hWnd, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);\n\t}\n\n// Operations\n\tint InitStorage(int nItems, UINT nBytes)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_INITSTORAGE, (WPARAM)nItems, nBytes);\n\t}\n\n\tvoid ResetContent()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LB_RESETCONTENT, 0, 0L);\n\t}\n\n\tUINT ItemFromPoint(POINT pt, BOOL& bOutside) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dw = (DWORD)::SendMessage(m_hWnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y));\n\t\tbOutside = (BOOL)HIWORD(dw);\n\t\treturn (UINT)LOWORD(dw);\n\t}\n\n\t// manipulating listbox items\n\tint AddString(LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_ADDSTRING, 0, (LPARAM)lpszItem);\n\t}\n\n\tint DeleteString(UINT nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_DELETESTRING, nIndex, 0L);\n\t}\n\n\tint InsertString(int nIndex, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_INSERTSTRING, nIndex, (LPARAM)lpszItem);\n\t}\n\n#ifndef _WIN32_WCE\n\tint Dir(UINT attr, LPCTSTR lpszWildCard)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_DIR, attr, (LPARAM)lpszWildCard);\n\t}\n\n\tint AddFile(LPCTSTR lpstrFileName)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_ADDFILE, 0, (LPARAM)lpstrFileName);\n\t}\n#endif // !_WIN32_WCE\n\n\t// selection helpers\n\tint FindString(int nStartAfter, LPCTSTR lpszItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_FINDSTRING, nStartAfter, (LPARAM)lpszItem);\n\t}\n\n\tint FindStringExact(int nIndexStart, LPCTSTR lpszFind) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind);\n\t}\n\n\tint SelectString(int nStartAfter, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LB_SELECTSTRING, nStartAfter, (LPARAM)lpszItem);\n\t}\n\n\tint SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != 0);\n\t\tATLASSERT(nFirstItem <= nLastItem);\n\t\treturn bSelect ? (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nFirstItem, nLastItem) : (int)::SendMessage(m_hWnd, LB_SELITEMRANGEEX, nLastItem, nFirstItem);\n\t}\n\n#ifdef WIN32_PLATFORM_WFSP   // SmartPhone only messages\n\tDWORD GetInputMode(BOOL bCurrentMode = TRUE)\n\t{\n\t\treturn SendMessage(LB_GETINPUTMODE, 0, (LPARAM)bCurrentMode);\n\t}\n\n\tBOOL SetInputMode(DWORD dwMode)\n\t{\n\t\treturn SendMessage(LB_SETINPUTMODE, 0, (LPARAM)dwMode);\n\t}\n#endif // WIN32_PLATFORM_WFSP\n};\n\ntypedef CListBoxT<ATL::CWindow>   CListBox;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CComboBox - client side for a Windows COMBOBOX control\n\n#ifndef WIN32_PLATFORM_WFSP   // No COMBOBOX on SmartPhones\n\ntemplate <class TBase>\nclass CComboBoxT : public TBase\n{\npublic:\n// Constructors\n\tCComboBoxT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCComboBoxT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"COMBOBOX\");\n\t}\n\n\t// for entire combo box\n\tint GetCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0L);\n\t}\n\n\tint GetCurSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0L);\n\t}\n\n\tint SetCurSel(int nSelect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0L);\n\t}\n\n\tLCID GetLocale() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LCID)::SendMessage(m_hWnd, CB_GETLOCALE, 0, 0L);\n\t}\n\n\tLCID SetLocale(LCID nNewLocale)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LCID)::SendMessage(m_hWnd, CB_SETLOCALE, (WPARAM)nNewLocale, 0L);\n\t}\n\n\tint GetTopIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETTOPINDEX, 0, 0L);\n\t}\n\n\tint SetTopIndex(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETTOPINDEX, nIndex, 0L);\n\t}\n\n\tUINT GetHorizontalExtent() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, CB_GETHORIZONTALEXTENT, 0, 0L);\n\t}\n\n\tvoid SetHorizontalExtent(UINT nExtent)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, CB_SETHORIZONTALEXTENT, nExtent, 0L);\n\t}\n\n\tint GetDroppedWidth() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETDROPPEDWIDTH, 0, 0L);\n\t}\n\n\tint SetDroppedWidth(UINT nWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETDROPPEDWIDTH, nWidth, 0L);\n\t}\n\n#if ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))\n\tBOOL GetComboBoxInfo(PCOMBOBOXINFO pComboBoxInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if ((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_GETCOMBOBOXINFO, 0, (LPARAM)pComboBoxInfo);\n#else // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))\n\t\treturn ::GetComboBoxInfo(m_hWnd, pComboBoxInfo);\n#endif // !((_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))\n\t}\n#endif // ((WINVER >= 0x0500) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 420))\n\n\t// for edit control\n\tDWORD GetEditSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0L);\n\t}\n\n\tBOOL SetEditSel(int nStartChar, int nEndChar)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar));\n\t}\n\n\t// for combobox item\n\tDWORD_PTR GetItemData(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD_PTR)::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0L);\n\t}\n\n\tint SetItemData(int nIndex, DWORD_PTR dwItemData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData);\n\t}\n\n\tvoid* GetItemDataPtr(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (void*)GetItemData(nIndex);\n\t}\n\n\tint SetItemDataPtr(int nIndex, void* pData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItemData(nIndex, (DWORD_PTR)pData);\n\t}\n\n\tint GetLBText(int nIndex, LPTSTR lpszText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETLBTEXT, nIndex, (LPARAM)lpszText);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetLBTextBSTR(int nIndex, BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\n\t\tint nLen = GetLBTextLen(nIndex);\n\t\tif(nLen == CB_ERR)\n\t\t\treturn FALSE;\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrText = buff.Allocate(nLen + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(GetLBText(nIndex, lpstrText) == CB_ERR)\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetLBText(int nIndex, _CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint cchLen = GetLBTextLen(nIndex);\n\t\tif(cchLen == CB_ERR)\n\t\t\treturn CB_ERR;\n\t\tint nRet = CB_ERR;\n\t\tLPTSTR lpstr = strText.GetBufferSetLength(cchLen);\n\t\tif(lpstr != NULL)\n\t\t{\n\t\t\tnRet = GetLBText(nIndex, lpstr);\n\t\t\tstrText.ReleaseBuffer();\n\t\t}\n\t\treturn nRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tint GetLBTextLen(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETLBTEXTLEN, nIndex, 0L);\n\t}\n\n\tint GetItemHeight(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETITEMHEIGHT, nIndex, 0L);\n\t}\n\n\tint SetItemHeight(int nIndex, UINT cyItemHeight)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETITEMHEIGHT, nIndex, MAKELONG(cyItemHeight, 0));\n\t}\n\n\tBOOL GetExtendedUI() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_GETEXTENDEDUI, 0, 0L);\n\t}\n\n\tint SetExtendedUI(BOOL bExtended = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SETEXTENDEDUI, bExtended, 0L);\n\t}\n\n\tvoid GetDroppedControlRect(LPRECT lprect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)lprect);\n\t}\n\n\tBOOL GetDroppedState() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_GETDROPPEDSTATE, 0, 0L);\n\t}\n\n#if (_WIN32_WINNT >= 0x0501)\n\tint GetMinVisible() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_GETMINVISIBLE, 0, 0L);\n\t}\n\n\tBOOL SetMinVisible(int nMinVisible)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_SETMINVISIBLE, nMinVisible, 0L);\n\t}\n\n\t// Vista only\n\tBOOL GetCueBannerText(LPWSTR lpwText, int cchText) const\n\t{\n#ifndef CB_GETCUEBANNER\n\t\tconst UINT CB_GETCUEBANNER = (CBM_FIRST + 4);\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_GETCUEBANNER, (WPARAM)lpwText, cchText);\n\t}\n\n\t// Vista only\n\tBOOL SetCueBannerText(LPCWSTR lpcwText)\n\t{\n#ifndef CB_SETCUEBANNER\n\t\tconst UINT CB_SETCUEBANNER = (CBM_FIRST + 3);\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_SETCUEBANNER, 0, (LPARAM)lpcwText);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n// Operations\n\tint InitStorage(int nItems, UINT nBytes)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_INITSTORAGE, (WPARAM)nItems, nBytes);\n\t}\n\n\tvoid ResetContent()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, CB_RESETCONTENT, 0, 0L);\n\t}\n\n\t// for edit control\n\tBOOL LimitText(int nMaxChars)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0L);\n\t}\n\n\t// for drop-down combo boxes\n\tvoid ShowDropDown(BOOL bShowIt = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, CB_SHOWDROPDOWN, bShowIt, 0L);\n\t}\n\n\t// manipulating listbox items\n\tint AddString(LPCTSTR lpszString)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_ADDSTRING, 0, (LPARAM)lpszString);\n\t}\n\n\tint DeleteString(UINT nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_DELETESTRING, nIndex, 0L);\n\t}\n\n\tint InsertString(int nIndex, LPCTSTR lpszString)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_INSERTSTRING, nIndex, (LPARAM)lpszString);\n\t}\n\n#ifndef _WIN32_WCE\n\tint Dir(UINT attr, LPCTSTR lpszWildCard)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_DIR, attr, (LPARAM)lpszWildCard);\n\t}\n#endif // !_WIN32_WCE\n\n\t// selection helpers\n\tint FindString(int nStartAfter, LPCTSTR lpszString) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_FINDSTRING, nStartAfter, (LPARAM)lpszString);\n\t}\n\n\tint FindStringExact(int nIndexStart, LPCTSTR lpszFind) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_FINDSTRINGEXACT, nIndexStart, (LPARAM)lpszFind);\n\t}\n\n\tint SelectString(int nStartAfter, LPCTSTR lpszString)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CB_SELECTSTRING, nStartAfter, (LPARAM)lpszString);\n\t}\n\n\t// Clipboard operations\n\tvoid Clear()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);\n\t}\n\n\tvoid Copy()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_COPY, 0, 0L);\n\t}\n\n\tvoid Cut()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CUT, 0, 0L);\n\t}\n\n\tvoid Paste()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_PASTE, 0, 0L);\n\t}\n};\n\ntypedef CComboBoxT<ATL::CWindow>   CComboBox;\n\n#endif // !WIN32_PLATFORM_WFSP\n\n///////////////////////////////////////////////////////////////////////////////\n// CEdit - client side for a Windows EDIT control\n\ntemplate <class TBase>\nclass CEditT : public TBase\n{\npublic:\n// Constructors\n\tCEditT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCEditT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"EDIT\");\n\t}\n\n\tBOOL CanUndo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);\n\t}\n\n\tint GetLineCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L);\n\t}\n\n\tBOOL GetModify() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);\n\t}\n\n\tvoid SetModify(BOOL bModified = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L);\n\t}\n\n\tvoid GetRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tDWORD GetSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L);\n\t}\n\n\tvoid GetSel(int& nStartChar, int& nEndChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);\n\t}\n\n#ifndef _WIN32_WCE\n\tHLOCAL GetHandle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HLOCAL)::SendMessage(m_hWnd, EM_GETHANDLE, 0, 0L);\n\t}\n\n\tvoid SetHandle(HLOCAL hBuffer)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETHANDLE, (WPARAM)hBuffer, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tDWORD GetMargins() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L);\n\t}\n\n\tvoid GetMargins(UINT& nLeft, UINT& nRight) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETMARGINS, 0, 0L);\n\t\tnLeft = LOWORD(dwRet);\n\t\tnRight = HIWORD(dwRet);\n\t}\n\n\tvoid SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight));\n\t}\n\n\tUINT GetLimitText() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L);\n\t}\n\n\tvoid SetLimitText(UINT nMax)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETLIMITTEXT, nMax, 0L);\n\t}\n\n\tPOINT PosFromChar(UINT nChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_POSFROMCHAR, nChar, 0);\n\t\tPOINT point = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) };\n\t\treturn point;\n\t}\n\n\tint CharFromPos(POINT pt, int* pLine = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y));\n\t\tif(pLine != NULL)\n\t\t\t*pLine = (int)(short)HIWORD(dwRet);\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n\t// NOTE: first word in lpszBuffer must contain the size of the buffer!\n\tint GetLine(int nIndex, LPTSTR lpszBuffer) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);\n\t}\n\n\tint GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t*(LPWORD)lpszBuffer = (WORD)nMaxLength;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);\n\t}\n\n\tTCHAR GetPasswordChar() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (TCHAR)::SendMessage(m_hWnd, EM_GETPASSWORDCHAR, 0, 0L);\n\t}\n\n\tvoid SetPasswordChar(TCHAR ch)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETPASSWORDCHAR, ch, 0L);\n\t}\n\n#ifndef _WIN32_WCE\n\tEDITWORDBREAKPROC GetWordBreakProc() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L);\n\t}\n\n\tvoid SetWordBreakProc(EDITWORDBREAKPROC ewbprc)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc);\n\t}\n#endif // !_WIN32_WCE\n\n\tint GetFirstVisibleLine() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetThumb() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & ES_MULTILINE) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTHUMB, 0, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL SetReadOnly(BOOL bReadOnly = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L);\n\t}\n\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\tUINT GetImeStatus(UINT uStatus) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETIMESTATUS, uStatus, 0L);\n\t}\n\n\tUINT SetImeStatus(UINT uStatus, UINT uData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_SETIMESTATUS, uStatus, uData);\n\t}\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tBOOL GetCueBannerText(LPCWSTR lpstrText, int cchText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETCUEBANNER, (WPARAM)lpstrText, cchText);\n\t}\n\n\t// bKeepWithFocus - Vista only\n\tBOOL SetCueBannerText(LPCWSTR lpstrText, BOOL bKeepWithFocus = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCUEBANNER, (WPARAM)bKeepWithFocus, (LPARAM)(lpstrText));\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n// Operations\n\tvoid EmptyUndoBuffer()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L);\n\t}\n\n\tBOOL FmtLines(BOOL bAddEOL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_FMTLINES, bAddEOL, 0L);\n\t}\n\n\tvoid LimitText(int nChars = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_LIMITTEXT, nChars, 0L);\n\t}\n\n\tint LineFromChar(int nIndex = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_LINEFROMCHAR, nIndex, 0L);\n\t}\n\n\tint LineIndex(int nLine = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L);\n\t}\n\n\tint LineLength(int nLine = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L);\n\t}\n\n\tvoid LineScroll(int nLines, int nChars = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_LINESCROLL, nChars, nLines);\n\t}\n\n\tvoid ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText);\n\t}\n\n\tvoid SetRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tvoid SetRectNP(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETRECTNP, 0, (LPARAM)lpRect);\n\t}\n\n\tvoid SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETSEL, LOWORD(dwSelection), HIWORD(dwSelection));\n\t\tif(!bNoScroll)\n\t\t\t::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);\n\t}\n\n\tvoid SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar);\n\t\tif(!bNoScroll)\n\t\t\t::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);\n\t}\n\n\tvoid SetSelAll(BOOL bNoScroll = FALSE)\n\t{\n\t\tSetSel(0, -1, bNoScroll);\n\t}\n\n\tvoid SetSelNone(BOOL bNoScroll = FALSE)\n\t{\n\t\tSetSel(-1, 0, bNoScroll);\n\t}\n\n\tBOOL SetTabStops(int nTabStops, LPINT rgTabStops)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);\n\t}\n\n\tBOOL SetTabStops()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L);\n\t}\n\n\tBOOL SetTabStops(const int& cxEachStop)    // takes an 'int'\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);\n\t}\n\n\tvoid ScrollCaret()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);\n\t}\n\n\tint Scroll(int nScrollAction)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & ES_MULTILINE) != 0);\n\t\tLRESULT lRet = ::SendMessage(m_hWnd, EM_SCROLL, nScrollAction, 0L);\n\t\tif(!(BOOL)HIWORD(lRet))\n\t\t\treturn -1;   // failed\n\t\treturn (int)(short)LOWORD(lRet);\n\t\t\n\t}\n\n\tvoid InsertText(int nInsertAfterChar, LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE)\n\t{\n\t\tSetSel(nInsertAfterChar, nInsertAfterChar, bNoScroll);\n\t\tReplaceSel(lpstrText, bCanUndo);\n\t}\n\n\tvoid AppendText(LPCTSTR lpstrText, BOOL bNoScroll = FALSE, BOOL bCanUndo = FALSE)\n\t{\n\t\tInsertText(GetWindowTextLength(), lpstrText, bNoScroll, bCanUndo);\n\t}\n\n#if (_WIN32_WINNT >= 0x0501)\n\tBOOL ShowBalloonTip(PEDITBALLOONTIP pEditBaloonTip)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SHOWBALLOONTIP, 0, (LPARAM)pEditBaloonTip);\n\t}\n\n\tBOOL HideBalloonTip()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_HIDEBALLOONTIP, 0, 0L);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tDWORD GetHilite() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L);\n\t}\n\n\tvoid GetHilite(int& nStartChar, int& nEndChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, EM_GETHILITE, 0, 0L);\n\t\tnStartChar = (int)(short)LOWORD(dwRet);\n\t\tnEndChar = (int)(short)HIWORD(dwRet);\n\t}\n\n\tvoid SetHilite(int nStartChar, int nEndChar)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETHILITE, nStartChar, nEndChar);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n\t// Clipboard operations\n\tBOOL Undo()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L);\n\t}\n\n\tvoid Clear()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);\n\t}\n\n\tvoid Copy()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_COPY, 0, 0L);\n\t}\n\n\tvoid Cut()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CUT, 0, 0L);\n\t}\n\n\tvoid Paste()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_PASTE, 0, 0L);\n\t}\n\n#ifdef WIN32_PLATFORM_WFSP   // SmartPhone only messages\n\tDWORD GetExtendedStyle()\n\t{\n\t\treturn SendMessage(EM_GETEXTENDEDSTYLE);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwMask, DWORD dwExStyle)\n\t{\n\t\treturn SendMessage(EM_SETEXTENDEDSTYLE, (WPARAM)dwMask, (LPARAM)dwExStyle);\n\t}\n\n\tDWORD GetInputMode(BOOL bCurrentMode = TRUE)\n\t{\n\t\treturn SendMessage(EM_GETINPUTMODE, 0, (LPARAM)bCurrentMode);\n\t}\n\n\tBOOL SetInputMode(DWORD dwMode)\n\t{\n\t\treturn SendMessage(EM_SETINPUTMODE, 0, (LPARAM)dwMode);\n\t}\n\n\tBOOL SetSymbols(LPCTSTR szSymbols)\n\t{\n\t\treturn SendMessage(EM_SETSYMBOLS, 0, (LPARAM)szSymbols);\n\t}\n\n\tBOOL ResetSymbols()\n\t{\n\t\treturn SendMessage(EM_SETSYMBOLS);\n\t}\n#endif // WIN32_PLATFORM_WFSP\n};\n\ntypedef CEditT<ATL::CWindow>   CEdit;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CEditCommands - message handlers for standard EDIT commands\n\n// Chain to CEditCommands message map. Your class must also derive from CEdit.\n// Example:\n// class CMyEdit : public CWindowImpl<CMyEdit, CEdit>,\n//                 public CEditCommands<CMyEdit>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyEdit)\n//              // your handlers...\n//              CHAIN_MSG_MAP_ALT(CEditCommands<CMyEdit>, 1)\n//      END_MSG_MAP()\n//      // other stuff...\n// };\n\ntemplate <class T>\nclass CEditCommands\n{\npublic:\n\tBEGIN_MSG_MAP(CEditCommands< T >)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CUT, OnEditCut)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_PASTE, OnEditPaste)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, OnEditSelectAll)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_UNDO, OnEditUndo)\n\tEND_MSG_MAP()\n\n\tLRESULT OnEditClear(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Clear();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetSel(0, -1);\n\t\tpT->Clear();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Copy();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Cut();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Paste();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetSel(0, -1);\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditUndo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Undo();\n\t\treturn 0;\n\t}\n\n// State (update UI) helpers\n\tBOOL CanCut() const\n\t{ return HasSelection(); }\n\n\tBOOL CanCopy() const\n\t{ return HasSelection(); }\n\n\tBOOL CanClear() const\n\t{ return HasSelection(); }\n\n\tBOOL CanSelectAll() const\n\t{ return HasText(); }\n\n\tBOOL CanFind() const\n\t{ return HasText(); }\n\n\tBOOL CanRepeat() const\n\t{ return HasText(); }\n\n\tBOOL CanReplace() const\n\t{ return HasText(); }\n\n\tBOOL CanClearAll() const\n\t{ return HasText(); }\n\n// Implementation\n\tBOOL HasSelection() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tint nMin = 0, nMax = 0;\n\t\t::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nMin, (LPARAM)&nMax);\n\t\treturn (nMin != nMax);\n\t}\n\n\tBOOL HasText() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\treturn (pT->GetWindowTextLength() > 0);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CScrollBar - client side for a Windows SCROLLBAR control\n\ntemplate <class TBase>\nclass CScrollBarT : public TBase\n{\npublic:\n// Constructors\n\tCScrollBarT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCScrollBarT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn _T(\"SCROLLBAR\");\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetScrollPos() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::GetScrollPos(m_hWnd, SB_CTL);\n\t}\n#endif // !_WIN32_WCE\n\n\tint SetScrollPos(int nPos, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::SetScrollPos(m_hWnd, SB_CTL, nPos, bRedraw);\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid GetScrollRange(LPINT lpMinPos, LPINT lpMaxPos) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::GetScrollRange(m_hWnd, SB_CTL, lpMinPos, lpMaxPos);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid SetScrollRange(int nMinPos, int nMaxPos, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SetScrollRange(m_hWnd, SB_CTL, nMinPos, nMaxPos, bRedraw);\n\t}\n\n\tBOOL GetScrollInfo(LPSCROLLINFO lpScrollInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::GetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo);\n\t}\n\n\tint SetScrollInfo(LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::SetScrollInfo(m_hWnd, SB_CTL, lpScrollInfo, bRedraw);\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetScrollLimit() const\n\t{\n\t\tSCROLLINFO info = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE };\n\t\t::GetScrollInfo(m_hWnd, SB_CTL, &info);\n\t\tif(info.nPage > 1)\n\t\t\tinfo.nMax -= info.nPage - 1;\n\n\t\treturn info.nMax;\n\t}\n\n#if (WINVER >= 0x0500)\n\tBOOL GetScrollBarInfo(PSCROLLBARINFO pScrollBarInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if (_WIN32_WINNT >= 0x0501)\n\t\treturn (BOOL)::SendMessage(m_hWnd, SBM_GETSCROLLBARINFO, 0, (LPARAM)pScrollBarInfo);\n#else // !(_WIN32_WINNT >= 0x0501)\n\t\treturn ::GetScrollBarInfo(m_hWnd, OBJID_CLIENT, pScrollBarInfo);\n#endif // !(_WIN32_WINNT >= 0x0501)\n\t}\n#endif // (WINVER >= 0x0500)\n\n// Operations\n\tvoid ShowScrollBar(BOOL bShow = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::ShowScrollBar(m_hWnd, SB_CTL, bShow);\n\t}\n\n\tBOOL EnableScrollBar(UINT nArrowFlags = ESB_ENABLE_BOTH)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::EnableScrollBar(m_hWnd, SB_CTL, nArrowFlags);\n\t}\n#endif // !_WIN32_WCE\n};\n\ntypedef CScrollBarT<ATL::CWindow>   CScrollBar;\n\n\n// --- Windows Common Controls ---\n\n///////////////////////////////////////////////////////////////////////////////\n// CImageList\n\n// forward declarations\ntemplate <bool t_bManaged> class CImageListT;\ntypedef CImageListT<false>   CImageList;\ntypedef CImageListT<true>    CImageListManaged;\n\n\ntemplate <bool t_bManaged>\nclass CImageListT\n{\npublic:\n// Data members\n\tHIMAGELIST m_hImageList;\n\n// Constructor/destructor/operators\n\tCImageListT(HIMAGELIST hImageList = NULL) : m_hImageList(hImageList)\n\t{ }\n\n\t~CImageListT()\n\t{\n\t\tif(t_bManaged && (m_hImageList != NULL))\n\t\t\tDestroy();\n\t}\n\n\tCImageListT<t_bManaged>& operator =(HIMAGELIST hImageList)\n\t{\n\t\tAttach(hImageList);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HIMAGELIST hImageList)\n\t{\n\t\tif(t_bManaged && (m_hImageList != NULL) && (m_hImageList != hImageList))\n\t\t\tImageList_Destroy(m_hImageList);\n\t\tm_hImageList = hImageList;\n\t}\n\n\tHIMAGELIST Detach()\n\t{\n\t\tHIMAGELIST hImageList = m_hImageList;\n\t\tm_hImageList = NULL;\n\t\treturn hImageList;\n\t}\n\n\toperator HIMAGELIST() const { return m_hImageList; }\n\n\tbool IsNull() const { return (m_hImageList == NULL); }\n\n// Attributes\n\tint GetImageCount() const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetImageCount(m_hImageList);\n\t}\n\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetBkColor(m_hImageList);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF cr)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetBkColor(m_hImageList, cr);\n\t}\n\n\tBOOL GetImageInfo(int nImage, IMAGEINFO* pImageInfo) const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetImageInfo(m_hImageList, nImage, pImageInfo);\n\t}\n\n\tHICON GetIcon(int nIndex, UINT uFlags = ILD_NORMAL) const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetIcon(m_hImageList, nIndex, uFlags);\n\t}\n\n\tBOOL GetIconSize(int& cx, int& cy) const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetIconSize(m_hImageList, &cx, &cy);\n\t}\n\n\tBOOL GetIconSize(SIZE& size) const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_GetIconSize(m_hImageList, (int*)&size.cx, (int*)&size.cy);\n\t}\n\n\tBOOL SetIconSize(int cx, int cy)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetIconSize(m_hImageList, cx, cy);\n\t}\n\n\tBOOL SetIconSize(SIZE size)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetIconSize(m_hImageList, size.cx, size.cy);\n\t}\n\n\tBOOL SetImageCount(UINT uNewCount)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetImageCount(m_hImageList, uNewCount);\n\t}\n\n\tBOOL SetOverlayImage(int nImage, int nOverlay)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetOverlayImage(m_hImageList, nImage, nOverlay);\n\t}\n\n// Operations\n\tBOOL Create(int cx, int cy, UINT nFlags, int nInitial, int nGrow)\n\t{\n\t\tATLASSERT(m_hImageList == NULL);\n\t\tm_hImageList = ImageList_Create(cx, cy, nFlags, nInitial, nGrow);\n\t\treturn (m_hImageList != NULL) ? TRUE : FALSE;\n\t}\n\n\tBOOL Create(ATL::_U_STRINGorID bitmap, int cx, int nGrow, COLORREF crMask)\n\t{\n\t\tATLASSERT(m_hImageList == NULL);\n\t\tm_hImageList = ImageList_LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, cx, nGrow, crMask);\n\t\treturn (m_hImageList != NULL) ? TRUE : FALSE;\n\t}\n\n\tBOOL CreateFromImage(ATL::_U_STRINGorID image, int cx, int nGrow, COLORREF crMask, UINT uType, UINT uFlags = LR_DEFAULTCOLOR | LR_DEFAULTSIZE)\n\t{\n\t\tATLASSERT(m_hImageList == NULL);\n\t\tm_hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, cx, nGrow, crMask, uType, uFlags);\n\t\treturn (m_hImageList != NULL) ? TRUE : FALSE;\n\t}\n\n\tBOOL Merge(HIMAGELIST hImageList1, int nImage1, HIMAGELIST hImageList2, int nImage2, int dx, int dy)\n\t{\n\t\tATLASSERT(m_hImageList == NULL);\n\t\tm_hImageList = ImageList_Merge(hImageList1, nImage1, hImageList2, nImage2, dx, dy);\n\t\treturn (m_hImageList != NULL) ? TRUE : FALSE;\n\t}\n\n#ifndef _WIN32_WCE\n#ifdef __IStream_INTERFACE_DEFINED__\n\tBOOL CreateFromStream(LPSTREAM lpStream)\n\t{\n\t\tATLASSERT(m_hImageList == NULL);\n\t\tm_hImageList = ImageList_Read(lpStream);\n\t\treturn (m_hImageList != NULL) ? TRUE : FALSE;\n\t}\n#endif // __IStream_INTERFACE_DEFINED__\n#endif // !_WIN32_WCE\n\n\tBOOL Destroy()\n\t{\n\t\tif (m_hImageList == NULL)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = ImageList_Destroy(m_hImageList);\n\t\tif(bRet)\n\t\t\tm_hImageList = NULL;\n\t\treturn bRet;\n\t}\n\n\tint Add(HBITMAP hBitmap, HBITMAP hBitmapMask = NULL)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_Add(m_hImageList, hBitmap, hBitmapMask);\n\t}\n\n\tint Add(HBITMAP hBitmap, COLORREF crMask)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_AddMasked(m_hImageList, hBitmap, crMask);\n\t}\n\n\tBOOL Remove(int nImage)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_Remove(m_hImageList, nImage);\n\t}\n\n\tBOOL RemoveAll()\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_RemoveAll(m_hImageList);\n\t}\n\n\tBOOL Replace(int nImage, HBITMAP hBitmap, HBITMAP hBitmapMask)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_Replace(m_hImageList, nImage, hBitmap, hBitmapMask);\n\t}\n\n\tint AddIcon(HICON hIcon)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_AddIcon(m_hImageList, hIcon);\n\t}\n\n\tint ReplaceIcon(int nImage, HICON hIcon)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_ReplaceIcon(m_hImageList, nImage, hIcon);\n\t}\n\n\tHICON ExtractIcon(int nImage)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_ExtractIcon(NULL, m_hImageList, nImage);\n\t}\n\n\tBOOL Draw(HDC hDC, int nImage, int x, int y, UINT nStyle)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\treturn ImageList_Draw(m_hImageList, nImage, hDC, x, y, nStyle);\n\t}\n\n\tBOOL Draw(HDC hDC, int nImage, POINT pt, UINT nStyle)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\treturn ImageList_Draw(m_hImageList, nImage, hDC, pt.x, pt.y, nStyle);\n\t}\n\n\tBOOL DrawEx(int nImage, HDC hDC, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\treturn ImageList_DrawEx(m_hImageList, nImage, hDC, x, y, dx, dy, rgbBk, rgbFg, fStyle);\n\t}\n\n\tBOOL DrawEx(int nImage, HDC hDC, RECT& rect, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\treturn ImageList_DrawEx(m_hImageList, nImage, hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rgbBk, rgbFg, fStyle);\n\t}\n\n\tstatic BOOL DrawIndirect(IMAGELISTDRAWPARAMS* pimldp)\n\t{\n\t\treturn ImageList_DrawIndirect(pimldp);\n\t}\n\n\tBOOL Copy(int nSrc, int nDst, UINT uFlags = ILCF_MOVE)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_Copy(m_hImageList, nDst, m_hImageList, nSrc, uFlags);\n\t}\n\n#ifdef __IStream_INTERFACE_DEFINED__\n#ifndef _WIN32_WCE\n\tstatic HIMAGELIST Read(LPSTREAM lpStream)\n\t{\n\t\treturn ImageList_Read(lpStream);\n\t}\n\n\tBOOL Write(LPSTREAM lpStream)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_Write(m_hImageList, lpStream);\n\t}\n#endif // !_WIN32_WCE\n\n#if (_WIN32_WINNT >= 0x0501)\n\tstatic HRESULT ReadEx(DWORD dwFlags, LPSTREAM lpStream, REFIID riid, PVOID* ppv)\n\t{\n\t\treturn ImageList_ReadEx(dwFlags, lpStream, riid, ppv);\n\t}\n\n\tHRESULT WriteEx(DWORD dwFlags, LPSTREAM lpStream)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_WriteEx(m_hImageList, dwFlags, lpStream);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n#endif // __IStream_INTERFACE_DEFINED__\n\n\t// Drag operations\n\tBOOL BeginDrag(int nImage, POINT ptHotSpot)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_BeginDrag(m_hImageList, nImage, ptHotSpot.x, ptHotSpot.y);\n\t}\n\n\tBOOL BeginDrag(int nImage, int xHotSpot, int yHotSpot)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_BeginDrag(m_hImageList, nImage, xHotSpot, yHotSpot);\n\t}\n\n\tstatic void EndDrag()\n\t{\n\t\tImageList_EndDrag();\n\t}\n\n\tstatic BOOL DragMove(POINT pt)\n\t{\n\t\treturn ImageList_DragMove(pt.x, pt.y);\n\t}\n\n\tstatic BOOL DragMove(int x, int y)\n\t{\n\t\treturn ImageList_DragMove(x, y);\n\t}\n\n\tBOOL SetDragCursorImage(int nDrag, POINT ptHotSpot)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetDragCursorImage(m_hImageList, nDrag, ptHotSpot.x, ptHotSpot.y);\n\t}\n\n\tBOOL SetDragCursorImage(int nDrag, int xHotSpot, int yHotSpot)\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn ImageList_SetDragCursorImage(m_hImageList, nDrag, xHotSpot, yHotSpot);\n\t}\n\n\tstatic BOOL DragShowNolock(BOOL bShow = TRUE)\n\t{\n\t\treturn ImageList_DragShowNolock(bShow);\n\t}\n\n\tstatic CImageList GetDragImage(LPPOINT lpPoint, LPPOINT lpPointHotSpot)\n\t{\n\t\treturn CImageList(ImageList_GetDragImage(lpPoint, lpPointHotSpot));\n\t}\n\n\tstatic BOOL DragEnter(HWND hWnd, POINT point)\n\t{\n\t\treturn ImageList_DragEnter(hWnd, point.x, point.y);\n\t}\n\n\tstatic BOOL DragEnter(HWND hWnd, int x, int y)\n\t{\n\t\treturn ImageList_DragEnter(hWnd, x, y);\n\t}\n\n\tstatic BOOL DragLeave(HWND hWnd)\n\t{\n\t\treturn ImageList_DragLeave(hWnd);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tCImageList Duplicate() const\n\t{\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn CImageList(ImageList_Duplicate(m_hImageList));\n\t}\n\n\tstatic CImageList Duplicate(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(hImageList != NULL);\n\t\treturn CImageList(ImageList_Duplicate(hImageList));\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CToolTipCtrl\n\n#ifndef _WIN32_WCE\n\nclass CToolInfo : public TOOLINFO\n{\npublic:\n\tCToolInfo(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL)\n\t{\n\t\tInit(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam);\n\t}\n\n\toperator LPTOOLINFO() { return this; }\n\n\toperator LPARAM() { return (LPARAM)this; }\n\n\tvoid Init(UINT nFlags, HWND hWnd, UINT_PTR nIDTool = 0, LPRECT lpRect = NULL, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tmemset(this, 0, sizeof(TOOLINFO));\n\t\tcbSize = RunTimeHelper::SizeOf_TOOLINFO();\n\t\tuFlags = nFlags;\n\t\tif(nIDTool == 0)\n\t\t{\n\t\t\thwnd = ::GetParent(hWnd);\n\t\t\tuFlags |= TTF_IDISHWND;\n\t\t\tuId = (UINT_PTR)hWnd;\n\t\t}\n\t\telse\n\t\t{\n\t\t\thwnd = hWnd;\n\t\t\tuId = nIDTool;\n\t\t}\n\t\tif(lpRect != NULL)\n\t\t\trect = *lpRect;\n\t\thinst = ModuleHelper::GetResourceInstance();\n\t\tlpszText = lpstrText;\n\t\tlParam = lUserParam;\n\t}\n};\n\ntemplate <class TBase>\nclass CToolTipCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCToolTipCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCToolTipCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn TOOLTIPS_CLASS;\n\t}\n\n\tvoid GetText(LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&lpToolInfo);\n\t}\n\n\tvoid GetText(LPTSTR lpstrText, HWND hWnd, UINT_PTR nIDTool = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\t\tCToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText);\n\t\t::SendMessage(m_hWnd, TTM_GETTEXT, 0, ti);\n\t}\n\n\tBOOL GetToolInfo(LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tBOOL GetToolInfo(HWND hWnd, UINT_PTR nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\t\tATLASSERT(puFlags != NULL);\n\t\tATLASSERT(lpRect != NULL);\n\t\tCToolInfo ti(0, hWnd, nIDTool, NULL, lpstrText);\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, ti);\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\t*puFlags = ti.uFlags;\n\t\t\t*lpRect = ti.rect;\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tvoid SetToolInfo(LPTOOLINFO lpToolInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid SetToolRect(LPTOOLINFO lpToolInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid SetToolRect(HWND hWnd, UINT_PTR nIDTool, LPCRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\t\tATLASSERT(nIDTool != 0);\n\n\t\tCToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, NULL);\n\t\t::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, ti);\n\t}\n\n\tint GetToolCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TTM_GETTOOLCOUNT, 0, 0L);\n\t}\n\n\tint GetDelayTime(DWORD dwType) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TTM_GETDELAYTIME, dwType, 0L);\n\t}\n\n\tvoid SetDelayTime(DWORD dwType, int nTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0));\n\t}\n\n\tvoid GetMargin(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_GETMARGIN, 0, (LPARAM)lpRect);\n\t}\n\n\tvoid SetMargin(LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETMARGIN, 0, (LPARAM)lpRect);\n\t}\n\n\tint GetMaxTipWidth() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TTM_GETMAXTIPWIDTH, 0, 0L);\n\t}\n\n\tint SetMaxTipWidth(int nWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TTM_SETMAXTIPWIDTH, 0, nWidth);\n\t}\n\n\tCOLORREF GetTipBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPBKCOLOR, 0, 0L);\n\t}\n\n\tvoid SetTipBkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L);\n\t}\n\n\tCOLORREF GetTipTextColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TTM_GETTIPTEXTCOLOR, 0, 0L);\n\t}\n\n\tvoid SetTipTextColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L);\n\t}\n\n\tBOOL GetCurrentTool(LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo);\n\t}\n\n#if (_WIN32_IE >= 0x0500)\n\tSIZE GetBubbleSize(LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo);\n\t\tSIZE size = { GET_X_LPARAM(dwRet), GET_Y_LPARAM(dwRet) };\n\t\treturn size;\n\t}\n\n\tBOOL SetTitle(UINT_PTR uIcon, LPCTSTR lpstrTitle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle);\n\t}\n\n\tBOOL SetTitle(HICON hIcon, LPCTSTR lpstrTitle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_SETTITLE, (WPARAM)hIcon, (LPARAM)lpstrTitle);\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tvoid GetTitle(PTTGETTITLE pTTGetTitle) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_GETTITLE, 0, (LPARAM)pTTGetTitle);\n\t}\n\n\tvoid SetWindowTheme(LPCWSTR lpstrTheme)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n// Operations\n\tvoid Activate(BOOL bActivate)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_ACTIVATE, bActivate, 0L);\n\t}\n\n\tBOOL AddTool(LPTOOLINFO lpToolInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tBOOL AddTool(HWND hWnd, ATL::_U_STRINGorID text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = NULL, UINT_PTR nIDTool = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\t\t// the toolrect and toolid must both be zero or both valid\n\t\tATLASSERT((lpRectTool != NULL && nIDTool != 0) || (lpRectTool == NULL && nIDTool == 0));\n\n\t\tCToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text.m_lpstr);\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_ADDTOOL, 0, ti);\n\t}\n\n\tvoid DelTool(LPTOOLINFO lpToolInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid DelTool(HWND hWnd, UINT_PTR nIDTool = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\n\t\tCToolInfo ti(0, hWnd, nIDTool, NULL, NULL);\n\t\t::SendMessage(m_hWnd, TTM_DELTOOL, 0, ti);\n\t}\n\n\tBOOL HitTest(LPTTHITTESTINFO lpHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)lpHitTestInfo);\n\t}\n\n\tBOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\t\tATLASSERT(lpToolInfo != NULL);\n\n\t\tTTHITTESTINFO hti = { 0 };\n\t\thti.ti.cbSize = RunTimeHelper::SizeOf_TOOLINFO();\n\t\thti.hwnd = hWnd;\n\t\thti.pt.x = pt.x;\n\t\thti.pt.y = pt.y;\n\t\tif((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti) != FALSE)\n\t\t{\n\t\t\t*lpToolInfo = hti.ti;\n\t\t\treturn TRUE;\n\t\t}\n\t\treturn FALSE;\n\t}\n\n\tvoid RelayEvent(LPMSG lpMsg)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_RELAYEVENT, 0, (LPARAM)lpMsg);\n\t}\n\n\tvoid UpdateTipText(LPTOOLINFO lpToolInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid UpdateTipText(ATL::_U_STRINGorID text, HWND hWnd, UINT_PTR nIDTool = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\n\t\tCToolInfo ti(0, hWnd, nIDTool, NULL, (LPTSTR)text.m_lpstr);\n\t\t::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, ti);\n\t}\n\n\tBOOL EnumTools(UINT_PTR nTool, LPTOOLINFO lpToolInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid Pop()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_POP, 0, 0L);\n\t}\n\n\tvoid TrackActivate(LPTOOLINFO lpToolInfo, BOOL bActivate)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, (LPARAM)lpToolInfo);\n\t}\n\n\tvoid TrackActivate(HWND hWnd, UINT_PTR nIDTool, BOOL bActivate)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hWnd != NULL);\n\n\t\tCToolInfo ti(0, hWnd, nIDTool);\n\t\t::SendMessage(m_hWnd, TTM_TRACKACTIVATE, bActivate, ti);\n\t}\n\n\tvoid TrackPosition(int xPos, int yPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos));\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tvoid Update()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_UPDATE, 0, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500)\n\tBOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect);\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tvoid Popup()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TTM_POPUP, 0, 0L);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n};\n\ntypedef CToolTipCtrlT<ATL::CWindow>   CToolTipCtrl;\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CHeaderCtrl\n\ntemplate <class TBase>\nclass CHeaderCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCHeaderCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCHeaderCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_HEADER;\n\t}\n\n\tint GetItemCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_GETITEMCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItem(int nIndex, LPHDITEM pHeaderItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETITEM, nIndex, (LPARAM)pHeaderItem);\n\t}\n\n\tBOOL SetItem(int nIndex, LPHDITEM pHeaderItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_SETITEM, nIndex, (LPARAM)pHeaderItem);\n\t}\n\n\tCImageList GetImageList() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_GETIMAGELIST, 0, 0L));\n\t}\n\n\tCImageList SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_SETIMAGELIST, 0, (LPARAM)hImageList));\n\t}\n\n\tBOOL GetOrderArray(int nSize, int* lpnArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETORDERARRAY, nSize, (LPARAM)lpnArray);\n\t}\n\n\tBOOL SetOrderArray(int nSize, int* lpnArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_SETORDERARRAY, nSize, (LPARAM)lpnArray);\n\t}\n\n\tBOOL GetItemRect(int nIndex, LPRECT lpItemRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETITEMRECT, nIndex, (LPARAM)lpItemRect);\n\t}\n\n\tint SetHotDivider(BOOL bPos, DWORD dwInputValue)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_SETHOTDIVIDER, bPos, dwInputValue);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tint GetBitmapMargin() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_GETBITMAPMARGIN, 0, 0L);\n\t}\n\n\tint SetBitmapMargin(int nWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_SETBITMAPMARGIN, nWidth, 0L);\n\t}\n\n\tint SetFilterChangeTimeout(DWORD dwTimeOut)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_SETFILTERCHANGETIMEOUT, 0, dwTimeOut);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tBOOL GetItemDropDownRect(int nIndex, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect);\n\t}\n\n\tBOOL GetOverflowRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_GETOVERFLOWRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tint GetFocusedItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_GETFOCUSEDITEM, 0, 0L);\n\t}\n\n\tBOOL SetFocusedItem(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_SETFOCUSEDITEM, 0, nIndex);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tint InsertItem(int nIndex, LPHDITEM phdi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_INSERTITEM, nIndex, (LPARAM)phdi);\n\t}\n\n\tint AddItem(LPHDITEM phdi)\n\t{\n\t\treturn InsertItem(GetItemCount(), phdi);\n\t}\n\n\tBOOL DeleteItem(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_DELETEITEM, nIndex, 0L);\n\t}\n\n\tBOOL Layout(HD_LAYOUT* pHeaderLayout)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, HDM_LAYOUT, 0, (LPARAM)pHeaderLayout);\n\t}\n\n\tint HitTest(LPHDHITTESTINFO lpHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_HITTEST, 0, (LPARAM)lpHitTestInfo);\n\t}\n\n\tint OrderToIndex(int nOrder)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_ORDERTOINDEX, nOrder, 0L);\n\t}\n\n\tCImageList CreateDragImage(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, HDM_CREATEDRAGIMAGE, nIndex, 0L));\n\t}\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tint EditFilter(int nColumn, BOOL bDiscardChanges)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_EDITFILTER, nColumn, MAKELPARAM(bDiscardChanges, 0));\n\t}\n\n\tint ClearFilter(int nColumn)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, nColumn, 0L);\n\t}\n\n\tint ClearAllFilters()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, HDM_CLEARFILTER, (WPARAM)-1, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n};\n\ntypedef CHeaderCtrlT<ATL::CWindow>   CHeaderCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CListViewCtrl\n\ntemplate <class TBase>\nclass CListViewCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCListViewCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCListViewCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_LISTVIEW;\n\t}\n\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_GETBKCOLOR, 0, 0L);\n\t}\n\n\tBOOL SetBkColor(COLORREF cr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETBKCOLOR, 0, cr);\n\t}\n\n\tCImageList GetImageList(int nImageListType) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_GETIMAGELIST, nImageListType, 0L));\n\t}\n\n\tCImageList SetImageList(HIMAGELIST hImageList, int nImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, nImageList, (LPARAM)hImageList));\n\t}\n\n\tint GetItemCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETITEMCOUNT, 0, 0L);\n\t}\n\n\tBOOL SetItemCount(int nItems)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, 0L);\n\t}\n\n\tBOOL GetItem(LPLVITEM pItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItem(const LVITEM* pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem,\n\t\tint nImage, UINT nState, UINT nStateMask, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.mask = nMask;\n\t\tlvi.iItem = nItem;\n\t\tlvi.iSubItem = nSubItem;\n\t\tlvi.stateMask = nStateMask;\n\t\tlvi.state = nState;\n\t\tlvi.pszText = (LPTSTR) lpszItem;\n\t\tlvi.iImage = nImage;\n\t\tlvi.lParam = lParam;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEM, 0, (LPARAM)&lvi);\n\t}\n\n\tUINT GetItemState(int nItem, UINT nMask) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, LVM_GETITEMSTATE, nItem, nMask);\n\t}\n\n\tBOOL SetItemState(int nItem, UINT nState, UINT nStateMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.state = nState;\n\t\tlvi.stateMask = nStateMask;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)&lvi);\n\t}\n\n\tBOOL SetItemState(int nItem, LPLVITEM pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMSTATE, nItem, (LPARAM)pItem);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetItemText(int nItem, int nSubItem, BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.iSubItem = nSubItem;\n\n\t\tLPTSTR lpstrText = NULL;\n\t\tint nRes = 0;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tATLTRY(lpstrText = new TCHAR[nLen]);\n\t\t\tif(lpstrText == NULL)\n\t\t\t\tbreak;\n\t\t\tlpstrText[0] = NULL;\n\t\t\tlvi.cchTextMax = nLen;\n\t\t\tlvi.pszText = lpstrText;\n\t\t\tnRes  = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);\n\t\t\tif(nRes < nLen - 1)\n\t\t\t\tbreak;\n\t\t\tdelete [] lpstrText;\n\t\t\tlpstrText = NULL;\n\t\t}\n\n\t\tif(lpstrText != NULL)\n\t\t{\n\t\t\tif(nRes != 0)\n\t\t\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\t\tdelete [] lpstrText;\n\t\t}\n\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetItemText(int nItem, int nSubItem, _CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.iSubItem = nSubItem;\n\n\t\tstrText.Empty();\n\t\tint nRes = 0;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tlvi.cchTextMax = nLen;\n\t\t\tlvi.pszText = strText.GetBufferSetLength(nLen);\n\t\t\tif(lvi.pszText == NULL)\n\t\t\t{\n\t\t\t\tnRes = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnRes  = (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);\n\t\t\tif(nRes < nLen - 1)\n\t\t\t\tbreak;\n\t\t}\n\t\tstrText.ReleaseBuffer();\n\t\treturn nRes;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tint GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.iSubItem = nSubItem;\n\t\tlvi.cchTextMax = nLen;\n\t\tlvi.pszText = lpszText;\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)&lvi);\n\t}\n\n\tBOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(nItem, nSubItem, LVIF_TEXT, lpszText, 0, 0, 0, 0);\n\t}\n\n\tDWORD_PTR GetItemData(int nItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.iItem = nItem;\n\t\tlvi.mask = LVIF_PARAM;\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)&lvi);\n\t\treturn (DWORD_PTR)(bRet ? lvi.lParam : NULL);\n\t}\n\n\tBOOL SetItemData(int nItem, DWORD_PTR dwData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(nItem, 0, LVIF_PARAM, NULL, 0, 0, 0, (LPARAM)dwData);\n\t}\n\n\tUINT GetCallbackMask() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, LVM_GETCALLBACKMASK, 0, 0L);\n\t}\n\n\tBOOL SetCallbackMask(UINT nMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETCALLBACKMASK, nMask, 0L);\n\t}\n\n\tBOOL GetItemPosition(int nItem, LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)lpPoint);\n\t}\n\n\tBOOL SetItemPosition(int nItem, POINT pt)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt);\n\t}\n\n\tBOOL SetItemPosition(int nItem, int x, int y)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(((GetStyle() & LVS_TYPEMASK) == LVS_ICON) || ((GetStyle() & LVS_TYPEMASK) == LVS_SMALLICON));\n\t\tPOINT pt = { x, y };\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMPOSITION32, nItem, (LPARAM)&pt);\n\t}\n\n\tint GetStringWidth(LPCTSTR lpsz) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETSTRINGWIDTH, 0, (LPARAM)lpsz);\n\t}\n\n\tCEdit GetEditControl() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CEdit((HWND)::SendMessage(m_hWnd, LVM_GETEDITCONTROL, 0, 0L));\n\t}\n\n\tBOOL GetColumn(int nCol, LVCOLUMN* pColumn) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMN, nCol, (LPARAM)pColumn);\n\t}\n\n\tBOOL SetColumn(int nCol, const LVCOLUMN* pColumn)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMN, nCol, (LPARAM)pColumn);\n\t}\n\n\tint GetColumnWidth(int nCol) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETCOLUMNWIDTH, nCol, 0L);\n\t}\n\n\tBOOL SetColumnWidth(int nCol, int cx)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNWIDTH, nCol, MAKELPARAM(cx, 0));\n\t}\n\n\tBOOL GetViewRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETVIEWRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tCOLORREF GetTextColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTCOLOR, 0, 0L);\n\t}\n\n\tBOOL SetTextColor(COLORREF cr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTCOLOR, 0, cr);\n\t}\n\n\tCOLORREF GetTextBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_GETTEXTBKCOLOR, 0, 0L);\n\t}\n\n\tBOOL SetTextBkColor(COLORREF cr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETTEXTBKCOLOR, 0, cr);\n\t}\n\n\tint GetTopIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETTOPINDEX, 0, 0L);\n\t}\n\n\tint GetCountPerPage() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETCOUNTPERPAGE, 0, 0L);\n\t}\n\n\tBOOL GetOrigin(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETORIGIN, 0, (LPARAM)lpPoint);\n\t}\n\n\tUINT GetSelectedCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, LVM_GETSELECTEDCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tlpRect->left = nCode;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETITEMRECT, (WPARAM)nItem, (LPARAM)lpRect);\n\t}\n\n#ifndef _WIN32_WCE\n\tHCURSOR GetHotCursor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HCURSOR)::SendMessage(m_hWnd, LVM_GETHOTCURSOR, 0, 0L);\n\t}\n\n\tHCURSOR SetHotCursor(HCURSOR hHotCursor)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HCURSOR)::SendMessage(m_hWnd, LVM_SETHOTCURSOR, 0, (LPARAM)hHotCursor);\n\t}\n\n\tint GetHotItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETHOTITEM, 0, 0L);\n\t}\n\n\tint SetHotItem(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SETHOTITEM, nIndex, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL GetColumnOrderArray(int nCount, int* lpnArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray);\n\t}\n\n\tBOOL SetColumnOrderArray(int nCount, int* lpnArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETCOLUMNORDERARRAY, nCount, (LPARAM)lpnArray);\n\t}\n\n\tCHeaderCtrl GetHeader() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CHeaderCtrl((HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0L));\n\t}\n\n\tBOOL GetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT);\n\t\tATLASSERT(lpRect != NULL);\n\t\tlpRect->top = nSubItem;\n\t\tlpRect->left = nFlag;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETSUBITEMRECT, nItem, (LPARAM)lpRect);\n\t}\n\n\tDWORD SetIconSpacing(int cx, int cy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LVS_TYPEMASK) == LVS_ICON);\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_SETICONSPACING, 0, MAKELPARAM(cx, cy));\n\t}\n\n\tint GetISearchString(LPTSTR lpstr) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETISEARCHSTRING, 0, (LPARAM)lpstr);\n\t}\n\n\tvoid GetItemSpacing(SIZE& sizeSpacing, BOOL bSmallIconView = FALSE) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, LVM_GETITEMSPACING, bSmallIconView, 0L);\n\t\tsizeSpacing.cx = GET_X_LPARAM(dwRet);\n\t\tsizeSpacing.cy = GET_Y_LPARAM(dwRet);\n\t}\n\n#if (_WIN32_WCE >= 410)\n\tvoid SetItemSpacing(INT cySpacing)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tListView_SetItemSpacing(m_hWnd, cySpacing);\n\t}\n#endif // (_WIN32_WCE >= 410)\n\n\t// single-selection only\n\tint GetSelectedIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LVS_SINGLESEL) != 0);\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0));\n\t}\n\n\tBOOL GetSelectedItem(LPLVITEM pItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & LVS_SINGLESEL) != 0);\n\t\tATLASSERT(pItem != NULL);\n\t\tpItem->iItem = (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_ALL | LVNI_SELECTED, 0));\n\t\tif(pItem->iItem == -1)\n\t\t\treturn FALSE;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETITEM, 0, (LPARAM)pItem);\n\t}\n\n\t// extended list view styles\n\tDWORD GetExtendedListViewStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0L);\n\t}\n\n\t// dwExMask = 0 means all styles\n\tDWORD SetExtendedListViewStyle(DWORD dwExStyle, DWORD dwExMask = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExMask, dwExStyle);\n\t}\n\n\t// checkboxes only\n\tBOOL GetCheckState(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetExtendedListViewStyle() & LVS_EX_CHECKBOXES) != 0);\n\t\tUINT uRet = GetItemState(nIndex, LVIS_STATEIMAGEMASK);\n\t\treturn (uRet >> 12) - 1;\n\t}\n\n\tBOOL SetCheckState(int nItem, BOOL bCheck)\n\t{\n\t\tint nCheck = bCheck ? 2 : 1;   // one based index\n\t\treturn SetItemState(nItem, INDEXTOSTATEIMAGEMASK(nCheck), LVIS_STATEIMAGEMASK);\n\t}\n\n\t// view type\n\tDWORD GetViewType() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (GetStyle() & LVS_TYPEMASK);\n\t}\n\n\tDWORD SetViewType(DWORD dwType)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(dwType == LVS_ICON || dwType == LVS_SMALLICON || dwType == LVS_LIST || dwType == LVS_REPORT);\n\t\tDWORD dwOldType = GetViewType();\n\t\tif(dwType != dwOldType)\n\t\t\tModifyStyle(LVS_TYPEMASK, (dwType & LVS_TYPEMASK));\n\t\treturn dwOldType;\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n#ifndef _WIN32_WCE\n\tBOOL GetBkImage(LPLVBKIMAGE plvbki) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETBKIMAGE, 0, (LPARAM)plvbki);\n\t}\n\n\tBOOL SetBkImage(LPLVBKIMAGE plvbki)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETBKIMAGE, 0, (LPARAM)plvbki);\n\t}\n#endif // !_WIN32_WCE\n\n\tint GetSelectionMark() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETSELECTIONMARK, 0, 0L);\n\t}\n\n\tint SetSelectionMark(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SETSELECTIONMARK, 0, nIndex);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetWorkAreas(int nWorkAreas, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETWORKAREAS, nWorkAreas, (LPARAM)lpRect);\n\t}\n\n\tBOOL SetWorkAreas(int nWorkAreas, LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETWORKAREAS, nWorkAreas, (LPARAM)lpRect);\n\t}\n\n\tDWORD GetHoverTime() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0);\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_GETHOVERTIME, 0, 0L);\n\t}\n\n\tDWORD SetHoverTime(DWORD dwHoverTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetExtendedListViewStyle() & (LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE | LVS_EX_TWOCLICKACTIVATE)) != 0);\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_SETHOVERTIME, 0, dwHoverTime);\n\t}\n\n\tBOOL GetNumberOfWorkAreas(int* pnWorkAreas) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETNUMBEROFWORKAREAS, 0, (LPARAM)pnWorkAreas);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL SetItemCountEx(int nItems, DWORD dwFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(((GetStyle() & LVS_OWNERDATA) != 0) && (((GetStyle() & LVS_TYPEMASK) == LVS_REPORT) || ((GetStyle() & LVS_TYPEMASK) == LVS_LIST)));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMCOUNT, nItems, dwFlags);\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_GETTOOLTIPS, 0, 0L));\n\t}\n\n\tCToolTipCtrl SetToolTips(HWND hWndTT)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, LVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L));\n\t}\n\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tint GetSelectedColumn() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETSELECTEDCOLUMN, 0, 0L);\n\t}\n\n\tvoid SetSelectedColumn(int nColumn)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_SETSELECTEDCOLUMN, nColumn, 0L);\n\t}\n\n\tDWORD GetView() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_GETVIEW, 0, 0L);\n\t}\n\n\tint SetView(DWORD dwView)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SETVIEW, dwView, 0L);\n\t}\n\n\tBOOL IsGroupViewEnabled() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_ISGROUPVIEWENABLED, 0, 0L);\n\t}\n\n\tint GetGroupInfo(int nGroupID, PLVGROUP pGroup) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETGROUPINFO, nGroupID, (LPARAM)pGroup);\n\t}\n\n\tint SetGroupInfo(int nGroupID, PLVGROUP pGroup)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SETGROUPINFO, nGroupID, (LPARAM)pGroup);\n\t}\n\n\tvoid GetGroupMetrics(PLVGROUPMETRICS pGroupMetrics) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_GETGROUPMETRICS, 0, (LPARAM)pGroupMetrics);\n\t}\n\n\tvoid SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_SETGROUPMETRICS, 0, (LPARAM)pGroupMetrics);\n\t}\n\n\tvoid GetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_GETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo);\n\t}\n\n\tBOOL SetTileViewInfo(PLVTILEVIEWINFO pTileViewInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETTILEVIEWINFO, 0, (LPARAM)pTileViewInfo);\n\t}\n\n\tvoid GetTileInfo(PLVTILEINFO pTileInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_GETTILEINFO, 0, (LPARAM)pTileInfo);\n\t}\n\n\tBOOL SetTileInfo(PLVTILEINFO pTileInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETTILEINFO, 0, (LPARAM)pTileInfo);\n\t}\n\n\tBOOL GetInsertMark(LPLVINSERTMARK pInsertMark) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETINSERTMARK, 0, (LPARAM)pInsertMark);\n\t}\n\n\tBOOL SetInsertMark(LPLVINSERTMARK pInsertMark)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETINSERTMARK, 0, (LPARAM)pInsertMark);\n\t}\n\n\tint GetInsertMarkRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETINSERTMARKRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tCOLORREF GetInsertMarkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_GETINSERTMARKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetInsertMarkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_SETINSERTMARKCOLOR, 0, clr);\n\t}\n\n\tCOLORREF GetOutlineColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_GETOUTLINECOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetOutlineColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, LVM_SETOUTLINECOLOR, 0, clr);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tint GetGroupCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETGROUPCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetGroupInfoByIndex(int nIndex, PLVGROUP pGroup) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPINFOBYINDEX, nIndex, (LPARAM)pGroup);\n\t}\n\n\tBOOL GetGroupRect(int nGroupID, int nType, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpRect != NULL);\n\t\tif(lpRect != NULL)\n\t\t\tlpRect->top = nType;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETGROUPRECT, nGroupID, (LPARAM)lpRect);\n\t}\n\n\tUINT GetGroupState(int nGroupID, UINT uMask) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, LVM_GETGROUPSTATE, nGroupID, (LPARAM)uMask);\n\t}\n\n\tint GetFocusedGroup() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETFOCUSEDGROUP, 0, 0L);\n\t}\n\n\tBOOL GetEmptyText(LPWSTR lpstrText, int cchText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETEMPTYTEXT, cchText, (LPARAM)lpstrText);\n\t}\n\n\tBOOL GetFooterRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tBOOL GetFooterInfo(LPLVFOOTERINFO lpFooterInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERINFO, 0, (LPARAM)lpFooterInfo);\n\t}\n\n\tBOOL GetFooterItemRect(int nItem, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEMRECT, nItem, (LPARAM)lpRect);\n\t}\n\n\tBOOL GetFooterItem(int nItem, LPLVFOOTERITEM lpFooterItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETFOOTERITEM, nItem, (LPARAM)lpFooterItem);\n\t}\n\n\tBOOL GetItemIndexRect(PLVITEMINDEX pItemIndex, int nSubItem, int nType, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pItemIndex != NULL);\n\t\tATLASSERT(lpRect != NULL);\n\t\tif(lpRect != NULL)\n\t\t{\n\t\t\tlpRect->top = nSubItem;\n\t\t\tlpRect->left = nType;\n\t\t}\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETITEMINDEXRECT, (WPARAM)pItemIndex, (LPARAM)lpRect);\n\t}\n\n\tBOOL SetItemIndexState(PLVITEMINDEX pItemIndex, UINT uState, UINT dwMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.state = uState;\n\t\tlvi.stateMask = dwMask;\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETITEMINDEXSTATE, (WPARAM)pItemIndex, (LPARAM)&lvi);\n\t}\n\n\tBOOL GetNextItemIndex(PLVITEMINDEX pItemIndex, WORD wFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_GETNEXTITEMINDEX, (WPARAM)pItemIndex, MAKELPARAM(wFlags, 0));\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tint InsertColumn(int nCol, const LVCOLUMN* pColumn)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_INSERTCOLUMN, nCol, (LPARAM)pColumn);\n\t}\n\n\tint InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, \n\t\t\tint nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1)\n\t{\n\t\tLVCOLUMN column = { 0 };\n\t\tcolumn.mask = LVCF_TEXT|LVCF_FMT;\n\t\tcolumn.pszText = (LPTSTR)lpszColumnHeading;\n\t\tcolumn.fmt = nFormat;\n\t\tif (nWidth != -1)\n\t\t{\n\t\t\tcolumn.mask |= LVCF_WIDTH;\n\t\t\tcolumn.cx = nWidth;\n\t\t}\n\t\tif (nSubItem != -1)\n\t\t{\n\t\t\tcolumn.mask |= LVCF_SUBITEM;\n\t\t\tcolumn.iSubItem = nSubItem;\n\t\t}\n\t\tif (iImage != -1)\n\t\t{\n\t\t\tcolumn.mask |= LVCF_IMAGE;\n\t\t\tcolumn.iImage = iImage;\n\t\t}\n\t\tif (iOrder != -1)\n\t\t{\n\t\t\tcolumn.mask |= LVCF_ORDER;\n\t\t\tcolumn.iOrder = iOrder;\n\t\t}\n\t\treturn InsertColumn(nCol, &column);\n\t}\n\n\tBOOL DeleteColumn(int nCol)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_DELETECOLUMN, nCol, 0L);\n\t}\n\n\tint InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM item = { 0 };\n\t\titem.mask = nMask;\n\t\titem.iItem = nItem;\n\t\titem.iSubItem = 0;\n\t\titem.pszText = (LPTSTR)lpszItem;\n\t\titem.state = nState;\n\t\titem.stateMask = nStateMask;\n\t\titem.iImage = nImage;\n\t\titem.lParam = lParam;\n\t\treturn InsertItem(&item);\n\t}\n\n\tint InsertItem(const LVITEM* pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem);\n\t}\n\n\tint InsertItem(int nItem, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0);\n\t}\n\n\tint InsertItem(int nItem, LPCTSTR lpszItem, int nImage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0);\n\t}\n\n\tint GetNextItem(int nItem, int nFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_GETNEXTITEM, nItem, MAKELPARAM(nFlags, 0));\n\t}\n\n\tBOOL DeleteItem(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_DELETEITEM, nItem, 0L);\n\t}\n\n\tBOOL DeleteAllItems()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_DELETEALLITEMS, 0, 0L);\n\t}\n\n\tint FindItem(LVFINDINFO* pFindInfo, int nStart = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)pFindInfo);\n\t}\n\n\tint FindItem(LPCTSTR lpstrFind, bool bPartial = true, bool bWrap = false, int nStart = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVFINDINFO lvfi = { 0 };\n\t\tlvfi.flags = LVFI_STRING | (bWrap ? LVFI_WRAP : 0) | (bPartial ? LVFI_PARTIAL : 0);\n\t\tlvfi.psz = lpstrFind;\n\t\treturn (int)::SendMessage(m_hWnd, LVM_FINDITEM, nStart, (LPARAM)&lvfi);\n\t}\n\n\tint HitTest(LVHITTESTINFO* pHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo);\n\t}\n\n\tint HitTest(POINT pt, UINT* pFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVHITTESTINFO hti = { 0 };\n\t\thti.pt = pt;\n\t\tint nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, 0, (LPARAM)&hti);\n\t\tif (pFlags != NULL)\n\t\t\t*pFlags = hti.flags;\n\t\treturn nRes;\n\t}\n\n\tBOOL EnsureVisible(int nItem, BOOL bPartialOK)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_ENSUREVISIBLE, nItem, MAKELPARAM(bPartialOK, 0));\n\t}\n\n\tBOOL Scroll(SIZE size)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SCROLL, size.cx, size.cy);\n\t}\n\n\tBOOL RedrawItems(int nFirst, int nLast)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_REDRAWITEMS, nFirst, nLast);\n\t}\n\n\tBOOL Arrange(UINT nCode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_ARRANGE, nCode, 0L);\n\t}\n\n\tCEdit EditLabel(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CEdit((HWND)::SendMessage(m_hWnd, LVM_EDITLABEL, nItem, 0L));\n\t}\n\n\tBOOL Update(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_UPDATE, nItem, 0L);\n\t}\n\n\tBOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMS, (WPARAM)lParamSort, (LPARAM)pfnCompare);\n\t}\n\n\tCImageList RemoveImageList(int nImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_SETIMAGELIST, (WPARAM)nImageList, NULL));\n\t}\n\n\tCImageList CreateDragImage(int nItem, LPPOINT lpPoint)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, LVM_CREATEDRAGIMAGE, nItem, (LPARAM)lpPoint));\n\t}\n\n\tDWORD ApproximateViewRect(int cx = -1, int cy = -1, int nCount = -1)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, LVM_APPROXIMATEVIEWRECT, nCount, MAKELPARAM(cx, cy));\n\t}\n\n\tint SubItemHitTest(LPLVHITTESTINFO lpInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, 0, (LPARAM)lpInfo);\n\t}\n\n\tint AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1,\n\t\t\tint nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,\n\t\t\tint nFmt = LVCFMT_LEFT)\n\t{\n\t\tconst int cxOffset = 15;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVCOLUMN lvc = { 0 };\n\t\tlvc.mask = nMask;\n\t\tlvc.fmt = nFmt;\n\t\tlvc.pszText = (LPTSTR)strItem;\n\t\tlvc.cx = GetStringWidth(lvc.pszText) + cxOffset;\n\t\tif(nMask & LVCF_SUBITEM)\n\t\t\tlvc.iSubItem = (nSubItem != -1) ? nSubItem : nItem;\n\t\treturn InsertColumn(nItem, &lvc);\n\t}\n\n\tint AddItem(int nItem, int nSubItem, LPCTSTR strItem, int nImageIndex = -3)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvItem = { 0 };\n\t\tlvItem.mask = LVIF_TEXT;\n\t\tlvItem.iItem = nItem;\n\t\tlvItem.iSubItem = nSubItem;\n\t\tlvItem.pszText = (LPTSTR)strItem;\n\t\tif(nImageIndex != -3)\n\t\t{\n\t\t\tlvItem.mask |= LVIF_IMAGE;\n\t\t\tlvItem.iImage = nImageIndex;\n\t\t}\n\t\tif(nSubItem == 0)\n\t\t\treturn InsertItem(&lvItem);\n\t\treturn SetItem(&lvItem) ? nItem : -1;\n\t}\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tBOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SORTITEMSEX, (WPARAM)lParamSort, (LPARAM)pfnCompare);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tint InsertGroup(int nItem, PLVGROUP pGroup)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_INSERTGROUP, nItem, (LPARAM)pGroup);\n\t}\n\n\tint AddGroup(PLVGROUP pGroup)\n\t{\n\t\treturn InsertGroup(-1, pGroup);\n\t}\n\n\tint RemoveGroup(int nGroupID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_REMOVEGROUP, nGroupID, 0L);\n\t}\n\n\tvoid MoveGroup(int nGroupID, int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_MOVEGROUP, nGroupID, nItem);\n\t}\n\n\tvoid MoveItemToGroup(int nItem, int nGroupID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_MOVEITEMTOGROUP, nItem, nGroupID);\n\t}\n\n\tint EnableGroupView(BOOL bEnable)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_ENABLEGROUPVIEW, bEnable, 0L);\n\t}\n\n\tint SortGroups(PFNLVGROUPCOMPARE pCompareFunc, LPVOID lpVoid = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SORTGROUPS, (WPARAM)pCompareFunc, (LPARAM)lpVoid);\n\t}\n\n\tvoid InsertGroupSorted(PLVINSERTGROUPSORTED pInsertGroupSorted)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_INSERTGROUPSORTED, (WPARAM)pInsertGroupSorted, 0L);\n\t}\n\n\tvoid RemoveAllGroups()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_REMOVEALLGROUPS, 0, 0L);\n\t}\n\n\tBOOL HasGroup(int nGroupID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_HASGROUP, nGroupID, 0L);\n\t}\n\n\tBOOL InsertMarkHitTest(LPPOINT lpPoint, LPLVINSERTMARK pInsertMark) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)pInsertMark);\n\t}\n\n\tBOOL SetInfoTip(PLVSETINFOTIP pSetInfoTip)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LVM_SETINFOTIP, 0, (LPARAM)pSetInfoTip);\n\t}\n\n\tvoid CancelEditLabel()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, LVM_CANCELEDITLABEL, 0, 0L);\n\t}\n\n\tUINT MapIndexToID(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, LVM_MAPINDEXTOID, nIndex, 0L);\n\t}\n\n\tint MapIDToIndex(UINT uID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_MAPIDTOINDEX, uID, 0L);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tint HitTestEx(LPLVHITTESTINFO lpHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo);\n\t}\n\n\tint HitTestEx(POINT pt, UINT* pFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVHITTESTINFO hti = { 0 };\n\t\thti.pt = pt;\n\t\tint nRes = (int)::SendMessage(m_hWnd, LVM_HITTEST, (WPARAM)-1, (LPARAM)&hti);\n\t\tif (pFlags != NULL)\n\t\t\t*pFlags = hti.flags;\n\t\treturn nRes;\n\t}\n\n\tint SubItemHitTestEx(LPLVHITTESTINFO lpHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LVM_SUBITEMHITTEST, (WPARAM)-1, (LPARAM)lpHitTestInfo);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n\t// Note: selects only one item\n\tBOOL SelectItem(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\t// multi-selection only: de-select all items\n\t\tif((GetStyle() & LVS_SINGLESEL) == 0)\n\t\t\tSetItemState(-1, 0, LVIS_SELECTED);\n\n\t\tBOOL bRet = SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);\n\t\tif(bRet)\n\t\t\tbRet = EnsureVisible(nIndex, FALSE);\n\n\t\treturn bRet;\n\t}\n};\n\ntypedef CListViewCtrlT<ATL::CWindow>   CListViewCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTreeViewCtrl\n\ntemplate <class TBase>\nclass CTreeViewCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCTreeViewCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCTreeViewCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_TREEVIEW;\n\t}\n\n\tUINT GetCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, TVM_GETCOUNT, 0, 0L);\n\t}\n\n\tUINT GetIndent() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, TVM_GETINDENT, 0, 0L);\n\t}\n\n\tvoid SetIndent(UINT nIndent)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TVM_SETINDENT, nIndent, 0L);\n\t}\n\n\tCImageList GetImageList(int nImageListType = TVSIL_NORMAL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_GETIMAGELIST, (WPARAM)nImageListType, 0L));\n\t}\n\n\tCImageList SetImageList(HIMAGELIST hImageList, int nImageListType = TVSIL_NORMAL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageListType, (LPARAM)hImageList));\n\t}\n\n\tBOOL GetItem(LPTVITEM pItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItem(LPTVITEM pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItem(HTREEITEM hItem, UINT nMask, LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = nMask;\n\t\titem.pszText = (LPTSTR) lpszItem;\n\t\titem.iImage = nImage;\n\t\titem.iSelectedImage = nSelectedImage;\n\t\titem.state = nState;\n\t\titem.stateMask = nStateMask;\n\t\titem.lParam = lParam;\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)&item);\n\t}\n\n\tBOOL GetItemText(HTREEITEM hItem, LPTSTR lpstrText, int nLen) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpstrText != NULL);\n\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_TEXT;\n\t\titem.pszText = lpstrText;\n\t\titem.cchTextMax = nLen;\n\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetItemText(HTREEITEM hItem, BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_TEXT;\n\n\t\tLPTSTR lpstrText = NULL;\n\t\tBOOL bRet = FALSE;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tATLTRY(lpstrText = new TCHAR[nLen]);\n\t\t\tif(lpstrText == NULL)\n\t\t\t\tbreak;\n\t\t\tlpstrText[0] = NULL;\n\t\t\titem.pszText = lpstrText;\n\t\t\titem.cchTextMax = nLen;\n\t\t\tbRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\t\tif(!bRet || (lstrlen(item.pszText) < nLen - 1))\n\t\t\t\tbreak;\n\t\t\tdelete [] lpstrText;\n\t\t\tlpstrText = NULL;\n\t\t}\n\n\t\tif(lpstrText != NULL)\n\t\t{\n\t\t\tif(bRet)\n\t\t\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\t\tdelete [] lpstrText;\n\t\t}\n\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL GetItemText(HTREEITEM hItem, _CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_TEXT;\n\n\t\tstrText.Empty();\n\t\tBOOL bRet = FALSE;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\titem.pszText = strText.GetBufferSetLength(nLen);\n\t\t\tif(item.pszText == NULL)\n\t\t\t{\n\t\t\t\tbRet = FALSE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\titem.cchTextMax = nLen;\n\t\t\tbRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\t\tif(!bRet || (lstrlen(item.pszText) < nLen - 1))\n\t\t\t\tbreak;\n\t\t}\n\t\tstrText.ReleaseBuffer();\n\t\treturn bRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL SetItemText(HTREEITEM hItem, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(hItem, TVIF_TEXT, lpszItem, 0, 0, 0, 0, NULL);\n\t}\n\n\tBOOL GetItemImage(HTREEITEM hItem, int& nImage, int& nSelectedImage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE;\n\t\tBOOL bRes = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\tif (bRes)\n\t\t{\n\t\t\tnImage = item.iImage;\n\t\t\tnSelectedImage = item.iSelectedImage;\n\t\t}\n\t\treturn bRes;\n\t}\n\n\tBOOL SetItemImage(HTREEITEM hItem, int nImage, int nSelectedImage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(hItem, TVIF_IMAGE|TVIF_SELECTEDIMAGE, NULL, nImage, nSelectedImage, 0, 0, NULL);\n\t}\n\n\tUINT GetItemState(HTREEITEM hItem, UINT nStateMask) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\t\treturn (((UINT)::SendMessage(m_hWnd, TVM_GETITEMSTATE, (WPARAM)hItem, (LPARAM)nStateMask)) & nStateMask);\n#else // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE))\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_STATE;\n\t\titem.state = 0;\n\t\titem.stateMask = nStateMask;\n\t\t::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\treturn (item.state & nStateMask);\n#endif // !((_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE))\n\t}\n\n\tBOOL SetItemState(HTREEITEM hItem, UINT nState, UINT nStateMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(hItem, TVIF_STATE, NULL, 0, 0, nState, nStateMask, NULL);\n\t}\n\n\tDWORD_PTR GetItemData(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_PARAM;\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\treturn (DWORD_PTR)(bRet ? item.lParam : NULL);\n\t}\n\n\tBOOL SetItemData(HTREEITEM hItem, DWORD_PTR dwData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(hItem, TVIF_PARAM, NULL, 0, 0, 0, 0, (LPARAM)dwData);\n\t}\n\n\tCEdit GetEditControl() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CEdit((HWND)::SendMessage(m_hWnd, TVM_GETEDITCONTROL, 0, 0L));\n\t}\n\n\tUINT GetVisibleCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, TVM_GETVISIBLECOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItemRect(HTREEITEM hItem, LPRECT lpRect, BOOL bTextOnly) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t*(HTREEITEM*)lpRect = hItem;\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETITEMRECT, (WPARAM)bTextOnly, (LPARAM)lpRect);\n\t}\n\n\tBOOL ItemHasChildren(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVITEM item = { 0 };\n\t\titem.hItem = hItem;\n\t\titem.mask = TVIF_CHILDREN;\n\t\t::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)&item);\n\t\treturn item.cChildren;\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_GETTOOLTIPS, 0, 0L));\n\t}\n\n\tCToolTipCtrl SetToolTips(HWND hWndTT)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, TVM_SETTOOLTIPS, (WPARAM)hWndTT, 0L));\n\t}\n#endif // !_WIN32_WCE\n\n\tint GetISearchString(LPTSTR lpstr) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TVM_GETISEARCHSTRING, 0, (LPARAM)lpstr);\n\t}\n\n\t// checkboxes only\n\tBOOL GetCheckState(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & TVS_CHECKBOXES) != 0);\n\t\tUINT uRet = GetItemState(hItem, TVIS_STATEIMAGEMASK);\n\t\treturn (uRet >> 12) - 1;\n\t}\n\n\tBOOL SetCheckState(HTREEITEM hItem, BOOL bCheck)\n\t{\n\t\tint nCheck = bCheck ? 2 : 1;   // one based index\n\t\treturn SetItemState(hItem, INDEXTOSTATEIMAGEMASK(nCheck), TVIS_STATEIMAGEMASK);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_GETBKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_SETBKCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tCOLORREF GetInsertMarkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_GETINSERTMARKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetInsertMarkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_SETINSERTMARKCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tint GetItemHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TVM_GETITEMHEIGHT, 0, 0L);\n\t}\n\n\tint SetItemHeight(int cyHeight)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TVM_SETITEMHEIGHT, cyHeight, 0L);\n\t}\n\n\tint GetScrollTime() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TVM_GETSCROLLTIME, 0, 0L);\n\t}\n\n\tint SetScrollTime(int nScrollTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TVM_SETSCROLLTIME, nScrollTime, 0L);\n\t}\n\n\tCOLORREF GetTextColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_GETTEXTCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetTextColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_SETTEXTCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tCOLORREF GetLineColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_GETLINECOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetLineColor(COLORREF clrNew /*= CLR_DEFAULT*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TVM_SETLINECOLOR, 0, (LPARAM)clrNew);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetItem(LPTVITEMEX pItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETITEM, 0, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItem(LPTVITEMEX pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETITEM, 0, (LPARAM)pItem);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n\tDWORD GetExtendedStyle() const\n\t{\n#ifndef TVM_GETEXTENDEDSTYLE\n\t\tconst UINT TVM_GETEXTENDEDSTYLE = (TV_FIRST + 45);\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TVM_GETEXTENDEDSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask)\n\t{\n#ifndef TVM_SETEXTENDEDSTYLE\n\t\tconst UINT TVM_SETEXTENDEDSTYLE = (TV_FIRST + 44);\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TVM_SETEXTENDEDSTYLE, dwMask, dwStyle);\n\t}\n\n#if (_WIN32_WINNT >= 0x0600)\n\tBOOL SetAutoScrollInfo(UINT uPixPerSec, UINT uUpdateTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETAUTOSCROLLINFO, (WPARAM)uPixPerSec, (LPARAM)uUpdateTime);\n\t}\n\n\tDWORD GetSelectedCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TVM_GETSELECTEDCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItemPartRect(HTREEITEM hItem, TVITEMPART partID, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVGETITEMPARTRECTINFO gipri = { hItem, lpRect, partID };\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_GETITEMPARTRECT, 0, (LPARAM)&gipri);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tHTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct);\n\t}\n\n\tHTREEITEM InsertItem(LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); \n\t}\n\n\tHTREEITEM InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter);\n\t}\n\n\tHTREEITEM InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam,\n\t\tHTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVINSERTSTRUCT tvis = { 0 };\n\t\ttvis.hParent = hParent;\n\t\ttvis.hInsertAfter = hInsertAfter;\n\t\ttvis.item.mask = nMask;\n\t\ttvis.item.pszText = (LPTSTR) lpszItem;\n\t\ttvis.item.iImage = nImage;\n\t\ttvis.item.iSelectedImage = nSelectedImage;\n\t\ttvis.item.state = nState;\n\t\ttvis.item.stateMask = nStateMask;\n\t\ttvis.item.lParam = lParam;\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis);\n\t}\n\n\tBOOL DeleteItem(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem);\n\t}\n\n\tBOOL DeleteAllItems()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);\n\t}\n\n\tBOOL Expand(HTREEITEM hItem, UINT nCode = TVE_EXPAND)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_EXPAND, nCode, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetNextItem(HTREEITEM hItem, UINT nCode) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetChildItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetNextSiblingItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); \n\t}\n\n\tHTREEITEM GetPrevSiblingItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetParentItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); \n\t}\n\n\tHTREEITEM GetFirstVisibleItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L);\n\t}\n\n\tHTREEITEM GetNextVisibleItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetPrevVisibleItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem);\n\t}\n\n\tHTREEITEM GetSelectedItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L);\n\t}\n\n\tHTREEITEM GetDropHilightItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L);\n\t}\n\n\tHTREEITEM GetRootItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L);\n\t}\n\n#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\tHTREEITEM GetLastVisibleItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L);\n\t}\n#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0600)\n\tHTREEITEM GetNextSelectedItem() const\n\t{\n#ifndef TVGN_NEXTSELECTED\n\t\tconst WORD TVGN_NEXTSELECTED = 0x000B;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0600)\n\n\tBOOL Select(HTREEITEM hItem, UINT nCode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, nCode, (LPARAM)hItem);\n\t}\n\n\tBOOL SelectItem(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem);\n\t}\n\n\tBOOL SelectDropTarget(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_DROPHILITE, (LPARAM)hItem);\n\t}\n\n\tBOOL SelectSetFirstVisible(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SELECTITEM, TVGN_FIRSTVISIBLE, (LPARAM)hItem);\n\t}\n\n\tCEdit EditLabel(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CEdit((HWND)::SendMessage(m_hWnd, TVM_EDITLABEL, 0, (LPARAM)hItem));\n\t}\n\n\tBOOL EndEditLabelNow(BOOL bCancel)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_ENDEDITLABELNOW, bCancel, 0L);\n\t}\n\n\tHTREEITEM HitTest(TVHITTESTINFO* pHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo);\n\t}\n\n\tHTREEITEM HitTest(POINT pt, UINT* pFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVHITTESTINFO hti = { 0 };\n\t\thti.pt = pt;\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti);\n\t\tif (pFlags != NULL)\n\t\t\t*pFlags = hti.flags;\n\t\treturn hTreeItem;\n\t}\n\n\tBOOL SortChildren(HTREEITEM hItem, BOOL bRecurse = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDREN, (WPARAM)bRecurse, (LPARAM)hItem);\n\t}\n\n\tBOOL EnsureVisible(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_ENSUREVISIBLE, 0, (LPARAM)hItem);\n\t}\n\n\tBOOL SortChildrenCB(LPTVSORTCB pSort, BOOL bRecurse = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SORTCHILDRENCB, (WPARAM)bRecurse, (LPARAM)pSort);\n\t}\n\n\tCImageList RemoveImageList(int nImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM)nImageList, NULL));\n\t}\n\n\tCImageList CreateDragImage(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)hItem));\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL SetInsertMark(HTREEITEM hTreeItem, BOOL bAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, bAfter, (LPARAM)hTreeItem);\n\t}\n\n\tBOOL RemoveInsertMark()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TVM_SETINSERTMARK, 0, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tHTREEITEM MapAccIDToHTREEITEM(UINT uID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L);\n\t}\n\n\tUINT MapHTREEITEMToAccID(HTREEITEM hTreeItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, TVM_MAPHTREEITEMTOACCID, (WPARAM)hTreeItem, 0L);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tvoid ShowInfoTip(HTREEITEM hItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TVM_SHOWINFOTIP, 0, (LPARAM)hItem);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n};\n\ntypedef CTreeViewCtrlT<ATL::CWindow>   CTreeViewCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTreeViewCtrlEx\n\n// forward declaration\ntemplate <class TBase> class CTreeViewCtrlExT;\n\n// Note: TBase here is for CTreeViewCtrlExT, and not for CTreeItemT itself\ntemplate <class TBase>\nclass CTreeItemT\n{\npublic:\n\tHTREEITEM m_hTreeItem;\n\tCTreeViewCtrlExT<TBase>* m_pTreeView;\n\n// Construction\n\tCTreeItemT(HTREEITEM hTreeItem = NULL, CTreeViewCtrlExT<TBase>* pTreeView = NULL) : m_hTreeItem(hTreeItem), m_pTreeView(pTreeView)\n\t{ }\n \n\tCTreeItemT(const CTreeItemT<TBase>& posSrc)\n\t{\n\t\t*this = posSrc;\n\t}\n\n\toperator HTREEITEM() { return m_hTreeItem; }\n\n\tCTreeItemT<TBase>& operator =(const CTreeItemT<TBase>& itemSrc)\n\t{\n\t\tm_hTreeItem = itemSrc.m_hTreeItem;\n\t\tm_pTreeView = itemSrc.m_pTreeView;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tCTreeViewCtrlExT<TBase>* GetTreeView() const { return m_pTreeView; }\n\n\tBOOL operator !() const { return m_hTreeItem == NULL; }\n\n\tBOOL IsNull() const { return m_hTreeItem == NULL; }\n\t\n\tBOOL GetRect(LPRECT lpRect, BOOL bTextOnly) const;\n\tBOOL GetText(LPTSTR lpstrText, int nLen) const;\n#ifndef _ATL_NO_COM\n\tBOOL GetText(BSTR& bstrText) const;\n#endif // !_ATL_NO_COM\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL GetText(_CSTRING_NS::CString& strText) const;\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL SetText(LPCTSTR lpszItem);\n\tBOOL GetImage(int& nImage, int& nSelectedImage) const;\n\tBOOL SetImage(int nImage, int nSelectedImage);\n\tUINT GetState(UINT nStateMask) const;\n\tBOOL SetState(UINT nState, UINT nStateMask);\n\tDWORD_PTR GetData() const;\n\tBOOL SetData(DWORD_PTR dwData);\n\tBOOL SetItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam);\n\n// Operations\n\tCTreeItemT<TBase> InsertAfter(LPCTSTR lpstrItem, HTREEITEM hItemAfter, int nImageIndex)\n\t{\n\t\treturn _Insert(lpstrItem, nImageIndex, hItemAfter);\n\t}\n\n\tCTreeItemT<TBase> AddHead(LPCTSTR lpstrItem, int nImageIndex)\n\t{\n\t\treturn _Insert(lpstrItem, nImageIndex, TVI_FIRST);\n\t}\n\n\tCTreeItemT<TBase> AddTail(LPCTSTR lpstrItem, int nImageIndex)\n\t{\n\t\treturn _Insert(lpstrItem, nImageIndex, TVI_LAST);\n\t}\n\n\tCTreeItemT<TBase> GetChild() const;\n\tCTreeItemT<TBase> GetNext(UINT nCode) const;\n\tCTreeItemT<TBase> GetNextSibling() const;\n\tCTreeItemT<TBase> GetPrevSibling() const;\n\tCTreeItemT<TBase> GetParent() const;\n\tCTreeItemT<TBase> GetFirstVisible() const;\n\tCTreeItemT<TBase> GetNextVisible() const;\n\tCTreeItemT<TBase> GetPrevVisible() const;\n\tCTreeItemT<TBase> GetSelected() const;\n\tCTreeItemT<TBase> GetDropHilight() const;\n\tCTreeItemT<TBase> GetRoot() const;\n#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\tCTreeItemT<TBase> GetLastVisible() const;\n#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0600)\n\tCTreeItemT<TBase> GetNextSelected() const;\n#endif // (_WIN32_IE >= 0x0600)\n\tBOOL HasChildren() const;\n\tBOOL Delete();\n\tBOOL Expand(UINT nCode = TVE_EXPAND);\n\tBOOL Select(UINT nCode);\n\tBOOL Select();\n\tBOOL SelectDropTarget();\n\tBOOL SelectSetFirstVisible();\n\tHWND EditLabel();\n\tHIMAGELIST CreateDragImage();\n\tBOOL SortChildren(BOOL bRecurse = FALSE);\n\tBOOL EnsureVisible();\n\tCTreeItemT<TBase> _Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter);\n\tint GetImageIndex() const;\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL SetInsertMark(BOOL bAfter);\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n#if (_WIN32_WINNT >= 0x0501)\n\tUINT MapHTREEITEMToAccID() const;\n#endif // (_WIN32_WINNT >= 0x0501)\n#if (_WIN32_WINNT >= 0x0600)\n\tvoid ShowInfoTip();\n\tBOOL GetPartRect(TVITEMPART partID, LPRECT lpRect) const;\n#endif // (_WIN32_WINNT >= 0x0600)\n};\n\ntypedef CTreeItemT<ATL::CWindow>   CTreeItem;\n\n\ntemplate <class TBase>\nclass CTreeViewCtrlExT : public CTreeViewCtrlT< TBase >\n{\npublic:\n// Constructors\n\tCTreeViewCtrlExT(HWND hWnd = NULL) : CTreeViewCtrlT< TBase >(hWnd)\n\t{ }\n\n\tCTreeViewCtrlExT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Operations (overides that return CTreeItem)\n\tCTreeItemT<TBase> InsertItem(LPTVINSERTSTRUCT lpInsertStruct)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct);\n\t\treturn CTreeItemT<TBase>(hTreeItem, this);\n\t}\n\n\tCTreeItemT<TBase> InsertItem(LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE, lpszItem, nImage, nSelectedImage, 0, 0, 0, hParent, hInsertAfter); \n\t}\n\n\tCTreeItemT<TBase> InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn InsertItem(TVIF_TEXT, lpszItem, 0, 0, 0, 0, 0, hParent, hInsertAfter);\n\t}\n\n\tCTreeItemT<TBase> GetNextItem(HTREEITEM hItem, UINT nCode) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, nCode, (LPARAM)hItem);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetChildItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hItem);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this); \n\t}\n\n\tCTreeItemT<TBase> GetNextSiblingItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)hItem); \n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetPrevSiblingItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUS, (LPARAM)hItem);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetParentItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hItem); \n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetFirstVisibleItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd)); \n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_FIRSTVISIBLE, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetNextVisibleItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTVISIBLE, (LPARAM)hItem);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetPrevVisibleItem(HTREEITEM hItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_PREVIOUSVISIBLE, (LPARAM)hItem);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetSelectedItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_CARET, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetDropHilightItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> GetRootItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\tCTreeItemT<TBase> GetLastVisibleItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_LASTVISIBLE, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0600)\n\tCTreeItemT<TBase> GetNextSelectedItem() const\n\t{\n#ifndef TVGN_NEXTSELECTED\n\t\tconst WORD TVGN_NEXTSELECTED = 0x000B;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_GETNEXTITEM, TVGN_NEXTSELECTED, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n#endif // (_WIN32_IE >= 0x0600)\n\n\tCTreeItemT<TBase> HitTest(TVHITTESTINFO* pHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)pHitTestInfo);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n\tCTreeItemT<TBase> InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam,\n\t\tHTREEITEM hParent, HTREEITEM hInsertAfter)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVINSERTSTRUCT tvis = { 0 };\n\t\ttvis.hParent = hParent;\n\t\ttvis.hInsertAfter = hInsertAfter;\n\t\ttvis.item.mask = nMask;\n\t\ttvis.item.pszText = (LPTSTR) lpszItem;\n\t\ttvis.item.iImage = nImage;\n\t\ttvis.item.iSelectedImage = nSelectedImage;\n\t\ttvis.item.state = nState;\n\t\ttvis.item.stateMask = nStateMask;\n\t\ttvis.item.lParam = lParam;\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)&tvis);\n\t\treturn CTreeItemT<TBase>(hTreeItem, this);\n\t}\n\n\tCTreeItemT<TBase> HitTest(POINT pt, UINT* pFlags) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTVHITTESTINFO hti = { 0 };\n\t\thti.pt = pt;\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_HITTEST, 0, (LPARAM)&hti);\n\t\tif (pFlags != NULL)\n\t\t\t*pFlags = hti.flags;\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n\n#if (_WIN32_WINNT >= 0x0501)\n\tCTreeItemT<TBase> MapAccIDToHTREEITEM(UINT uID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHTREEITEM hTreeItem = (HTREEITEM)::SendMessage(m_hWnd, TVM_MAPACCIDTOHTREEITEM, uID, 0L);\n\t\treturn CTreeItemT<TBase>(hTreeItem, (CTreeViewCtrlExT<TBase>*)this);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n};\n\ntypedef CTreeViewCtrlExT<ATL::CWindow>   CTreeViewCtrlEx;\n\n\n// CTreeItem inline methods\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetRect(LPRECT lpRect, BOOL bTextOnly) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemRect(m_hTreeItem,lpRect,bTextOnly);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetNext(UINT nCode) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetNextItem(m_hTreeItem,nCode);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetChild() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetChildItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextSibling() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetNextSiblingItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetPrevSibling() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetPrevSiblingItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetParent() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetParentItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetFirstVisible() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetFirstVisibleItem();\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextVisible() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetNextVisibleItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetPrevVisible() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetPrevVisibleItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetSelected() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetSelectedItem();\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetDropHilight() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetDropHilightItem();\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetRoot() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetRootItem();\n}\n\n#if !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetLastVisible() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetLastVisibleItem();\n}\n#endif // !defined(_WIN32_WCE) && (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0600)\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::GetNextSelected() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetNextSelectedItem();\n}\n#endif // (_WIN32_IE >= 0x0600)\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetText(LPTSTR lpstrText, int nLen) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemText(m_hTreeItem, lpstrText, nLen);\n}\n\n#ifndef _ATL_NO_COM\n#ifdef _OLEAUTO_H_\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetText(BSTR& bstrText) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemText(m_hTreeItem, bstrText);\n}\n#endif // _OLEAUTO_H_\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetText(_CSTRING_NS::CString& strText) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemText(m_hTreeItem, strText);\n}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetImage(int& nImage, int& nSelectedImage) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemImage(m_hTreeItem,nImage,nSelectedImage);\n}\n\ntemplate <class TBase>\ninline UINT CTreeItemT<TBase>::GetState(UINT nStateMask) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemState(m_hTreeItem,nStateMask);\n}\n\ntemplate <class TBase>\ninline DWORD_PTR CTreeItemT<TBase>::GetData() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemData(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetItem(UINT nMask, LPCTSTR lpszItem, int nImage,\n\t\tint nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetItem(m_hTreeItem, nMask, lpszItem, nImage, nSelectedImage, nState, nStateMask, lParam);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetText(LPCTSTR lpszItem)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetItemText(m_hTreeItem,lpszItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetImage(int nImage, int nSelectedImage)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetItemImage(m_hTreeItem,nImage,nSelectedImage);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetState(UINT nState, UINT nStateMask)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetItemState(m_hTreeItem,nState,nStateMask);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetData(DWORD_PTR dwData)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetItemData(m_hTreeItem,dwData);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::HasChildren() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->ItemHasChildren(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::Delete()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->DeleteItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::Expand(UINT nCode /*= TVE_EXPAND*/)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->Expand(m_hTreeItem,nCode);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::Select(UINT nCode)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->Select(m_hTreeItem,nCode);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::Select()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SelectItem(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SelectDropTarget()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SelectDropTarget(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SelectSetFirstVisible()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SelectSetFirstVisible(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline HWND CTreeItemT<TBase>::EditLabel()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->EditLabel(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline HIMAGELIST CTreeItemT<TBase>::CreateDragImage()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->CreateDragImage(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SortChildren(BOOL bRecurse /*= FALSE*/)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SortChildren(m_hTreeItem, bRecurse);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::EnsureVisible()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->EnsureVisible(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline CTreeItemT<TBase> CTreeItemT<TBase>::_Insert(LPCTSTR lpstrItem, int nImageIndex, HTREEITEM hItemAfter)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\tTVINSERTSTRUCT ins = { 0 };\n\tins.hParent = m_hTreeItem;\n\tins.hInsertAfter = hItemAfter;\n\tins.item.mask = TVIF_TEXT;\n\tins.item.pszText = (LPTSTR)lpstrItem;\n\tif(nImageIndex != -1)\n\t{\n\t\tins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;\n\t\tins.item.iImage = nImageIndex;\n\t\tins.item.iSelectedImage = nImageIndex;\n\t}\n\treturn CTreeItemT<TBase>(m_pTreeView->InsertItem(&ins), m_pTreeView);\n}\n\ntemplate <class TBase>\ninline int CTreeItemT<TBase>::GetImageIndex() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\tTVITEM item = { 0 };\n\titem.mask = TVIF_HANDLE | TVIF_IMAGE;\n\titem.hItem = m_hTreeItem;\n\tm_pTreeView->GetItem(&item);\n\treturn item.iImage;\n}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::SetInsertMark(BOOL bAfter)\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->SetInsertMark(m_hTreeItem, bAfter);\n}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501)\ntemplate <class TBase>\ninline UINT CTreeItemT<TBase>::MapHTREEITEMToAccID() const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->MapHTREEITEMToAccID(m_hTreeItem);\n}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\ntemplate <class TBase>\ninline void CTreeItemT<TBase>::ShowInfoTip()\n{\n\tATLASSERT(m_pTreeView != NULL);\n\tm_pTreeView->ShowInfoTip(m_hTreeItem);\n}\n\ntemplate <class TBase>\ninline BOOL CTreeItemT<TBase>::GetPartRect(TVITEMPART partID, LPRECT lpRect) const\n{\n\tATLASSERT(m_pTreeView != NULL);\n\treturn m_pTreeView->GetItemPartRect(m_hTreeItem, partID, lpRect);\n}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CToolBarCtrl\n\ntemplate <class TBase>\nclass CToolBarCtrlT : public TBase\n{\npublic:\n// Construction\n\tCToolBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCToolBarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn TOOLBARCLASSNAME;\n\t}\n\n\tBOOL IsButtonEnabled(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0L);\n\t}\n\n\tBOOL IsButtonChecked(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONCHECKED, nID, 0L);\n\t}\n\n\tBOOL IsButtonPressed(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0L);\n\t}\n\n\tBOOL IsButtonHidden(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn(BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0L);\n\t}\n\n\tBOOL IsButtonIndeterminate(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONINDETERMINATE, nID, 0L);\n\t}\n\n\tint GetState(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L);\n\t}\n\n\tBOOL SetState(int nID, UINT nState)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0));\n\t}\n\n\tBOOL GetButton(int nIndex, LPTBBUTTON lpButton) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETBUTTON, nIndex, (LPARAM)lpButton);\n\t}\n\n\tint GetButtonCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_BUTTONCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItemRect(int nIndex, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETITEMRECT, nIndex, (LPARAM)lpRect);\n\t}\n\n\tvoid SetButtonStructSize(int nSize = sizeof(TBBUTTON))\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_BUTTONSTRUCTSIZE, nSize, 0L);\n\t}\n\n\tBOOL SetButtonSize(SIZE size)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy));\n\t}\n\n\tBOOL SetButtonSize(int cx, int cy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, cy));\n\t}\n\n\tBOOL SetBitmapSize(SIZE size)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy));\n\t}\n\n\tBOOL SetBitmapSize(int cx, int cy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(cx, cy));\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, TB_GETTOOLTIPS, 0, 0L));\n\t}\n\n\tvoid SetToolTips(HWND hWndToolTip)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid SetNotifyWnd(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)hWnd, 0L);\n\t}\n\n\tint GetRows() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETROWS, 0, 0L);\n\t}\n\n\tvoid SetRows(int nRows, BOOL bLarger, LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETROWS, MAKELPARAM(nRows, bLarger), (LPARAM)lpRect);\n\t}\n\n\tBOOL SetCmdID(int nIndex, UINT nID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETCMDID, nIndex, nID);\n\t}\n\n\tDWORD GetBitmapFlags() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L);\n\t}\n\n\tint GetBitmap(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETBITMAP, nID, 0L);\n\t}\n\n\tint GetButtonText(int nID, LPTSTR lpstrText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETBUTTONTEXT, nID, (LPARAM)lpstrText);\n\t}\n\n\t// nIndex - IE5 or higher only\n\tCImageList GetImageList(int nIndex = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETIMAGELIST, nIndex, 0L));\n\t}\n\n\t// nIndex - IE5 or higher only\n\tCImageList SetImageList(HIMAGELIST hImageList, int nIndex = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETIMAGELIST, nIndex, (LPARAM)hImageList));\n\t}\n\n\t// nIndex - IE5 or higher only\n\tCImageList GetDisabledImageList(int nIndex = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETDISABLEDIMAGELIST, nIndex, 0L));\n\t}\n\n\t// nIndex - IE5 or higher only\n\tCImageList SetDisabledImageList(HIMAGELIST hImageList, int nIndex = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETDISABLEDIMAGELIST, nIndex, (LPARAM)hImageList));\n\t}\n\n#ifndef _WIN32_WCE\n\t// nIndex - IE5 or higher only\n\tCImageList GetHotImageList(int nIndex = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETHOTIMAGELIST, nIndex, 0L));\n\t}\n\n\t// nIndex - IE5 or higher only\n\tCImageList SetHotImageList(HIMAGELIST hImageList, int nIndex = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETHOTIMAGELIST, nIndex, (LPARAM)hImageList));\n\t}\n#endif // !_WIN32_WCE\n\n\tDWORD GetStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_GETSTYLE, 0, 0L);\n\t}\n\n\tvoid SetStyle(DWORD dwStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETSTYLE, 0, dwStyle);\n\t}\n\n\tDWORD GetButtonSize() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L);\n\t}\n\n\tvoid GetButtonSize(SIZE& size) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETBUTTONSIZE, 0, 0L);\n\t\tsize.cx = LOWORD(dwRet);\n\t\tsize.cy = HIWORD(dwRet);\n\t}\n\n\tBOOL GetRect(int nID, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETRECT, nID, (LPARAM)lpRect);\n\t}\n\n\tint GetTextRows() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETTEXTROWS, 0, 0L);\n\t}\n\n\tBOOL SetButtonWidth(int cxMin, int cxMax)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONWIDTH, 0, MAKELPARAM(cxMin, cxMax));\n\t}\n\n\tBOOL SetIndent(int nIndent)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETINDENT, nIndent, 0L);\n\t}\n\n\tBOOL SetMaxTextRows(int nMaxTextRows)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETMAXTEXTROWS, nMaxTextRows, 0L);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n#ifndef _WIN32_WCE\n\tBOOL GetAnchorHighlight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETANCHORHIGHLIGHT, 0, 0L);\n\t}\n\n\tBOOL SetAnchorHighlight(BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETANCHORHIGHLIGHT, bEnable, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tint GetButtonInfo(int nID, LPTBBUTTONINFO lptbbi) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETBUTTONINFO, nID, (LPARAM)lptbbi);\n\t}\n\n\tBOOL SetButtonInfo(int nID, LPTBBUTTONINFO lptbbi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)lptbbi);\n\t}\n\n\tBOOL SetButtonInfo(int nID, DWORD dwMask, BYTE Style, BYTE State, LPCTSTR lpszItem, \n\t                   int iImage, WORD cx, int iCommand, DWORD_PTR lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBBUTTONINFO tbbi = { 0 };\n\t\ttbbi.cbSize = sizeof(TBBUTTONINFO);\n\t\ttbbi.dwMask = dwMask;\n\t\ttbbi.idCommand = iCommand;\n\t\ttbbi.iImage = iImage;\n\t\ttbbi.fsState = State;\n\t\ttbbi.fsStyle = Style;\n\t\ttbbi.cx = cx;\n\t\ttbbi.pszText = (LPTSTR) lpszItem;\n\t\ttbbi.lParam = lParam;\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETBUTTONINFO, nID, (LPARAM)&tbbi);\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetHotItem() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETHOTITEM, 0, 0L);\n\t}\n\n\tint SetHotItem(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_SETHOTITEM, nItem, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL IsButtonHighlighted(int nButtonID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ISBUTTONHIGHLIGHTED, nButtonID, 0L);\n\t}\n\n\tDWORD SetDrawTextFlags(DWORD dwMask, DWORD dwFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_SETDRAWTEXTFLAGS, dwMask, dwFlags);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetColorScheme(LPCOLORSCHEME lpcs) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETCOLORSCHEME, 0, (LPARAM)lpcs);\n\t}\n\n\tvoid SetColorScheme(LPCOLORSCHEME lpcs)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETCOLORSCHEME, 0, (LPARAM)lpcs);\n\t}\n\n\tDWORD GetExtendedStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_GETEXTENDEDSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TB_SETEXTENDEDSTYLE, 0, dwStyle);\n\t}\n\n\tvoid GetInsertMark(LPTBINSERTMARK lptbim) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_GETINSERTMARK, 0, (LPARAM)lptbim);\n\t}\n\n\tvoid SetInsertMark(LPTBINSERTMARK lptbim)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETINSERTMARK, 0, (LPARAM)lptbim);\n\t}\n\n\tCOLORREF GetInsertMarkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TB_GETINSERTMARKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetInsertMarkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, TB_SETINSERTMARKCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tBOOL GetMaxSize(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETMAXSIZE, 0, (LPARAM)lpSize);\n\t}\n\n\tvoid GetPadding(LPSIZE lpSizePadding) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpSizePadding != NULL);\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_GETPADDING, 0, 0L);\n\t\tlpSizePadding->cx = GET_X_LPARAM(dwRet);\n\t\tlpSizePadding->cy = GET_Y_LPARAM(dwRet);\n\t}\n\n\tvoid SetPadding(int cx, int cy, LPSIZE lpSizePadding = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, TB_SETPADDING, 0, MAKELPARAM(cx, cy));\n\t\tif(lpSizePadding != NULL)\n\t\t{\n\t\t\tlpSizePadding->cx = GET_X_LPARAM(dwRet);\n\t\t\tlpSizePadding->cy = GET_Y_LPARAM(dwRet);\n\t\t}\n\t}\n\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tint GetString(int nString, LPTSTR lpstrString, int cchMaxLen) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(cchMaxLen, nString), (LPARAM)lpstrString);\n\t}\n\n\tint GetStringBSTR(int nString, BSTR& bstrString) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrString == NULL);\n\t\tint nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL));\n\t\tif(nLength != -1)\n\t\t{\n\t\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\t\tLPTSTR lpstrText = buff.Allocate(nLength + 1);\n\t\t\tif(lpstrText != NULL)\n\t\t\t{\n\t\t\t\tnLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstrText);\n\t\t\t\tif(nLength != -1)\n\t\t\t\t\tbstrString = ::SysAllocString(T2OLE(lpstrText));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnLength = -1;\n\t\t\t}\n\t\t}\n\n\t\treturn nLength;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetString(int nString, _CSTRING_NS::CString& str) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(0, nString), NULL));\n\t\tif(nLength != -1)\n\t\t{\n\t\t\tLPTSTR lpstr = str.GetBufferSetLength(nLength + 1);\n\t\t\tif(lpstr != NULL)\n\t\t\t\tnLength = (int)::SendMessage(m_hWnd, TB_GETSTRING, MAKEWPARAM(nLength + 1, nString), (LPARAM)lpstr);\n\t\t\telse\n\t\t\t\tnLength = -1;\n\t\t\tstr.ReleaseBuffer();\n\t\t}\n\t\treturn nLength;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tvoid GetMetrics(LPTBMETRICS lptbm) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_GETMETRICS, 0, (LPARAM)lptbm);\n\t}\n\n\tvoid SetMetrics(LPTBMETRICS lptbm)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETMETRICS, 0, (LPARAM)lptbm);\n\t}\n\n\tvoid SetWindowTheme(LPCWSTR lpstrTheme)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tCImageList GetPressedImageList(int nIndex = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_GETPRESSEDIMAGELIST, nIndex, 0L));\n\t}\n\n\tCImageList SetPressedImageList(HIMAGELIST hImageList, int nIndex = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TB_SETPRESSEDIMAGELIST, nIndex, (LPARAM)hImageList));\n\t}\n\n\tvoid GetItemDropDownRect(int nIndex, LPRECT lpRect) const\n\t{\n#ifndef TB_GETITEMDROPDOWNRECT\n\t\tconst int TB_GETITEMDROPDOWNRECT = WM_USER + 103;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, TB_GETITEMDROPDOWNRECT, nIndex, (LPARAM)lpRect);\n\t\tbRet;   // avoid level 4 warning\n\t\tATLASSERT(bRet != FALSE);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tBOOL EnableButton(int nID, BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0));\n\t}\n\n\tBOOL CheckButton(int nID, BOOL bCheck = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_CHECKBUTTON, nID, MAKELPARAM(bCheck, 0));\n\t}\n\n\tBOOL PressButton(int nID, BOOL bPress = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0));\n\t}\n\n\tBOOL HideButton(int nID, BOOL bHide = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0));\n\t}\n\n\tBOOL Indeterminate(int nID, BOOL bIndeterminate = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_INDETERMINATE, nID, MAKELPARAM(bIndeterminate, 0));\n\t}\n\n\tint AddBitmap(int nNumButtons, UINT nBitmapID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBADDBITMAP tbab = { 0 };\n\t\ttbab.hInst = ModuleHelper::GetResourceInstance();\n\t\tATLASSERT(tbab.hInst != NULL);\n\t\ttbab.nID = nBitmapID;\n\t\treturn (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab);\n\t}\n\n\tint AddBitmap(int nNumButtons, HBITMAP hBitmap)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBADDBITMAP tbab = { 0 };\n\t\ttbab.hInst = NULL;\n\t\ttbab.nID = (UINT_PTR)hBitmap;\n\t\treturn (int)::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab);\n\t}\n\n\tBOOL AddButtons(int nNumButtons, LPTBBUTTON lpButtons)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_ADDBUTTONS, nNumButtons, (LPARAM)lpButtons);\n\t}\n\n\tBOOL InsertButton(int nIndex, LPTBBUTTON lpButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)lpButton);\n\t}\n\n\tBOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, \n\t                  INT_PTR iString, DWORD_PTR lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBBUTTON tbb = { 0 };\n\t\ttbb.fsStyle = Style;\n\t\ttbb.fsState = State;\n\t\ttbb.idCommand = iCommand;\n\t\ttbb.iBitmap = iBitmap;\n\t\ttbb.iString = iString;\n\t\ttbb.dwData = lParam;\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_INSERTBUTTON, nIndex, (LPARAM)&tbb);\n\t}\n\n\tBOOL InsertButton(int nIndex, int iCommand, BYTE Style, BYTE State, int iBitmap, \n\t                  LPCTSTR lpszItem, DWORD_PTR lParam)\n\t{\n\t\treturn InsertButton(nIndex, iCommand, Style, State, iBitmap, (INT_PTR)lpszItem, lParam);\n\t}\n\n\tBOOL AddButton(LPTBBUTTON lpButton)\n\t{\n\t\treturn InsertButton(-1, lpButton);\n\t}\n\n\tBOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, INT_PTR iString, DWORD_PTR lParam)\n\t{\n\t\treturn InsertButton(-1, iCommand, Style, State, iBitmap, iString, lParam);\n\t}\n\n\tBOOL AddButton(int iCommand, BYTE Style, BYTE State, int iBitmap, LPCTSTR lpszItem, DWORD_PTR lParam)\n\t{\n\t\treturn InsertButton(-1, iCommand, Style, State, iBitmap, lpszItem, lParam);\n\t}\n\n\tBOOL DeleteButton(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_DELETEBUTTON, nIndex, 0L);\n\t}\n\n\tBOOL InsertSeparator(int nIndex, int cxWidth = 8)\n\t{\n\t\treturn InsertButton(nIndex, 0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0);\n\t}\n\n\tBOOL AddSeparator(int cxWidth = 8)\n\t{\n\t\treturn AddButton(0, BTNS_SEP, 0, cxWidth, (INT_PTR)0, 0);\n\t}\n\n\tint CommandToIndex(UINT nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_COMMANDTOINDEX, nID, 0L);\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid SaveState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBSAVEPARAMS tbs = { 0 };\n\t\ttbs.hkr = hKeyRoot;\n\t\ttbs.pszSubKey = lpszSubKey;\n\t\ttbs.pszValueName = lpszValueName;\n\t\t::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)TRUE, (LPARAM)&tbs);\n\t}\n\n\tvoid RestoreState(HKEY hKeyRoot, LPCTSTR lpszSubKey, LPCTSTR lpszValueName)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTBSAVEPARAMS tbs = { 0 };\n\t\ttbs.hkr = hKeyRoot;\n\t\ttbs.pszSubKey = lpszSubKey;\n\t\ttbs.pszValueName = lpszValueName;\n\t\t::SendMessage(m_hWnd, TB_SAVERESTORE, (WPARAM)FALSE, (LPARAM)&tbs);\n\t}\n\n\tvoid Customize()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_CUSTOMIZE, 0, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tint AddString(UINT nStringID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)ModuleHelper::GetResourceInstance(), (LPARAM)nStringID);\n\t}\n\n\tint AddStrings(LPCTSTR lpszStrings)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings);\n\t}\n\n\tvoid AutoSize()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TB_AUTOSIZE, 0, 0L);\n\t}\n\n\tBOOL ChangeBitmap(int nID, int nBitmap)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_CHANGEBITMAP, nID, MAKELPARAM(nBitmap, 0));\n\t}\n\n\tint LoadImages(int nBitmapID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)ModuleHelper::GetResourceInstance());\n\t}\n\n\tint LoadStdImages(int nBitmapID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_LOADIMAGES, nBitmapID, (LPARAM)HINST_COMMCTRL);\n\t}\n\n\tBOOL ReplaceBitmap(LPTBREPLACEBITMAP ptbrb)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_REPLACEBITMAP, 0, (LPARAM)ptbrb);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tint HitTest(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TB_HITTEST, 0, (LPARAM)lpPoint);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL InsertMarkHitTest(LPPOINT lpPoint, LPTBINSERTMARK lptbim) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)lpPoint, (LPARAM)lptbim);\n\t}\n\n\tBOOL InsertMarkHitTest(int x, int y, LPTBINSERTMARK lptbim) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tPOINT pt = { x, y };\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_INSERTMARKHITTEST, (WPARAM)&pt, (LPARAM)lptbim);\n\t}\n\n\tBOOL MapAccelerator(TCHAR chAccel, int& nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_MAPACCELERATOR, (WPARAM)chAccel, (LPARAM)&nID);\n\t}\n\n\tBOOL MarkButton(int nID, BOOL bHighlight = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_MARKBUTTON, nID, MAKELPARAM(bHighlight, 0));\n\t}\n\n\tBOOL MoveButton(int nOldPos, int nNewPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TB_MOVEBUTTON, nOldPos, nNewPos);\n\t}\n\n\tHRESULT GetObject(REFIID iid, LPVOID* ppvObject)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, TB_GETOBJECT, (WPARAM)&iid, (LPARAM)ppvObject);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n};\n\ntypedef CToolBarCtrlT<ATL::CWindow>   CToolBarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CStatusBarCtrl\n\ntemplate <class TBase>\nclass CStatusBarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCStatusBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCStatusBarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Methods\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn STATUSCLASSNAME;\n\t}\n\n\tint GetParts(int nParts, int* pParts) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, SB_GETPARTS, nParts, (LPARAM)pParts);\n\t}\n\n\tBOOL SetParts(int nParts, int* pWidths)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_SETPARTS, nParts, (LPARAM)pWidths);\n\t}\n\n\tint GetTextLength(int nPane, int* pType = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L);\n\t\tif (pType != NULL)\n\t\t\t*pType = (int)(short)HIWORD(dwRet);\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n\tint GetText(int nPane, LPTSTR lpszText, int* pType = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, SB_GETTEXT, (WPARAM)nPane, (LPARAM)lpszText);\n\t\tif(pType != NULL)\n\t\t\t*pType = (int)(short)HIWORD(dwRet);\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetTextBSTR(int nPane, BSTR& bstrText, int* pType = NULL) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\tATLASSERT(bstrText == NULL);\n\t\tint nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L));\n\t\tif(nLength == 0)\n\t\t\treturn FALSE;\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrText = buff.Allocate(nLength + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(!GetText(nPane, lpstrText, pType))\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetText(int nPane, _CSTRING_NS::CString& strText, int* pType = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\tint nLength = (int)(short)LOWORD(::SendMessage(m_hWnd, SB_GETTEXTLENGTH, (WPARAM)nPane, 0L));\n\t\tif(nLength == 0)\n\t\t\treturn 0;\n\n\t\tLPTSTR lpstr = strText.GetBufferSetLength(nLength);\n\t\tif(lpstr == NULL)\n\t\t\treturn 0;\n\t\treturn GetText(nPane, lpstr, pType);\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL SetText(int nPane, LPCTSTR lpszText, int nType = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_SETTEXT, (nPane | nType), (LPARAM)lpszText);\n\t}\n\n\tBOOL GetRect(int nPane, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_GETRECT, nPane, (LPARAM)lpRect);\n\t}\n\n\tBOOL GetBorders(int* pBorders) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)pBorders);\n\t}\n\n\tBOOL GetBorders(int& nHorz, int& nVert, int& nSpacing) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint borders[3] = { 0, 0, 0 };\n\t\tBOOL bResult = (BOOL)::SendMessage(m_hWnd, SB_GETBORDERS, 0, (LPARAM)&borders);\n\t\tif(bResult)\n\t\t{\n\t\t\tnHorz = borders[0];\n\t\t\tnVert = borders[1];\n\t\t\tnSpacing = borders[2];\n\t\t}\n\t\treturn bResult;\n\t}\n\n\tvoid SetMinHeight(int nMin)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, SB_SETMINHEIGHT, nMin, 0L);\n\t}\n\n\tBOOL SetSimple(BOOL bSimple = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_SIMPLE, bSimple, 0L);\n\t}\n\n\tBOOL IsSimple() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_ISSIMPLE, 0, 0L);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n\n\tvoid GetTipText(int nPane, LPTSTR lpstrText, int nSize) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\t::SendMessage(m_hWnd, SB_GETTIPTEXT, MAKEWPARAM(nPane, nSize), (LPARAM)lpstrText);\n\t}\n\n\tvoid SetTipText(int nPane, LPCTSTR lpstrText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\t::SendMessage(m_hWnd, SB_SETTIPTEXT, nPane, (LPARAM)lpstrText);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))\n\tCOLORREF SetBkColor(COLORREF clrBk)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, SB_SETBKCOLOR, 0, (LPARAM)clrBk);\n\t}\n\n\tHICON GetIcon(int nPane) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\treturn (HICON)::SendMessage(m_hWnd, SB_GETICON, nPane, 0L);\n\t}\n\n\tBOOL SetIcon(int nPane, HICON hIcon)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPane < 256);\n\t\treturn (BOOL)::SendMessage(m_hWnd, SB_SETICON, nPane, (LPARAM)hIcon);\n\t}\n#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))\n};\n\ntypedef CStatusBarCtrlT<ATL::CWindow>   CStatusBarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTabCtrl\n\ntemplate <class TBase>\nclass CTabCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCTabCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCTabCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_TABCONTROL;\n\t}\n\n\tCImageList GetImageList() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_GETIMAGELIST, 0, 0L));\n\t}\n\n\tCImageList SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, TCM_SETIMAGELIST, 0, (LPARAM)hImageList));\n\t}\n\n\tint GetItemCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_GETITEMCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetItem(int nItem, LPTCITEM pTabCtrlItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_GETITEM, nItem, (LPARAM)pTabCtrlItem);\n\t}\n\n\tBOOL SetItem(int nItem, LPTCITEM pTabCtrlItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)pTabCtrlItem);\n\t}\n\n\tint SetItem(int nItem, UINT mask, LPCTSTR lpszItem, DWORD dwState, DWORD dwStateMask, int iImage, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTCITEM tci = { 0 };\n\t\ttci.mask = mask;\n\t\ttci.pszText = (LPTSTR) lpszItem;\n\t\ttci.dwState = dwState;\n\t\ttci.dwStateMask = dwStateMask;\n\t\ttci.iImage = iImage;\n\t\ttci.lParam = lParam;\n\t\treturn (int)::SendMessage(m_hWnd, TCM_SETITEM, nItem, (LPARAM)&tci);\n\t}\n\n\tBOOL GetItemRect(int nItem, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_GETITEMRECT, nItem, (LPARAM)lpRect);\n\t}\n\n\tint GetCurSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_GETCURSEL, 0, 0L);\n\t}\n\n\tint SetCurSel(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_SETCURSEL, nItem, 0L);\n\t}\n\n\tSIZE SetItemSize(SIZE size)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwSize = (DWORD)::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(size.cx, size.cy));\n\t\tSIZE sizeRet = { GET_X_LPARAM(dwSize), GET_Y_LPARAM(dwSize) };\n\t\treturn sizeRet;\n\t}\n\n\tvoid SetItemSize(int cx, int cy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_SETITEMSIZE, 0, MAKELPARAM(cx, cy));\n\t}\n\n\tvoid SetPadding(SIZE size)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_SETPADDING, 0, MAKELPARAM(size.cx, size.cy));\n\t}\n\n\tint GetRowCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_GETROWCOUNT, 0, 0L);\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, TCM_GETTOOLTIPS, 0, 0L));\n\t}\n\n\t// this method is deprecated, please use GetToolTips\n\tCToolTipCtrl GetTooltips() const { return GetToolTips(); }\n\n\tvoid SetToolTips(HWND hWndToolTip)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_SETTOOLTIPS, (WPARAM)hWndToolTip, 0L);\n\t}\n\n\t// this method is deprecated, please use SetToolTips\n\tvoid SetTooltips(HWND hWndToolTip) { SetToolTips(hWndToolTip); }\n\n#endif // !_WIN32_WCE\n\n\tint GetCurFocus() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_GETCURFOCUS, 0, 0L);\n\t}\n\n\tvoid SetCurFocus(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_SETCURFOCUS, nItem, 0L);\n\t}\n\n\tBOOL SetItemExtra(int cbExtra)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetItemCount() == 0);   // must be empty\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_SETITEMEXTRA, cbExtra, 0L);\n\t}\n\n\tint SetMinTabWidth(int nWidth = -1)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_SETMINTABWIDTH, 0, nWidth);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tDWORD GetExtendedStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TCM_GETEXTENDEDSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, TCM_SETEXTENDEDSTYLE, dwExMask, dwExStyle);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n// Operations\n\tint InsertItem(int nItem, LPTCITEM pTabCtrlItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)pTabCtrlItem);\n\t}\n\n\tint InsertItem(int nItem, UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTCITEM tci = { 0 };\n\t\ttci.mask = mask;\n\t\ttci.pszText = (LPTSTR) lpszItem;\n\t\ttci.iImage = iImage;\n\t\ttci.lParam = lParam;\n\t\treturn (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci);\n\t}\n\n\tint InsertItem(int nItem, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTCITEM tci = { 0 };\n\t\ttci.mask = TCIF_TEXT;\n\t\ttci.pszText = (LPTSTR) lpszItem;\n\t\treturn (int)::SendMessage(m_hWnd, TCM_INSERTITEM, nItem, (LPARAM)&tci);\n\t}\n\n\tint AddItem(LPTCITEM pTabCtrlItem)\n\t{\n\t\treturn InsertItem(GetItemCount(), pTabCtrlItem);\n\t}\n\n\tint AddItem(UINT mask, LPCTSTR lpszItem, int iImage, LPARAM lParam)\n\t{\n\t\treturn InsertItem(GetItemCount(), mask, lpszItem, iImage, lParam);\n\t}\n\n\tint AddItem(LPCTSTR lpszItem)\n\t{\n\t\treturn InsertItem(GetItemCount(), lpszItem);\n\t}\n\n\tBOOL DeleteItem(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_DELETEITEM, nItem, 0L);\n\t}\n\n\tBOOL DeleteAllItems()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_DELETEALLITEMS, 0, 0L);\n\t}\n\n\tvoid AdjustRect(BOOL bLarger, LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_ADJUSTRECT, bLarger, (LPARAM)lpRect);\n\t}\n\n\tvoid RemoveImage(int nImage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_REMOVEIMAGE, nImage, 0L);\n\t}\n\n\tint HitTest(TC_HITTESTINFO* pHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo);\n\t}\n\n\tvoid DeselectAll(BOOL bExcludeFocus = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TCM_DESELECTALL, bExcludeFocus, 0L);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tBOOL HighlightItem(int nIndex, BOOL bHighlight = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TCM_HIGHLIGHTITEM, nIndex, MAKELPARAM(bHighlight, 0));\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n};\n\ntypedef CTabCtrlT<ATL::CWindow>   CTabCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTrackBarCtrl\n\ntemplate <class TBase>\nclass CTrackBarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCTrackBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCTrackBarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn TRACKBAR_CLASS;\n\t}\n\n\tint GetLineSize() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETLINESIZE, 0, 0L);\n\t}\n\n\tint SetLineSize(int nSize)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_SETLINESIZE, 0, nSize);\n\t}\n\n\tint GetPageSize() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETPAGESIZE, 0, 0L);\n\t}\n\n\tint SetPageSize(int nSize)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_SETPAGESIZE, 0, nSize);\n\t}\n\n\tint GetRangeMin() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETRANGEMIN, 0, 0L);\n\t}\n\n\tvoid SetRangeMin(int nMin, BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETRANGEMIN, bRedraw, nMin);\n\t}\n\n\tint GetRangeMax() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETRANGEMAX, 0, 0L);\n\t}\n\n\tvoid SetRangeMax(int nMax, BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETRANGEMAX, bRedraw, nMax);\n\t}\n\n\tvoid GetRange(int& nMin, int& nMax) const\n\t{\n\t\tnMin = GetRangeMin();\n\t\tnMax = GetRangeMax();\n\t}\n\n\tvoid SetRange(int nMin, int nMax, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETRANGE, bRedraw, MAKELPARAM(nMin, nMax));\n\t}\n\n\tint GetSelStart() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETSELSTART, 0, 0L);\n\t}\n\n\tvoid SetSelStart(int nMin, BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETSELSTART, bRedraw, (LPARAM)nMin);\n\t}\n\n\tint GetSelEnd() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETSELEND, 0, 0L);\n\t}\n\n\tvoid SetSelEnd(int nMax, BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETSELEND, bRedraw, (LPARAM)nMax);\n\t}\n\n\tvoid GetSelection(int& nMin, int& nMax) const\n\t{\n\t\tnMin = GetSelStart();\n\t\tnMax = GetSelEnd();\n\t}\n\n\tvoid SetSelection(int nMin, int nMax, BOOL bRedraw = TRUE)\n\t{\n\t\tSetSelStart(nMin, FALSE);\n\t\tSetSelEnd(nMax, bRedraw);\n\t}\n\n\tvoid GetChannelRect(LPRECT lprc) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_GETCHANNELRECT, 0, (LPARAM)lprc);\n\t}\n\n\tvoid GetThumbRect(LPRECT lprc) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_GETTHUMBRECT, 0, (LPARAM)lprc);\n\t}\n\n\tint GetPos() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETPOS, 0, 0L);\n\t}\n\n\tvoid SetPos(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETPOS, TRUE, nPos);\n\t}\n\n\tUINT GetNumTics() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, TBM_GETNUMTICS, 0, 0L);\n\t}\n\n\tDWORD* GetTicArray() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD*)::SendMessage(m_hWnd, TBM_GETPTICS, 0, 0L);\n\t}\n\n\tint GetTic(int nTic) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETTIC, nTic, 0L);\n\t}\n\n\tBOOL SetTic(int nTic)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TBM_SETTIC, 0, nTic);\n\t}\n\n\tint GetTicPos(int nTic) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETTICPOS, nTic, 0L);\n\t}\n\n\tvoid SetTicFreq(int nFreq)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETTICFREQ, nFreq, 0L);\n\t}\n\n\tint GetThumbLength() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_GETTHUMBLENGTH, 0, 0L);\n\t}\n\n\tvoid SetThumbLength(int nLength)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETTHUMBLENGTH, nLength, 0L);\n\t}\n\n\tvoid SetSel(int nStart, int nEnd, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & TBS_ENABLESELRANGE) != 0);\n\t\t::SendMessage(m_hWnd, TBM_SETSEL, bRedraw, MAKELPARAM(nStart, nEnd));\n\t}\n\n\tATL::CWindow GetBuddy(BOOL bLeft = TRUE) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_GETBUDDY, bLeft, 0L));\n\t}\n\n\tATL::CWindow SetBuddy(HWND hWndBuddy, BOOL bLeft = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow((HWND)::SendMessage(m_hWnd, TBM_SETBUDDY, bLeft, (LPARAM)hWndBuddy));\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, TBM_GETTOOLTIPS, 0, 0L));\n\t}\n\n\tvoid SetToolTips(HWND hWndTT)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETTOOLTIPS, (WPARAM)hWndTT, 0L);\n\t}\n\n\tint SetTipSide(int nSide)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, TBM_SETTIPSIDE, nSide, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TBM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, TBM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n// Operations\n\tvoid ClearSel(BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_CLEARSEL, bRedraw, 0L);\n\t}\n\n\tvoid VerifyPos()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_SETPOS, FALSE, 0L);\n\t}\n\n\tvoid ClearTics(BOOL bRedraw = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, TBM_CLEARTICS, bRedraw, 0L);\n\t}\n};\n\ntypedef CTrackBarCtrlT<ATL::CWindow>   CTrackBarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CUpDownCtrl\n\ntemplate <class TBase>\nclass CUpDownCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCUpDownCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCUpDownCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn UPDOWN_CLASS;\n\t}\n\n\tUINT GetAccel(int nAccel, UDACCEL* pAccel) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETACCEL, nAccel, (LPARAM)pAccel));\n\t}\n\n\tBOOL SetAccel(int nAccel, UDACCEL* pAccel)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)LOWORD(::SendMessage(m_hWnd, UDM_SETACCEL, nAccel, (LPARAM)pAccel));\n\t}\n\n\tUINT GetBase() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)LOWORD(::SendMessage(m_hWnd, UDM_GETBASE, 0, 0L));\n\t}\n\n\tint SetBase(int nBase)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, UDM_SETBASE, nBase, 0L);\n\t}\n\n\tATL::CWindow GetBuddy() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0L));\n\t}\n\n\tATL::CWindow SetBuddy(HWND hWndBuddy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow((HWND)::SendMessage(m_hWnd, UDM_SETBUDDY, (WPARAM)hWndBuddy, 0L));\n\t}\n\n\tint GetPos(LPBOOL lpbError = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETPOS, 0, 0L);\n\t\t// Note: Seems that Windows always sets error to TRUE if\n\t\t// UDS_SETBUDDYINT style is not used\n\t\tif(lpbError != NULL)\n\t\t\t*lpbError = (HIWORD(dwRet) != 0) ? TRUE : FALSE;\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n\tint SetPos(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)(short)LOWORD(::SendMessage(m_hWnd, UDM_SETPOS, 0, MAKELPARAM(nPos, 0)));\n\t}\n\n\tDWORD GetRange() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L);\n\t}\n\n\tvoid GetRange(int& nLower, int& nUpper) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, UDM_GETRANGE, 0, 0L);\n\t\tnLower = (int)(short)HIWORD(dwRet);\n\t\tnUpper = (int)(short)LOWORD(dwRet);\n\t}\n\n\tvoid SetRange(int nLower, int nUpper)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, UDM_SETRANGE, 0, MAKELPARAM(nUpper, nLower));\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tvoid SetRange32(int nLower, int nUpper)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, UDM_SETRANGE32, nLower, nUpper);\n\t}\n\n\tvoid GetRange32(int& nLower, int& nUpper) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, UDM_GETRANGE32, (WPARAM)&nLower, (LPARAM)&nUpper);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, UDM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, UDM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tint GetPos32(LPBOOL lpbError = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t// Note: Seems that Windows always sets error to TRUE if\n\t\t// UDS_SETBUDDYINT style is not used\n\t\treturn (int)::SendMessage(m_hWnd, UDM_GETPOS32, 0, (LPARAM)lpbError);\n\t}\n\n\tint SetPos32(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, UDM_SETPOS32, 0, (LPARAM)nPos);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n};\n\ntypedef CUpDownCtrlT<ATL::CWindow>   CUpDownCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CProgressBarCtrl\n\ntemplate <class TBase>\nclass CProgressBarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCProgressBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCProgressBarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn PROGRESS_CLASS;\n\t}\n\n\tDWORD SetRange(int nLower, int nUpper)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE, 0, MAKELPARAM(nLower, nUpper));\n\t}\n\n\tint SetPos(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L));\n\t}\n\n\tint OffsetPos(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_DELTAPOS, nPos, 0L));\n\t}\n\n\tint SetStep(int nStep)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_SETSTEP, nStep, 0L));\n\t}\n\n\tUINT GetPos() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, PBM_GETPOS, 0, 0L);\n\t}\n\n\tvoid GetRange(PPBRANGE pPBRange) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pPBRange != NULL);\n\t\t::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)pPBRange);\n\t}\n\n\tvoid GetRange(int& nLower, int& nUpper) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tPBRANGE range = { 0 };\n\t\t::SendMessage(m_hWnd, PBM_GETRANGE, TRUE, (LPARAM)&range);\n\t\tnLower = range.iLow;\n\t\tnUpper = range.iHigh;\n\t}\n\n\tint GetRangeLimit(BOOL bLowLimit) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PBM_GETRANGE, bLowLimit, (LPARAM)NULL);\n\t}\n\n\tDWORD SetRange32(int nMin, int nMax)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, PBM_SETRANGE32, nMin, nMax);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tCOLORREF SetBarColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PBM_SETBARCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PBM_SETBKCOLOR, 0, (LPARAM)clr);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE)\n\tBOOL SetMarquee(BOOL bMarquee, UINT uUpdateTime = 0U)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PBM_SETMARQUEE, (WPARAM)bMarquee, (LPARAM)uUpdateTime);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501) && defined(PBM_SETMARQUEE)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tint GetStep() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PBM_GETSTEP, 0, 0L);\n\t}\n\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PBM_GETBKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF GetBarColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PBM_GETBARCOLOR, 0, 0L);\n\t}\n\n\tint GetState() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PBM_GETSTATE, 0, 0L);\n\t}\n\n\tint SetState(int nState)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PBM_SETSTATE, nState, 0L);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n// Operations\n\tint StepIt()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)(short)LOWORD(::SendMessage(m_hWnd, PBM_STEPIT, 0, 0L));\n\t}\n};\n\ntypedef CProgressBarCtrlT<ATL::CWindow>   CProgressBarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CHotKeyCtrl\n\n#ifndef _WIN32_WCE\n\ntemplate <class TBase>\nclass CHotKeyCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCHotKeyCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCHotKeyCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn HOTKEY_CLASS;\n\t}\n\n\tDWORD GetHotKey() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L);\n\t}\n\n\tvoid GetHotKey(WORD &wVirtualKeyCode, WORD &wModifiers) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dw = (DWORD)::SendMessage(m_hWnd, HKM_GETHOTKEY, 0, 0L);\n\t\twVirtualKeyCode = LOBYTE(LOWORD(dw));\n\t\twModifiers = HIBYTE(LOWORD(dw));\n\t}\n\n\tvoid SetHotKey(WORD wVirtualKeyCode, WORD wModifiers)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, HKM_SETHOTKEY, MAKEWORD(wVirtualKeyCode, wModifiers), 0L);\n\t}\n\n\tvoid SetRules(WORD wInvalidComb, WORD wModifiers)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, HKM_SETRULES, wInvalidComb, MAKELPARAM(wModifiers, 0));\n\t}\n};\n\ntypedef CHotKeyCtrlT<ATL::CWindow>   CHotKeyCtrl;\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAnimateCtrl\n\n#ifndef _WIN32_WCE\n\ntemplate <class TBase>\nclass CAnimateCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCAnimateCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCAnimateCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn ANIMATE_CLASS;\n\t}\n\n// Operations\n\tBOOL Open(ATL::_U_STRINGorID FileName)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, (LPARAM)FileName.m_lpstr);\n\t}\n\n\tBOOL Play(UINT nFrom, UINT nTo, UINT nRep)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_PLAY, nRep, MAKELPARAM(nFrom, nTo));\n\t}\n\n\tBOOL Stop()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_STOP, 0, 0L);\n\t}\n\n\tBOOL Close()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_OPEN, 0, 0L);\n\t}\n\n\tBOOL Seek(UINT nTo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_PLAY, 0, MAKELPARAM(nTo, nTo));\n\t}\n\n\t// Vista only\n\tBOOL IsPlaying() const\n\t{\n#ifndef ACM_ISPLAYING\n\t\tconst UINT ACM_ISPLAYING = (WM_USER+104);\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, ACM_ISPLAYING, 0, 0L);\n\t}\n};\n\ntypedef CAnimateCtrlT<ATL::CWindow>   CAnimateCtrl;\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRichEditCtrl\n\n#ifndef _WIN32_WCE\n\n#if defined(_UNICODE) && (_RICHEDIT_VER == 0x0100)\n  #undef RICHEDIT_CLASS\n  #define RICHEDIT_CLASS\tL\"RICHEDIT\"\n#endif\n\n#if !defined(_UNICODE) && (_RICHEDIT_VER >= 0x0500)\n  #undef MSFTEDIT_CLASS\n  #define MSFTEDIT_CLASS\t\"RICHEDIT50W\"\n#endif\n\ntemplate <class TBase>\nclass CRichEditCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCRichEditCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCRichEditCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n#if (_RICHEDIT_VER >= 0x0500)\n\t\treturn MSFTEDIT_CLASS;\n#else\n\t\treturn RICHEDIT_CLASS;\n#endif\n\t}\n\n\tstatic LPCTSTR GetLibraryName()\n\t{\n#if (_RICHEDIT_VER >= 0x0500)\n\t\treturn _T(\"MSFTEDIT.DLL\");\n#elif (_RICHEDIT_VER >= 0x0200)\n\t\treturn _T(\"RICHED20.DLL\");\n#else\n\t\treturn _T(\"RICHED32.DLL\");\n#endif\n\t}\n\n\tint GetLineCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINECOUNT, 0, 0L);\n\t}\n\n\tBOOL GetModify() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);\n\t}\n\n\tvoid SetModify(BOOL bModified = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETMODIFY, bModified, 0L);\n\t}\n\n\tvoid GetRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_GETRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tDWORD GetOptions() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETOPTIONS, 0, 0L);\n\t}\n\n\tDWORD SetOptions(WORD wOperation, DWORD dwOptions)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_SETOPTIONS, wOperation, dwOptions);\n\t}\n\n\t// NOTE: first word in lpszBuffer must contain the size of the buffer!\n\tint GetLine(int nIndex, LPTSTR lpszBuffer) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);\n\t}\n\n\tint GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t*(LPWORD)lpszBuffer = (WORD)nMaxLength;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);\n\t}\n\n\tBOOL CanUndo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);\n\t}\n\n\tBOOL CanPaste(UINT nFormat = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, nFormat, 0L);\n\t}\n\n\tvoid GetSel(LONG& nStartChar, LONG& nEndChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCHARRANGE cr = { 0, 0 };\n\t\t::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);\n\t\tnStartChar = cr.cpMin;\n\t\tnEndChar = cr.cpMax;\n\t}\n\n\tvoid GetSel(CHARRANGE &cr) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);\n\t}\n\n\tint SetSel(LONG nStartChar, LONG nEndChar)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCHARRANGE cr = { nStartChar, nEndChar };\n\t\treturn (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr);\n\t}\n\n\tint SetSel(CHARRANGE &cr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr);\n\t}\n\n\tint SetSelAll()\n\t{\n\t\treturn SetSel(0, -1);\n\t}\n\n\tint SetSelNone()\n\t{\n\t\treturn SetSel(-1, 0);\n\t}\n\n\tDWORD GetDefaultCharFormat(CHARFORMAT& cf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf);\n\t}\n\n\tDWORD GetSelectionCharFormat(CHARFORMAT& cf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf);\n\t}\n\n\tDWORD GetEventMask() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETEVENTMASK, 0, 0L);\n\t}\n\n\tLONG GetLimitText() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_GETLIMITTEXT, 0, 0L);\n\t}\n\n\tDWORD GetParaFormat(PARAFORMAT& pf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tpf.cbSize = sizeof(PARAFORMAT);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);\n\t}\n\n#if (_RICHEDIT_VER >= 0x0200)\n\tLONG GetSelText(LPTSTR lpstrBuff) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff);\n\t}\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t// RichEdit 1.0 EM_GETSELTEXT is ANSI only\n\tLONG GetSelText(LPSTR lpstrBuff) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrBuff);\n\t}\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\n#ifndef _ATL_NO_COM\n\tBOOL GetSelTextBSTR(BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\n\t\tCHARRANGE cr = { 0, 0 };\n\t\t::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);\n\n#if (_RICHEDIT_VER >= 0x0200)\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn FALSE;\n\t\tif(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0)\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(T2W(lpstrText));\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t\tCTempBuffer<char, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn FALSE;\n\t\tif(::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText) == 0)\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(A2W(lpstrText));\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tLONG GetSelText(_CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tCHARRANGE cr = { 0, 0 };\n\t\t::SendMessage(m_hWnd, EM_EXGETSEL, 0, (LPARAM)&cr);\n\n#if (_RICHEDIT_VER >= 0x0200)\n\t\tLONG lLen = 0;\n\t\tLPTSTR lpstrText = strText.GetBufferSetLength(cr.cpMax - cr.cpMin);\n\t\tif(lpstrText != NULL)\n\t\t{\n\t\t\tlLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText);\n\t\t\tstrText.ReleaseBuffer();\n\t\t}\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t\tCTempBuffer<char, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPSTR lpstrText = buff.Allocate(cr.cpMax - cr.cpMin + 1);\n\t\tif(lpstrText == NULL)\n\t\t\treturn 0;\n\t\tLONG lLen = (LONG)::SendMessage(m_hWnd, EM_GETSELTEXT, 0, (LPARAM)lpstrText);\n\t\tif(lLen == 0)\n\t\t\treturn 0;\n\n\t\tUSES_CONVERSION;\n\t\tstrText = A2T(lpstrText);\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\n\t\treturn lLen;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tWORD GetSelectionType() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (WORD)::SendMessage(m_hWnd, EM_SELECTIONTYPE, 0, 0L);\n\t}\n\n\tCOLORREF SetBackgroundColor(COLORREF cr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 0, cr);\n\t}\n\n\tCOLORREF SetBackgroundColor()   // sets to system background\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, EM_SETBKGNDCOLOR, 1, 0);\n\t}\n\n\tBOOL SetCharFormat(CHARFORMAT& cf, WORD wFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf);\n\t}\n\n\tBOOL SetDefaultCharFormat(CHARFORMAT& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf);\n\t}\n\n\tBOOL SetSelectionCharFormat(CHARFORMAT& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);\n\t}\n\n\tBOOL SetWordCharFormat(CHARFORMAT& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf);\n\t}\n\n\tDWORD SetEventMask(DWORD dwEventMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_SETEVENTMASK, 0, dwEventMask);\n\t}\n\n\tBOOL SetParaFormat(PARAFORMAT& pf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tpf.cbSize = sizeof(PARAFORMAT);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);\n\t}\n\n\tBOOL SetTargetDevice(HDC hDC, int cxLineWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTARGETDEVICE, (WPARAM)hDC, cxLineWidth);\n\t}\n\n\tint GetTextLength() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L);\n\t}\n\n\tBOOL SetReadOnly(BOOL bReadOnly = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETREADONLY, bReadOnly, 0L);\n\t}\n\n\tint GetFirstVisibleLine() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETFIRSTVISIBLELINE, 0, 0L);\n\t}\n\n\tint GetTextRange(TEXTRANGE* pTextRange) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)pTextRange);\n\t}\n\n#if (_RICHEDIT_VER < 0x0200)\n\tEDITWORDBREAKPROCEX GetWordBreakProcEx() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_GETWORDBREAKPROCEX, 0, 0L);\n\t}\n\n\tEDITWORDBREAKPROCEX SetWordBreakProcEx(EDITWORDBREAKPROCEX pfnEditWordBreakProcEx)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (EDITWORDBREAKPROCEX)::SendMessage(m_hWnd, EM_SETWORDBREAKPROCEX, 0, (LPARAM)pfnEditWordBreakProcEx);\n\t}\n#endif // (_RICHEDIT_VER < 0x0200)\n\n#if (_RICHEDIT_VER >= 0x0200)\n\tint GetTextRange(LONG nStartChar, LONG nEndChar, LPTSTR lpstrText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTEXTRANGE tr = { 0 };\n\t\ttr.chrg.cpMin = nStartChar;\n\t\ttr.chrg.cpMax = nEndChar;\n\t\ttr.lpstrText = lpstrText;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\n\t}\n#else // !(_RICHEDIT_VER >= 0x0200)\n\tint GetTextRange(LONG nStartChar, LONG nEndChar, LPSTR lpstrText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tTEXTRANGE tr = { 0 };\n\t\ttr.chrg.cpMin = nStartChar;\n\t\ttr.chrg.cpMax = nEndChar;\n\t\ttr.lpstrText = lpstrText;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTRANGE, 0, (LPARAM)&tr);\n\t}\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\n#if (_RICHEDIT_VER >= 0x0200)\n\tDWORD GetDefaultCharFormat(CHARFORMAT2& cf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 0, (LPARAM)&cf);\n\t}\n\n\tBOOL SetCharFormat(CHARFORMAT2& cf, WORD wFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, (WPARAM)wFlags, (LPARAM)&cf);\n\t}\n\n\tBOOL SetDefaultCharFormat(CHARFORMAT2& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, 0, (LPARAM)&cf);\n\t}\n\n\tDWORD GetSelectionCharFormat(CHARFORMAT2& cf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETCHARFORMAT, 1, (LPARAM)&cf);\n\t}\n\n\tBOOL SetSelectionCharFormat(CHARFORMAT2& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);\n\t}\n\n\tBOOL SetWordCharFormat(CHARFORMAT2& cf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tcf.cbSize = sizeof(CHARFORMAT2);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION | SCF_WORD, (LPARAM)&cf);\n\t}\n\n\tDWORD GetParaFormat(PARAFORMAT2& pf) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tpf.cbSize = sizeof(PARAFORMAT2);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETPARAFORMAT, 0, (LPARAM)&pf);\n\t}\n\n\tBOOL SetParaFormat(PARAFORMAT2& pf)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tpf.cbSize = sizeof(PARAFORMAT2);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETPARAFORMAT, 0, (LPARAM)&pf);\n\t}\n\n\tTEXTMODE GetTextMode() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (TEXTMODE)::SendMessage(m_hWnd, EM_GETTEXTMODE, 0, 0L);\n\t}\n\n\tBOOL SetTextMode(TEXTMODE enumTextMode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn !(BOOL)::SendMessage(m_hWnd, EM_SETTEXTMODE, enumTextMode, 0L);\n\t}\n\n\tUNDONAMEID GetUndoName() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UNDONAMEID)::SendMessage(m_hWnd, EM_GETUNDONAME, 0, 0L);\n\t}\n\n\tUNDONAMEID GetRedoName() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UNDONAMEID)::SendMessage(m_hWnd, EM_GETREDONAME, 0, 0L);\n\t}\n\n\tBOOL CanRedo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L);\n\t}\n\n\tBOOL GetAutoURLDetect() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETAUTOURLDETECT, 0, 0L);\n\t}\n\n\tBOOL SetAutoURLDetect(BOOL bAutoDetect = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn !(BOOL)::SendMessage(m_hWnd, EM_AUTOURLDETECT, bAutoDetect, 0L);\n\t}\n\n\t// this method is deprecated, please use SetAutoURLDetect\n\tBOOL EnableAutoURLDetect(BOOL bEnable = TRUE) { return SetAutoURLDetect(bEnable); }\n\n\tUINT SetUndoLimit(UINT uUndoLimit)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_SETUNDOLIMIT, uUndoLimit, 0L);\n\t}\n\n\tvoid SetPalette(HPALETTE hPalette)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETPALETTE, (WPARAM)hPalette, 0L);\n\t}\n\n\tint GetTextEx(GETTEXTEX* pGetTextEx, LPTSTR lpstrText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)pGetTextEx, (LPARAM)lpstrText);\n\t}\n\n\tint GetTextEx(LPTSTR lpstrText, int nTextLen, DWORD dwFlags = GT_DEFAULT, UINT uCodePage = CP_ACP, LPCSTR lpDefaultChar = NULL, LPBOOL lpUsedDefChar = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tGETTEXTEX gte = { 0 };\n\t\tgte.cb = nTextLen * sizeof(TCHAR);\n\t\tgte.codepage = uCodePage;\n\t\tgte.flags = dwFlags;\n\t\tgte.lpDefaultChar = lpDefaultChar;\n\t\tgte.lpUsedDefChar = lpUsedDefChar;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTEX, (WPARAM)&gte, (LPARAM)lpstrText);\n\t}\n\n\tint GetTextLengthEx(GETTEXTLENGTHEX* pGetTextLengthEx) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)pGetTextLengthEx, 0L);\n\t}\n\n\tint GetTextLengthEx(DWORD dwFlags = GTL_DEFAULT, UINT uCodePage = CP_ACP) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tGETTEXTLENGTHEX gtle = { 0 };\n\t\tgtle.codepage = uCodePage;\n\t\tgtle.flags = dwFlags;\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtle, 0L);\n\t}\n\n\tEDITWORDBREAKPROC GetWordBreakProc() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (EDITWORDBREAKPROC)::SendMessage(m_hWnd, EM_GETWORDBREAKPROC, 0, 0L);\n\t}\n\n\tvoid SetWordBreakProc(EDITWORDBREAKPROC ewbprc)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETWORDBREAKPROC, 0, (LPARAM)ewbprc);\n\t}\n#endif // (_RICHEDIT_VER >= 0x0200)\n\n#if (_RICHEDIT_VER >= 0x0300)\n\tint SetTextEx(SETTEXTEX* pSetTextEx, LPCTSTR lpstrText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)pSetTextEx, (LPARAM)lpstrText);\n\t}\n\n\tint SetTextEx(LPCTSTR lpstrText, DWORD dwFlags = ST_DEFAULT, UINT uCodePage = CP_ACP)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tSETTEXTEX ste = { 0 };\n\t\tste.flags = dwFlags;\n\t\tste.codepage = uCodePage;\n\t\treturn (int)::SendMessage(m_hWnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpstrText);\n\t}\n\n\tint GetEditStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_GETEDITSTYLE, 0, 0L);\n\t}\n\n\tint SetEditStyle(int nStyle, int nMask = -1)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tif(nMask == -1)\n\t\t\tnMask = nStyle;   // set everything specified\n\t\treturn (int)::SendMessage(m_hWnd, EM_SETEDITSTYLE, nStyle, nMask);\n\t}\n\n\tBOOL SetFontSize(int nFontSizeDelta)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nFontSizeDelta >= -1637 && nFontSizeDelta <= 1638);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETFONTSIZE, nFontSizeDelta, 0L);\n\t}\n\n\tvoid GetScrollPos(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpPoint != NULL);\n\t\t::SendMessage(m_hWnd, EM_GETSCROLLPOS, 0, (LPARAM)lpPoint);\n\t}\n\n\tvoid SetScrollPos(LPPOINT lpPoint)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpPoint != NULL);\n\t\t::SendMessage(m_hWnd, EM_SETSCROLLPOS, 0, (LPARAM)lpPoint);\n\t}\n\n\tBOOL GetZoom(int& nNum, int& nDen) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETZOOM, (WPARAM)&nNum, (LPARAM)&nDen);\n\t}\n\n\tBOOL SetZoom(int nNum, int nDen)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nNum >= 0 && nNum <= 64);\n\t\tATLASSERT(nDen >= 0 && nDen <= 64);\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, nNum, nDen);\n\t}\n\n\tBOOL SetZoomOff()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETZOOM, 0, 0L);\n\t}\n\n\tvoid SetMargins(UINT nLeft, UINT nRight, WORD wFlags = EC_LEFTMARGIN | EC_RIGHTMARGIN)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETMARGINS, wFlags, MAKELONG(nLeft, nRight));\n\t}\n#endif // (_RICHEDIT_VER >= 0x0300)\n\n// Operations\n\tvoid LimitText(LONG nChars = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_EXLIMITTEXT, 0, nChars);\n\t}\n\n\tint LineFromChar(LONG nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nIndex);\n\t}\n\n\tPOINT PosFromChar(LONG nChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tPOINT point = { 0, 0 };\n\t\t::SendMessage(m_hWnd, EM_POSFROMCHAR, (WPARAM)&point, nChar);\n\t\treturn point;\n\t}\n\n\tint CharFromPos(POINT pt) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tPOINTL ptl = { pt.x, pt.y };\n\t\treturn (int)::SendMessage(m_hWnd, EM_CHARFROMPOS, 0, (LPARAM)&ptl);\n\t}\n\n\tvoid EmptyUndoBuffer()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_EMPTYUNDOBUFFER, 0, 0L);\n\t}\n\n\tint LineIndex(int nLine = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_LINEINDEX, nLine, 0L);\n\t}\n\n\tint LineLength(int nLine = -1) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, EM_LINELENGTH, nLine, 0L);\n\t}\n\n\tBOOL LineScroll(int nLines)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_LINESCROLL, 0, nLines);\n\t}\n\n\tvoid ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM) bCanUndo, (LPARAM)lpszNewText);\n\t}\n\n\tvoid SetRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETRECT, 0, (LPARAM)lpRect);\n\t}\n\n\tBOOL DisplayBand(LPRECT pDisplayRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_DISPLAYBAND, 0, (LPARAM)pDisplayRect);\n\t}\n\n\tLONG FindText(DWORD dwFlags, FINDTEXT& ft) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE)\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FINDTEXTW, dwFlags, (LPARAM)&ft);\n#else\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FINDTEXT, dwFlags, (LPARAM)&ft);\n#endif\n\t}\n\n\tLONG FindText(DWORD dwFlags, FINDTEXTEX& ft) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#if (_RICHEDIT_VER >= 0x0200) && defined(_UNICODE)\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEXW, dwFlags, (LPARAM)&ft);\n#else\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&ft);\n#endif\n\t}\n\n\tLONG FormatRange(FORMATRANGE& fr, BOOL bDisplay = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)&fr);\n\t}\n\n\tLONG FormatRange(FORMATRANGE* pFormatRange, BOOL bDisplay = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_FORMATRANGE, bDisplay, (LPARAM)pFormatRange);\n\t}\n\n\tvoid HideSelection(BOOL bHide = TRUE, BOOL bChangeStyle = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_HIDESELECTION, bHide, bChangeStyle);\n\t}\n\n\tvoid PasteSpecial(UINT uClipFormat, DWORD dwAspect = 0, HMETAFILE hMF = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tREPASTESPECIAL reps = { dwAspect, (DWORD_PTR)hMF };\n\t\t::SendMessage(m_hWnd, EM_PASTESPECIAL, uClipFormat, (LPARAM)&reps);\n\t}\n\n\tvoid RequestResize()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_REQUESTRESIZE, 0, 0L);\n\t}\n\n\tLONG StreamIn(UINT uFormat, EDITSTREAM& es)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_STREAMIN, uFormat, (LPARAM)&es);\n\t}\n\n\tLONG StreamOut(UINT uFormat, EDITSTREAM& es)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, uFormat, (LPARAM)&es);\n\t}\n\n\tDWORD FindWordBreak(int nCode, LONG nStartChar)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_FINDWORDBREAK, nCode, nStartChar);\n\t}\n\n\t// Additional operations\n\tvoid ScrollCaret()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SCROLLCARET, 0, 0L);\n\t}\n\n\tint InsertText(long nInsertAfterChar, LPCTSTR lpstrText, BOOL bCanUndo = FALSE)\n\t{\n\t\tint nRet = SetSel(nInsertAfterChar, nInsertAfterChar);\n\t\tReplaceSel(lpstrText, bCanUndo);\n\t\treturn nRet;\n\t}\n\n\tint AppendText(LPCTSTR lpstrText, BOOL bCanUndo = FALSE)\n\t{\n\t\treturn InsertText(GetWindowTextLength(), lpstrText, bCanUndo);\n\t}\n\n\t// Clipboard operations\n\tBOOL Undo()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0L);\n\t}\n\n\tvoid Clear()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);\n\t}\n\n\tvoid Copy()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_COPY, 0, 0L);\n\t}\n\n\tvoid Cut()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CUT, 0, 0L);\n\t}\n\n\tvoid Paste()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_PASTE, 0, 0L);\n\t}\n\n\t// OLE support\n\tIRichEditOle* GetOleInterface() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tIRichEditOle *pRichEditOle = NULL;\n\t\t::SendMessage(m_hWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pRichEditOle);\n\t\treturn pRichEditOle;\n\t}\n\n\tBOOL SetOleCallback(IRichEditOleCallback* pCallback)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETOLECALLBACK, 0, (LPARAM)pCallback);\n\t}\n\n#if (_RICHEDIT_VER >= 0x0200)\n\tBOOL Redo()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_REDO, 0, 0L);\n\t}\n\n\tvoid StopGroupTyping()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_STOPGROUPTYPING, 0, 0L);\n\t}\n\n\tvoid ShowScrollBar(int nBarType, BOOL bVisible = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SHOWSCROLLBAR, nBarType, bVisible);\n\t}\n#endif // (_RICHEDIT_VER >= 0x0200)\n\n#if (_RICHEDIT_VER >= 0x0300)\n\tBOOL SetTabStops(int nTabStops, LPINT rgTabStops)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, nTabStops, (LPARAM)rgTabStops);\n\t}\n\n\tBOOL SetTabStops()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 0, 0L);\n\t}\n\n\tBOOL SetTabStops(const int& cxEachStop)    // takes an 'int'\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETTABSTOPS, 1, (LPARAM)(LPINT)&cxEachStop);\n\t}\n#endif // (_RICHEDIT_VER >= 0x0300)\n\n#if (_RICHEDIT_VER >= 0x0800)\n\tAutoCorrectProc GetAutoCorrectProc() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (AutoCorrectProc)::SendMessage(m_hWnd, EM_GETAUTOCORRECTPROC, 0, 0L);\n\t}\n\n\tBOOL SetAutoCorrectProc(AutoCorrectProc pfn)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETAUTOCORRECTPROC, (WPARAM)pfn, 0L);\n\t}\n\n\tBOOL CallAutoCorrectProc(WCHAR ch)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CALLAUTOCORRECTPROC, (WPARAM)ch, 0L);\n\t}\n\n\tDWORD GetEditStyleEx() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETEDITSTYLEEX, 0, 0L);\n\t}\n\n\tDWORD SetEditStyleEx(DWORD dwStyleEx, DWORD dwMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_SETEDITSTYLEEX, dwStyleEx, dwMask);\n\t}\n\n\tDWORD GetStoryType(int nStoryIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETSTORYTYPE, nStoryIndex, 0L);\n\t}\n\n\tDWORD SetStoryType(int nStoryIndex, DWORD dwStoryType)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_SETSTORYTYPE, nStoryIndex, dwStoryType);\n\t}\n\n\tDWORD GetEllipsisMode() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tDWORD dwMode = 0;\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISMODE, 0, (LPARAM)&dwMode);\n\t\tbRet;   // avoid level 4 warning\n\t\tATLASSERT(bRet != FALSE);\n\n\t\treturn dwMode;\n\t}\n\n\tBOOL SetEllipsisMode(DWORD dwEllipsisMode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETELLIPSISMODE, 0, dwEllipsisMode);\n\t}\n\n\tBOOL GetEllipsisState() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETELLIPSISSTATE, 0, 0L);\n\t}\n\n\tBOOL GetTouchOptions(int nTouchOptions) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETTOUCHOPTIONS, nTouchOptions, 0L);\n\t}\n\n\tvoid SetTouchOptions(int nTouchOptions, BOOL bEnable)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETTOUCHOPTIONS, nTouchOptions, bEnable);\n\t}\n\n\tHRESULT InsertTable(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, EM_INSERTTABLE, (WPARAM)pRowParams, (LPARAM)pCellParams);\n\t}\n\n\tHRESULT GetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, EM_GETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams);\n\t}\n\n\tHRESULT SetTableParams(TABLEROWPARMS* pRowParams, TABLECELLPARMS* pCellParams)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, EM_SETTABLEPARMS, (WPARAM)pRowParams, (LPARAM)pCellParams);\n\t}\n\n\tHRESULT InsertImage(RICHEDIT_IMAGE_PARAMETERS* pParams)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, EM_INSERTIMAGE, 0, (LPARAM)pParams);\n\t}\n\n\tBOOL SetUiaName(LPCTSTR lpstrName)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_SETUIANAME, 0, (LPARAM)lpstrName);\n\t}\n#endif // (_RICHEDIT_VER >= 0x0800)\n};\n\ntypedef CRichEditCtrlT<ATL::CWindow>   CRichEditCtrl;\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRichEditCommands - message handlers for standard EDIT commands\n\n#ifndef _WIN32_WCE\n\n// Chain to CRichEditCommands message map. Your class must also derive from CRichEditCtrl.\n// Example:\n// class CMyRichEdit : public CWindowImpl<CMyRichEdit, CRichEditCtrl>,\n//                     public CRichEditCommands<CMyRichEdit>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyRichEdit)\n//              // your handlers...\n//              CHAIN_MSG_MAP_ALT(CRichEditCommands<CMyRichEdit>, 1)\n//      END_MSG_MAP()\n//      // other stuff...\n// };\n\ntemplate <class T>\nclass CRichEditCommands : public CEditCommands< T >\n{\npublic:\n\tBEGIN_MSG_MAP(CRichEditCommands< T >)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CLEAR, CEditCommands< T >::OnEditClear)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, CEditCommands< T >::OnEditClearAll)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_COPY, CEditCommands< T >::OnEditCopy)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_CUT, CEditCommands< T >::OnEditCut)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_PASTE, CEditCommands< T >::OnEditPaste)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, CEditCommands< T >::OnEditSelectAll)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_UNDO, CEditCommands< T >::OnEditUndo)\n#if (_RICHEDIT_VER >= 0x0200)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_REDO, OnEditRedo)\n#endif // (_RICHEDIT_VER >= 0x0200)\n\tEND_MSG_MAP()\n\n#if (_RICHEDIT_VER >= 0x0200)\n\tLRESULT OnEditRedo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Redo();\n\t\treturn 0;\n\t}\n#endif // (_RICHEDIT_VER >= 0x0200)\n\n// State (update UI) helpers\n\tBOOL CanCut() const\n\t{ return HasSelection(); }\n\n\tBOOL CanCopy() const\n\t{ return HasSelection(); }\n\n\tBOOL CanClear() const\n\t{ return HasSelection(); }\n\n// Implementation\n\tBOOL HasSelection() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\treturn (pT->GetSelectionType() != SEL_EMPTY);\n\t}\n};\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDragListBox\n\n#ifndef _WIN32_WCE\n\ntemplate <class TBase>\nclass CDragListBoxT : public CListBoxT< TBase >\n{\npublic:\n// Constructors\n\tCDragListBoxT(HWND hWnd = NULL) : CListBoxT< TBase >(hWnd)\n\t{ }\n\n\tCDragListBoxT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tif(hWnd != NULL)\n\t\t\tMakeDragList();\n\t\treturn hWnd;\n\t}\n\n// Operations\n\tBOOL MakeDragList()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((GetStyle() & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == 0);\n\t\treturn ::MakeDragList(m_hWnd);\n\t}\n\n\tint LBItemFromPt(POINT pt, BOOL bAutoScroll = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::LBItemFromPt(m_hWnd, pt, bAutoScroll);\n\t}\n\n\tvoid DrawInsert(int nItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::DrawInsert(GetParent(), m_hWnd, nItem);\n\t}\n\n\tstatic UINT GetDragListMessage()\n\t{\n\t\tstatic UINT uDragListMessage = 0;\n\t\tif(uDragListMessage == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CDragListBox::GetDragListMessage.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uDragListMessage == 0)\n\t\t\t\tuDragListMessage = ::RegisterWindowMessage(DRAGLISTMSGSTRING);\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uDragListMessage != 0);\n\t\treturn uDragListMessage;\n\t}\n};\n\ntypedef CDragListBoxT<ATL::CWindow>   CDragListBox;\n\ntemplate <class T>\nclass CDragListNotifyImpl\n{\npublic:\n\tBEGIN_MSG_MAP(CDragListNotifyImpl< T >)\n\t\tMESSAGE_HANDLER(CDragListBox::GetDragListMessage(), OnDragListNotify)\n\tEND_MSG_MAP()\n\n\tLRESULT OnDragListNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tuMsg;   // avoid level 4 warning\n\t\tATLASSERT(uMsg == CDragListBox::GetDragListMessage());\n\t\tT* pT = static_cast<T*>(this);\n\t\tLPDRAGLISTINFO lpDragListInfo = (LPDRAGLISTINFO)lParam;\n\t\tLRESULT lRet = 0;\n\t\tswitch(lpDragListInfo->uNotification)\n\t\t{\n\t\tcase DL_BEGINDRAG:\n\t\t\tlRet = (LPARAM)pT->OnBeginDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);\n\t\t\tbreak;\n\t\tcase DL_CANCELDRAG:\n\t\t\tpT->OnCancelDrag((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);\n\t\t\tbreak;\n\t\tcase DL_DRAGGING:\n\t\t\tlRet = (LPARAM)pT->OnDragging((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);\n\t\t\tbreak;\n\t\tcase DL_DROPPED:\n\t\t\tpT->OnDropped((int)wParam, lpDragListInfo->hWnd, lpDragListInfo->ptCursor);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Unknown DragListBox notification\\n\"));\n\t\t\tbHandled = FALSE;   // don't handle it\n\t\t\tbreak;\n\t\t}\n\t\treturn lRet;\n\t}\n\n// Overrideables\n\tBOOL OnBeginDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)\n\t{\n\t\treturn TRUE;   // allow dragging\n\t}\n\n\tvoid OnCancelDrag(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)\n\t{\n\t\t// nothing to do\n\t}\n\n\tint OnDragging(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)\n\t{\n\t\treturn 0;   // don't change cursor\n\t}\n\n\tvoid OnDropped(int /*nCtlID*/, HWND /*hWndDragList*/, POINT /*ptCursor*/)\n\t{\n\t\t// nothing to do\n\t}\n};\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CReBarCtrl\n\ntemplate <class TBase>\nclass CReBarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCReBarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCReBarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn REBARCLASSNAME;\n\t}\n\n\tUINT GetBandCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, RB_GETBANDCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetBandInfo(int nBand, LPREBARBANDINFO lprbbi) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_GETBANDINFO, nBand, (LPARAM)lprbbi);\n\t}\n\n\tBOOL SetBandInfo(int nBand, LPREBARBANDINFO lprbbi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SETBANDINFO, nBand, (LPARAM)lprbbi);\n\t}\n\n\tBOOL GetBarInfo(LPREBARINFO lprbi) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)lprbi);\n\t}\n\n\tBOOL SetBarInfo(LPREBARINFO lprbi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)lprbi);\n\t}\n\n\tCImageList GetImageList() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tREBARINFO rbi = { 0 };\n\t\trbi.cbSize = sizeof(REBARINFO);\n\t\trbi.fMask = RBIM_IMAGELIST;\n\t\tBOOL bRet = (BOOL)::SendMessage(m_hWnd, RB_GETBARINFO, 0, (LPARAM)&rbi);\n\t\treturn CImageList((bRet != FALSE) ? rbi.himl : NULL);\n\t}\n\n\tBOOL SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tREBARINFO rbi = { 0 };\n\t\trbi.cbSize = sizeof(REBARINFO);\n\t\trbi.fMask = RBIM_IMAGELIST;\n\t\trbi.himl = hImageList;\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SETBARINFO, 0, (LPARAM)&rbi);\n\t}\n\n\tUINT GetRowCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, RB_GETROWCOUNT, 0, 0L);\n\t}\n\n\tUINT GetRowHeight(int nBand) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, RB_GETROWHEIGHT, nBand, 0L);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tCOLORREF GetTextColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, RB_GETTEXTCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetTextColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, RB_SETTEXTCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, RB_GETBKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, RB_SETBKCOLOR, 0, (LPARAM)clr);\n\t}\n\n\tUINT GetBarHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, RB_GETBARHEIGHT, 0, 0L);\n\t}\n\n\tBOOL GetRect(int nBand, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_GETRECT, nBand, (LPARAM)lpRect);\n\t}\n\n#ifndef _WIN32_WCE\n\tCToolTipCtrl GetToolTips() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CToolTipCtrl((HWND)::SendMessage(m_hWnd, RB_GETTOOLTIPS, 0, 0L));\n\t}\n\n\tvoid SetToolTips(HWND hwndToolTip)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_SETTOOLTIPS, (WPARAM)hwndToolTip, 0L);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid GetBandBorders(int nBand, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpRect != NULL);\n\t\t::SendMessage(m_hWnd, RB_GETBANDBORDERS, nBand, (LPARAM)lpRect);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetColorScheme(LPCOLORSCHEME lpColorScheme) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpColorScheme != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_GETCOLORSCHEME, 0, (LPARAM)lpColorScheme);\n\t}\n\n\tvoid SetColorScheme(LPCOLORSCHEME lpColorScheme)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpColorScheme != NULL);\n\t\t::SendMessage(m_hWnd, RB_SETCOLORSCHEME, 0, (LPARAM)lpColorScheme);\n\t}\n\n\tHPALETTE GetPalette() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HPALETTE)::SendMessage(m_hWnd, RB_GETPALETTE, 0, 0L);\n\t}\n\n\tHPALETTE SetPalette(HPALETTE hPalette)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HPALETTE)::SendMessage(m_hWnd, RB_SETPALETTE, 0, (LPARAM)hPalette);\n\t}\n\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_WINNT >= 0x0501)\n\t// requires uxtheme.h to be included to use MARGINS struct\n#ifndef _UXTHEME_H_\n\ttypedef struct _MARGINS*   PMARGINS;\n#endif // !_UXTHEME_H_\n\tvoid GetBandMargins(PMARGINS pMargins) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_GETBANDMARGINS, 0, (LPARAM)pMargins);\n\t}\n\n\tvoid SetWindowTheme(LPCWSTR lpstrTheme)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n#if (_WIN32_IE >= 0x0600)\n\tDWORD GetExtendedStyle() const\n\t{\n#ifndef RB_GETEXTENDEDSTYLE\n\tconst UINT RB_GETEXTENDEDSTYLE = WM_USER + 42;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, RB_GETEXTENDEDSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwStyle, DWORD dwMask)\n\t{\n#ifndef RB_SETEXTENDEDSTYLE\n\t\tconst UINT RB_SETEXTENDEDSTYLE = WM_USER + 41;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, RB_SETEXTENDEDSTYLE, dwMask, dwStyle);\n\t}\n#endif // (_WIN32_IE >= 0x0600)\n\n// Operations\n\tBOOL InsertBand(int nBand, LPREBARBANDINFO lprbbi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_INSERTBAND, nBand, (LPARAM)lprbbi);\n\t}\n\n\tBOOL AddBand(LPREBARBANDINFO lprbbi)\n\t{\n\t\treturn InsertBand(-1, lprbbi);\n\t}\n\n\tBOOL DeleteBand(int nBand)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_DELETEBAND, nBand, 0L);\n\t}\n\n\tATL::CWindow SetNotifyWnd(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow((HWND)::SendMessage(m_hWnd, RB_SETPARENT, (WPARAM)hWnd, 0L));\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tvoid BeginDrag(int nBand, DWORD dwPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, dwPos);\n\t}\n\n\tvoid BeginDrag(int nBand, int xPos, int yPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_BEGINDRAG, nBand, MAKELPARAM(xPos, yPos));\n\t}\n\n\tvoid EndDrag()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_ENDDRAG, 0, 0L);\n\t}\n\n\tvoid DragMove(DWORD dwPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_DRAGMOVE, 0, dwPos);\n\t}\n\n\tvoid DragMove(int xPos, int yPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_DRAGMOVE, 0, MAKELPARAM(xPos, yPos));\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid GetDropTarget(IDropTarget** ppDropTarget) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_GETDROPTARGET, 0, (LPARAM)ppDropTarget);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid MaximizeBand(int nBand, BOOL bIdeal = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_MAXIMIZEBAND, nBand, bIdeal);\n\t}\n\n\tvoid MinimizeBand(int nBand)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_MINIMIZEBAND, nBand, 0L);\n\t}\n\n\tBOOL SizeToRect(LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SIZETORECT, 0, (LPARAM)lpRect);\n\t}\n\n\tint IdToIndex(UINT uBandID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, RB_IDTOINDEX, uBandID, 0L);\n\t}\n\n\tint HitTest(LPRBHITTESTINFO lprbht) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, RB_HITTEST, 0, (LPARAM)lprbht);\n\t}\n\n\tBOOL ShowBand(int nBand, BOOL bShow)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SHOWBAND, nBand, bShow);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL MoveBand(int nBand, int nNewPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nNewPos >= 0 && nNewPos <= ((int)GetBandCount() - 1));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_MOVEBAND, nBand, nNewPos);\n\t}\n#endif // !_WIN32_WCE\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tvoid PushChevron(int nBand, LPARAM lAppValue)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, RB_PUSHCHEVRON, nBand, lAppValue);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n// Extra operations\n#if (_WIN32_IE >= 0x0400)\n\tvoid LockBands(bool bLock)\n\t{\n\t\tint nBandCount = GetBandCount();\n\t\tfor(int i =0; i < nBandCount; i++)\n\t\t{\n\t\t\tREBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };\n\t\t\trbbi.fMask = RBBIM_STYLE;\n\t\t\tBOOL bRet = GetBandInfo(i, &rbbi);\n\t\t\tATLASSERT(bRet);\n\n\t\t\tif((rbbi.fStyle & RBBS_GRIPPERALWAYS) == 0)\n\t\t\t{\n\t\t\t\trbbi.fStyle |= RBBS_GRIPPERALWAYS;\n\t\t\t\tbRet = SetBandInfo(i, &rbbi);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t\trbbi.fStyle &= ~RBBS_GRIPPERALWAYS;\n\t\t\t}\n\n\t\t\tif(bLock)\n\t\t\t\trbbi.fStyle |= RBBS_NOGRIPPER;\n\t\t\telse\n\t\t\t\trbbi.fStyle &= ~RBBS_NOGRIPPER;\n\n\t\t\tbRet = SetBandInfo(i, &rbbi);\n\t\t\tATLASSERT(bRet);\n\t\t}\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_WINNT >= 0x0600)\n\tBOOL SetBandWidth(int nBand, int cxWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, RB_SETBANDWIDTH, nBand, cxWidth);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n};\n\ntypedef CReBarCtrlT<ATL::CWindow>   CReBarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CComboBoxEx\n\n#ifndef _WIN32_WCE\n\ntemplate <class TBase>\nclass CComboBoxExT : public CComboBoxT< TBase >\n{\npublic:\n// Constructors\n\tCComboBoxExT(HWND hWnd = NULL) : CComboBoxT< TBase >(hWnd)\n\t{ }\n\n\tCComboBoxExT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_COMBOBOXEX;\n\t}\n\n\tCImageList GetImageList() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_GETIMAGELIST, 0, 0L));\n\t}\n\n\tCImageList SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CImageList((HIMAGELIST)::SendMessage(m_hWnd, CBEM_SETIMAGELIST, 0, (LPARAM)hImageList));\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tDWORD GetExtendedStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetExtendedStyle(DWORD dwExMask, DWORD dwExStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, dwExMask, dwExStyle);\n\t}\n\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_WINNT >= 0x0501)\n\tvoid SetWindowTheme(LPCWSTR lpstrTheme)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, CBEM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n// Operations\n\tint InsertItem(const COMBOBOXEXITEM* lpcCBItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)lpcCBItem);\n\t}\n\n\tint InsertItem(UINT nMask, int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, \n\t               int iIndent, int iOverlay, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = nMask;\n\t\tcbex.iItem = nIndex;\n\t\tcbex.pszText = (LPTSTR) lpszItem;\n\t\tcbex.iImage = nImage;\n\t\tcbex.iSelectedImage = nSelImage;\n\t\tcbex.iIndent = iIndent;\n\t\tcbex.iOverlay = iOverlay;\n\t\tcbex.lParam = lParam;\n\t\treturn (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex);\n\t}\n\n\tint InsertItem(int nIndex, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_INDENT | CBEIF_LPARAM;\n\t\tcbex.iItem = nIndex;\n\t\tcbex.pszText = (LPTSTR) lpszItem;\n\t\tcbex.iImage = nImage;\n\t\tcbex.iSelectedImage = nSelImage;\n\t\tcbex.iIndent = iIndent;\n\t\tcbex.lParam = lParam;\n\t\treturn (int)::SendMessage(m_hWnd, CBEM_INSERTITEM, 0, (LPARAM)&cbex);\n\t}\n\n\tint AddItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, int iOverlay, LPARAM lParam)\n\t{\n\t\treturn InsertItem(nMask, -1, lpszItem, nImage, nSelImage, iIndent, iOverlay, lParam);\n\t}\n\n\tint AddItem(LPCTSTR lpszItem, int nImage, int nSelImage, int iIndent, LPARAM lParam = 0)\n\t{\n\t\treturn InsertItem(-1, lpszItem, nImage, nSelImage, iIndent, lParam);\n\t}\n\n\tint DeleteItem(int nIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, CBEM_DELETEITEM, nIndex, 0L);\n\t}\n\n\tBOOL GetItem(PCOMBOBOXEXITEM pCBItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)pCBItem);\n\t}\n\n\tBOOL SetItem(const COMBOBOXEXITEM* lpcCBItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)lpcCBItem);\n\t}\n\n\tint SetItem(int nIndex, UINT nMask, LPCTSTR lpszItem, int nImage, int nSelImage, \n\t            int iIndent, int iOverlay, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = nMask;\n\t\tcbex.iItem = nIndex;\n\t\tcbex.pszText = (LPTSTR) lpszItem;\n\t\tcbex.iImage = nImage;\n\t\tcbex.iSelectedImage = nSelImage;\n\t\tcbex.iIndent = iIndent;\n\t\tcbex.iOverlay = iOverlay;\n\t\tcbex.lParam = lParam;\n\t\treturn (int)::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM)&cbex);\n\t}\n\n\tBOOL GetItemText(int nIndex, LPTSTR lpszItem, int nLen) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpszItem != NULL);\n\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = CBEIF_TEXT;\n\t\tcbex.iItem = nIndex;\n\t\tcbex.pszText = lpszItem;\n\t\tcbex.cchTextMax = nLen;\n\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetItemText(int nIndex, BSTR& bstrText) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(bstrText == NULL);\n\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = CBEIF_TEXT;\n\t\tcbex.iItem = nIndex;\n\n\t\tLPTSTR lpstrText = NULL;\n\t\tBOOL bRet = FALSE;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tATLTRY(lpstrText = new TCHAR[nLen]);\n\t\t\tif(lpstrText == NULL)\n\t\t\t\tbreak;\n\t\t\tlpstrText[0] = NULL;\n\t\t\tcbex.pszText = lpstrText;\n\t\t\tcbex.cchTextMax = nLen;\n\t\t\tbRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);\n\t\t\tif(!bRet || (lstrlen(cbex.pszText) < nLen - 1))\n\t\t\t\tbreak;\n\t\t\tdelete [] lpstrText;\n\t\t\tlpstrText = NULL;\n\t\t}\n\n\t\tif(lpstrText != NULL)\n\t\t{\n\t\t\tif(bRet)\n\t\t\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\t\tdelete [] lpstrText;\n\t\t}\n\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL GetItemText(int nIndex, _CSTRING_NS::CString& strText) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tCOMBOBOXEXITEM cbex = { 0 };\n\t\tcbex.mask = CBEIF_TEXT;\n\t\tcbex.iItem = nIndex;\n\n\t\tstrText.Empty();\n\t\tBOOL bRet = FALSE;\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tcbex.pszText = strText.GetBufferSetLength(nLen);\n\t\t\tif(cbex.pszText == NULL)\n\t\t\t{\n\t\t\t\tbRet = FALSE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcbex.cchTextMax = nLen;\n\t\t\tbRet = (BOOL)::SendMessage(m_hWnd, CBEM_GETITEM, 0, (LPARAM)&cbex);\n\t\t\tif(!bRet || (lstrlen(cbex.pszText) < nLen - 1))\n\t\t\t\tbreak;\n\t\t}\n\t\tstrText.ReleaseBuffer();\n\t\treturn bRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL SetItemText(int nIndex, LPCTSTR lpszItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn SetItem(nIndex, CBEIF_TEXT, lpszItem, 0, 0, 0, 0, 0);\n\t}\n\n\tCComboBox GetComboCtrl() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CComboBox((HWND)::SendMessage(m_hWnd, CBEM_GETCOMBOCONTROL, 0, 0L));\n\t}\n\n\tCEdit GetEditCtrl() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CEdit((HWND)::SendMessage(m_hWnd, CBEM_GETEDITCONTROL, 0, 0L));\n\t}\n\n\tBOOL HasEditChanged() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, CBEM_HASEDITCHANGED, 0, 0L);\n\t}\n\n// Non-functional\n\tint AddString(LPCTSTR /*lpszItem*/)\n\t{\n\t\tATLASSERT(FALSE);  // Not available in CComboBoxEx; use InsertItem\n\t\treturn 0;\n\t}\n\n\tint InsertString(int /*nIndex*/, LPCTSTR /*lpszString*/)\n\t{\n\t\tATLASSERT(FALSE);  // Not available in CComboBoxEx; use InsertItem\n\t\treturn 0;\n\t}\n\n\tint Dir(UINT /*attr*/, LPCTSTR /*lpszWildCard*/)\n\t{\n\t\tATLASSERT(FALSE);  // Not available in CComboBoxEx\n\t\treturn 0;\n\t}\n\n\tint FindString(int /*nStartAfter*/, LPCTSTR /*lpszString*/) const\n\t{\n\t\tATLASSERT(FALSE);  // Not available in CComboBoxEx; try FindStringExact\n\t\treturn 0;\n\t}\n};\n\ntypedef CComboBoxExT<ATL::CWindow>   CComboBoxEx;\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMonthCalendarCtrl\n\ntemplate <class TBase>\nclass CMonthCalendarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCMonthCalendarCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCMonthCalendarCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn MONTHCAL_CLASS;\n\t}\n\n\tCOLORREF GetColor(int nColorType) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, MCM_GETCOLOR, nColorType, 0L);\n\t}\n\n\tCOLORREF SetColor(int nColorType, COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, MCM_SETCOLOR, nColorType, clr);\n\t}\n\n\tBOOL GetCurSel(LPSYSTEMTIME lpSysTime) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETCURSEL, 0, (LPARAM)lpSysTime);\n\t}\n\n\tBOOL SetCurSel(LPSYSTEMTIME lpSysTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETCURSEL, 0, (LPARAM)lpSysTime);\n\t}\n\n\tint GetFirstDayOfWeek(BOOL* pbLocaleVal = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_GETFIRSTDAYOFWEEK, 0, 0L);\n\t\tif(pbLocaleVal != NULL)\n\t\t\t*pbLocaleVal = (BOOL)HIWORD(dwRet);\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n\tint SetFirstDayOfWeek(int nDay, BOOL* pbLocaleVal = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tDWORD dwRet = (DWORD)::SendMessage(m_hWnd, MCM_SETFIRSTDAYOFWEEK, 0, nDay);\n\t\tif(pbLocaleVal != NULL)\n\t\t\t*pbLocaleVal = (BOOL)HIWORD(dwRet);\n\t\treturn (int)(short)LOWORD(dwRet);\n\t}\n\n\tint GetMaxSelCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_GETMAXSELCOUNT, 0, 0L);\n\t}\n\n\tBOOL SetMaxSelCount(int nMax)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETMAXSELCOUNT, nMax, 0L);\n\t}\n\n\tint GetMonthDelta() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_GETMONTHDELTA, 0, 0L);\n\t}\n\n\tint SetMonthDelta(int nDelta)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_SETMONTHDELTA, nDelta, 0L);\n\t}\n\n\tDWORD GetRange(LPSYSTEMTIME lprgSysTimeArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, MCM_GETRANGE, 0, (LPARAM)lprgSysTimeArray);\n\t}\n\n\tBOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETRANGE, dwFlags, (LPARAM)lprgSysTimeArray);\n\t}\n\n\tBOOL GetSelRange(LPSYSTEMTIME lprgSysTimeArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETSELRANGE, 0, (LPARAM)lprgSysTimeArray);\n\t}\n\n\tBOOL SetSelRange(LPSYSTEMTIME lprgSysTimeArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETSELRANGE, 0, (LPARAM)lprgSysTimeArray);\n\t}\n\n\tBOOL GetToday(LPSYSTEMTIME lpSysTime) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETTODAY, 0, (LPARAM)lpSysTime);\n\t}\n\n\tvoid SetToday(LPSYSTEMTIME lpSysTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, MCM_SETTODAY, 0, (LPARAM)lpSysTime);\n\t}\n\n\tBOOL GetMinReqRect(LPRECT lpRectInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETMINREQRECT, 0, (LPARAM)lpRectInfo);\n\t}\n\n\tint GetMaxTodayWidth() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_GETMAXTODAYWIDTH, 0, 0L);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetUnicodeFormat() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETUNICODEFORMAT, 0, 0L);\n\t}\n\n\tBOOL SetUnicodeFormat(BOOL bUnicode = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETUNICODEFORMAT, bUnicode, 0L);\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\tDWORD GetCurrentView() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, MCM_GETCURRENTVIEW, 0, 0L);\n\t}\n\n\tBOOL SetCurrentView(DWORD dwView)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETCURRENTVIEW, 0, dwView);\n\t}\n\n\tDWORD GetCalendarCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, MCM_GETCALENDARCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetCalendarGridInfo(PMCGRIDINFO pGridInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_GETCALENDARGRIDINFO, 0, (LPARAM)pGridInfo);\n\t}\n\n\tCALID GetCALID() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (CALID)::SendMessage(m_hWnd, MCM_GETCALID, 0, 0L);\n\t}\n\n\tvoid SetCALID(CALID calid)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, MCM_SETCALID, (LPARAM)calid, 0L);\n\t}\n\n\tint GetCalendarBorder() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_GETCALENDARBORDER, 0, 0L);\n\t}\n\n\tvoid SetCalendarBorder(int cxyBorder, BOOL bSet = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, MCM_SETCALENDARBORDER, (WPARAM)bSet, (LPARAM)cxyBorder);\n\t}\n#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\n// Operations\n\tint GetMonthRange(DWORD dwFlags, LPSYSTEMTIME lprgSysTimeArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, MCM_GETMONTHRANGE, dwFlags, (LPARAM)lprgSysTimeArray);\n\t}\n\n\tBOOL SetDayState(int nMonths, LPMONTHDAYSTATE lpDayStateArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, MCM_SETDAYSTATE, nMonths, (LPARAM)lpDayStateArray);\n\t}\n\n\tDWORD HitTest(PMCHITTESTINFO pMCHitTest) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, MCM_HITTEST, 0, (LPARAM)pMCHitTest);\n\t}\n\n#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\tvoid SizeRectToMin(LPRECT lpRect)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, MCM_SIZERECTTOMIN, 0, (LPARAM)lpRect);\n\t}\n#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n};\n\ntypedef CMonthCalendarCtrlT<ATL::CWindow>   CMonthCalendarCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDateTimePickerCtrl\n\ntemplate <class TBase>\nclass CDateTimePickerCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCDateTimePickerCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCDateTimePickerCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Operations\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn DATETIMEPICK_CLASS;\n\t}\n\n\tBOOL SetFormat(LPCTSTR lpszFormat)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DTM_SETFORMAT, 0, (LPARAM)lpszFormat);\n\t}\n\n\tCOLORREF GetMonthCalColor(int nColorType) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, DTM_GETMCCOLOR, nColorType, 0L);\n\t}\n\n\tCOLORREF SetMonthCalColor(int nColorType, COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, DTM_SETMCCOLOR, nColorType, clr);\n\t}\n\n\tDWORD GetRange(LPSYSTEMTIME lpSysTimeArray) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, DTM_GETRANGE, 0, (LPARAM)lpSysTimeArray);\n\t}\n\n\tBOOL SetRange(DWORD dwFlags, LPSYSTEMTIME lpSysTimeArray)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DTM_SETRANGE, dwFlags, (LPARAM)lpSysTimeArray);\n\t}\n\n\tDWORD GetSystemTime(LPSYSTEMTIME lpSysTime) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, DTM_GETSYSTEMTIME, 0, (LPARAM)lpSysTime);\n\t}\n\n\tBOOL SetSystemTime(DWORD dwFlags, LPSYSTEMTIME lpSysTime)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DTM_SETSYSTEMTIME, dwFlags, (LPARAM)lpSysTime);\n\t}\n\n\tCMonthCalendarCtrl GetMonthCal() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CMonthCalendarCtrl((HWND)::SendMessage(m_hWnd, DTM_GETMONTHCAL, 0, 0L));\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tCFontHandle GetMonthCalFont() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CFontHandle((HFONT)::SendMessage(m_hWnd, DTM_GETMCFONT, 0, 0L));\n\t}\n\n\tvoid SetMonthCalFont(HFONT hFont, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_SETMCFONT, (WPARAM)hFont, MAKELPARAM(bRedraw, 0));\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\tDWORD GetMonthCalStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, DTM_GETMCSTYLE, 0, 0L);\n\t}\n\n\tDWORD SetMonthCalStyle(DWORD dwStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (DWORD)::SendMessage(m_hWnd, DTM_SETMCSTYLE, 0, (LPARAM)dwStyle);\n\t}\n\n\tvoid GetDateTimePickerInfo(LPDATETIMEPICKERINFO lpPickerInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_GETDATETIMEPICKERINFO, 0, (LPARAM)lpPickerInfo);\n\t}\n\n\tBOOL GetIdealSize(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)lpSize);\n\t}\n\n\tvoid CloseMonthCal()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_CLOSEMONTHCAL, 0, 0L);\n\t}\n#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n};\n\ntypedef CDateTimePickerCtrlT<ATL::CWindow>   CDateTimePickerCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFlatScrollBarImpl - support for flat scroll bars\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\ntemplate <class T>\nclass CFlatScrollBarImpl\n{\npublic:\n// Initialization\n\tBOOL FlatSB_Initialize()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::InitializeFlatSB(pT->m_hWnd);\n\t}\n\n\tHRESULT FlatSB_Uninitialize()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::UninitializeFlatSB(pT->m_hWnd);\n\t}\n\n// Flat scroll bar properties\n\tBOOL FlatSB_GetScrollProp(UINT uIndex, LPINT lpnValue) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_GetScrollProp(pT->m_hWnd, uIndex, lpnValue);\n\t}\n\n\tBOOL FlatSB_SetScrollProp(UINT uIndex, int nValue, BOOL bRedraw = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_SetScrollProp(pT->m_hWnd, uIndex, nValue, bRedraw);\n\t}\n\n// Attributes\n\tint FlatSB_GetScrollPos(int nBar) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_GetScrollPos(pT->m_hWnd, nBar);\n\t}\n\n\tint FlatSB_SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_SetScrollPos(pT->m_hWnd, nBar, nPos, bRedraw);\n\t}\n\n\tBOOL FlatSB_GetScrollRange(int nBar, LPINT lpMinPos, LPINT lpMaxPos) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_GetScrollRange(pT->m_hWnd, nBar, lpMinPos, lpMaxPos);\n\t}\n\n\tBOOL FlatSB_SetScrollRange(int nBar, int nMinPos, int nMaxPos, BOOL bRedraw = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_SetScrollRange(pT->m_hWnd, nBar, nMinPos, nMaxPos, bRedraw);\n\t}\n\n\tBOOL FlatSB_GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_GetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo);\n\t}\n\n\tint FlatSB_SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_SetScrollInfo(pT->m_hWnd, nBar, lpScrollInfo, bRedraw);\n\t}\n\n// Operations\n\tBOOL FlatSB_ShowScrollBar(UINT nBar, BOOL bShow = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_ShowScrollBar(pT->m_hWnd, nBar, bShow);\n\t}\n\n\tBOOL FlatSB_EnableScrollBar(UINT uSBFlags, UINT uArrowFlags = ESB_ENABLE_BOTH)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::FlatSB_EnableScrollBar(pT->m_hWnd, uSBFlags, uArrowFlags);\n\t}\n};\n\ntemplate <class TBase>\nclass CFlatScrollBarT : public TBase, public CFlatScrollBarImpl<CFlatScrollBarT< TBase > >\n{\npublic:\n\tCFlatScrollBarT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCFlatScrollBarT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n};\n\ntypedef CFlatScrollBarT<ATL::CWindow>   CFlatScrollBar;\n\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CIPAddressCtrl\n\n#if (_WIN32_IE >= 0x0400)\n\ntemplate <class TBase>\nclass CIPAddressCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCIPAddressCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCIPAddressCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Atteributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_IPADDRESS;\n\t}\n\n\tBOOL IsBlank() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, IPM_ISBLANK, 0, 0L);\n\t}\n\n\tint GetAddress(LPDWORD lpdwAddress) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, IPM_GETADDRESS, 0, (LPARAM)lpdwAddress);\n\t}\n\n\tvoid SetAddress(DWORD dwAddress)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IPM_SETADDRESS, 0, dwAddress);\n\t}\n\n\tvoid ClearAddress()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IPM_CLEARADDRESS, 0, 0L);\n\t}\n\n\tvoid SetRange(int nField, WORD wRange)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IPM_SETRANGE, nField, wRange);\n\t}\n\n\tvoid SetRange(int nField, BYTE nMin, BYTE nMax)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IPM_SETRANGE, nField, MAKEIPRANGE(nMin, nMax));\n\t}\n\n\tvoid SetFocus(int nField)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IPM_SETFOCUS, nField, 0L);\n\t}\n};\n\ntypedef CIPAddressCtrlT<ATL::CWindow>   CIPAddressCtrl;\n\n#endif // (_WIN32_IE >= 0x0400)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPagerCtrl\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\ntemplate <class TBase>\nclass CPagerCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCPagerCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCPagerCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_PAGESCROLLER;\n\t}\n\n\tint GetButtonSize() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_GETBUTTONSIZE, 0, 0L);\n\t}\n\n\tint SetButtonSize(int nButtonSize)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_SETBUTTONSIZE, 0, nButtonSize);\n\t}\n\n\tDWORD GetButtonState(int nButton) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nButton == PGB_TOPORLEFT || nButton == PGB_BOTTOMORRIGHT);\n\t\treturn (DWORD)::SendMessage(m_hWnd, PGM_GETBUTTONSTATE, 0, nButton);\n\t}\n\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PGM_GETBKCOLOR, 0, 0L);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF clrBk)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (COLORREF)::SendMessage(m_hWnd, PGM_SETBKCOLOR, 0, (LPARAM)clrBk);\n\t}\n\n\tint GetBorder() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_GETBORDER, 0, 0L);\n\t}\n\n\tint SetBorder(int nBorderSize)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_SETBORDER, 0, nBorderSize);\n\t}\n\n\tint GetPos() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_GETPOS, 0, 0L);\n\t}\n\n\tint SetPos(int nPos)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PGM_SETPOS, 0, nPos);\n\t}\n\n// Operations\n\tvoid SetChild(HWND hWndChild)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PGM_SETCHILD, 0, (LPARAM)hWndChild);\n\t}\n\n\tvoid ForwardMouse(BOOL bForward = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PGM_FORWARDMOUSE, bForward, 0L);\n\t}\n\n\tvoid RecalcSize()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PGM_RECALCSIZE, 0, 0L);\n\t}\n\n\tvoid GetDropTarget(IDropTarget** ppDropTarget)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(ppDropTarget != NULL);\n\t\t::SendMessage(m_hWnd, PGM_GETDROPTARGET, 0, (LPARAM)ppDropTarget);\n\t}\n};\n\ntypedef CPagerCtrlT<ATL::CWindow>   CPagerCtrl;\n\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CLinkCtrl - Windows SYSLINK control\n\n#if (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)\n\ntemplate <class TBase>\nclass CLinkCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCLinkCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCLinkCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\treturn TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n#ifdef _UNICODE\n\t\treturn WC_LINK;\n#else // !_UNICODE\n\t\treturn \"SysLink\";\n#endif // !_UNICODE\n\t}\n\n\tint GetIdealHeight(int cxMaxWidth = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LM_GETIDEALHEIGHT, cxMaxWidth, 0L);\n\t}\n\n\tBOOL GetItem(PLITEM pLItem) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LM_GETITEM, 0, (LPARAM)pLItem);\n\t}\n\n\tBOOL SetItem(PLITEM pLItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LM_SETITEM, 0, (LPARAM)pLItem);\n\t}\n\n\t// Vista only\n\tint GetIdealSize(SIZE& size, int cxMaxWidth = 0) const\n\t{\n#ifndef LM_GETIDEALSIZE\n\t\tconst UINT LM_GETIDEALSIZE = LM_GETIDEALHEIGHT;\n#endif\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, LM_GETIDEALSIZE, cxMaxWidth, (LPARAM)&size);\n\t}\n\n// Operations\n\tBOOL HitTest(PLHITTESTINFO pLHitTestInfo) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, LM_HITTEST, 0, (LPARAM)pLHitTestInfo);\n\t}\n};\n\ntypedef CLinkCtrlT<ATL::CWindow>   CLinkCtrl;\n\n#endif // (_WIN32_WINNT >= 0x0501) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCustomDraw - MI class for custom-draw support\n\ntemplate <class T>\nclass CCustomDraw\n{\npublic:\n#if (_ATL_VER < 0x0700)\n\tBOOL m_bHandledCD;\n\n\tBOOL IsMsgHandled() const\n\t{\n\t\treturn m_bHandledCD;\n\t}\n\n\tvoid SetMsgHandled(BOOL bHandled)\n\t{\n\t\tm_bHandledCD = bHandled;\n\t}\n#endif // !(_ATL_VER < 0x0700)\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CCustomDraw< T >)\n\t\tNOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)\n\tALT_MSG_MAP(1)\n\t\tREFLECTED_NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)\n\tEND_MSG_MAP()\n\n// message handler\n\tLRESULT OnCustomDraw(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetMsgHandled(TRUE);\n\t\tLPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)pnmh;\n\t\tDWORD dwRet = 0;\n\t\tswitch(lpNMCustomDraw->dwDrawStage)\n\t\t{\n\t\tcase CDDS_PREPAINT:\n\t\t\tdwRet = pT->OnPrePaint(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_POSTPAINT:\n\t\t\tdwRet = pT->OnPostPaint(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_PREERASE:\n\t\t\tdwRet = pT->OnPreErase(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_POSTERASE:\n\t\t\tdwRet = pT->OnPostErase(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_ITEMPREPAINT:\n\t\t\tdwRet = pT->OnItemPrePaint(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_ITEMPOSTPAINT:\n\t\t\tdwRet = pT->OnItemPostPaint(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_ITEMPREERASE:\n\t\t\tdwRet = pT->OnItemPreErase(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n\t\tcase CDDS_ITEMPOSTERASE:\n\t\t\tdwRet = pT->OnItemPostErase(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n#if (_WIN32_IE >= 0x0400)\n\t\tcase (CDDS_ITEMPREPAINT | CDDS_SUBITEM):\n\t\t\tdwRet = pT->OnSubItemPrePaint(idCtrl, lpNMCustomDraw);\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0400)\n\t\tdefault:\n\t\t\tpT->SetMsgHandled(FALSE);\n\t\t\tbreak;\n\t\t}\n\t\tbHandled = pT->IsMsgHandled();\n\t\treturn dwRet;\n\t}\n\n// Overrideables\n\tDWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnItemPreErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n\tDWORD OnItemPostErase(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tDWORD OnSubItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_DODEFAULT;\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n};\n\n\n// --- Windows CE common controls ---\n\n#ifdef _WIN32_WCE\n\n///////////////////////////////////////////////////////////////////////////////\n// CCECommandBarCtrl\n\ntemplate <class TBase>\nclass CCECommandBarCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCCECommandBarCtrlT(HWND hWnd = NULL) : TBase(hWnd) { }\n\n\tCCECommandBarCtrlT< TBase >& operator=(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tBOOL IsVisible() const\n\t{\n\t\treturn IsWindowVisible();\n\t}\n\n\tint GetHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_Height(m_hWnd);\n\t}\n\n\tHMENU GetMenu(WORD wButton) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_GetMenu(m_hWnd, wButton);\n\t}\n\n// Operations\n\tHWND Create(HWND hWndParent, int nCmdBarID)\n\t{\n\t\tm_hWnd = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), hWndParent, nCmdBarID);\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_hWnd;\n\t}\n\n\tvoid Destroy()\n\t{\n\t\tDestroyWindow();\n\t}\n\n\tBOOL Show(BOOL bShow = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_Show(m_hWnd, bShow);\n\t}\n\n\tBOOL DrawMenuBar(WORD wButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_DrawMenuBar(m_hWnd, wButton);\n\t}\n\n\tBOOL AddAdornments(DWORD dwFlags = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_AddAdornments(m_hWnd, dwFlags, 0);\n\t}\n\n\tint AddBitmap(int nBitmapID, int nNumImages)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_AddBitmap(m_hWnd, ModuleHelper::GetResourceInstance(), nBitmapID, nNumImages, 16, 16);\n\t}\n\n\tBOOL AddButtons(UINT uNumButtons, LPTBBUTTON lpButtons)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CommandBar_AddButtons(m_hWnd, uNumButtons, lpButtons);\n\t}\n\n\tBOOL AddToolTips(UINT uNumToolTips, LPTSTR lpToolTips)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CommandBar_AddToolTips(m_hWnd, uNumToolTips, lpToolTips);\n\t}\n\n\tBOOL InsertButton(int nButton, LPTBBUTTON lpButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CommandBar_InsertButton(m_hWnd, nButton, lpButton);\n\t}\n\n\tHWND InsertComboBox(int nWidth, UINT dwStyle, WORD wComboBoxID, WORD wButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_InsertComboBox(m_hWnd, ModuleHelper::GetModuleInstance(), nWidth, dwStyle, wComboBoxID, wButton);\n\t}\n\n\tBOOL InsertMenubar(WORD wMenuID, WORD wButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_InsertMenubar(m_hWnd, ModuleHelper::GetResourceInstance(), wMenuID, wButton);\n\t}\n\n\tBOOL InsertMenubarEx(ATL::_U_STRINGorID menu, WORD wButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBar_InsertMenubarEx(m_hWnd, ModuleHelper::GetResourceInstance(), (LPTSTR)menu.m_lpstr, wButton);\n\t}\n\n\tBOOL IsCommandBarMessage(LPMSG lpMsg)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::IsCommandBarMessage(m_hWnd, lpMsg);\n\t}\n};\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC MenuBar\n\ttypedef CCECommandBarCtrlT<CToolBarCtrl>\tCMenuBarCtrl;\n#else\n\ttypedef CCECommandBarCtrlT<CToolBarCtrl>\tCCECommandBarCtrl;\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)\n\n///////////////////////////////////////////////////////////////////////////////\n// CCECommandBandsCtrl\n\ntemplate <class TBase>\nclass CCECommandBandsCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCCECommandBandsCtrlT(HWND hWnd = NULL) : TBase(hWnd) { }\n\n\tCCECommandBandsCtrlT< TBase >& operator=(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tBOOL IsVisible() const\n\t{\n\t\treturn IsWindowVisible();\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tUINT GetHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CommandBands_Height(m_hWnd);\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n\tHWND GetCommandBar(UINT uBand) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBands_GetCommandBar(m_hWnd, uBand);\n\t}\n\n\tBOOL GetRestoreInformation(UINT uBand, LPCOMMANDBANDSRESTOREINFO pcbr) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBands_GetRestoreInformation(m_hWnd, uBand, pcbr);\n\t}\n\n// Operations\n\tHWND Create(HWND hWndParent, UINT wID, DWORD dwStyles, HIMAGELIST hImageList = NULL)\n\t{\n\t\tm_hWnd = ::CommandBands_Create(ModuleHelper::GetModuleInstance(), hWndParent, wID, dwStyles, hImageList);\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_hWnd;\n\t}\n\n\tBOOL AddAdornments(DWORD dwFlags = 0, LPREBARBANDINFO prbbi = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBands_AddAdornments(m_hWnd, ModuleHelper::GetModuleInstance(), dwFlags, prbbi);\n\t}\n\n\tBOOL AddBands(UINT uBandCount, LPREBARBANDINFO prbbi)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBands_AddBands(m_hWnd, ModuleHelper::GetModuleInstance(), uBandCount, prbbi);\n\t}\n\n\tBOOL Show(BOOL bShow = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::CommandBands_Show(m_hWnd, bShow);\n\t}\n};\n\ntypedef CCECommandBandsCtrlT<ATL::CWindow>\tCCECommandBandsCtrl;\n\n#endif // _WIN32_WCE\n\n}; // namespace WTL\n\n#endif // __ATLCTRLS_H__\n"
  },
  {
    "path": "WTL/atlctrlw.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLCTRLW_H__\n#define __ATLCTRLW_H__\n\n#pragma once\n\n#ifdef _WIN32_WCE\n\t#error atlctrlw.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLAPP_H__\n\t#error atlctrlw.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLCTRLS_H__\n\t#error atlctrlw.h requires atlctrls.h to be included first\n#endif\n\n#if (_WIN32_IE < 0x0400)\n\t#error atlctrlw.h requires _WIN32_IE >= 0x0400\n#endif\n\n// Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support\n#if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\n  #define _WTL_CMDBAR_VISTA_MENUS 1\n#endif\n\n#if _WTL_CMDBAR_VISTA_MENUS\n  #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501))\n\t#error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\n  #endif\n#endif\n\n// Note: Define _WTL_CMDBAR_VISTA_STD_MENUBAR to use Vista standard menubar look with Vista menus\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CCommandBarCtrlImpl<T, TBase, TWinTraits>\n// CCommandBarCtrl\n// CMDICommandBarCtrlImpl<T, TBase, TWinTraits>\n// CMDICommandBarCtrl\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// Command Bars\n\n// Window Styles:\n#define CBRWS_TOP\t\tCCS_TOP\n#define CBRWS_BOTTOM\t\tCCS_BOTTOM\n#define CBRWS_NORESIZE\t\tCCS_NORESIZE\n#define CBRWS_NOPARENTALIGN\tCCS_NOPARENTALIGN\n#define CBRWS_NODIVIDER\t\tCCS_NODIVIDER\n\n// Extended styles\n#define CBR_EX_TRANSPARENT\t0x00000001L\n#define CBR_EX_SHAREMENU\t0x00000002L\n#define CBR_EX_ALTFOCUSMODE\t0x00000004L\n#define CBR_EX_TRACKALWAYS\t0x00000008L\n#define CBR_EX_NOVISTAMENUS\t0x00000010L\n\n// standard command bar styles\n#define ATL_SIMPLE_CMDBAR_PANE_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)\n\n// Messages - support chevrons for frame windows\n#define CBRM_GETCMDBAR\t\t\t(WM_USER + 301) // returns command bar HWND\n#define CBRM_GETMENU\t\t\t(WM_USER + 302) // returns loaded or attached menu\n#define CBRM_TRACKPOPUPMENU\t\t(WM_USER + 303) // displays a popup menu\n\ntypedef struct tagCBRPOPUPMENU\n{\n\tint cbSize;\n\tHMENU hMenu;         // popup menu do display\n\tUINT uFlags;         // TPM_* flags for ::TrackPopupMenuEx\n\tint x;\n\tint y;\n\tLPTPMPARAMS lptpm;   // ptr to TPMPARAMS for ::TrackPopupMenuEx\n} CBRPOPUPMENU, *LPCBRPOPUPMENU;\n\n// helper class\ntemplate <class T>\nclass CSimpleStack : public ATL::CSimpleArray< T >\n{\npublic:\n\tBOOL Push(T t)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - STACK-PUSH (%8.8X) size = %i\\n\"), t, GetSize());\n#endif\n\t\treturn Add(t);\n\t}\n\n\tT Pop()\n\t{\n\t\tint nLast = GetSize() - 1;\n\t\tif(nLast < 0)\n\t\t\treturn NULL;   // must be able to convert to NULL\n\t\tT t = m_aT[nLast];\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - STACK-POP (%8.8X) size = %i\\n\"), t, GetSize());\n#endif\n\t\tif(!RemoveAt(nLast))\n\t\t\treturn NULL;\n\t\treturn t;\n\t}\n\n\tT GetCurrent()\n\t{\n\t\tint nLast = GetSize() - 1;\n\t\tif(nLast < 0)\n\t\t\treturn NULL;   // must be able to convert to NULL\n\t\treturn m_aT[nLast];\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCommandBarCtrlBase - base class for the Command Bar implementation\n\nclass CCommandBarCtrlBase : public CToolBarCtrl\n{\npublic:\n\tstruct _MsgHookData\n\t{\n\t\tHHOOK hMsgHook;\n\t\tDWORD dwUsage;\n\n\t\t_MsgHookData() : hMsgHook(NULL), dwUsage(0)\n\t\t{ }\n\t};\n\n\ttypedef ATL::CSimpleMap<DWORD, _MsgHookData*>   CMsgHookMap;\n\tstatic CMsgHookMap* s_pmapMsgHook;\n\n\tstatic HHOOK s_hCreateHook;\n\tstatic bool s_bW2K;  // For animation flag\n\tstatic CCommandBarCtrlBase* s_pCurrentBar;\n\tstatic bool s_bStaticInit;\n\n\tCSimpleStack<HWND> m_stackMenuWnd;\n\tCSimpleStack<HMENU> m_stackMenuHandle;\n\n\tHWND m_hWndHook;\n\tDWORD m_dwMagic;\n\n\n\tCCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314)\n\t{\n\t\t// init static variables\n\t\tif(!s_bStaticInit)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif(!s_bStaticInit)\n\t\t\t{\n\t\t\t\t// Just in case...\n\t\t\t\tAtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);\n\t\t\t\t// Animation on Win2000 only\n\t\t\t\ts_bW2K = !AtlIsOldWindows();\n\t\t\t\t// done\n\t\t\t\ts_bStaticInit = true;\n\t\t\t}\n\n\t\t\tlock.Unlock();\n\t\t}\n\t}\n\n\tbool IsCommandBarBase() const { return m_dwMagic == 1314; }\n};\n\n__declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL;\n__declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL;\n__declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL;\n__declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false;\n__declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCommandBarCtrl - ATL implementation of Command Bars\n\ntemplate <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\n\n// Declarations\n\tstruct _MenuItemData\t// menu item data\n\t{\n\t\tDWORD dwMagic;\n\t\tLPTSTR lpstrText;\n\t\tUINT fType;\n\t\tUINT fState;\n\t\tint iButton;\n\n\t\t_MenuItemData() { dwMagic = 0x1313; }\n\t\tbool IsCmdBarMenuItem() { return (dwMagic == 0x1313); }\n\t};\n\n\tstruct _ToolBarData\t// toolbar resource data\n\t{\n\t\tWORD wVersion;\n\t\tWORD wWidth;\n\t\tWORD wHeight;\n\t\tWORD wItemCount;\n\t\t//WORD aItems[wItemCount]\n\n\t\tWORD* items()\n\t\t\t{ return (WORD*)(this+1); }\n\t};\n\n// Constants\n\tenum _CmdBarDrawConstants\n\t{\n\t\ts_kcxGap = 1,\n\t\ts_kcxTextMargin = 2,\n\t\ts_kcxButtonMargin = 3,\n\t\ts_kcyButtonMargin = 3\n\t};\n\n\tenum\n\t{\n\t\t_nMaxMenuItemTextLength = 100,\n\t\t_chChevronShortcut = _T('/')\n\t};\n\n#ifndef DT_HIDEPREFIX\n\tenum { DT_HIDEPREFIX = 0x00100000 };\n#endif // !DT_HIDEPREFIX\n\n// Data members\n\tHMENU m_hMenu;\n\tHIMAGELIST m_hImageList;\n\tATL::CSimpleValArray<WORD> m_arrCommand;\n\n\tDWORD m_dwExtendedStyle;   // Command Bar specific extended styles\n\n\tATL::CContainedWindow m_wndParent;\n\n\tbool m_bMenuActive:1;\n\tbool m_bAttachedMenu:1;\n\tbool m_bImagesVisible:1;\n\tbool m_bPopupItem:1;\n\tbool m_bContextMenu:1;\n\tbool m_bEscapePressed:1;\n\tbool m_bSkipMsg:1;\n\tbool m_bParentActive:1;\n\tbool m_bFlatMenus:1;\n\tbool m_bUseKeyboardCues:1;\n\tbool m_bShowKeyboardCues:1;\n\tbool m_bAllowKeyboardCues:1;\n\tbool m_bKeyboardInput:1;\n\tbool m_bAlphaImages:1;\n\tbool m_bLayoutRTL:1;\n\tbool m_bSkipPostDown:1;\n\tbool m_bVistaMenus:1;\n\n\tint m_nPopBtn;\n\tint m_nNextPopBtn;\n\n\tSIZE m_szBitmap;\n\tSIZE m_szButton;\n\n\tCOLORREF m_clrMask;\n\tCFont m_fontMenu;   // used internally, only to measure text\n\n\tUINT m_uSysKey;\n\n\tHWND m_hWndFocus;   // Alternate focus mode\n\n\tint m_cxExtraSpacing;\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\tATL::CSimpleValArray<HBITMAP> m_arrVistaBitmap;   // Bitmaps for Vista menus\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n// Constructor/destructor\n\tCCommandBarCtrlImpl() : \n\t\t\tm_hMenu(NULL), \n\t\t\tm_hImageList(NULL), \n\t\t\tm_wndParent(this, 1), \n\t\t\tm_bMenuActive(false), \n\t\t\tm_bAttachedMenu(false), \n\t\t\tm_nPopBtn(-1), \n\t\t\tm_nNextPopBtn(-1), \n\t\t\tm_bPopupItem(false),\n\t\t\tm_bImagesVisible(true),\n\t\t\tm_bSkipMsg(false),\n\t\t\tm_uSysKey(0),\n\t\t\tm_hWndFocus(NULL),\n\t\t\tm_bContextMenu(false),\n\t\t\tm_bEscapePressed(false),\n\t\t\tm_clrMask(RGB(192, 192, 192)),\n\t\t\tm_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS),\n\t\t\tm_bParentActive(true),\n\t\t\tm_bFlatMenus(false),\n\t\t\tm_bUseKeyboardCues(false),\n\t\t\tm_bShowKeyboardCues(false),\n\t\t\tm_bAllowKeyboardCues(true),\n\t\t\tm_bKeyboardInput(false),\n\t\t\tm_cxExtraSpacing(0),\n\t\t\tm_bAlphaImages(false),\n\t\t\tm_bLayoutRTL(false),\n\t\t\tm_bSkipPostDown(false),\n\t\t\tm_bVistaMenus(false)\n\t{\n\t\tSetImageSize(16, 15);   // default\n \t}\n\n\t~CCommandBarCtrlImpl()\n\t{\n\t\tif(m_wndParent.IsWindow())\n/*scary!*/\t\t\tm_wndParent.UnsubclassWindow();\n\n\t\tif(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)\n\t\t\t::DestroyMenu(m_hMenu);\n\n\t\tif(m_hImageList != NULL)\n\t\t\t::ImageList_Destroy(m_hImageList);\n\t}\n\n// Attributes\n\tDWORD GetCommandBarExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\t\treturn dwPrevStyle;\n\t}\n\n\tCMenuHandle GetMenu() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_hMenu;\n\t}\n\n\tCOLORREF GetImageMaskColor() const\n\t{\n\t\treturn m_clrMask;\n\t}\n\n\tCOLORREF SetImageMaskColor(COLORREF clrMask)\n\t{\n\t\tCOLORREF clrOld = m_clrMask;\n\t\tm_clrMask = clrMask;\n\t\treturn clrOld;\n\t}\n\n\tbool GetImagesVisible() const\n\t{\n\t\treturn m_bImagesVisible;\n\t}\n\n\tbool SetImagesVisible(bool bVisible)\n\t{\n\t\tbool bOld = m_bImagesVisible;\n\t\tm_bImagesVisible = bVisible;\n\t\treturn bOld;\n\t}\n\n\tvoid GetImageSize(SIZE& size) const\n\t{\n\t\tsize = m_szBitmap;\n\t}\n\n\tbool SetImageSize(SIZE& size)\n\t{\n\t\treturn SetImageSize(size.cx, size.cy);\n\t}\n\n\tbool SetImageSize(int cx, int cy)\n\t{\n\t\tif(m_hImageList != NULL)\n\t\t{\n\t\t\tif(::ImageList_GetImageCount(m_hImageList) == 0)   // empty\n\t\t\t{\n\t\t\t\t::ImageList_Destroy(m_hImageList);\n\t\t\t\tm_hImageList = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;   // can't set, image list exists\n\t\t\t}\n\t\t}\n\n\t\tif(cx == 0 || cy == 0)\n\t\t\treturn false;\n\n\t\tm_szBitmap.cx = cx;\n\t\tm_szBitmap.cy = cy;\n\t\tm_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin;\n\t\tm_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin;\n\n\t\treturn true;\n\t}\n\n\tbool GetAlphaImages() const\n\t{\n\t\treturn m_bAlphaImages;\n\t}\n\n\tbool SetAlphaImages(bool bAlphaImages)\n\t{\n\t\tif(m_hImageList != NULL)\n\t\t{\n\t\t\tif(::ImageList_GetImageCount(m_hImageList) == 0)   // empty\n\t\t\t{\n\t\t\t\t::ImageList_Destroy(m_hImageList);\n\t\t\t\tm_hImageList = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;   // can't set, image list exists\n\t\t\t}\n\t\t}\n\n\t\tm_bAlphaImages = bAlphaImages;\n\t\treturn true;\n\t}\n\n\tHWND GetCmdBar() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);\n\t}\n\n// Methods\n\tHWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tUINT nID = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\t// These styles are required for command bars\n\t\tdwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT;\n#if (_MSC_VER >= 1300)\n\t\treturn ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\treturn _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);\n#endif // !(_MSC_VER >= 1300)\n\t}\n\n\tBOOL AttachToWindow(HWND hWnd)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tBOOL bRet = SubclassWindow(hWnd);\n\t\tif(bRet)\n\t\t{\n\t\t\tm_bAttachedMenu = true;\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings();\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL LoadMenu(ATL::_U_STRINGorID menu)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tif(m_bAttachedMenu)   // doesn't work in this mode\n\t\t\treturn FALSE;\n\t\tif(menu.m_lpstr == NULL)\n\t\t\treturn FALSE;\n\n\t\tHMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);\n\t\tif(hMenu == NULL)\n\t\t\treturn FALSE;\n\n\t\treturn AttachMenu(hMenu);\n\t}\n\n\tBOOL AttachMenu(HMENU hMenu)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hMenu == NULL || ::IsMenu(hMenu));\n\t\tif(hMenu != NULL && !::IsMenu(hMenu))\n\t\t\treturn FALSE;\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t// remove Vista bitmaps if used\n\t\tif(m_bVistaMenus && (m_hMenu != NULL))\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_RemoveVistaBitmapsFromMenu();\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n\t\t// destroy old menu, if needed, and set new one\n\t\tif(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)\n\t\t\t::DestroyMenu(m_hMenu);\n\n\t\tm_hMenu = hMenu;\n\n\t\tif(m_bAttachedMenu)   // Nothing else in this mode\n\t\t\treturn TRUE;\n\n\t\t// Build buttons according to menu\n\t\tSetRedraw(FALSE);\n\n\t\t// Clear all buttons\n\t\tint nCount = GetButtonCount();\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t\tATLVERIFY(DeleteButton(0) != FALSE);\n\n\t\t// Add buttons for each menu item\n\t\tif(m_hMenu != NULL)\n\t\t{\n\t\t\tint nItems = ::GetMenuItemCount(m_hMenu);\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT;   // avoid level 4 warning\n\t\t\tTCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };\n\t\t\tfor(int i = 0; i < nItems; i++)\n\t\t\t{\n\t\t\t\tCMenuItemInfo mii;\n\t\t\t\tmii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU;\n\t\t\t\tmii.fType = MFT_STRING;\n\t\t\t\tmii.dwTypeData = szString;\n\t\t\t\tmii.cch = pT->_nMaxMenuItemTextLength;\n\t\t\t\tBOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t\t// If we have more than the buffer, we assume we have bitmaps bits\n\t\t\t\tif(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1)\n\t\t\t\t{\n\t\t\t\t\tmii.fType = MFT_BITMAP;\n\t\t\t\t\t::SetMenuItemInfo(m_hMenu, i, TRUE, &mii);\n\t\t\t\t\tszString[0] = 0;\n\t\t\t\t}\n\n\t\t\t\t// NOTE: Command Bar currently supports only drop-down menu items\n\t\t\t\tATLASSERT(mii.hSubMenu != NULL);\n\n\t\t\t\tTBBUTTON btn = { 0 };\n\t\t\t\tbtn.iBitmap = 0;\n\t\t\t\tbtn.idCommand = i;\n\t\t\t\tbtn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0);\n\t\t\t\tbtn.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_DROPDOWN;\n\t\t\t\tbtn.dwData = 0;\n\t\t\t\tbtn.iString = 0;\n\n\t\t\t\tbRet = InsertButton(-1, &btn);\n\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\tTBBUTTONINFO bi = { 0 };\n\t\t\t\tbi.cbSize = sizeof(TBBUTTONINFO);\n\t\t\t\tbi.dwMask = TBIF_TEXT;\n\t\t\t\tbi.pszText = szString;\n\n\t\t\t\tbRet = SetButtonInfo(i, &bi);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t}\n\t\t}\n\n\t\tSetRedraw(TRUE);\n\t\tInvalidate();\n\t\tUpdateWindow();\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL LoadImages(ATL::_U_STRINGorID image)\n\t{\n\t\treturn _LoadImagesHelper(image, false);\n\t}\n\n\tBOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)\n\t{\n\t\treturn _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize);\n\t}\n\n\tBOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHINSTANCE hInstance = ModuleHelper::GetResourceInstance();\n\n\t\tHRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR);\n\t\tif(hRsrc == NULL)\n\t\t\treturn FALSE;\n\n\t\tHGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc);\n\t\tif(hGlobal == NULL)\n\t\t\treturn FALSE;\n\n\t\t_ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal);\n\t\tif(pData == NULL)\n\t\t\treturn FALSE;\n\t\tATLASSERT(pData->wVersion == 1);\n\n\t\tWORD* pItems = pData->items();\n\t\tint nItems = pData->wItemCount;\n\n\t\t// Set internal data\n\t\tSetImageSize(pData->wWidth, pData->wHeight);\n\n\t\t// Create image list if needed\n\t\tif(m_hImageList == NULL)\n\t\t{\n\t\t\t// Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only)\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tm_bAlphaImages = AtlIsAlphaBitmapResource(image);\n\n\t\t\tif(!pT->CreateInternalImageList(pData->wItemCount))\n\t\t\t\treturn FALSE;\n\t\t}\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\tint nOldImageCount = ::ImageList_GetImageCount(m_hImageList);\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n\t\t// Add bitmap to our image list\n\t\tCBitmap bmp;\n\t\tif(bMapped)\n\t\t{\n\t\t\tATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0);   // if mapped, must be a numeric ID\n\t\t\tint nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr));\n\t\t\tbmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(m_bAlphaImages)\n\t\t\t\tbmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);\n\t\t\telse\n\t\t\t\tbmp.LoadBitmap(image.m_lpstr);\n\t\t}\n\t\tATLASSERT(bmp.m_hBitmap != NULL);\n\t\tif(bmp.m_hBitmap == NULL)\n\t\t\treturn FALSE;\n\t\tif(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1)\n\t\t\treturn FALSE;\n\n\t\t// Fill the array with command IDs\n\t\tfor(int i = 0; i < nItems; i++)\n\t\t{\n\t\t\tif(pItems[i] != 0)\n\t\t\t\tm_arrCommand.Add(pItems[i]);\n\t\t}\n\n\t\tint nImageCount = ::ImageList_GetImageCount(m_hImageList);\n\t\tATLASSERT(nImageCount == m_arrCommand.GetSize());\n\t\tif(nImageCount != m_arrCommand.GetSize())\n\t\t\treturn FALSE;\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\tif(RunTimeHelper::IsVista())\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount);\n\t\t\tATLASSERT(nImageCount == m_arrVistaBitmap.GetSize());\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCBitmap bmp;\n\t\tbmp.LoadBitmap(bitmap.m_lpstr);\n\t\tif(bmp.m_hBitmap == NULL)\n\t\t\treturn FALSE;\n\t\treturn AddBitmap(bmp, nCommandID);\n\t}\n\n\tBOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\t// Create image list if it doesn't exist\n\t\tif(m_hImageList == NULL)\n\t\t{\n\t\t\tif(!pT->CreateInternalImageList(1))\n\t\t\t\treturn FALSE;\n\t\t}\n\t\t// check bitmap size\n\t\tCBitmapHandle bmp = hBitmap;\n\t\tSIZE size = { 0, 0 };\n\t\tbmp.GetSize(size);\n\t\tif(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy)\n\t\t{\n\t\t\tATLASSERT(FALSE);   // must match size!\n\t\t\treturn FALSE;\n\t\t}\n\t\t// add bitmap\n\t\tint nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask);\n\t\tif(nRet == -1)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = m_arrCommand.Add((WORD)nCommandID);\n\t\tATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\tif(RunTimeHelper::IsVista())\n\t\t{\n\t\t\tpT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);\n\t\t\tATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\treturn bRet;\n\t}\n\n\tBOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\n\t\tif(hIcon == NULL)\n\t\t\treturn FALSE;\n\t\treturn AddIcon(hIcon, nCommandID);\n\t}\n\n\tBOOL AddIcon(HICON hIcon, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\t// create image list if it doesn't exist\n\t\tif(m_hImageList == NULL)\n\t\t{\n\t\t\tif(!pT->CreateInternalImageList(1))\n\t\t\t\treturn FALSE;\n\t\t}\n\n\t\tint nRet = ::ImageList_AddIcon(m_hImageList, hIcon);\n\t\tif(nRet == -1)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = m_arrCommand.Add((WORD)nCommandID);\n\t\tATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\tif(RunTimeHelper::IsVista())\n\t\t{\n\t\t\tpT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);\n\t\t\tATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\treturn bRet;\n\t}\n\n\tBOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tCBitmap bmp;\n\t\tbmp.LoadBitmap(bitmap.m_lpstr);\n\t\tif(bmp.m_hBitmap == NULL)\n\t\t\treturn FALSE;\n\t\treturn ReplaceBitmap(bmp, nCommandID);\n\t}\n\n\tBOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tBOOL bRet = FALSE;\n\t\tfor(int i = 0; i < m_arrCommand.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrCommand[i] == nCommandID)\n\t\t\t{\n\t\t\t\tbRet = ::ImageList_Remove(m_hImageList, i);\n\t\t\t\tif(bRet)\n\t\t\t\t{\n\t\t\t\t\tm_arrCommand.RemoveAt(i);\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\t\tif(RunTimeHelper::IsVista())\n\t\t\t\t\t{\n\t\t\t\t\t\tif(m_arrVistaBitmap[i] != NULL)\n\t\t\t\t\t\t\t::DeleteObject(m_arrVistaBitmap[i]);\n\t\t\t\t\t\tm_arrVistaBitmap.RemoveAt(i);\n\t\t\t\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(bRet)\n\t\t\tbRet = AddBitmap(hBitmap, nCommandID);\n\t\treturn bRet;\n\t}\n\n\tBOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\n\t\tif(hIcon == NULL)\n\t\t\treturn FALSE;\n\t\treturn ReplaceIcon(hIcon, nCommandID);\n\t}\n\n\tBOOL ReplaceIcon(HICON hIcon, UINT nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tBOOL bRet = FALSE;\n\t\tfor(int i = 0; i < m_arrCommand.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrCommand[i] == nCommandID)\n\t\t\t{\n\t\t\t\tbRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1);\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\tif(RunTimeHelper::IsVista() && bRet != FALSE)\n\t\t\t\t{\n\t\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\t\tpT->_ReplaceVistaBitmapFromImageList(i);\n\t\t\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL RemoveImage(int nCommandID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tBOOL bRet = FALSE;\n\t\tfor(int i = 0; i < m_arrCommand.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrCommand[i] == nCommandID)\n\t\t\t{\n\t\t\t\tbRet = ::ImageList_Remove(m_hImageList, i);\n\t\t\t\tif(bRet)\n\t\t\t\t{\n\t\t\t\t\tm_arrCommand.RemoveAt(i);\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\t\tif(RunTimeHelper::IsVista())\n\t\t\t\t\t{\n\t\t\t\t\t\tif(m_arrVistaBitmap[i] != NULL)\n\t\t\t\t\t\t\t::DeleteObject(m_arrVistaBitmap[i]);\n\t\t\t\t\t\tm_arrVistaBitmap.RemoveAt(i);\n\t\t\t\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL RemoveAllImages()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Removing all images\\n\"));\n\t\tBOOL bRet = ::ImageList_RemoveAll(m_hImageList);\n\t\tif(bRet)\n\t\t{\n\t\t\tm_arrCommand.RemoveAll();\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t\tfor(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)\n\t\t\t{\n\t\t\t\tif(m_arrVistaBitmap[i] != NULL)\n\t\t\t\t\t::DeleteObject(m_arrVistaBitmap[i]);\n\t\t\t}\n\t\t\tm_arrVistaBitmap.RemoveAll();\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(::IsMenu(hMenu));\n\t\tif(!::IsMenu(hMenu))\n\t\t\treturn FALSE;\n\t\tm_bContextMenu = true;\n\t\tif(m_bUseKeyboardCues)\n\t\t\tm_bShowKeyboardCues = m_bKeyboardInput;\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams);\n\t}\n\n\tBOOL SetMDIClient(HWND /*hWndMDIClient*/)\n\t{\n\t\t// Use CMDICommandBarCtrl for MDI support\n\t\tATLASSERT(FALSE);\n\t\treturn FALSE;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CCommandBarCtrlImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_INITMENU, OnInitMenu)\n\t\tMESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)\n\t\tMESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)\n\t\tMESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup)\n\t\tMESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)\n\t\tMESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)\n\n\t\tMESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n\t\tMESSAGE_HANDLER(WM_KEYUP, OnKeyUp)\n\t\tMESSAGE_HANDLER(WM_CHAR, OnChar)\n\t\tMESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)\n\t\tMESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)\n\t\tMESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)\n// public API handlers - these stay to support chevrons in atlframe.h\n\t\tMESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu)\n\t\tMESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu)\n\t\tMESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar)\n\n\t\tMESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)\n\t\tMESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)\n\n\t\tMESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)\n\tALT_MSG_MAP(1)   // Parent window messages\n\t\tNOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange)\n\t\tNOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown)\n\t\tMESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup)\n\t\tMESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar)\n\t\tMESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand)\n\t\tMESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu)\n\t\tMESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar)\n\t\tMESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu)\n\t\tMESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange)\n\n\t\tMESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem)\n\t\tMESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem)\n\n\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)\n\t\tNOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw)\n\tALT_MSG_MAP(2)   // MDI client window messages\n\t\t// Use CMDICommandBarCtrl for MDI support\n\tALT_MSG_MAP(3)   // Message hook messages\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove)\n\t\tMESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown)\n\t\tMESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp)\n\t\tMESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar)\n\t\tMESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown)\n\t\tMESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu)\n\t\tMESSAGE_HANDLER(WM_CHAR, OnHookChar)\n\tEND_MSG_MAP()\n\n\tLRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLPMSG pMsg = (LPMSG)lParam;\n\t\tif(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)\n\t\t\tm_bKeyboardInput = false;\n\t\telse if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)\n\t\t\tm_bKeyboardInput = true;\n\t\tLRESULT lRet = 0;\n\t\tProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3);\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\t// Let the toolbar initialize itself\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\t// get and use system settings\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->GetSystemSettings();\n\t\t// Parent init\n\t\tATL::CWindow wndParent = GetParent();\n\t\tATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent();\n\t\tm_wndParent.SubclassWindow(wndTopLevelParent);\n\t\t// Toolbar Init\n\t\tSetButtonStructSize();\n\t\tSetImageList(NULL);\n\n\t\t// Create message hook if needed\n\t\tCWindowCreateCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn -1;\n\t\t}\n\n\t\tif(s_pmapMsgHook == NULL)\n\t\t{\n\t\t\tATLTRY(s_pmapMsgHook = new CMsgHookMap);\n\t\t\tATLASSERT(s_pmapMsgHook != NULL);\n\t\t}\n\n\t\tif(s_pmapMsgHook != NULL)\n\t\t{\n\t\t\tDWORD dwThreadID = ::GetCurrentThreadId();\n\t\t\t_MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\n\t\t\tif(pData == NULL)\n\t\t\t{\n\t\t\t\tATLTRY(pData = new _MsgHookData);\n\t\t\t\tATLASSERT(pData != NULL);\n\t\t\t\tHHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID);\n\t\t\t\tATLASSERT(hMsgHook != NULL);\n\t\t\t\tif(pData != NULL && hMsgHook != NULL)\n\t\t\t\t{\n\t\t\t\t\tpData->hMsgHook = hMsgHook;\n\t\t\t\t\tpData->dwUsage = 1;\n\t\t\t\t\tBOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData);\n\t\t\t\t\tbRet;\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t(pData->dwUsage)++;\n\t\t\t}\n\t\t}\n\t\tlock.Unlock();\n\n\t\t// Get layout\n#if (WINVER >= 0x0500)\n\t\tm_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0);\n#endif // (WINVER >= 0x0500)\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\tif(m_bVistaMenus && (m_hMenu != NULL))\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_RemoveVistaBitmapsFromMenu();\n\t\t}\n\n\t\tfor(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrVistaBitmap[i] != NULL)\n\t\t\t\t::DeleteObject(m_arrVistaBitmap[i]);\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n\t\tif(m_bAttachedMenu)   // nothing to do in this mode\n\t\t\treturn lRet;\n\n\t\tCWindowCreateCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn lRet;\n\t\t}\n\n\t\tif(s_pmapMsgHook != NULL)\n\t\t{\n\t\t\tDWORD dwThreadID = ::GetCurrentThreadId();\n\t\t\t_MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\n\t\t\tif(pData != NULL)\n\t\t\t{\n\t\t\t\t(pData->dwUsage)--;\n\t\t\t\tif(pData->dwUsage == 0)\n\t\t\t\t{\n\t\t\t\t\tBOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook);\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t\tbRet = s_pmapMsgHook->Remove(dwThreadID);\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t\tif(bRet)\n\t\t\t\t\t\tdelete pData;\n\t\t\t\t}\n\n\t\t\t\tif(s_pmapMsgHook->GetSize() == 0)\n\t\t\t\t{\n\t\t\t\t\tdelete s_pmapMsgHook;\n\t\t\t\t\ts_pmapMsgHook = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlock.Unlock();\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnKeyDown\\n\"));\n#endif\n\t\tif(m_bAttachedMenu)   // nothing to do in this mode\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\t// Simulate Alt+Space for the parent\n\t\tif(wParam == VK_SPACE)\n\t\t{\n\t\t\tm_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29));\n\t\t\tbHandled = TRUE;\n\t\t}\n#if (_WIN32_IE >= 0x0500)\n\t\telse if(wParam == VK_LEFT || wParam == VK_RIGHT)\n\t\t{\n\t\t\tWPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;\n\n\t\t\tif(!m_bMenuActive)\n\t\t\t{\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tint nBtn = GetHotItem();\n\t\t\t\tint nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn);\n\t\t\t\tif(nNextBtn == -2)\n\t\t\t\t{\n\t\t\t\t\tSetHotItem(-1);\n\t\t\t\t\tif(pT->DisplayChevronMenu())\n\t\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\treturn 0;\n\t}\n\n\tLRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnKeyUp\\n\"));\n#endif\n\t\tif(m_bAttachedMenu)   // nothing to do in this mode\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tif(wParam != VK_SPACE)\n\t\t\tbHandled = FALSE;\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnChar\\n\"));\n#endif\n\t\tif(m_bAttachedMenu)   // nothing to do in this mode\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tif(wParam != VK_SPACE)\n\t\t\tbHandled = FALSE;\n\t\telse\n\t\t\treturn 0;\n\t\t// Security\n\t\tif(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd)\n\t\t\treturn 0;\n\n\t\t// Handle mnemonic press when we have focus\n\t\tint nBtn = 0;\n\t\tif(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn))\n\t\t{\n#if (_WIN32_IE >= 0x0500)\n\t\t\tif((TCHAR)LOWORD(wParam) != _chChevronShortcut)\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t\t::MessageBeep(0);\n\t\t}\n\t\telse\n\t\t{\n#if (_WIN32_IE >= 0x0500)\n\t\t\tRECT rcClient = { 0 };\n\t\t\tGetClientRect(&rcClient);\n\t\t\tRECT rcBtn = { 0 };\n\t\t\tGetItemRect(nBtn, &rcBtn);\n\t\t\tTBBUTTON tbb = { 0 };\n\t\t\tGetButton(nBtn, &tbb);\n\t\t\tif((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)\n\t\t\t{\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t\tPostMessage(WM_KEYDOWN, VK_DOWN, 0L);\n\t\t\t\tif(wParam != VK_RETURN)\n\t\t\t\t\tSetHotItem(nBtn);\n#if (_WIN32_IE >= 0x0500)\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t::MessageBeep(0);\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnSysKeyDown\\n\"));\n#endif\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnSysKeyUp\\n\"));\n#endif\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnSysChar\\n\"));\n#endif\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT))\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 0;\n\t\t}\n\n\t\tCDCHandle dc = (HDC)wParam;\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\t\tdc.FillRect(&rect, COLOR_MENU);\n\n\t\treturn 1;   // don't do the default erase\n\t}\n\n\tLRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tint nIndex = GetHotItem();\n\t\tSendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif((BOOL)HIWORD(lParam))   // System menu, do nothing\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tif(!(m_bAttachedMenu || m_bMenuActive))   // Not attached or ours, do nothing\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnInitMenuPopup\\n\"));\n#endif\n\t\t// forward to the parent or subclassed window, so it can handle update UI\n\t\tLRESULT lRet = 0;\n\t\tif(m_bAttachedMenu)\n\t\t\tlRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());\n\t\telse\n\t\t\tlRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t// If Vista menus are active, just set bitmaps and return\n\t\tif(m_bVistaMenus)\n\t\t{\n\t\t\tCMenuHandle menu = (HMENU)wParam;\n\t\t\tATLASSERT(menu.m_hMenu != NULL);\n\n\t\t\tfor(int i = 0; i < menu.GetMenuItemCount(); i++)\n\t\t\t{\n\t\t\t\tWORD nID = (WORD)menu.GetMenuItemID(i);\n\t\t\t\tint nIndex = m_arrCommand.Find(nID);\n\n\t\t\t\tCMenuItemInfo mii;\n\t\t\t\tmii.fMask = MIIM_BITMAP;\n\t\t\t\tmii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL;\n\t\t\t\tmenu.SetMenuItemInfo(i, TRUE, &mii);\n\t\t\t}\n\n\t\t\treturn lRet;\n\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n\t\t// Convert menu items to ownerdraw, add our data\n\t\tif(m_bImagesVisible)\n\t\t{\n\t\t\tCMenuHandle menuPopup = (HMENU)wParam;\n\t\t\tATLASSERT(menuPopup.m_hMenu != NULL);\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT;   // avoid level 4 warning\n\t\t\tTCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };\n\t\t\tBOOL bRet = FALSE;\n\t\t\tfor(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\n\t\t\t{\n\t\t\t\tCMenuItemInfo mii;\n\t\t\t\tmii.cch = pT->_nMaxMenuItemTextLength;\n\t\t\t\tmii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;\n\t\t\t\tmii.dwTypeData = szString;\n\t\t\t\tbRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\tif(!(mii.fType & MFT_OWNERDRAW))   // Not already an ownerdraw item\n\t\t\t\t{\n\t\t\t\t\tmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\n\t\t\t\t\t_MenuItemData* pMI = NULL;\n\t\t\t\t\tATLTRY(pMI = new _MenuItemData);\n\t\t\t\t\tATLASSERT(pMI != NULL);\n\t\t\t\t\tif(pMI != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tpMI->fType = mii.fType;\n\t\t\t\t\t\tpMI->fState = mii.fState;\n\t\t\t\t\t\tmii.fType |= MFT_OWNERDRAW;\n\t\t\t\t\t\tpMI->iButton = -1;\n\t\t\t\t\t\tfor(int j = 0; j < m_arrCommand.GetSize(); j++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(m_arrCommand[j] == mii.wID)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpMI->iButton = j;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tint cchLen = lstrlen(szString) + 1;\n\t\t\t\t\t\tpMI->lpstrText = NULL;\n\t\t\t\t\t\tATLTRY(pMI->lpstrText = new TCHAR[cchLen]);\n\t\t\t\t\t\tATLASSERT(pMI->lpstrText != NULL);\n\t\t\t\t\t\tif(pMI->lpstrText != NULL)\n\t\t\t\t\t\t\tSecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString);\n\t\t\t\t\t\tmii.dwItemData = (ULONG_PTR)pMI;\n\t\t\t\t\t\tbRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add it to the list\n\t\t\tm_stackMenuHandle.Push(menuPopup.m_hMenu);\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bAttachedMenu)   // Not attached, do nothing, forward to parent\n\t\t{\n\t\t\tm_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP);\n\t\t\tif(m_wndParent.IsWindow())\n\t\t\t\tm_wndParent.SendMessage(uMsg, wParam, lParam);\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Check if a menu is closing, do a cleanup\n\t\tif(HIWORD(wParam) == 0xFFFF && lParam == NULL)   // Menu closing\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnMenuSelect - CLOSING!!!!\\n\"));\n#endif\n\t\t\tATLASSERT(m_stackMenuWnd.GetSize() == 0);\n\t\t\t// Restore the menu items to the previous state for all menus that were converted\n\t\t\tif(m_bImagesVisible)\n\t\t\t{\n\t\t\t\tHMENU hMenu = NULL;\n\t\t\t\twhile((hMenu = m_stackMenuHandle.Pop()) != NULL)\n\t\t\t\t{\n\t\t\t\t\tCMenuHandle menuPopup = hMenu;\n\t\t\t\t\tATLASSERT(menuPopup.m_hMenu != NULL);\n\t\t\t\t\t// Restore state and delete menu item data\n\t\t\t\t\tBOOL bRet = FALSE;\n\t\t\t\t\tfor(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tCMenuItemInfo mii;\n\t\t\t\t\t\tmii.fMask = MIIM_DATA | MIIM_TYPE;\n\t\t\t\t\t\tbRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\t\t\t_MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;\n\t\t\t\t\t\tif(pMI != NULL && pMI->IsCmdBarMenuItem())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\n\t\t\t\t\t\t\tmii.fType = pMI->fType;\n\t\t\t\t\t\t\tmii.dwTypeData = pMI->lpstrText;\n\t\t\t\t\t\t\tmii.cch = lstrlen(pMI->lpstrText);\n\t\t\t\t\t\t\tmii.dwItemData = NULL;\n\n\t\t\t\t\t\t\tbRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\t\t\t\tdelete [] pMI->lpstrText;\n\t\t\t\t\t\t\tpMI->dwMagic = 0x6666;\n\t\t\t\t\t\t\tdelete pMI;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tint nIndex = (int)wParam;\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->DoPopupMenu(nIndex, false);\n\t\treturn 0;\n\t}\n\n\tLRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\t// Let's make sure we're not embedded in another process\n\t\tif((LPVOID)wParam != NULL)\n\t\t\t*((DWORD*)wParam) = GetCurrentProcessId();\n\t\tif(IsWindowVisible())\n\t\t\treturn (LRESULT)static_cast<CCommandBarCtrlBase*>(this);\n\t\telse\n\t\t\treturn NULL;\n\t}\n\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n#ifndef SPI_SETKEYBOARDCUES\n\t\tconst UINT SPI_SETKEYBOARDCUES = 0x100B;\n#endif // !SPI_SETKEYBOARDCUES\n#ifndef SPI_GETFLATMENU\n\t\tconst UINT SPI_SETFLATMENU = 0x1023;\n#endif // !SPI_GETFLATMENU\n\n\t\tif(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\n\t\tLPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;\n\t\tint cyMin = ::GetSystemMetrics(SM_CYMENU);\n\t\tif(lpWP->cy < cyMin)\n\t\tlpWP->cy = cyMin;\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - OnMenuChar\\n\"));\n#endif\n\t\tbHandled = TRUE;\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tLRESULT lRet;\n\t\tif(m_bMenuActive && LOWORD(wParam) != 0x0D)\n\t\t\tlRet = 0;\n\t\telse\n\t\t\tlRet = MAKELRESULT(1, 1);\n\n\t\tif(m_bMenuActive && HIWORD(wParam) == MF_POPUP)\n\t\t{\n\t\t\t// Convert character to lower/uppercase and possibly Unicode, using current keyboard layout\n\t\t\tTCHAR ch = (TCHAR)LOWORD(wParam);\n\t\t\tCMenuHandle menu = (HMENU)lParam;\n\t\t\tint nCount = ::GetMenuItemCount(menu);\n\t\t\tint nRetCode = MNC_EXECUTE;\n\t\t\tBOOL bRet = FALSE;\n\t\t\tTCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };\n\t\t\tWORD wMnem = 0;\n\t\t\tbool bFound = false;\n\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t{\n\t\t\t\tCMenuItemInfo mii;\n\t\t\t\tmii.cch = pT->_nMaxMenuItemTextLength;\n\t\t\t\tmii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;\n\t\t\t\tmii.dwTypeData = szString;\n\t\t\t\tbRet = menu.GetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\tif(!bRet || (mii.fType & MFT_SEPARATOR))\n\t\t\t\t\tcontinue;\n\t\t\t\t_MenuItemData* pmd = (_MenuItemData*)mii.dwItemData;\n\t\t\t\tif(pmd != NULL && pmd->IsCmdBarMenuItem())\n\t\t\t\t{\n\t\t\t\t\tLPTSTR p = pmd->lpstrText;\n\n\t\t\t\t\tif(p != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\twhile(*p && *p != _T('&'))\n\t\t\t\t\t\t\tp = ::CharNext(p);\n\t\t\t\t\t\tif(p != NULL && *p)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDWORD dwP = MAKELONG(*(++p), 0);\n\t\t\t\t\t\t\tDWORD dwC = MAKELONG(ch, 0);\n\t\t\t\t\t\t\tif(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif(!bFound)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\twMnem = (WORD)i;\n\t\t\t\t\t\t\t\t\tbFound = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnRetCode = MNC_SELECT;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(bFound)\n\t\t\t{\n\t\t\t\tif(nRetCode == MNC_EXECUTE)\n\t\t\t\t{\n\t\t\t\t\tPostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\n\t\t\t\t\tpT->GiveFocusBack();\n\t\t\t\t}\n\t\t\t\tbHandled = TRUE;\n\t\t\t\tlRet = MAKELRESULT(wMnem, nRetCode);\n\t\t\t}\n\t\t} \n\t\telse if(!m_bMenuActive)\n\t\t{\n\t\t\tint nBtn = 0;\n\t\t\tif(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn))\n\t\t\t{\n\t\t\t\tbHandled = FALSE;\n\t\t\t\tPostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\n\t\t\t\tpT->GiveFocusBack();\n\n#if (_WIN32_IE >= 0x0500)\n\t\t\t\t// check if we should display chevron menu\n\t\t\t\tif((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut)\n\t\t\t\t{\n\t\t\t\t\tif(pT->DisplayChevronMenu())\n\t\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t}\n\t\t\telse if(m_wndParent.IsWindowEnabled())\n\t\t\t{\n#if (_WIN32_IE >= 0x0500)\n\t\t\t\tRECT rcClient = { 0 };\n\t\t\t\tGetClientRect(&rcClient);\n\t\t\t\tRECT rcBtn = { 0 };\n\t\t\t\tGetItemRect(nBtn, &rcBtn);\n\t\t\t\tTBBUTTON tbb = { 0 };\n\t\t\t\tGetButton(nBtn, &tbb);\n\t\t\t\tif((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)\n\t\t\t\t{\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t\t\tif(m_bUseKeyboardCues && !m_bShowKeyboardCues)\n\t\t\t\t\t{\n\t\t\t\t\t\tm_bAllowKeyboardCues = true;\n\t\t\t\t\t\tShowKeyboardCues(true);\n\t\t\t\t\t}\n\t\t\t\t\tpT->TakeFocus();\n\t\t\t\t\tPostMessage(WM_KEYDOWN, VK_DOWN, 0L);\n\t\t\t\t\tSetHotItem(nBtn);\n#if (_WIN32_IE >= 0x0500)\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t::MessageBeep(0);\n\t\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t}\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bUseKeyboardCues && m_bShowKeyboardCues)\n\t\t\tShowKeyboardCues(false);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tLPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam;\n\t\t_MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\n\t\tif(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->DrawItem(lpDrawItemStruct);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\t\treturn (LRESULT)TRUE;\n\t}\n\n\tLRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tLPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;\n\t\t_MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;\n\t\tif(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->MeasureItem(lpMeasureItemStruct);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\t\treturn (LRESULT)TRUE;\n\t}\n\n// API message handlers\n\tLRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)m_hMenu;\n\t}\n\n\tLRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(lParam == NULL)\n\t\t\treturn FALSE;\n\t\tLPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam;\n\t\tif(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU))\n\t\t\treturn FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm);\n\t}\n\n\tLRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)m_hWnd;\n\t}\n\n// Parent window message handlers\n\tLRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tLPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh;\n\n\t\t// Check if this comes from us\n\t\tif(pnmh->hwndFrom != m_hWnd)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 0;\n\t\t}\n\n\t\tbool bBlockTracking = false;\n\t\tif((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0)\n\t\t{\n\t\t\tDWORD dwProcessID;\n\t\t\t::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID);\n\t\t\tbBlockTracking = (::GetCurrentProcessId() != dwProcessID);\n\t\t}\n\n\t\tif((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE))\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\t\telse\n\t\t{\n#ifndef HICF_LMOUSE\n\t\t\tconst DWORD HICF_LMOUSE = 0x00000080;   // left mouse button selected\n#endif\n\t\t\tbHandled = FALSE;\n\n\t\t\t// Send WM_MENUSELECT to the app if it needs to display a status text\n\t\t\tif(!(lpNMHT->dwFlags & HICF_MOUSE)\n\t\t\t\t&& !(lpNMHT->dwFlags & HICF_ACCELERATOR)\n\t\t\t\t&& !(lpNMHT->dwFlags & HICF_LMOUSE))\n\t\t\t{\n\t\t\t\tif(lpNMHT->dwFlags & HICF_ENTERING)\n\t\t\t\t\tm_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu);\n\t\t\t\tif(lpNMHT->dwFlags & HICF_LEAVING)\n\t\t\t\t\tm_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL);\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tLRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\t// Check if this comes from us\n\t\tif(pnmh->hwndFrom != m_hWnd)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(::GetFocus() != m_hWnd)\n\t\t\tpT->TakeFocus();\n\t\tLPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh;\n\t\tint nIndex = CommandToIndex(pNMToolBar->iItem);\n\t\tm_bContextMenu = false;\n\t\tm_bEscapePressed = false;\n\t\tpT->DoPopupMenu(nIndex, true);\n\n\t\treturn TBDDRET_DEFAULT;\n\t}\n\n\tLRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnInitMenuPopup(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnInternalGetBar(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n\t\tif((m_uSysKey == VK_MENU \n\t\t\t|| (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80))\n\t\t\t|| m_uSysKey == VK_SPACE) \n\t\t\t&& wParam == SC_KEYMENU)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tif(::GetFocus() == m_hWnd)\n\t\t\t{\n\t\t\t\tpT->GiveFocusBack();   // exit menu \"loop\"\n\t\t\t\tPostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\n\t\t\t}\n\t\t\telse if(m_uSysKey != VK_SPACE && !m_bSkipMsg)\n\t\t\t{\n\t\t\t\tif(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)\n\t\t\t\t\tShowKeyboardCues(true);\n\n\t\t\t\tpT->TakeFocus();      // enter menu \"loop\"\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t\telse if(m_uSysKey != VK_SPACE)\n\t\t\t{\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t}\n\t\tm_bSkipMsg = false;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnAPIGetMenu(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnMenuChar(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tOnSettingChange(uMsg, wParam, lParam, bHandled);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnDrawItem(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\treturn OnMeasureItem(uMsg, wParam, lParam, bHandled);\n\t}\n\n\tLRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tm_bParentActive = (LOWORD(wParam) != WA_INACTIVE);\n\t\tif(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues)\n\t\t{\n\t\t\tShowKeyboardCues(false);   // this will repaint our window\n\t\t}\n\t\telse\n\t\t{\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tLRESULT lRet = CDRF_DODEFAULT;\n\t\tbHandled = FALSE;\n\t\tif(pnmh->hwndFrom == m_hWnd)\n\t\t{\n\t\t\tLPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh;\n\t\t\tif(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)\n\t\t\t{\n\t\t\t\tlRet = CDRF_NOTIFYITEMDRAW;\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t\telse if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)\n\t\t\t{\n#if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR)\n\t\t\t\tif(m_bVistaMenus)\n\t\t\t\t{\n\t\t\t\t\t::SetRectEmpty(&lpTBCustomDraw->rcText);\n\t\t\t\t\tlRet = CDRF_NOTIFYPOSTPAINT;\n\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t}\n\t\t\t\telse\n#endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR)\n\t\t\t\t{\n\t\t\t\t\tif(m_bFlatMenus)\n\t\t\t\t\t{\n#ifndef COLOR_MENUHILIGHT\n\t\t\t\t\t\tconst int COLOR_MENUHILIGHT = 29;\n#endif // !COLOR_MENUHILIGHT\n\t\t\t\t\t\tbool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED);\n\t\t\t\t\t\tif(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT || \n\t\t\t\t\t\t\t(lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT));\n\t\t\t\t\t\t\t::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));\n\t\t\t\t\t\t\tlpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if(bDisabled || !m_bParentActive)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_ParentCustomDrawHelper(lpTBCustomDraw);\n\n\t\t\t\t\t\tlRet = CDRF_SKIPDEFAULT;\n\t\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t\t}\n\t\t\t\t\telse if(!m_bParentActive)\n\t\t\t\t\t{\n\t\t\t\t\t\tlpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);\n\t\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n#if _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR)\n\t\t\telse if (lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPOSTPAINT)\n\t\t\t{\n\t\t\t\tbool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED);\n\t\t\t\tif(bDisabled || !m_bParentActive)\n\t\t\t\t\tlpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);\n\n\t\t\t\t_ParentCustomDrawHelper(lpTBCustomDraw);\n\n\t\t\t\tlRet = CDRF_SKIPDEFAULT;\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS && defined(_WTL_CMDBAR_VISTA_STD_MENUBAR)\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tvoid _ParentCustomDrawHelper(LPNMTBCUSTOMDRAW lpTBCustomDraw)\n\t{\n\t\tCDCHandle dc = lpTBCustomDraw->nmcd.hdc;\n\t\tdc.SetTextColor(lpTBCustomDraw->clrText);\n\t\tdc.SetBkMode(lpTBCustomDraw->nStringBkMode);\n\n\t\tHFONT hFont = GetFont();\n\t\tHFONT hFontOld = NULL;\n\t\tif(hFont != NULL)\n\t\t\thFontOld = dc.SelectFont(hFont);\n\n\t\tconst int cchText = 200;\n\t\tTCHAR szText[cchText] = { 0 };\n\t\tTBBUTTONINFO tbbi = { 0 };\n\t\ttbbi.cbSize = sizeof(TBBUTTONINFO);\n\t\ttbbi.dwMask = TBIF_TEXT;\n\t\ttbbi.pszText = szText;\n\t\ttbbi.cchText = cchText;\n\t\tGetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi);\n\n\t\tdc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\n\n\t\tif(hFont != NULL)\n\t\t\tdc.SelectFont(hFontOld);\n\t}\n\n// Message hook handlers\n\tLRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tstatic POINT s_point = { -1, -1 };\n\t\tDWORD dwPoint = ::GetMessagePos();\n\t\tPOINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) };\n\n\t\tbHandled = FALSE;\n\t\tif(m_bMenuActive)\n\t\t{\n\t\t\tif(::WindowFromPoint(point) == m_hWnd)\n\t\t\t{\n\t\t\t\tScreenToClient(&point);\n\t\t\t\tint nHit = HitTest(&point);\n\n\t\t\t\tif((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1)\n\t\t\t\t{\n\t\t\t\t\tTBBUTTON tbb = { 0 };\n\t\t\t\t\tGetButton(nHit, &tbb);\n\t\t\t\t\tif((tbb.fsState & TBSTATE_ENABLED) != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tm_nNextPopBtn = nHit | 0xFFFF0000;\n\t\t\t\t\t\tHWND hWndMenu = m_stackMenuWnd.GetCurrent();\n\t\t\t\t\t\tATLASSERT(hWndMenu != NULL);\n\n\t\t\t\t\t\t// this one is needed to close a menu if mouse button was down\n\t\t\t\t\t\t::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y));\n\t\t\t\t\t\t// this one closes a popup menu\n\t\t\t\t\t\t::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\n\n\t\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tScreenToClient(&point);\n\t\t}\n\n\t\ts_point = point;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\\n\"), wParam);\n#endif\n\n\t\tif(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)\n\t\t\tShowKeyboardCues(true);\n\n\t\tif(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd)\n\t\t{\n\t\t\tm_bAllowKeyboardCues = false;\n\t\t\tPostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GiveFocusBack();\n\t\t\tm_bSkipMsg = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues)\n\t\t\t{\n\t\t\t\tm_bAllowKeyboardCues = true;\n\t\t\t\tShowKeyboardCues(false);\n\t\t\t}\n\t\t\tm_uSysKey = (UINT)wParam;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(!m_bAllowKeyboardCues)\n\t\t\tm_bAllowKeyboardCues = true;\n\t\tbHandled = FALSE;\n\t\twParam;\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\\n\"), wParam);\n#endif\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_SYSCHAR (0x%2.2X)\\n\"), wParam);\n#endif\n\n\t\tif(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE)\n\t\t\tbHandled = TRUE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_KEYDOWN (0x%2.2X)\\n\"), wParam);\n#endif\n\t\tbHandled = FALSE;\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tif(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1)\n\t\t{\n\t\t\tif(m_bMenuActive && !m_bContextMenu)\n\t\t\t{\n\t\t\t\tint nHot = GetHotItem();\n\t\t\t\tif(nHot == -1)\n\t\t\t\t\tnHot = m_nPopBtn;\n\t\t\t\tif(nHot == -1)\n\t\t\t\t\tnHot = 0;\n\t\t\t\tSetHotItem(nHot);\n\t\t\t\tbHandled = TRUE;\n\t\t\t\tpT->TakeFocus();\n\t\t\t\tm_bEscapePressed = true; // To keep focus\n\t\t\t\tm_bSkipPostDown = false;\n\t\t\t}\n\t\t\telse if(::GetFocus() == m_hWnd && m_wndParent.IsWindow())\n\t\t\t{\n\t\t\t\tSetHotItem(-1);\n\t\t\t\tpT->GiveFocusBack();\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t}\n\t\telse if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN)\n\t\t{\n\t\t\tif(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow())\n\t\t\t{\n\t\t\t\tint nHot = GetHotItem();\n\t\t\t\tif(nHot != -1)\n\t\t\t\t{\n\t\t\t\t\tif(wParam != VK_RETURN)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(!m_bSkipPostDown)\n\t\t\t\t\t\t{\n// IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click\n#if (_WIN32_IE < 0x0500)\n\t\t\t\t\t\t\tDWORD dwMajor = 0, dwMinor = 0;\n\t\t\t\t\t\t\tATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);\n\t\t\t\t\t\t\tif(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tRECT rect = { 0 };\n\t\t\t\t\t\t\t\tGetItemRect(nHot, &rect);\n\t\t\t\t\t\t\t\tPostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top));\n\t\t\t\t\t\t\t}\n#endif // (_WIN32_IE < 0x0500)\n\t\t\t\t\t\t\tPostMessage(WM_KEYDOWN, VK_DOWN, 0L);\n\t\t\t\t\t\t\tm_bSkipPostDown = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - skipping posting another VK_DOWN\\n\"));\n\t\t\t\t\t\t\tm_bSkipPostDown = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Can't find hot button\\n\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(wParam == VK_RETURN && m_bMenuActive)\n\t\t\t{\n\t\t\t\tPostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);\n\t\t\t\tm_nNextPopBtn = -1;\n\t\t\t\tpT->GiveFocusBack();\n\t\t\t}\n\t\t}\n\t\telse if(wParam == VK_LEFT || wParam == VK_RIGHT)\n\t\t{\n\t\t\tWPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;\n\t\t\tWPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT;\n\n\t\t\tif(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem))\n\t\t\t{\n\t\t\t\tbool bAction = false;\n\t\t\t\tif(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1)\n\t\t\t\t{\n\t\t\t\t\tm_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn);\n\t\t\t\t\tif(m_nNextPopBtn != -1)\n\t\t\t\t\t\tbAction = true;\n\t\t\t\t}\n\t\t\t\telse if(wParam == wpNext)\n\t\t\t\t{\n\t\t\t\t\tm_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn);\n\t\t\t\t\tif(m_nNextPopBtn != -1)\n\t\t\t\t\t\tbAction = true;\n\t\t\t\t}\n\t\t\t\tHWND hWndMenu = m_stackMenuWnd.GetCurrent();\n\t\t\t\tATLASSERT(hWndMenu != NULL);\n\n\t\t\t\t// Close the popup menu\n\t\t\t\tif(bAction)\n\t\t\t\t{\n\t\t\t\t\t::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\n\t\t\t\t\tif(wParam == wpNext)\n\t\t\t\t\t{\n\t\t\t\t\t\tint cItem = m_stackMenuWnd.GetSize() - 1;\n\t\t\t\t\t\twhile(cItem >= 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thWndMenu = m_stackMenuWnd[cItem];\n\t\t\t\t\t\t\tif(hWndMenu != NULL)\n\t\t\t\t\t\t\t\t::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);\n\t\t\t\t\t\t\tcItem--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n#if (_WIN32_IE >= 0x0500)\n\t\t\t\t\tif(m_nNextPopBtn == -2)\n\t\t\t\t\t{\n\t\t\t\t\t\tm_nNextPopBtn = -1;\n\t\t\t\t\t\tpT->DisplayChevronMenu();\n\t\t\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\t\t\tbHandled = TRUE;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_NEXTMENU\\n\"));\n#endif\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n \tLRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook WM_CHAR (0x%2.2X)\\n\"), wParam);\n#endif\n\t\tbHandled = (wParam == VK_ESCAPE);\n\t\treturn 0;\n\t}\n\n// Implementation - ownerdraw overrideables and helpers\n\tvoid DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(m_bFlatMenus)\n\t\t\tpT->DrawItemFlat(lpDrawItemStruct);\n\t\telse\n\t\t\tpT->DrawItem3D(lpDrawItemStruct);\n\n\t}\n\n\tvoid DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct)\n\t{\n\t\t_MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\n\t\tCDCHandle dc = lpDrawItemStruct->hDC;\n\t\tconst RECT& rcItem = lpDrawItemStruct->rcItem;\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tif(pmd->fType & MFT_SEPARATOR)\n\t\t{\n\t\t\t// draw separator\n\t\t\tRECT rc = rcItem;\n\t\t\trc.top += (rc.bottom - rc.top) / 2;      // vertical center\n\t\t\tdc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP);   // draw separator line\n\t\t}\n\t\telse\t\t// not a separator\n\t\t{\n\t\t\tBOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;\n\t\t\tBOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;\n\t\t\tBOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;\n\t\t\tBOOL bHasImage = FALSE;\n\n\t\t\tif(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)\n\t\t\t\tbSelected = FALSE;\n\t\t\tRECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy };   // button rect\n\t\t\t::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2);          // center vertically\n\n\t\t\tint iButton = pmd->iButton;\n\t\t\tif(iButton >= 0)\n\t\t\t{\n\t\t\t\tbHasImage = TRUE;\n\n\t\t\t\t// calc drawing point\n\t\t\t\tSIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };\n\t\t\t\tsz.cx /= 2;\n\t\t\t\tsz.cy /= 2;\n\t\t\t\tPOINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };\n\n\t\t\t\t// fill background depending on state\n\t\t\t\tif(!bChecked || (bSelected && !bDisabled))\n\t\t\t\t{\n\t\t\t\t\tif(!bDisabled)\n\t\t\t\t\t\tdc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU);\n\t\t\t\t\telse\n\t\t\t\t\t\tdc.FillRect(&rcButn, COLOR_MENU);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCOLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));\n\t\t\t\t\tCOLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));\n\t\t\t\t\tCBrush hbr(CDCHandle::GetHalftoneBrush());\n\t\t\t\t\tdc.SetBrushOrg(rcButn.left, rcButn.top);\n\t\t\t\t\tdc.FillRect(&rcButn, hbr);\n\t\t\t\t\tdc.SetTextColor(crTxt);\n\t\t\t\t\tdc.SetBkColor(crBk);\n\t\t\t\t}\n\n\t\t\t\t// draw disabled or normal\n\t\t\t\tif(!bDisabled)\n\t\t\t\t{\n\t\t\t\t\t// draw pushed-in or popped-out edge\n\t\t\t\t\tif(bSelected || bChecked)\n\t\t\t\t\t{\n\t\t\t\t\t\tRECT rc2 = rcButn;\n\t\t\t\t\t\tdc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT);\n\t\t\t\t\t}\n\t\t\t\t\t// draw the image\n\t\t\t\t\t::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU);\n\t\t\t\t\tpT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// no image - look for custom checked/unchecked bitmaps\n\t\t\t\tCMenuItemInfo info;\n\t\t\t\tinfo.fMask = MIIM_CHECKMARKS | MIIM_TYPE;\n\t\t\t\t::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);\n\t\t\t\tif(bChecked || info.hbmpUnchecked != NULL)\n\t\t\t\t{\n\t\t\t\t\tBOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);\n\t\t\t\t\tbHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// draw item text\n\t\t\tint cxButn = m_szButton.cx;\n\t\t\tCOLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);\n\t\t\tif(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)\n\t\t\t{\n\t\t\t\tRECT rcBG = rcItem;\n\t\t\t\tif(bHasImage)\n\t\t\t\t\trcBG.left += cxButn + s_kcxGap;\n\t\t\t\tdc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);\n\t\t\t}\n\n\t\t\t// calc text rectangle and colors\n\t\t\tRECT rcText = rcItem;\n\t\t\trcText.left += cxButn + s_kcxGap + s_kcxTextMargin;\n\t\t\trcText.right -= cxButn;\n\t\t\tdc.SetBkMode(TRANSPARENT);\n\t\t\tCOLORREF colorText = ::GetSysColor(bDisabled ?  (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));\n\n\t\t\t// font already selected by Windows\n\t\t\tif(bDisabled && (!bSelected || colorText == colorBG))\n\t\t\t{\n\t\t\t\t// disabled - draw shadow text shifted down and right 1 pixel (unles selected)\n\t\t\t\tRECT rcDisabled = rcText;\n\t\t\t\t::OffsetRect(&rcDisabled, 1, 1);\n\t\t\t\tpT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT));\n\t\t\t}\n\t\t\tpT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!\n\t\t}\n\t}\n\n\tvoid DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct)\n\t{\n\t\t_MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;\n\t\tCDCHandle dc = lpDrawItemStruct->hDC;\n\t\tconst RECT& rcItem = lpDrawItemStruct->rcItem;\n\t\tT* pT = static_cast<T*>(this);\n\n#ifndef COLOR_MENUHILIGHT\n\t\tconst int COLOR_MENUHILIGHT = 29;\n#endif // !COLOR_MENUHILIGHT\n\n\t\tBOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;\n\t\tBOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;\n\t\tBOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;\n\n\t\t// paint background\n\t\tif(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)\n\t\t{\n\t\t\tif(bSelected)\n\t\t\t{\n\t\t\t\tdc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT));\n\t\t\t\tdc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU));\n\t\t\t}\n\t\t}\n\n\t\tif(pmd->fType & MFT_SEPARATOR)\n\t\t{\n\t\t\t// draw separator\n\t\t\tRECT rc = rcItem;\n\t\t\trc.top += (rc.bottom - rc.top) / 2;      // vertical center\n\t\t\tdc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP);   // draw separator line\n\t\t}\n\t\telse\t\t// not a separator\n\t\t{\n\t\t\tif(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)\n\t\t\t\tbSelected = FALSE;\n\t\t\tRECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy };   // button rect\n\t\t\t::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2);          // center vertically\n\n\t\t\t// draw background and border for checked items\n\t\t\tif(bChecked)\n\t\t\t{\n\t\t\t\tRECT rcCheck = rcButn;\n\t\t\t\t::InflateRect(&rcCheck, -1, -1);\n\t\t\t\tif(bSelected)\n\t\t\t\t\tdc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU));\n\t\t\t\tdc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT));\n\t\t\t}\n\n\t\t\tint iButton = pmd->iButton;\n\t\t\tif(iButton >= 0)\n\t\t\t{\n\t\t\t\t// calc drawing point\n\t\t\t\tSIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };\n\t\t\t\tsz.cx /= 2;\n\t\t\t\tsz.cy /= 2;\n\t\t\t\tPOINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };\n\n\t\t\t\t// draw disabled or normal\n\t\t\t\tif(!bDisabled)\n\t\t\t\t{\n\t\t\t\t\t::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tHBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU);\n\t\t\t\t\tHBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW);\n\t\t\t\t\tpT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// no image - look for custom checked/unchecked bitmaps\n\t\t\t\tCMenuItemInfo info;\n\t\t\t\tinfo.fMask = MIIM_CHECKMARKS | MIIM_TYPE;\n\t\t\t\t::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);\n\t\t\t\tif(bChecked || info.hbmpUnchecked != NULL)\n\t\t\t\t{\n\t\t\t\t\tBOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);\n\t\t\t\t\tpT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// draw item text\n\t\t\tint cxButn = m_szButton.cx;\n\t\t\t// calc text rectangle and colors\n\t\t\tRECT rcText = rcItem;\n\t\t\trcText.left += cxButn + s_kcxGap + s_kcxTextMargin;\n\t\t\trcText.right -= cxButn;\n\t\t\tdc.SetBkMode(TRANSPARENT);\n\t\t\tCOLORREF colorText = ::GetSysColor(bDisabled ?  (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));\n\n\t\t\tpT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!\n\t\t}\n\t}\n\n\tvoid DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color)\n\t{\n\t\tint nTab = -1;\n\t\tconst int nLen = lstrlen(lpstrText);\n\t\tfor(int i = 0; i < nLen; i++)\n\t\t{\n\t\t\tif(lpstrText[i] == _T('\\t'))\n\t\t\t{\n\t\t\t\tnTab = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tdc.SetTextColor(color);\n\t\tdc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\n\t\tif(nTab != -1)\n\t\t\tdc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));\n\t}\n\n\tvoid DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point,\n\t\t\tHBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),\n\t\t\tHBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),\n\t\t\tHBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))\n\t{\n#if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\n\t\tif(m_bAlphaImages)\n\t\t{\n\t\t\tIMAGELISTDRAWPARAMS ildp = { 0 };\n\t\t\tildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);\n\t\t\tildp.himl = m_hImageList;\n\t\t\tildp.i = nImage;\n\t\t\tildp.hdcDst = dc;\n\t\t\tildp.x = point.x;\n\t\t\tildp.y = point.y;\n\t\t\tildp.cx = 0;\n\t\t\tildp.cy = 0;\n\t\t\tildp.xBitmap = 0;\n\t\t\tildp.yBitmap = 0;\n\t\t\tildp.fStyle = ILD_TRANSPARENT;\n\t\t\tildp.fState = ILS_SATURATE;\n\t\t\tildp.Frame = 0;\n\t\t\t::ImageList_DrawIndirect(&ildp);\n\t\t}\n\t\telse\n#endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)\n\t\t{\n\t\t\t// create memory DC\n\t\t\tCDC dcMem;\n\t\t\tdcMem.CreateCompatibleDC(dc);\n\t\t\t// create mono or color bitmap\n\t\t\tCBitmap bmp;\n\t\t\tbmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy);\n\t\t\tATLASSERT(bmp.m_hBitmap != NULL);\n\t\t\t// draw image into memory DC--fill BG white first\n\t\t\tHBITMAP hBmpOld = dcMem.SelectBitmap(bmp);\n\t\t\tdcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS);\n\t\t\t// If white is the text color, we can't use the normal painting since\n\t\t\t// it would blend with the WHITENESS, but the mask is OK\n\t\t\tUINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL;\n\t\t\t::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle);\n\t\t\tdc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage);\n\t\t\tdcMem.SelectBitmap(hBmpOld);   // restore\n\t\t}\n\t}\n\n\t// old name\n\tBOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)\n\t{\n\t\treturn DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck);\n\t}\n\n\tBOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)\n\t{\n\t\t// get checkmark bitmap, if none, use Windows standard\n\t\tSIZE size = { 0, 0 };\n\t\tCBitmapHandle bmp = hBmpCheck;\n\t\tif(hBmpCheck != NULL)\n\t\t{\n\t\t\tbmp.GetSize(size);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsize.cx = ::GetSystemMetrics(SM_CXMENUCHECK); \n\t\t\tsize.cy = ::GetSystemMetrics(SM_CYMENUCHECK); \n\t\t\tbmp.CreateCompatibleBitmap(dc, size.cx, size.cy);\n\t\t\tATLASSERT(bmp.m_hBitmap != NULL);\n\t\t}\n\t\t// center bitmap in caller's rectangle\n\t\tRECT rcDest = rc;\n\t\tif((rc.right - rc.left) > size.cx)\n\t\t{\n\t\t\trcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2;\n\t\t\trcDest.right = rcDest.left + size.cx;\n\t\t}\n\t\tif((rc.bottom - rc.top) > size.cy)\n\t\t{\n\t\t\trcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2;\n\t\t\trcDest.bottom = rcDest.top + size.cy;\n\t\t}\n\t\t// paint background\n\t\tif(!m_bFlatMenus)\n\t\t{\n\t\t\tif(bSelected && !bDisabled)\n\t\t\t{\n\t\t\t\tdc.FillRect(&rcDest, COLOR_MENU);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCOLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));\n\t\t\t\tCOLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));\n\t\t\t\tCBrush hbr(CDCHandle::GetHalftoneBrush());\n\t\t\t\tdc.SetBrushOrg(rcDest.left, rcDest.top);\n\t\t\t\tdc.FillRect(&rcDest, hbr);\n\t\t\t\tdc.SetTextColor(clrTextOld);\n\t\t\t\tdc.SetBkColor(clrBkOld);\n\t\t\t}\n\t\t}\n\n\t\t// create source image\n\t\tCDC dcSource;\n\t\tdcSource.CreateCompatibleDC(dc);\n\t\tHBITMAP hBmpOld = dcSource.SelectBitmap(bmp);\n\t\t// set colors\n\t\tconst COLORREF clrBlack = RGB(0, 0, 0);\n\t\tconst COLORREF clrWhite = RGB(255, 255, 255);\n\t\tCOLORREF clrTextOld = dc.SetTextColor(clrBlack);\n\t\tCOLORREF clrBkOld = dc.SetBkColor(clrWhite);\n\t\t// create mask\n\t\tCDC dcMask;\n\t\tdcMask.CreateCompatibleDC(dc);\n\t\tCBitmap bmpMask;\n\t\tbmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL);\n\t\tHBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask);\n\n\t\t// draw the checkmark transparently\n\t\tint cx = rcDest.right - rcDest.left;\n\t\tint cy = rcDest.bottom - rcDest.top;\n\t\tif(hBmpCheck != NULL)\n\t\t{\n\t\t\t// build mask based on transparent color\t\n\t\t\tdcSource.SetBkColor(m_clrMask);\n\t\t\tdcMask.SetBkColor(clrBlack);\n\t\t\tdcMask.SetTextColor(clrWhite);\n\t\t\tdcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY);\n\t\t\t// draw bitmap using the mask\n\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);\n\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND);\n\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst DWORD ROP_DSno = 0x00BB0226L;\n\t\t\tconst DWORD ROP_DSa = 0x008800C6L;\n\t\t\tconst DWORD ROP_DSo = 0x00EE0086L;\n\t\t\tconst DWORD ROP_DSna = 0x00220326L;\n\n\t\t\t// draw mask\n\t\t\tRECT rcSource = { 0, 0, __min(size.cx, rc.right - rc.left), __min(size.cy, rc.bottom - rc.top) };\n\t\t\tdcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK);\n\n\t\t\t// draw shadow if disabled\n\t\t\tif(!m_bFlatMenus && bDisabled)\n\t\t\t{\n\t\t\t\t// offset by one pixel\n\t\t\t\tint x = rcDest.left + 1;\n\t\t\t\tint y = rcDest.top + 1;\n\t\t\t\t// paint source bitmap\n\t\t\t\tconst int nColor = COLOR_3DHILIGHT;\n\t\t\t\tdcSource.FillRect(&rcSource, nColor);\n\t\t\t\t// draw checkmark - special case black and white colors\n\t\t\t\tCOLORREF clrCheck = ::GetSysColor(nColor);\n\t\t\t\tif(clrCheck == clrWhite)\n\t\t\t\t{\n\t\t\t\t\tdc.BitBlt(x, y, cx, cy, dcMask,  0, 0,   ROP_DSno);\n\t\t\t\t\tdc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif(clrCheck != clrBlack)\n\t\t\t\t\t{\n\t\t\t\t\t\tATLASSERT(dcSource.GetTextColor() == clrBlack);\n\t\t\t\t\t\tATLASSERT(dcSource.GetBkColor() == clrWhite);\n\t\t\t\t\t\tdcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);\n\t\t\t\t\t}\n\t\t\t\t\tdc.BitBlt(x, y, cx, cy, dcMask,  0,  0,  ROP_DSa);\n\t\t\t\t\tdc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// paint source bitmap\n\t\t\tconst int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT;\n\t\t\tdcSource.FillRect(&rcSource, nColor);\n\t\t\t// draw checkmark - special case black and white colors\n\t\t\tCOLORREF clrCheck = ::GetSysColor(nColor);\n\t\t\tif(clrCheck == clrWhite)\n\t\t\t{\n\t\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask,  0, 0,   ROP_DSno);\n\t\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(clrCheck != clrBlack)\n\t\t\t\t{\n\t\t\t\t\tATLASSERT(dcSource.GetTextColor() == clrBlack);\n\t\t\t\t\tATLASSERT(dcSource.GetBkColor() == clrWhite);\n\t\t\t\t\tdcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);\n\t\t\t\t}\n\t\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask,  0,  0,  ROP_DSa);\n\t\t\t\tdc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo);\n\t\t\t}\n\t\t}\n\t\t// restore all\n\t\tdc.SetTextColor(clrTextOld);\n\t\tdc.SetBkColor(clrBkOld);\n\t\tdcSource.SelectBitmap(hBmpOld);\n\t\tdcMask.SelectBitmap(hBmpOld1);\n\t\tif(hBmpCheck == NULL)\n\t\t\tbmp.DeleteObject();\n\t\t// draw pushed-in hilight\n\t\tif(!m_bFlatMenus && !bDisabled)\n\t\t{\n\t\t\tif(rc.right - rc.left > size.cx)\n\t\t\t\t::InflateRect(&rcDest, 1,1);   // inflate checkmark by one pixel all around\n\t\t\tdc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\tvoid MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)\n\t{\n\t\t_MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;\n\n\t\tif(pmd->fType & MFT_SEPARATOR)   // separator - use half system height and zero width\n\t\t{\n\t\t\tlpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2;\n\t\t\tlpMeasureItemStruct->itemWidth  = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// compute size of text - use DrawText with DT_CALCRECT\n\t\t\tCWindowDC dc(NULL);\n\t\t\tCFont fontBold;\n\t\t\tHFONT hOldFont = NULL;\n\t\t\tif(pmd->fState & MFS_DEFAULT)\n\t\t\t{\n\t\t\t\t// need bold version of font\n\t\t\t\tLOGFONT lf = { 0 };\n\t\t\t\tm_fontMenu.GetLogFont(lf);\n\t\t\t\tlf.lfWeight += 200;\n\t\t\t\tfontBold.CreateFontIndirect(&lf);\n\t\t\t\tATLASSERT(fontBold.m_hFont != NULL);\n\t\t\t\thOldFont = dc.SelectFont(fontBold);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\thOldFont = dc.SelectFont(m_fontMenu);\n\t\t\t}\n\n\t\t\tRECT rcText = { 0 };\n\t\t\tdc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\n\t\t\tint cx = rcText.right - rcText.left;\n\t\t\tdc.SelectFont(hOldFont);\n\n\t\t\tLOGFONT lf = { 0 };\n\t\t\tm_fontMenu.GetLogFont(lf);\n\t\t\tint cy = lf.lfHeight;\n\t\t\tif(cy < 0)\n\t\t\t\tcy = -cy;\n\t\t\tconst int cyMargin = 8;\n\t\t\tcy += cyMargin;\n\n\t\t\t// height of item is the bigger of these two\n\t\t\tlpMeasureItemStruct->itemHeight = __max(cy, (int)m_szButton.cy);\n\n\t\t\t// width is width of text plus a bunch of stuff\n\t\t\tcx += 2 * s_kcxTextMargin;   // L/R margin for readability\n\t\t\tcx += s_kcxGap;              // space between button and menu text\n\t\t\tcx += 2 * m_szButton.cx;     // button width (L=button; R=empty margin)\n\t\t\tcx += m_cxExtraSpacing;      // extra between item text and accelerator keys\n\n\t\t\t// Windows adds 1 to returned value\n\t\t\tcx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1;\n\t\t\tlpMeasureItemStruct->itemWidth = cx;   // done deal\n\t\t}\n\t}\n\n// Implementation - Hook procs\n\tstatic LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tconst int cchClassName = 7;\n\t\tTCHAR szClassName[cchClassName] = { 0 };\n\n\t\tif(nCode == HCBT_CREATEWND)\n\t\t{\n\t\t\tHWND hWndMenu = (HWND)wParam;\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - HCBT_CREATEWND (HWND = %8.8X)\\n\"), hWndMenu);\n#endif\n\n\t\t\t::GetClassName(hWndMenu, szClassName, cchClassName);\n\t\t\tif(!lstrcmp(_T(\"#32768\"), szClassName))\n\t\t\t\ts_pCurrentBar->m_stackMenuWnd.Push(hWndMenu);\n\t\t}\n\t\telse if(nCode == HCBT_DESTROYWND)\n\t\t{\n\t\t\tHWND hWndMenu = (HWND)wParam;\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\\n\"), hWndMenu);\n#endif\n\n\t\t\t::GetClassName(hWndMenu, szClassName, cchClassName);\n\t\t\tif(!lstrcmp(_T(\"#32768\"), szClassName))\n\t\t\t{\n\t\t\t\tATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent());\n\t\t\t\ts_pCurrentBar->m_stackMenuWnd.Pop();\n\t\t\t}\n\t\t}\n\n\t\treturn ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam);\n\t}\n\n\tstatic LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tLPMSG pMsg = (LPMSG)lParam;\n\n\t\tif(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG)\n\t\t{\n\t\t\tCCommandBarCtrlBase* pCmdBar = NULL;\n\t\t\tHWND hWnd = pMsg->hwnd;\n\t\t\tDWORD dwPID = 0;\n\t\t\twhile(pCmdBar == NULL && hWnd != NULL)\n\t\t\t{\n\t\t\t\tpCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L);\n\t\t\t\thWnd = ::GetParent(hWnd);\n\t\t\t}\n\n\t\t\tif(pCmdBar != NULL && dwPID == GetCurrentProcessId())\n\t\t\t{\n\t\t\t\tpCmdBar->m_hWndHook = pMsg->hwnd;\n\t\t\t\tATLASSERT(pCmdBar->IsCommandBarBase());\n\n\t\t\t\tif(::IsWindow(pCmdBar->m_hWnd))\n\t\t\t\t\tpCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);\n\t\t\t\telse\n\t\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - Hook skipping message, can't find command bar!\\n\"));\n\t\t\t}\n\t\t}\n\n\t\tLRESULT lRet = 0;\n\t\tATLASSERT(s_pmapMsgHook != NULL);\n\t\tif(s_pmapMsgHook != NULL)\n\t\t{\n\t\t\tDWORD dwThreadID = ::GetCurrentThreadId();\n\t\t\t_MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);\n\t\t\tif(pData != NULL)\n\t\t\t{\n\t\t\t\tlRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam);\n\t\t\t}\n\t\t}\n\t\treturn lRet;\n\t}\n\n// Implementation\n\tvoid DoPopupMenu(int nIndex, bool bAnimate)\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - DoPopupMenu, bAnimate = %s\\n\"), bAnimate ? \"true\" : \"false\");\n#endif\n\n\t\t// Menu animation flags\n#ifndef TPM_VERPOSANIMATION\n\t\tconst UINT TPM_VERPOSANIMATION = 0x1000L;\n#endif\n#ifndef TPM_NOANIMATION\n\t\tconst UINT TPM_NOANIMATION = 0x4000L;\n#endif\n\t\tT* pT = static_cast<T*>(this);\n\n\t\t// get popup menu and it's position\n\t\tRECT rect = { 0 };\n\t\tGetItemRect(nIndex, &rect);\n\t\tPOINT pt = { rect.left, rect.bottom };\n\t\tMapWindowPoints(NULL, &pt, 1);\n\t\tMapWindowPoints(NULL, &rect);\n\t\tTPMPARAMS TPMParams = { 0 };\n\t\tTPMParams.cbSize = sizeof(TPMPARAMS);\n\t\tTPMParams.rcExclude = rect;\n\t\tHMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex);\n\t\tATLASSERT(hMenuPopup != NULL);\n\n\t\t// get button ID\n\t\tTBBUTTON tbb = { 0 };\n\t\tGetButton(nIndex, &tbb);\n\t\tint nCmdID = tbb.idCommand;\n\n\t\tm_nPopBtn = nIndex;   // remember current button's index\n\n\t\t// press button and display popup menu\n\t\tPressButton(nCmdID, TRUE);\n\t\tSetHotItem(nCmdID);\n\t\tpT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN |\n\t\t\t(s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams);\n\t\tPressButton(nCmdID, FALSE);\n\t\tif(::GetFocus() != m_hWnd)\n\t\t\tSetHotItem(-1);\n\n\t\tm_nPopBtn = -1;   // restore\n\n\t\t// eat next message if click is on the same button\n\t\tMSG msg = { 0 };\n\t\tif(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt))\n\t\t\t::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);\n\n\t\t// check if another popup menu should be displayed\n\t\tif(m_nNextPopBtn != -1)\n\t\t{\n\t\t\tPostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF);\n\t\t\tif(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem)\n\t\t\t\tPostMessage(WM_KEYDOWN, VK_DOWN, 0);\n\t\t\tm_nNextPopBtn = -1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_bContextMenu = false;\n\t\t\t// If user didn't hit escape, give focus back\n\t\t\tif(!m_bEscapePressed)\n\t\t\t{\n\t\t\t\tif(m_bUseKeyboardCues && m_bShowKeyboardCues)\n\t\t\t\t\tm_bAllowKeyboardCues = false;\n\t\t\t\tpT->GiveFocusBack();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSetHotItem(nCmdID);\n\t\t\t\tSetAnchorHighlight(TRUE);\n\t\t\t}\n\t\t}\n\t}\n\n\tBOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)\n\t{\n\t\tCMenuHandle menuPopup = hMenu;\n\n\t\tCWindowCreateCriticalSectionLock lock;\n\t\tif(FAILED(lock.Lock()))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\\n\"));\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tATLASSERT(s_hCreateHook == NULL);\n\n\t\ts_pCurrentBar = static_cast<CCommandBarCtrlBase*>(this);\n\n\t\ts_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId());\n\t\tATLASSERT(s_hCreateHook != NULL);\n\n\t\tm_bPopupItem = false;\n\t\tm_bMenuActive = true;\n\n\t\tBOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams);\n\t\tm_bMenuActive = false;\n\n\t\t::UnhookWindowsHookEx(s_hCreateHook);\n\n\t\ts_hCreateHook = NULL;\n\t\ts_pCurrentBar = NULL;\n\n\t\tlock.Unlock();\n\n\t\t// cleanup - convert menus back to original state\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - TrackPopupMenu - cleanup\\n\"));\n#endif\n\n\t\tATLASSERT(m_stackMenuWnd.GetSize() == 0);\n\n\t\tUpdateWindow();\n\t\tATL::CWindow wndTL = GetTopLevelParent();\n\t\twndTL.UpdateWindow();\n\n\t\t// restore the menu items to the previous state for all menus that were converted\n\t\tif(m_bImagesVisible)\n\t\t{\n\t\t\tHMENU hMenuSav = NULL;\n\t\t\twhile((hMenuSav = m_stackMenuHandle.Pop()) != NULL)\n\t\t\t{\n\t\t\t\tmenuPopup = hMenuSav;\n\t\t\t\tBOOL bRet = FALSE;\n\t\t\t\t// restore state and delete menu item data\n\t\t\t\tfor(int i = 0; i < menuPopup.GetMenuItemCount(); i++)\n\t\t\t\t{\n\t\t\t\t\tCMenuItemInfo mii;\n\t\t\t\t\tmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;\n\t\t\t\t\tbRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\t\t_MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;\n\t\t\t\t\tif(pMI != NULL && pMI->IsCmdBarMenuItem())\n\t\t\t\t\t{\n\t\t\t\t\t\tmii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;\n\t\t\t\t\t\tmii.fType = pMI->fType;\n\t\t\t\t\t\tmii.fState = pMI->fState;\n\t\t\t\t\t\tmii.dwTypeData = pMI->lpstrText;\n\t\t\t\t\t\tmii.cch = lstrlen(pMI->lpstrText);\n\t\t\t\t\t\tmii.dwItemData = NULL;\n\n\t\t\t\t\t\tbRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\t\t// this one triggers WM_MEASUREITEM\n\t\t\t\t\t\tmenuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText);\n\t\t\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\t\t\tdelete [] pMI->lpstrText;\n\t\t\t\t\t\tdelete pMI;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn bTrackRet;\n\t}\n\n\tint GetPreviousMenuItem(int nBtn) const\n\t{\n\t\tif(nBtn == -1)\n\t\t\treturn -1;\n#if (_WIN32_IE >= 0x0500)\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n#endif // (_WIN32_IE >= 0x0500)\n\t\tint nNextBtn;\n\t\tfor(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--)\n\t\t{\n\t\t\tif(nNextBtn < 0)\n\t\t\t\tnNextBtn = ::GetMenuItemCount(m_hMenu) - 1;\n\t\t\tTBBUTTON tbb = { 0 };\n\t\t\tGetButton(nNextBtn, &tbb);\n#if (_WIN32_IE >= 0x0500)\n\t\t\tRECT rcBtn = { 0 };\n\t\t\tGetItemRect(nNextBtn, &rcBtn);\n\t\t\tif(rcBtn.right > rcClient.right)\n\t\t\t{\n\t\t\t\tnNextBtn = -2;   // chevron\n\t\t\t\tbreak;\n\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\tif((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)\n\t\t\t\tbreak;\n\t\t}\n\t\treturn (nNextBtn != nBtn) ? nNextBtn : -1;\n\t}\n\n\tint GetNextMenuItem(int nBtn) const\n\t{\n\t\tif(nBtn == -1)\n\t\t\treturn -1;\n#if (_WIN32_IE >= 0x0500)\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n#endif // (_WIN32_IE >= 0x0500)\n\t\tint nNextBtn = 0;\n\t\tint nCount = ::GetMenuItemCount(m_hMenu);\n\t\tfor(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++)\n\t\t{\n\t\t\tif(nNextBtn >= nCount)\n\t\t\t\tnNextBtn = 0;\n\t\t\tTBBUTTON tbb = { 0 };\n\t\t\tGetButton(nNextBtn, &tbb);\n#if (_WIN32_IE >= 0x0500)\n\t\t\tRECT rcBtn = { 0 };\n\t\t\tGetItemRect(nNextBtn, &rcBtn);\n\t\t\tif(rcBtn.right > rcClient.right)\n\t\t\t{\n\t\t\t\tnNextBtn = -2;   // chevron\n\t\t\t\tbreak;\n\t\t\t}\n#endif // (_WIN32_IE >= 0x0500)\n\t\t\tif((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)\n\t\t\t\tbreak;\n\t\t}\n\t\treturn (nNextBtn != nBtn) ? nNextBtn : -1;\n\t}\n\n#if (_WIN32_IE >= 0x0500)\n\tbool DisplayChevronMenu()\n\t{\n\t\t// assume we are in a rebar\n\t\tHWND hWndReBar = GetParent();\n\t\tint nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);\n\t\tbool bRet = false;\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tREBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE };\n\t\t\tBOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi);\n\t\t\tif(bRetBandInfo && rbbi.hwndChild == m_hWnd)\n\t\t\t{\n\t\t\t\tif((rbbi.fStyle & RBBS_USECHEVRON) != 0)\n\t\t\t\t{\n\t\t\t\t\t::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L);\n\t\t\t\t\tPostMessage(WM_KEYDOWN, VK_DOWN, 0L);\n\t\t\t\t\tbRet = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn bRet;\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n\n\tvoid GetSystemSettings()\n\t{\n\t\t// refresh our font\n\t\tNONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tBOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);\n\t\tATLASSERT(bRet);\n\t\tif(bRet)\n\t\t{\n\t\t\tLOGFONT logfont = { 0 };\n\t\t\tif(m_fontMenu.m_hFont != NULL)\n\t\t\t\tm_fontMenu.GetLogFont(logfont);\n\t\t\tif(logfont.lfHeight != info.lfMenuFont.lfHeight ||\n\t\t\t   logfont.lfWidth != info.lfMenuFont.lfWidth ||\n\t\t\t   logfont.lfEscapement != info.lfMenuFont.lfEscapement ||\n\t\t\t   logfont.lfOrientation != info.lfMenuFont.lfOrientation ||\n\t\t\t   logfont.lfWeight != info.lfMenuFont.lfWeight ||\n\t\t\t   logfont.lfItalic != info.lfMenuFont.lfItalic ||\n\t\t\t   logfont.lfUnderline != info.lfMenuFont.lfUnderline ||\n\t\t\t   logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||\n\t\t\t   logfont.lfCharSet != info.lfMenuFont.lfCharSet ||\n\t\t\t   logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||\n\t\t\t   logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||\n\t\t\t   logfont.lfQuality != info.lfMenuFont.lfQuality ||\n\t\t\t   logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||\n\t\t\t   lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)\n\t\t\t{\n\t\t\t\tHFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);\n\t\t\t\tATLASSERT(hFontMenu != NULL);\n\t\t\t\tif(hFontMenu != NULL)\n\t\t\t\t{\n\t\t\t\t\tif(m_fontMenu.m_hFont != NULL)\n\t\t\t\t\t\tm_fontMenu.DeleteObject();\n\t\t\t\t\tm_fontMenu.Attach(hFontMenu);\n\t\t\t\t\tSetFont(m_fontMenu);\n\t\t\t\t\tAddStrings(_T(\"NS\\0\"));   // for proper item height\n\t\t\t\t\tAutoSize();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// check if we need extra spacing for menu item text\n\t\tCWindowDC dc(m_hWnd);\n\t\tHFONT hFontOld = dc.SelectFont(m_fontMenu);\n\t\tRECT rcText = { 0 };\n\t\tdc.DrawText(_T(\"\\t\"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\n\t\tif((rcText.right - rcText.left) < 4)\n\t\t{\n\t\t\t::SetRectEmpty(&rcText);\n\t\t\tdc.DrawText(_T(\"x\"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);\n\t\t\tm_cxExtraSpacing = rcText.right - rcText.left;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_cxExtraSpacing = 0;\n\t\t}\n\t\tdc.SelectFont(hFontOld);\n\n\t\t// get Windows version\n#ifndef _versionhelpers_H_INCLUDED_\n\t\tOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\t\t::GetVersionEx(&ovi);\n#endif // !_versionhelpers_H_INCLUDED_\n\n\t\t// query keyboard cues mode (Windows 2000 or later)\n#ifdef _versionhelpers_H_INCLUDED_\n\t\tif(::IsWindowsVersionOrGreater(5, 0, 0))\n#else // !_versionhelpers_H_INCLUDED_\n\t\tif (ovi.dwMajorVersion >= 5)\n#endif // _versionhelpers_H_INCLUDED_\n\t\t{\n#ifndef SPI_GETKEYBOARDCUES\n\t\t\tconst UINT SPI_GETKEYBOARDCUES = 0x100A;\n#endif // !SPI_GETKEYBOARDCUES\n\t\t\tBOOL bRetVal = TRUE;\n\t\t\tbRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0);\n\t\t\tm_bUseKeyboardCues = (bRet && !bRetVal);\n\t\t\tm_bAllowKeyboardCues = true;\n\t\t\tShowKeyboardCues(!m_bUseKeyboardCues);\n\t\t}\n\n\t\t// query flat menu mode (Windows XP or later)\n#ifdef _versionhelpers_H_INCLUDED_\n\t\tif(::IsWindowsXPOrGreater())\n#else // !_versionhelpers_H_INCLUDED_\n\t\tif ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))\n#endif // _versionhelpers_H_INCLUDED_\n\t\t{\n#ifndef SPI_GETFLATMENU\n\t\t\tconst UINT SPI_GETFLATMENU = 0x1022;\n#endif // !SPI_GETFLATMENU\n\t\t\tBOOL bRetVal = FALSE;\n\t\t\tbRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0);\n\t\t\tm_bFlatMenus = (bRet && bRetVal);\n\t\t}\n\n#if _WTL_CMDBAR_VISTA_MENUS\n\t\t// check if we should use Vista menus\n\t\tbool bVistaMenus = (((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0) && RunTimeHelper::IsVista() && RunTimeHelper::IsThemeAvailable());\n\t\tif(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0))\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_RemoveVistaBitmapsFromMenu();\n\t\t}\n\n\t\tm_bVistaMenus = bVistaMenus;\n#endif // _WTL_CMDBAR_VISTA_MENUS\n\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CmdBar - GetSystemSettings:\\n     m_bFlatMenus = %s\\n     m_bUseKeyboardCues = %s     m_bVistaMenus = %s\\n\"),\n\t\t\tm_bFlatMenus ? \"true\" : \"false\", m_bUseKeyboardCues ? \"true\" : \"false\", m_bVistaMenus ? \"true\" : \"false\");\n#endif\n\t}\n\n// Implementation - alternate focus mode support\n\tvoid TakeFocus()\n\t{\n\t\tif((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL)\n\t\t\tm_hWndFocus = ::GetFocus();\n\t\tSetFocus();\n\t}\n\n\tvoid GiveFocusBack()\n\t{\n\t\tif(m_bParentActive)\n\t\t{\n\t\t\tif((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus))\n\t\t\t\t::SetFocus(m_hWndFocus);\n\t\t\telse if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow())\n\t\t\t\tm_wndParent.SetFocus();\n\t\t}\n\t\tm_hWndFocus = NULL;\n\t\tSetAnchorHighlight(FALSE);\n\t\tif(m_bUseKeyboardCues && m_bShowKeyboardCues)\n\t\t\tShowKeyboardCues(false);\n\t\tm_bSkipPostDown = false;\n\t}\n\n\tvoid ShowKeyboardCues(bool bShow)\n\t{\n\t\tm_bShowKeyboardCues = bShow;\n\t\tSetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX);\n\t\tInvalidate();\n\t\tUpdateWindow();\n\t}\n\n// Implementation - internal message helpers\n\tstatic UINT GetAutoPopupMessage()\n\t{\n\t\tstatic UINT uAutoPopupMessage = 0;\n\t\tif(uAutoPopupMessage == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uAutoPopupMessage == 0)\n\t\t\t\tuAutoPopupMessage = ::RegisterWindowMessage(_T(\"WTL_CmdBar_InternalAutoPopupMsg\"));\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uAutoPopupMessage != 0);\n\t\treturn uAutoPopupMessage;\n\t}\n\n\tstatic UINT GetGetBarMessage()\n\t{\n\t\tstatic UINT uGetBarMessage = 0;\n\t\tif(uGetBarMessage == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uGetBarMessage == 0)\n\t\t\t\tuGetBarMessage = ::RegisterWindowMessage(_T(\"WTL_CmdBar_InternalGetBarMsg\"));\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uGetBarMessage != 0);\n\t\treturn uGetBarMessage;\n\t}\n\n// Implementation\n\tbool CreateInternalImageList(int cImages)\n\t{\n\t\tUINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK;\n\t\tm_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1);\n\t\tATLASSERT(m_hImageList != NULL);\n\t\treturn (m_hImageList != NULL);\n\t}\n\n// Implementation - support for Vista menus\n#if _WTL_CMDBAR_VISTA_MENUS\n\tvoid _AddVistaBitmapsFromImageList(int nStartIndex, int nCount)\n\t{\n\t\t// Create display compatible memory DC\n\t\tCClientDC dc(NULL);\n\t\tCDC dcMem;\n\t\tdcMem.CreateCompatibleDC(dc);\n\t\tHBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\n\n\t\tT* pT = static_cast<T*>(this);\n\t\t// Create bitmaps for all menu items\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tHBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, dc, dcMem);\n\t\t\tdcMem.SelectBitmap(hBitmapSave);\n\t\t\tm_arrVistaBitmap.Add(hBitmap);\n\t\t}\n\t}\n\n\tvoid _AddVistaBitmapFromImageList(int nIndex)\n\t{\n\t\t// Create display compatible memory DC\n\t\tCClientDC dc(NULL);\n\t\tCDC dcMem;\n\t\tdcMem.CreateCompatibleDC(dc);\n\t\tHBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\n\n\t\t// Create bitmap for menu item\n\t\tT* pT = static_cast<T*>(this);\n\t\tHBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);\n\n\t\t// Select saved bitmap back and add bitmap to the array\n\t\tdcMem.SelectBitmap(hBitmapSave);\n\t\tm_arrVistaBitmap.Add(hBitmap);\n\t}\n\n\tvoid _ReplaceVistaBitmapFromImageList(int nIndex)\n\t{\n\t\t// Delete existing bitmap\n\t\tif(m_arrVistaBitmap[nIndex] != NULL)\n\t\t\t::DeleteObject(m_arrVistaBitmap[nIndex]);\n\n\t\t// Create display compatible memory DC\n\t\tCClientDC dc(NULL);\n\t\tCDC dcMem;\n\t\tdcMem.CreateCompatibleDC(dc);\n\t\tHBITMAP hBitmapSave = dcMem.GetCurrentBitmap();\n\n\t\t// Create bitmap for menu item\n\t\tT* pT = static_cast<T*>(this);\n\t\tHBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);\n\n\t\t// Select saved bitmap back and replace bitmap in the array\n\t\tdcMem.SelectBitmap(hBitmapSave);\n\t\tm_arrVistaBitmap.SetAtIndex(nIndex, hBitmap);\n\t}\n\n\tHBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget)\n\t{\n\t\t// Create 32-bit bitmap\n\t\tBITMAPINFO bi = { 0 };\n\t\tbi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n\t\tbi.bmiHeader.biWidth = m_szBitmap.cx;\n\t\tbi.bmiHeader.biHeight = m_szBitmap.cy;\n\t\tbi.bmiHeader.biPlanes = 1;\n\t\tbi.bmiHeader.biBitCount = 32;\n\t\tbi.bmiHeader.biCompression = BI_RGB;\n\t\tbi.bmiHeader.biSizeImage = 0;\n\t\tbi.bmiHeader.biXPelsPerMeter = 0;\n\t\tbi.bmiHeader.biYPelsPerMeter = 0;\n\t\tbi.bmiHeader.biClrUsed = 0;\n\t\tbi.bmiHeader.biClrImportant = 0;\n\t\tHBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0);\n\t\tATLASSERT(hBitmap != NULL);\n\n\t\t// Select bitmap into target DC and draw from image list to it\n\t\tif(hBitmap != NULL)\n\t\t{\n\t\t\t::SelectObject(hDCTarget, hBitmap);\n\n\t\t\tIMAGELISTDRAWPARAMS ildp = { 0 };\n\t\t\tildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);\n\t\t\tildp.himl = m_hImageList;\n\t\t\tildp.i = nIndex;\n\t\t\tildp.hdcDst = hDCTarget;\n\t\t\tildp.x = 0;\n\t\t\tildp.y = 0;\n\t\t\tildp.cx = 0;\n\t\t\tildp.cy = 0;\n\t\t\tildp.xBitmap = 0;\n\t\t\tildp.yBitmap = 0;\n\t\t\tildp.fStyle = ILD_TRANSPARENT;\n\t\t\tildp.fState = ILS_ALPHA;\n\t\t\tildp.Frame = 255;\n\t\t\t::ImageList_DrawIndirect(&ildp);\n\t\t}\n\n\t\treturn hBitmap;\n\t}\n\n\tvoid _RemoveVistaBitmapsFromMenu()\n\t{\n\t\tCMenuHandle menu = m_hMenu;\n\t\tfor(int i = 0; i < m_arrCommand.GetSize(); i++)\n\t\t{\n\t\t\tCMenuItemInfo mii;\n\t\t\tmii.fMask = MIIM_BITMAP;\n\t\t\tmii.hbmpItem = NULL;\n\t\t\tmenu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii);\n\t\t}\n\t}\n#endif // _WTL_CMDBAR_VISTA_MENUS\n};\n\n\nclass CCommandBarCtrl : public CCommandBarCtrlImpl<CCommandBarCtrl>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_CommandBar\"), GetWndClassName())\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps\n\ntemplate <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits>\n{\npublic:\n// Data members\n\tATL::CContainedWindow m_wndMDIClient;\n\tbool m_bChildMaximized;\n\tHWND m_hWndChildMaximized;\n\tHICON m_hIconChildMaximized;\n\tint m_nBtnPressed;\n\tint m_nBtnWasPressed;\n\n\tint m_cxyOffset;      // offset between nonclient elements\n\tint m_cxIconWidth;    // small icon width\n\tint m_cyIconHeight;   // small icon height\n\tint m_cxBtnWidth;     // nonclient button width\n\tint m_cyBtnHeight;    // nonclient button height\n\tint m_cxLeft;         // left nonclient area width\n\tint m_cxRight;        // right nonclient area width\n\n// Theme declarations and data members\n#ifndef _WTL_NO_AUTO_THEME\n#ifndef _UXTHEME_H_\n\ttypedef HANDLE HTHEME;\n#endif // !_UXTHEME_H_\n\ttypedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList);\n\ttypedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme);\n\ttypedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);\n\ttypedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc);\n\n\tHMODULE m_hThemeDLL;\n\tHTHEME m_hTheme;\n\tPFN_DrawThemeBackground m_pfnDrawThemeBackground;\n\tPFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground;\n#endif // !_WTL_NO_AUTO_THEME\n\n// Constructor/destructor\n\tCMDICommandBarCtrlImpl() : \n\t\t\tm_wndMDIClient(this, 2), m_bChildMaximized(false), \n\t\t\tm_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL), \n\t\t\tm_nBtnPressed(-1), m_nBtnWasPressed(-1),\n#ifndef _WTL_NO_AUTO_THEME\n\t\t\tm_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL), \n#endif // !_WTL_NO_AUTO_THEME\n\t\t\tm_cxyOffset(2),\n\t\t\tm_cxIconWidth(16), m_cyIconHeight(16),\n\t\t\tm_cxBtnWidth(16), m_cyBtnHeight(14),\n\t\t\tm_cxLeft(20), m_cxRight(55)\n\t{ }\n\n\t~CMDICommandBarCtrlImpl()\n\t{\n\t\tif(m_wndMDIClient.IsWindow())\n/*scary!*/\t\t\tm_wndMDIClient.UnsubclassWindow();\n\t}\n\n// Operations\n\tBOOL SetMDIClient(HWND hWndMDIClient)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(::IsWindow(hWndMDIClient));\n\t\tif(!::IsWindow(hWndMDIClient))\n\t\t\treturn FALSE;\n\n#ifdef _DEBUG\n\t\t// BLOCK: Test if the passed window is MDICLIENT\n\t\t{\n\t\t\tLPCTSTR lpszMDIClientClass = _T(\"MDICLIENT\");\n\t\t\tconst int nNameLen = 9 + 1;   // \"MDICLIENT\" + NULL\n\t\t\tTCHAR szClassName[nNameLen] = { 0 };\n\t\t\t::GetClassName(hWndMDIClient, szClassName, nNameLen);\n\t\t\tATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0);\n\t\t}\n#endif // _DEBUG\n\n\t\tif(m_wndMDIClient.IsWindow())\n/*scary!*/\t\tm_wndMDIClient.UnsubclassWindow();\n\n\t\treturn m_wndMDIClient.SubclassWindow(hWndMDIClient);\n\t}\n\n// Message maps\n\ttypedef CCommandBarCtrlImpl< T, TBase, TWinTraits >   _baseClass;\n\tBEGIN_MSG_MAP(CMDICommandBarCtrlImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n#ifndef _WTL_NO_AUTO_THEME\n\t\tMESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged)\n#endif // !_WTL_NO_AUTO_THEME\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)\n\t\tMESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)\n\t\tMESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)\n\t\tMESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tALT_MSG_MAP(1)   // Parent window messages\n\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)\n\t\tCHAIN_MSG_MAP_ALT(_baseClass, 1)\n\tALT_MSG_MAP(2)   // MDI client window messages\n\t\tMESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)\n\t\t// no chaining needed since this was moved from the base class here\n\tALT_MSG_MAP(3)   // Message hook messages\n\t\tMESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages)\n\t\tCHAIN_MSG_MAP_ALT(_baseClass, 3)\n\tEND_MSG_MAP()\n\n// Additional MDI message handlers\n\tLRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tLRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled);\n\t\tif(lRet == (LRESULT)-1)\n\t\t\treturn lRet;\n\n#ifndef _WTL_NO_AUTO_THEME\n\t\t// this will fail if theming is not supported\n\t\tm_hThemeDLL = ::LoadLibrary(_T(\"uxtheme.dll\"));\n\t\tif(m_hThemeDLL != NULL)\n\t\t{\n\t\t\tm_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, \"DrawThemeBackground\");\n\t\t\tATLASSERT(m_pfnDrawThemeBackground != NULL);\n\t\t\tif(m_pfnDrawThemeBackground != NULL)\n\t\t\t{\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->_OpenThemeData();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t::FreeLibrary(m_hThemeDLL);\n\t\t\t\tm_hThemeDLL = NULL;\n\t\t\t}\n\t\t\tm_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, \"DrawThemeParentBackground\");\n\t\t\tATLASSERT(m_pfnDrawThemeParentBackground != NULL);\n\t\t}\n#endif // !_WTL_NO_AUTO_THEME\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tLRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled);\n\n#ifndef _WTL_NO_AUTO_THEME\n\t\tif(m_hThemeDLL != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_CloseThemeData();\n\t\t\t::FreeLibrary(m_hThemeDLL);\n\t\t\tm_hThemeDLL = NULL;\n\t\t}\n#endif // !_WTL_NO_AUTO_THEME\n\n\t\treturn lRet;\n\t}\n\n#ifndef _WTL_NO_AUTO_THEME\n\tLRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_hThemeDLL != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->_CloseThemeData();\n\t\t\tpT->_OpenThemeData();\n\t\t}\n\t\treturn 0;\n\t}\n#endif // !_WTL_NO_AUTO_THEME\n\n\tLRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_AdjustBtnSize(GET_Y_LPARAM(lParam));\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\n\t\tif(m_bChildMaximized && (BOOL)wParam)\n\t\t{\n\t\t\tLPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam;\n\t\t\tif(m_bLayoutRTL)\n\t\t\t{\n\t\t\t\tlpParams->rgrc[0].left += m_cxRight;\n\t\t\t\tlpParams->rgrc[0].right -= m_cxLeft;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlpParams->rgrc[0].left += m_cxLeft;\n\t\t\t\tlpParams->rgrc[0].right -= m_cxRight;\n\t\t\t}\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\n\t\tif(!m_bChildMaximized)\n\t\t\treturn lRet;\n\n\t\tATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL);\n\n\t\t// get DC and window rectangle\n\t\tCWindowDC dc(m_hWnd);\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tint cxWidth = rect.right - rect.left;\n\t\tint cyHeight = rect.bottom - rect.top;\n\n\t\t// paint left side nonclient background and draw icon\n\t\t::SetRect(&rect, 0, 0, m_cxLeft, cyHeight);\n#ifndef _WTL_NO_AUTO_THEME\n\t\tif(m_hTheme != NULL)\n\t\t{\n\t\t\tif(m_pfnDrawThemeParentBackground != NULL)\n\t\t\t\tm_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);\n\t\t\telse\n\t\t\t\tdc.FillRect(&rect, COLOR_WINDOW);\n\t\t}\n\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t{\n\t\t\tif((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)\n\t\t\t\tdc.FillRect(&rect, COLOR_3DFACE);\n\t\t\telse\n\t\t\t\tdc.FillRect(&rect, COLOR_MENU);\n\t\t}\n\n\t\tRECT rcIcon = { 0 };\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_CalcIconRect(cxWidth, cyHeight, rcIcon);\n\t\tdc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight);\n\n\t\t// paint right side nonclient background\n\t\t::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight);\n#ifndef _WTL_NO_AUTO_THEME\n\t\tif(m_hTheme != NULL)\n\t\t{\n\t\t\tif(m_pfnDrawThemeParentBackground != NULL)\n\t\t\t{\n\t\t\t\t// this is to account for the left non-client area\n\t\t\t\tPOINT ptOrg = { 0, 0 };\n\t\t\t\tdc.GetViewportOrg(&ptOrg);\n\t\t\t\tdc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y);\n\t\t\t\t::OffsetRect(&rect, -m_cxLeft, 0);\n\n\t\t\t\tm_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);\n\n\t\t\t\t// restore\n\t\t\t\tdc.SetViewportOrg(ptOrg);\n\t\t\t\t::OffsetRect(&rect, m_cxLeft, 0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdc.FillRect(&rect, COLOR_3DFACE);\n\t\t\t}\n\t\t}\n\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t{\n\t\t\tif((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)\n\t\t\t\tdc.FillRect(&rect, COLOR_3DFACE);\n\t\t\telse\n\t\t\t\tdc.FillRect(&rect, COLOR_MENU);\n\t\t}\n\n\t\t// draw buttons\n\t\tRECT arrRect[3] = { 0 };\n\t\tpT->_CalcBtnRects(cxWidth, cyHeight, arrRect);\n\t\tpT->_DrawMDIButton(dc, arrRect, -1);   // draw all buttons\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(m_bChildMaximized)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tGetWindowRect(&rect);\n\t\t\tPOINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top };\n\t\t\tif(m_bLayoutRTL)\n\t\t\t{\n\t\t\t\tif((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft)))\n\t\t\t\t\tlRet = HTBORDER;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight)))\n\t\t\t\t\tlRet = HTBORDER;\n\t\t\t}\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bChildMaximized)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tATLASSERT(_DebugCheckChild());\n\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tpt.x -= rect.left;\n\t\tpt.y -= rect.top;\n\n\t\tRECT rcIcon = { 0 };\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);\n\t\tRECT arrRect[3] = { 0 };\n\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\n\n\t\tif(::PtInRect(&rcIcon, pt))\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonDown: icon\\n\"));\n#endif\n#ifndef TPM_VERPOSANIMATION\n\t\t\tconst UINT TPM_VERPOSANIMATION = 0x1000L;   // Menu animation flag\n#endif\n\t\t\tCMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);\n\t\t\tUINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |  \n\t\t\t\t(s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized);\n\n\t\t\t// eat next message if click is on the same button\n\t\t\t::OffsetRect(&rcIcon, rect.left, rect.top);\n\t\t\tMSG msg = { 0 };\n\t\t\tif(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt))\n\t\t\t\t::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE);\n\n\t\t\tif(uRet != 0)\n\t\t\t\t::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L);\n\t\t}\n\t\telse if(::PtInRect(&arrRect[0], pt))\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonDown: close button\\n\"));\n#endif\n\t\t\tm_nBtnWasPressed = m_nBtnPressed = 0;\n\t\t}\n\t\telse if(::PtInRect(&arrRect[1], pt))\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonDown: restore button\\n\"));\n#endif\n\t\t\tm_nBtnWasPressed = m_nBtnPressed = 1;\n\t\t}\n\t\telse if(::PtInRect(&arrRect[2], pt))\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonDown: minimize button\\n\"));\n#endif\n\t\t\tm_nBtnWasPressed = m_nBtnPressed = 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\t// draw the button state if it was pressed\n\t\tif(m_nBtnPressed != -1)\n\t\t{\n\t\t\tSetCapture();\n\t\t\tCWindowDC dc(m_hWnd);\n\t\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\n\t\t\tpT->_DrawMDIButton(dc, arrRect, m_nBtnPressed);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tClientToScreen(&pt);\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tpt.x -= rect.left;\n\t\tpt.y -= rect.top;\n\t\tRECT arrRect[3] = { 0 };\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\n\t\tint nOldBtnPressed = m_nBtnPressed;\n\t\tm_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1;\n\t\tif(nOldBtnPressed != m_nBtnPressed)\n\t\t{\n\t\t\tCWindowDC dc(m_hWnd);\n\t\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\n\t\t\tpT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tATLASSERT(_DebugCheckChild());\n\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tClientToScreen(&pt);\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tpt.x -= rect.left;\n\t\tpt.y -= rect.top;\n\n\t\tint nBtn = m_nBtnWasPressed;\n\t\tReleaseCapture();\n\n\t\tRECT arrRect[3] = { 0 };\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\n\t\tif(::PtInRect(&arrRect[nBtn], pt))\n\t\t{\n\t\t\tswitch(nBtn)\n\t\t\t{\n\t\t\tcase 0:\t\t// close\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonUp: close button\\n\"));\n#endif\n\t\t\t\t::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L);\n\t\t\t\tbreak;\n\t\t\tcase 1:\t\t// restore\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonUp: restore button\\n\"));\n#endif\n\t\t\t\t::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L);\n\t\t\t\tbreak;\n\t\t\tcase 2:\t\t// minimize\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - LButtonUp: minimize button\\n\"));\n#endif\n\t\t\t\t::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bChildMaximized || m_nBtnWasPressed != -1)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tATLASSERT(_DebugCheckChild());\n\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tpt.x -= rect.left;\n\t\tpt.y -= rect.top;\n\n\t\tRECT rcIcon = { 0 };\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);\n\t\tRECT arrRect[3] = { 0 };\n\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);\n\n\t\tif(::PtInRect(&rcIcon, pt))\n\t\t{\n\t\t\tCMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);\n\t\t\tUINT uDefID = menu.GetMenuDefaultItem();\n\t\t\tif(uDefID == (UINT)-1)\n\t\t\t\tuDefID = SC_CLOSE;\n\t\t\t::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bChildMaximized)\n\t\t{\n\t\t\tif(m_nBtnPressed != -1)\n\t\t\t{\n\t\t\t\tATLASSERT(m_nBtnPressed == m_nBtnWasPressed);   // must be\n\t\t\t\tm_nBtnPressed = -1;\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\tGetWindowRect(&rect);\n\t\t\t\tRECT arrRect[3] = { 0 };\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);\n\t\t\t\tCWindowDC dc(m_hWnd);\n\t\t\t\tpT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed);\n\t\t\t}\n\t\t\tm_nBtnWasPressed = -1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\t\treturn 0;\n\t}\n\n// Parent window message handlers\n\tLRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tm_bParentActive = (LOWORD(wParam) != WA_INACTIVE);\n\t\tRedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n// MDI client window message handlers\n\tLRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tm_wndMDIClient.DefWindowProc(uMsg, NULL, lParam);\n\t\tHMENU hOldMenu = GetMenu();\n\t\tBOOL bRet = AttachMenu((HMENU)wParam);\n\t\tbRet;   // avoid level 4 warning\n\t\tATLASSERT(bRet);\n\n#if (_WIN32_IE >= 0x0400)\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateRebarBandIdealSize();\n#endif // (_WIN32_IE >= 0x0400)\n\n\t\treturn (LRESULT)hOldMenu;\n\t}\n\n// All messages from the message hook\n\tLRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_ProcessAllHookMessages(uMsg, wParam, lParam);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n// Overrideables\n\t// override this to provide different ideal size\n\tvoid UpdateRebarBandIdealSize()\n\t{\n\t\t// assuming we are in a rebar, change ideal size to our size\n\t\t// we hope that if we are not in a rebar, nCount will be 0\n\t\tint nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tREBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };\n\t\t\t::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\n\t\t\tif(rbi.hwndChild == m_hWnd)\n\t\t\t{\n\t\t\t\trbi.fMask = RBBIM_IDEALSIZE;\n\t\t\t\trbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0;\n\t\t\t\tint nBtnCount = GetButtonCount();\n\t\t\t\tif(nBtnCount > 0)\n\t\t\t\t{\n\t\t\t\t\tRECT rect = { 0 };\n\t\t\t\t\tGetItemRect(nBtnCount - 1, &rect);\n\t\t\t\t\trbi.cxIdeal += rect.right;\n\t\t\t\t}\n\t\t\t\t::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// all hook messages - check for the maximized MDI child window change\n\tvoid _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)\n\t{\n\t\tif(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU)\n\t\t\treturn;\n\n\t\tBOOL bMaximized = FALSE;\n\t\tHWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);\n\t\tbool bMaxOld = m_bChildMaximized;\n\t\tm_bChildMaximized = (hWndChild != NULL && bMaximized);\n\t\tHICON hIconOld = m_hIconChildMaximized;\n\n\t\tif(m_bChildMaximized)\n\t\t{\n\t\t\tif(m_hWndChildMaximized != hWndChild)\n\t\t\t{\n\t\t\t\tATL::CWindow wnd = m_hWndChildMaximized = hWndChild;\n\t\t\t\tm_hIconChildMaximized = wnd.GetIcon(FALSE);\n\t\t\t\tif(m_hIconChildMaximized == NULL)\n\t\t\t\t{\n\t\t\t\t\tm_hIconChildMaximized = wnd.GetIcon(TRUE);\n\t\t\t\t\tif(m_hIconChildMaximized == NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// no icon set with WM_SETICON, get the class one\n// need conditional code because types don't match in winuser.h\n#ifdef _WIN64\n\t\t\t\t\t\tm_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM);\n#else\n\t\t\t\t\t\tm_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM));\n#endif\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_hWndChildMaximized = NULL;\n\t\t\tm_hIconChildMaximized = NULL;\n\t\t}\n\n\t\tif(bMaxOld != m_bChildMaximized)\n\t\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - All messages hook change: m_bChildMaximized = %s\\n\"), m_bChildMaximized ? \"true\" : \"false\");\n#endif\n\t\t\t// assuming we are in a rebar, change our size to accomodate new state\n\t\t\t// we hope that if we are not in a rebar, nCount will be 0\n\t\t\tint nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);\n\t\t\tint cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight);\n\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t{\n#if (_WIN32_IE >= 0x0500)\n\t\t\t\tREBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };\n\t\t\t\t::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\tif(rbi.hwndChild == m_hWnd)\n\t\t\t\t{\n\t\t\t\t\tif((rbi.fStyle & RBBS_USECHEVRON) != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\trbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;\n\t\t\t\t\t\trbi.cxMinChild += cxDiff;\n\t\t\t\t\t\trbi.cxIdeal += cxDiff;\n\t\t\t\t\t\t::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#elif (_WIN32_IE >= 0x0400)\n\t\t\t\tREBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };\n\t\t\t\t::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\tif(rbi.hwndChild == m_hWnd)\n\t\t\t\t{\n\t\t\t\t\trbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;\n\t\t\t\t\trbi.cxMinChild += cxDiff;\n\t\t\t\t\trbi.cxIdeal += cxDiff;\n\t\t\t\t\t::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#else // (_WIN32_IE < 0x0400)\n\t\t\t\tREBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE };\n\t\t\t\t::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\tif(rbi.hwndChild == m_hWnd)\n\t\t\t\t{\n\t\t\t\t\trbi.fMask = RBBIM_CHILDSIZE;\n\t\t\t\t\trbi.cxMinChild += cxDiff;\n\t\t\t\t\t::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#endif // (_WIN32_IE < 0x0400)\n\t\t\t}\n\t\t}\n\n\t\tif(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized)\n\t\t{\n\t\t\t// force size change and redraw everything\n\t\t\tRECT rect = { 0 };\n\t\t\tGetWindowRect(&rect);\n\t\t\t::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2);\n\t\t\tSetRedraw(FALSE);\n\t\t\tSetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE);\n\t\t\tSetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);\n\t\t\tSetRedraw(TRUE);\n\t\t\tRedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);\n\t\t}\n\t}\n\n// Implementation\n\tvoid GetSystemSettings()\n\t{\n#ifdef _CMDBAR_EXTRA_TRACE\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI CmdBar - GetSystemSettings\\n\"));\n#endif\n\t\t_baseClass::GetSystemSettings();\n\n\t\tNONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tBOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);\n\t\tATLASSERT(bRet);\n\t\tif(bRet)\n\t\t{\n\t\t\tm_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON);\n\t\t\tm_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON);\n\t\t\tm_cxLeft = m_cxIconWidth;\n\n#ifndef _WTL_NO_AUTO_THEME\n\t\t\tif(m_hTheme != NULL)\n\t\t\t{\n\t\t\t\tm_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset;\n\t\t\t\tm_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;\n\t\t\t\tm_cxRight = 3 * m_cxBtnWidth;\n\t\t\t}\n\t\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t\t{\n\t\t\t\tm_cxBtnWidth = info.iCaptionWidth - m_cxyOffset;\n\t\t\t\tm_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;\n\t\t\t\tm_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;\n\t\t\t}\n\t\t}\n\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_AdjustBtnSize(rect.bottom);\n\t}\n\n\tvoid _AdjustBtnSize(int cyHeight)\n\t{\n\t\tif(cyHeight > 1 && m_cyBtnHeight > cyHeight)\n\t\t{\n#ifndef _WTL_NO_AUTO_THEME\n\t\t\tif(m_hTheme != NULL)\n\t\t\t{\n\t\t\t\tm_cyBtnHeight = cyHeight;\n\t\t\t\tm_cxBtnWidth = cyHeight;\n\t\t\t\tm_cxRight = 3 * m_cxBtnWidth;\n\t\t\t}\n\t\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t\t{\n\t\t\t\tm_cyBtnHeight = cyHeight;\n\t\t\t\tm_cxBtnWidth = cyHeight + m_cxyOffset;\n\t\t\t\tm_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const\n\t{\n\t\tint xStart = (m_cxLeft - m_cxIconWidth) / 2;\n\t\tif(xStart < 0)\n\t\t\txStart = 0;\n\t\tint yStart = (cyHeight - m_cyIconHeight) / 2;\n\t\tif(yStart < 0)\n\t\t\tyStart = 0;\n\n\t\tif(bInvertX)\n\t\t\t::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight);\n\t\telse\n\t\t\t::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight);\n\t}\n\n\tvoid _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const\n\t{\n\t\tint yStart = (cyHeight - m_cyBtnHeight) / 2;\n\t\tif(yStart < 0)\n\t\t\tyStart = 0;\n\n\t\tRECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight };\n\t\tint nDirection = -1;\n\t\tif(bInvertX)\n\t\t{\n\t\t\t::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight);\n\t\t\tnDirection = 1;\n\t\t}\n\n\t\tarrRect[0] = rcBtn;\n#ifndef _WTL_NO_AUTO_THEME\n\t\tif(m_hTheme != NULL)\n\t\t\t::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);\n\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t\t::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0);\n\t\tarrRect[1] = rcBtn;\n\t\t::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);\n\t\tarrRect[2] = rcBtn;\n\t}\n\n\tvoid _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn)\n\t{\n#ifndef _WTL_NO_AUTO_THEME\n\t\tif(m_hTheme != NULL)\n\t\t{\n#if !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__)\n\t\t\tconst int WP_MDICLOSEBUTTON = 20;\n\t\t\tconst int CBS_NORMAL = 1;\n\t\t\tconst int CBS_PUSHED = 3;\n\t\t\tconst int CBS_DISABLED = 4;\n\t\t\tconst int WP_MDIRESTOREBUTTON = 22;\n\t\t\tconst int RBS_NORMAL = 1;\n\t\t\tconst int RBS_PUSHED = 3;\n\t\t\tconst int RBS_DISABLED = 4;\n\t\t\tconst int WP_MDIMINBUTTON = 16;\n\t\t\tconst int MINBS_NORMAL = 1;\n\t\t\tconst int MINBS_PUSHED = 3;\n\t\t\tconst int MINBS_DISABLED = 4;\n#endif // !defined(TMSCHEMA_H) && !defined(__VSSYM32_H__)\n\t\t\tif(nBtn == -1 || nBtn == 0)\n\t\t\t\tm_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL);\n\t\t\tif(nBtn == -1 || nBtn == 1)\n\t\t\t\tm_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL);\n\t\t\tif(nBtn == -1 || nBtn == 2)\n\t\t\t\tm_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL);\n\t\t}\n\t\telse\n#endif // !_WTL_NO_AUTO_THEME\n\t\t{\n\t\t\tif(nBtn == -1 || nBtn == 0)\n\t\t\t\tdc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0));\n\t\t\tif(nBtn == -1 || nBtn == 1)\n\t\t\t\tdc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0));\n\t\t\tif(nBtn == -1 || nBtn == 2)\n\t\t\t\tdc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0));\n\t\t}\n\t}\n\n#ifndef _WTL_NO_AUTO_THEME\n\tstatic UINT _GetThemeChangedMsg()\n\t{\n#ifndef WM_THEMECHANGED\n\t\tstatic const UINT WM_THEMECHANGED = 0x031A;\n#endif // !WM_THEMECHANGED\n\t\treturn WM_THEMECHANGED;\n\t}\n\n\tvoid _OpenThemeData()\n\t{\n\t\tATLASSERT(m_hThemeDLL != NULL);\n\n\t\tPFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, \"OpenThemeData\");\n\t\tATLASSERT(pfnOpenThemeData != NULL);\n\t\tif(pfnOpenThemeData != NULL)\n\t\t\tm_hTheme = pfnOpenThemeData(m_hWnd, L\"Window\");\n\t}\n\n\tvoid _CloseThemeData()\n\t{\n\t\tATLASSERT(m_hThemeDLL != NULL);\n\n\t\tif(m_hTheme == NULL)\n\t\t\treturn;   // nothing to do\n\n\t\tPFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, \"CloseThemeData\");\n\t\tATLASSERT(pfnCloseThemeData != NULL);\n\t\tif(pfnCloseThemeData != NULL)\n\t\t{\n\t\t\tpfnCloseThemeData(m_hTheme);\n\t\t\tm_hTheme = NULL;\n\t\t}\n\t}\n#endif // !_WTL_NO_AUTO_THEME\n\n\tbool _DebugCheckChild()\n\t{\n#ifdef _DEBUG\n\t\tBOOL bMaximized = FALSE;\n\t\tHWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);\n\t\treturn (bMaximized && hWndChild == m_hWndChildMaximized);\n#else // !_DEBUG\n\t\treturn true;\n#endif // !_DEBUG\n\t}\n};\n\nclass CMDICommandBarCtrl : public CMDICommandBarCtrlImpl<CMDICommandBarCtrl>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_MDICommandBar\"), GetWndClassName())\n};\n\n}; // namespace WTL\n\n#endif // __ATLCTRLW_H__\n"
  },
  {
    "path": "WTL/atlctrlx.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLCTRLX_H__\n#define __ATLCTRLX_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlctrlx.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLCTRLS_H__\n\t#error atlctrlx.h requires atlctrls.h to be included first\n#endif\n\n#ifndef WM_UPDATEUISTATE\n  #define WM_UPDATEUISTATE                0x0128\n#endif // !WM_UPDATEUISTATE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CBitmapButtonImpl<T, TBase, TWinTraits>\n// CBitmapButton\n// CCheckListViewCtrlImpl<T, TBase, TWinTraits>\n// CCheckListViewCtrl\n// CHyperLinkImpl<T, TBase, TWinTraits>\n// CHyperLink\n// CWaitCursor\n// CCustomWaitCursor\n// CMultiPaneStatusBarCtrlImpl<T, TBase>\n// CMultiPaneStatusBarCtrl\n// CPaneContainerImpl<T, TBase, TWinTraits>\n// CPaneContainer\n// CSortListViewImpl<T>\n// CSortListViewCtrlImpl<T, TBase, TWinTraits>\n// CSortListViewCtrl\n// CTabViewImpl<T, TBase, TWinTraits>\n// CTabView\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CBitmapButton - bitmap button implementation\n\n#ifndef _WIN32_WCE\n\n// bitmap button extended styles\n#define BMPBTN_HOVER            0x00000001\n#define BMPBTN_AUTO3D_SINGLE    0x00000002\n#define BMPBTN_AUTO3D_DOUBLE    0x00000004\n#define BMPBTN_AUTOSIZE         0x00000008\n#define BMPBTN_SHAREIMAGELISTS  0x00000010\n#define BMPBTN_AUTOFIRE         0x00000020\n#define BMPBTN_CHECK            0x00000040\n#define BMPBTN_AUTOCHECK        0x00000080\n\n// Note: BMPBTN_CHECK/BMPBTN_AUTOCHECK disables BN_DOUBLECLICKED,\n// BMPBTN_AUTOFIRE doesn't work with BMPBTN_CHECK/BMPBTN_AUTOCHECK\n\ntemplate <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\n\n\tenum\n\t{\n\t\t_nImageNormal = 0,\n\t\t_nImagePushed,\n\t\t_nImageFocusOrHover,\n\t\t_nImageDisabled,\n\n\t\t_nImageCount = 4,\n\t};\n\n\tenum\n\t{\n\t\tID_TIMER_FIRST = 1000,\n\t\tID_TIMER_REPEAT = 1001\n\t};\n\n\t// Bitmap button specific extended styles\n\tDWORD m_dwExtendedStyle;\n\n\tCImageList m_ImageList;\n\tint m_nImage[_nImageCount];\n\n\tCToolTipCtrl m_tip;\n\tLPTSTR m_lpstrToolTipText;\n\n\t// Internal states\n\tunsigned m_fMouseOver:1;\n\tunsigned m_fFocus:1;\n\tunsigned m_fPressed:1;\n\tunsigned m_fChecked:1;\n\n\n// Constructor/Destructor\n\tCBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : \n\t                  m_dwExtendedStyle(dwExtendedStyle), m_ImageList(hImageList), \n\t                  m_lpstrToolTipText(NULL),\n\t                  m_fMouseOver(0), m_fFocus(0), m_fPressed(0), m_fChecked(0)\n\t{\n\t\tm_nImage[_nImageNormal] = -1;\n\t\tm_nImage[_nImagePushed] = -1;\n\t\tm_nImage[_nImageFocusOrHover] = -1;\n\t\tm_nImage[_nImageDisabled] = -1;\n\n#ifdef _DEBUG\n\t\tif(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode())\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\\n\"));\n#endif // _DEBUG\n\t}\n\n\t~CBitmapButtonImpl()\n\t{\n\t\tif((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)\n\t\t\tm_ImageList.Destroy();\n\t\tdelete [] m_lpstrToolTipText;\n\t}\n\n\t// overridden to provide proper initialization\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tDWORD GetBitmapButtonExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\n#ifdef _DEBUG\n\t\tif(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode())\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\\n\"));\n#endif // _DEBUG\n\n\t\treturn dwPrevStyle;\n\t}\n\n\tHIMAGELIST GetImageList() const\n\t{\n\t\treturn m_ImageList;\n\t}\n\n\tHIMAGELIST SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tHIMAGELIST hImageListPrev = m_ImageList;\n\t\tm_ImageList = hImageList;\n\t\tif((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd))\n\t\t\tSizeToImage();\n\n\t\treturn hImageListPrev;\n\t}\n\n\tint GetToolTipTextLength() const\n\t{\n\t\treturn (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText);\n\t}\n\n\tbool GetToolTipText(LPTSTR lpstrText, int nLength) const\n\t{\n\t\tATLASSERT(lpstrText != NULL);\n\t\tif(m_lpstrToolTipText == NULL)\n\t\t\treturn false;\n\n\t\terrno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE);\n\n\t\treturn (nRet == 0 || nRet == STRUNCATE);\n\t}\n\n\tbool SetToolTipText(LPCTSTR lpstrText)\n\t{\n\t\tif(m_lpstrToolTipText != NULL)\n\t\t{\n\t\t\tdelete [] m_lpstrToolTipText;\n\t\t\tm_lpstrToolTipText = NULL;\n\t\t}\n\n\t\tif(lpstrText == NULL)\n\t\t{\n\t\t\tif(m_tip.IsWindow())\n\t\t\t\tm_tip.Activate(FALSE);\n\t\t\treturn true;\n\t\t}\n\n\t\tint cchLen = lstrlen(lpstrText) + 1;\n\t\tATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]);\n\t\tif(m_lpstrToolTipText == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText);\n\t\tif(m_tip.IsWindow())\n\t\t{\n\t\t\tm_tip.Activate(TRUE);\n\t\t\tm_tip.AddTool(m_hWnd, m_lpstrToolTipText);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool GetCheck() const\n\t{\n\t\treturn (m_fChecked == 1);\n\t}\n\n\tvoid SetCheck(bool bCheck, bool bUpdate = true)\n\t{\n\t\tm_fChecked = bCheck ? 1 : 0;\n\n\t\tif(bUpdate)\n\t\t{\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t}\n\n// Operations\n\tvoid SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1)\n\t{\n\t\tif(nNormal != -1)\n\t\t\tm_nImage[_nImageNormal] = nNormal;\n\t\tif(nPushed != -1)\n\t\t\tm_nImage[_nImagePushed] = nPushed;\n\t\tif(nFocusOrHover != -1)\n\t\t\tm_nImage[_nImageFocusOrHover] = nFocusOrHover;\n\t\tif(nDisabled != -1)\n\t\t\tm_nImage[_nImageDisabled] = nDisabled;\n\t}\n\n\tBOOL SizeToImage()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL);\n\t\tint cx = 0;\n\t\tint cy = 0;\n\t\tif(!m_ImageList.GetIconSize(cx, cy))\n\t\t\treturn FALSE;\n\t\treturn ResizeClient(cx, cy);\n\t}\n\n// Overrideables\n\tvoid DoPaint(CDCHandle dc)\n\t{\n\t\tATLASSERT(m_ImageList.m_hImageList != NULL);   // image list must be set\n\t\tATLASSERT(m_nImage[0] != -1);                  // main bitmap must be set\n\n\t\t// set bitmap according to the current button state\n\t\tbool bHover = IsHoverMode();\n\t\tbool bPressed = (m_fPressed == 1) || (IsCheckMode() && (m_fChecked == 1));\n\t\tint nImage = -1;\n\t\tif(!IsWindowEnabled())\n\t\t\tnImage = m_nImage[_nImageDisabled];\n\t\telse if(bPressed)\n\t\t\tnImage = m_nImage[_nImagePushed];\n\t\telse if((!bHover && (m_fFocus == 1)) || (bHover && (m_fMouseOver == 1)))\n\t\t\tnImage = m_nImage[_nImageFocusOrHover];\n\n\t\t// if none is set, use default one\n\t\tif(nImage == -1)\n\t\t\tnImage = m_nImage[_nImageNormal];\n\n\t\t// draw the button image\n\t\tbool bAuto3D = (m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0;\n\t\tint xyPos = (bPressed && bAuto3D && (m_nImage[_nImagePushed] == -1)) ? 1 : 0;\n\t\tm_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);\n\n\t\t// draw 3D border if required\n\t\tif(bAuto3D)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\n\t\t\tif(bPressed)\n\t\t\t\tdc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);\n\t\t\telse if(!bHover || (m_fMouseOver == 1))\n\t\t\t\tdc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);\n\n\t\t\tif(!bHover && (m_fFocus == 1))\n\t\t\t{\n\t\t\t\t::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));\n\t\t\t\tdc.DrawFocusRect(&rect);\n\t\t\t}\n\t\t}\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CBitmapButtonImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnFocus)\n\t\tMESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\n\t\tMESSAGE_HANDLER(WM_ENABLE, OnEnable)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)\n\t\tMESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n\t\tMESSAGE_HANDLER(WM_KEYUP, OnKeyUp)\n\t\tMESSAGE_HANDLER(WM_TIMER, OnTimer)\n\t\tMESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Init();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_tip.IsWindow())\n\t\t{\n\t\t\tm_tip.DestroyWindow();\n\t\t\tm_tip.m_hWnd = NULL;\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tMSG msg = { m_hWnd, uMsg, wParam, lParam };\n\t\tif(m_tip.IsWindow())\n\t\t\tm_tip.RelayEvent(&msg);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background needed\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tpT->DoPaint((HDC)wParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(m_hWnd);\n\t\t\tpT->DoPaint(dc.m_hDC);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tm_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;\n\t\tInvalidate();\n\t\tUpdateWindow();\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = 0;\n\t\tif(IsHoverMode())\n\t\t\tSetCapture();\n\t\telse\n\t\t\tlRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(::GetCapture() == m_hWnd)\n\t\t{\n\t\t\tm_fPressed = 1;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\tif(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && !IsCheckMode())\n\t\t{\n\t\t\tint nElapse = 250;\n\t\t\tint nDelay = 0;\n\t\t\tif(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))\n\t\t\t\tnElapse += nDelay * 250;   // all milli-seconds\n\t\t\tSetTimer(ID_TIMER_FIRST, nElapse);\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = 0;\n\t\tif(!IsHoverMode() && !IsCheckMode())\n\t\t\tlRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(::GetCapture() != m_hWnd)\n\t\t\tSetCapture();\n\t\tif(m_fPressed == 0)\n\t\t{\n\t\t\tm_fPressed = 1;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) && (m_fPressed == 1))\n\t\t\tSetCheck(!GetCheck(), false);\n\n\t\tLRESULT lRet = 0;\n\t\tif(!IsHoverMode() && !IsCheckMode())\n\t\t\tlRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(::GetCapture() == m_hWnd)\n\t\t{\n\t\t\tif((IsHoverMode() || IsCheckMode()) && (m_fPressed == 1))\n\t\t\t\t::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);\n\t\t\t::ReleaseCapture();\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_fPressed == 1)\n\t\t{\n\t\t\tm_fPressed = 0;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tInvalidate();\n\t\tUpdateWindow();\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(::GetCapture() == m_hWnd)\n\t\t{\n\t\t\tPOINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\t\tClientToScreen(&ptCursor);\n\t\t\tRECT rect = { 0 };\n\t\t\tGetWindowRect(&rect);\n\t\t\tunsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;\n\t\t\tif(m_fPressed != uPressed)\n\t\t\t{\n\t\t\t\tm_fPressed = uPressed;\n\t\t\t\tInvalidate();\n\t\t\t\tUpdateWindow();\n\t\t\t}\n\t\t}\n\t\telse if(IsHoverMode() && m_fMouseOver == 0)\n\t\t{\n\t\t\tm_fMouseOver = 1;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t\tStartTrackMouseLeave();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_fMouseOver == 1)\n\t\t{\n\t\t\tm_fMouseOver = 0;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam == VK_SPACE && IsHoverMode())\n\t\t\treturn 0;   // ignore if in hover mode\n\t\tif(wParam == VK_SPACE && m_fPressed == 0)\n\t\t{\n\t\t\tm_fPressed = 1;\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam == VK_SPACE && IsHoverMode())\n\t\t\treturn 0;   // ignore if in hover mode\n\t\tif(wParam == VK_SPACE && m_fPressed == 1)\n\t\t{\n\t\t\tm_fPressed = 0;\n\t\t\tif((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0)\n\t\t\t\tSetCheck(!GetCheck(), false);\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);\n\t\tswitch(wParam)   // timer ID\n\t\t{\n\t\tcase ID_TIMER_FIRST:\n\t\t\tKillTimer(ID_TIMER_FIRST);\n\t\t\tif(m_fPressed == 1)\n\t\t\t{\n\t\t\t\t::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);\n\t\t\t\tint nElapse = 250;\n\t\t\t\tint nRepeat = 40;\n\t\t\t\tif(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))\n\t\t\t\t\tnElapse = 10000 / (10 * nRepeat + 25);   // milli-seconds, approximated\n\t\t\t\tSetTimer(ID_TIMER_REPEAT, nElapse);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase ID_TIMER_REPEAT:\n\t\t\tif(m_fPressed == 1)\n\t\t\t\t::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);\n\t\t\telse if(::GetCapture() != m_hWnd)\n\t\t\t\tKillTimer(ID_TIMER_REPEAT);\n\t\t\tbreak;\n\t\tdefault:\t// not our timer\n\t\t\tbreak;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\t// If the control is subclassed or superclassed, this message can cause\n\t\t// repainting without WM_PAINT. We don't use this state, so just do nothing.\n\t\treturn 0;\n\t}\n\n// Implementation\n\tvoid Init()\n\t{\n\t\t// We need this style to prevent Windows from painting the button\n\t\tModifyStyle(0, BS_OWNERDRAW);\n\n\t\t// create a tool tip\n\t\tm_tip.Create(m_hWnd);\n\t\tATLASSERT(m_tip.IsWindow());\n\t\tif(m_tip.IsWindow() && m_lpstrToolTipText != NULL)\n\t\t{\n\t\t\tm_tip.Activate(TRUE);\n\t\t\tm_tip.AddTool(m_hWnd, m_lpstrToolTipText);\n\t\t}\n\n\t\tif(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0)\n\t\t\tSizeToImage();\n\t}\n\n\tBOOL StartTrackMouseLeave()\n\t{\n\t\tTRACKMOUSEEVENT tme = { 0 };\n\t\ttme.cbSize = sizeof(tme);\n\t\ttme.dwFlags = TME_LEAVE;\n\t\ttme.hwndTrack = m_hWnd;\n\t\treturn _TrackMouseEvent(&tme);\n\t}\n\n\tbool IsHoverMode() const\n\t{\n\t\treturn ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);\n\t}\n\n\tbool IsCheckMode() const\n\t{\n\t\treturn ((m_dwExtendedStyle & (BMPBTN_CHECK | BMPBTN_AUTOCHECK)) != 0);\n\t}\n};\n\nclass CBitmapButton : public CBitmapButtonImpl<CBitmapButton>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_BitmapButton\"), GetWndClassName())\n\n\tCBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : \n\t\tCBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)\n\t{ }\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCheckListCtrlView - list view control with check boxes\n\ntemplate <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>\nclass CCheckListViewCtrlImplTraits\n{\npublic:\n\tstatic DWORD GetWndStyle(DWORD dwStyle)\n\t{\n\t\treturn (dwStyle == 0) ? t_dwStyle : dwStyle;\n\t}\n\n\tstatic DWORD GetWndExStyle(DWORD dwExStyle)\n\t{\n\t\treturn (dwExStyle == 0) ? t_dwExStyle : dwExStyle;\n\t}\n\n\tstatic DWORD GetExtendedLVStyle()\n\t{\n\t\treturn t_dwExListViewStyle;\n\t}\n};\n\ntypedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT>   CCheckListViewCtrlTraits;\n\ntemplate <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits>\nclass ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, TWinTraits >\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\n\n// Attributes\n\tstatic DWORD GetExtendedLVStyle()\n\t{\n\t\treturn TWinTraits::GetExtendedLVStyle();\n\t}\n\n// Operations\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tvoid CheckSelectedItems(int nCurrItem)\n\t{\n\t\t// first check if this item is selected\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.iItem = nCurrItem;\n\t\tlvi.iSubItem = 0;\n\t\tlvi.mask = LVIF_STATE;\n\t\tlvi.stateMask = LVIS_SELECTED;\n\t\tGetItem(&lvi);\n\t\t// if item is not selected, don't do anything\n\t\tif(!(lvi.state & LVIS_SELECTED))\n\t\t\treturn;\n\t\t// new check state will be reverse of the current state,\n\t\tBOOL bCheck = !GetCheckState(nCurrItem);\n\t\tint nItem = -1;\n\t\tint nOldItem = -1;\n\t\twhile((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1)\n\t\t{\n\t\t\tif(nItem != nCurrItem)\n\t\t\t\tSetCheckState(nItem, bCheck);\n\t\t\tnOldItem = nItem;\n\t\t}\n\t}\n\n// Implementation\n\tvoid Init()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);\n\t\tSetExtendedListViewStyle(pT->GetExtendedLVStyle());\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CCheckListViewCtrlImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\t// first let list view control initialize everything\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(lRet == 0)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tPOINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tLVHITTESTINFO lvh = { 0 };\n\t\tlvh.pt = ptMsg;\n\t\tif(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CheckSelectedItems(lvh.iItem);\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam == VK_SPACE)\n\t\t{\n\t\t\tint nCurrItem = GetNextItem(-1, LVNI_FOCUSED);\n\t\t\tif(nCurrItem != -1  && ::GetKeyState(VK_CONTROL) >= 0)\n\t\t\t{\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->CheckSelectedItems(nCurrItem);\n\t\t\t}\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n};\n\nclass CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_CheckListView\"), GetWndClassName())\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CHyperLink - hyper link control implementation\n\n#if (WINVER < 0x0500) && !defined(_WIN32_WCE)\n__declspec(selectany) struct\n{\n\tenum { cxWidth = 32, cyHeight = 32 };\n\tint xHotSpot;\n\tint yHotSpot;\n\tunsigned char arrANDPlane[cxWidth * cyHeight / 8];\n\tunsigned char arrXORPlane[cxWidth * cyHeight / 8];\n} _AtlHyperLink_CursorData = \n{\n\t5, 0, \n\t{\n\t\t0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, \n\t\t0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, \n\t\t0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, \n\t\t0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, \n\t\t0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, \n\t\t0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n\t\t0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n\t\t0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF\n\t},\n\t{\n\t\t0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, \n\t\t0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, \n\t\t0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, \n\t\t0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, \n\t\t0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, \n\t\t0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t}\n};\n#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)\n\n#define HLINK_UNDERLINED           0x00000000\n#define HLINK_NOTUNDERLINED        0x00000001\n#define HLINK_UNDERLINEHOVER       0x00000002\n#define HLINK_COMMANDBUTTON        0x00000004\n#define HLINK_NOTIFYBUTTON         0x0000000C\n#define HLINK_USETAGS              0x00000010\n#define HLINK_USETAGSBOLD          0x00000030\n#define HLINK_NOTOOLTIP            0x00000040\n#define HLINK_AUTOCREATELINKFONT   0x00000080\n#define HLINK_SINGLELINE           0x00000100\n\n// Notes:\n// - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned\n// - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >\n{\npublic:\n\tLPTSTR m_lpstrLabel;\n\tLPTSTR m_lpstrHyperLink;\n\n\tHCURSOR m_hCursor;\n\tHFONT m_hFontLink;\n\tHFONT m_hFontNormal;\n\n\tRECT m_rcLink;\n#ifndef _WIN32_WCE\n\tCToolTipCtrl m_tip;\n#endif // !_WIN32_WCE\n\n\tCOLORREF m_clrLink;\n\tCOLORREF m_clrVisited;\n\n\tDWORD m_dwExtendedStyle;   // Hyper Link specific extended styles\n\n\tbool m_bPaintLabel:1;\n\tbool m_bVisited:1;\n\tbool m_bHover:1;\n\tbool m_bInternalLinkFont:1;\n\tbool m_bInternalNormalFont:1;\n\n\n// Constructor/Destructor\n\tCHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : \n\t\t\tm_lpstrLabel(NULL), m_lpstrHyperLink(NULL),\n\t\t\tm_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL),\n\t\t\tm_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),\n\t\t\tm_dwExtendedStyle(dwExtendedStyle),\n\t\t\tm_bPaintLabel(true), m_bVisited(false),\n\t\t\tm_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false)\n\t{\n\t\t::SetRectEmpty(&m_rcLink);\n\t}\n\n\t~CHyperLinkImpl()\n\t{\n\t\tdelete [] m_lpstrLabel;\n\t\tdelete [] m_lpstrHyperLink;\n#if (WINVER < 0x0500) && !defined(_WIN32_WCE)\n\t\t// It was created, not loaded, so we have to destroy it\n\t\tif(m_hCursor != NULL)\n\t\t\t::DestroyCursor(m_hCursor);\n#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)\n\t}\n\n// Attributes\n\tDWORD GetHyperLinkExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\t\treturn dwPrevStyle;\n\t}\n\n\tbool GetLabel(LPTSTR lpstrBuffer, int nLength) const\n\t{\n\t\tif(m_lpstrLabel == NULL)\n\t\t\treturn false;\n\t\tATLASSERT(lpstrBuffer != NULL);\n\t\tif(nLength <= lstrlen(m_lpstrLabel))\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel);\n\n\t\treturn true;\n\t}\n\n\tbool SetLabel(LPCTSTR lpstrLabel)\n\t{\n\t\tdelete [] m_lpstrLabel;\n\t\tm_lpstrLabel = NULL;\n\t\tint cchLen = lstrlen(lpstrLabel) + 1;\n\t\tATLTRY(m_lpstrLabel = new TCHAR[cchLen]);\n\t\tif(m_lpstrLabel == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcLabelRect();\n\n\t\tif(m_hWnd != NULL)\n\t\t\tSetWindowText(lpstrLabel);   // Set this for accessibility\n\n\t\treturn true;\n\t}\n\n\tbool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const\n\t{\n\t\tif(m_lpstrHyperLink == NULL)\n\t\t\treturn false;\n\t\tATLASSERT(lpstrBuffer != NULL);\n\t\tif(nLength <= lstrlen(m_lpstrHyperLink))\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink);\n\n\t\treturn true;\n\t}\n\n\tbool SetHyperLink(LPCTSTR lpstrLink)\n\t{\n\t\tdelete [] m_lpstrHyperLink;\n\t\tm_lpstrHyperLink = NULL;\n\t\tint cchLen = lstrlen(lpstrLink) + 1;\n\t\tATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]);\n\t\tif(m_lpstrHyperLink == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink);\n\t\tif(m_lpstrLabel == NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CalcLabelRect();\n\t\t}\n#ifndef _WIN32_WCE\n\t\tif(m_tip.IsWindow())\n\t\t{\n\t\t\tm_tip.Activate(TRUE);\n\t\t\tm_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);\n\t\t}\n#endif // !_WIN32_WCE\n\t\treturn true;\n\t}\n\n\tHFONT GetLinkFont() const\n\t{\n\t\treturn m_hFontLink;\n\t}\n\n\tvoid SetLinkFont(HFONT hFont)\n\t{\n\t\tif(m_bInternalLinkFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFontLink);\n\t\t\tm_bInternalLinkFont = false;\n\t\t}\n\n\t\tm_hFontLink = hFont;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcLabelRect();\n\t}\n\n\tint GetIdealHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tif(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)\n\t\t\treturn -1;\n\t\tif(!m_bPaintLabel)\n\t\t\treturn -1;\n\n\t\tUINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\n\t\tCClientDC dc(m_hWnd);\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\t\tHFONT hFontOld = dc.SelectFont(m_hFontNormal);\n\t\tRECT rcText = rect;\n\t\tdc.DrawText(_T(\"NS\"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT);\n\t\tdc.SelectFont(m_hFontLink);\n\t\tRECT rcLink = rect;\n\t\tdc.DrawText(_T(\"NS\"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);\n\t\tdc.SelectFont(hFontOld);\n\t\treturn __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top);\n\t}\n\n\tbool GetIdealSize(SIZE& size) const\n\t{\n\t\tint cx = 0, cy = 0;\n\t\tbool bRet = GetIdealSize(cx, cy);\n\t\tif(bRet)\n\t\t{\n\t\t\tsize.cx = cx;\n\t\t\tsize.cy = cy;\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tbool GetIdealSize(int& cx, int& cy) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tif(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)\n\t\t\treturn false;\n\t\tif(!m_bPaintLabel)\n\t\t\treturn false;\n\n\t\tCClientDC dc(m_hWnd);\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tRECT rcAll = rcClient;\n\n\t\tif(IsUsingTags())\n\t\t{\n\t\t\t// find tags and label parts\n\t\t\tLPTSTR lpstrLeft = NULL;\n\t\t\tint cchLeft = 0;\n\t\t\tLPTSTR lpstrLink = NULL;\n\t\t\tint cchLink = 0;\n\t\t\tLPTSTR lpstrRight = NULL;\n\t\t\tint cchRight = 0;\n\n\t\t\tconst T* pT = static_cast<const T*>(this);\n\t\t\tpT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);\n\n\t\t\t// get label part rects\n\t\t\tUINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\n\t\t\tHFONT hFontOld = dc.SelectFont(m_hFontNormal);\n\t\t\tRECT rcLeft = rcClient;\n\t\t\tdc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);\n\n\t\t\tdc.SelectFont(m_hFontLink);\n\t\t\tRECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom };\n\t\t\tdc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);\n\n\t\t\tdc.SelectFont(m_hFontNormal);\n\t\t\tRECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom };\n\t\t\tdc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT);\n\n\t\t\tdc.SelectFont(hFontOld);\n\n\t\t\tint cyMax = __max(rcLeft.bottom, __max(rcLink.bottom, rcRight.bottom));\n\t\t\t::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tHFONT hOldFont = NULL;\n\t\t\tif(m_hFontLink != NULL)\n\t\t\t\thOldFont = dc.SelectFont(m_hFontLink);\n\t\t\tLPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;\n\t\t\tDWORD dwStyle = GetStyle();\n\t\t\tUINT uFormat = DT_LEFT;\n\t\t\tif (dwStyle & SS_CENTER)\n\t\t\t\tuFormat = DT_CENTER;\n\t\t\telse if (dwStyle & SS_RIGHT)\n\t\t\t\tuFormat = DT_RIGHT;\n\t\t\tuFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\t\t\tdc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT);\n\t\t\tif(m_hFontLink != NULL)\n\t\t\t\tdc.SelectFont(hOldFont);\n\t\t\tif (dwStyle & SS_CENTER)\n\t\t\t{\n\t\t\t\tint dx = (rcClient.right - rcAll.right) / 2;\n\t\t\t\t::OffsetRect(&rcAll, dx, 0);\n\t\t\t}\n\t\t\telse if (dwStyle & SS_RIGHT)\n\t\t\t{\n\t\t\t\tint dx = rcClient.right - rcAll.right;\n\t\t\t\t::OffsetRect(&rcAll, dx, 0);\n\t\t\t}\n\t\t}\n\n\t\tcx = rcAll.right - rcAll.left;\n\t\tcy = rcAll.bottom - rcAll.top;\n\n\t\treturn true;\n\t}\n\n\t// for command buttons only\n\tbool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const\n\t{\n\t\tATLASSERT(IsCommandButton());\n\t\treturn GetHyperLink(lpstrBuffer, nLength);\n\t}\n\n\tbool SetToolTipText(LPCTSTR lpstrToolTipText)\n\t{\n\t\tATLASSERT(IsCommandButton());\n\t\treturn SetHyperLink(lpstrToolTipText);\n\t}\n\n// Operations\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tif(m_hFontNormal == NULL)\n\t\t\tm_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);\n\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tbool Navigate()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tbool bRet = true;\n\t\tif(IsNotifyButton())\n\t\t{\n\t\t\tNMHDR nmhdr = { m_hWnd, (UINT_PTR)GetDlgCtrlID(), NM_CLICK };\n\t\t\t::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);\n\t\t}\n\t\telse if(IsCommandButton())\n\t\t{\n\t\t\t::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(m_lpstrHyperLink != NULL);\n#ifndef _WIN32_WCE\n\t\t\tDWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T(\"open\"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);\n\t\t\tbRet = (dwRet > 32);\n#else // CE specific\n\t\t\tSHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L\"open\", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 };\n\t\t\t::ShellExecuteEx(&shExeInfo);\n\t\t\tDWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp;\n\t\t\tbRet = (dwRet == 0) || (dwRet > 32);\n#endif // _WIN32_WCE\n\t\t\tATLASSERT(bRet);\n\t\t\tif(bRet)\n\t\t\t{\n\t\t\t\tm_bVisited = true;\n\t\t\t\tInvalidate();\n\t\t\t}\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tvoid CreateLinkFontFromNormal()\n\t{\n\t\tif(m_bInternalLinkFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFontLink);\n\t\t\tm_bInternalLinkFont = false;\n\t\t}\n\n\t\tCFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT);\n\t\tLOGFONT lf = { 0 };\n\t\tfont.GetLogFont(&lf);\n\n\t\tif(IsUsingTagsBold())\n\t\t\tlf.lfWeight = FW_BOLD;\n\t\telse if(!IsNotUnderlined())\n\t\t\tlf.lfUnderline = TRUE;\n\n\t\tm_hFontLink = ::CreateFontIndirect(&lf);\n\t\tm_bInternalLinkFont = true;\n\t\tATLASSERT(m_hFontLink != NULL);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CHyperLinkImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnFocus)\n\t\tMESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CHAR, OnChar)\n\t\tMESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)\n\t\tMESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)\n\t\tMESSAGE_HANDLER(WM_ENABLE, OnEnable)\n\t\tMESSAGE_HANDLER(WM_GETFONT, OnGetFont)\n\t\tMESSAGE_HANDLER(WM_SETFONT, OnSetFont)\n\t\tMESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Init();\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_tip.IsWindow())\n\t\t{\n\t\t\tm_tip.DestroyWindow();\n\t\t\tm_tip.m_hWnd = NULL;\n\t\t}\n\n\t\tif(m_bInternalLinkFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFontLink);\n\t\t\tm_hFontLink = NULL;\n\t\t\tm_bInternalLinkFont = false;\n\t\t}\n\n\t\tif(m_bInternalNormalFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFontNormal);\n\t\t\tm_hFontNormal = NULL;\n\t\t\tm_bInternalNormalFont = false;\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tMSG msg = { m_hWnd, uMsg, wParam, lParam };\n\t\tif(m_tip.IsWindow() && IsUsingToolTip())\n\t\t\tm_tip.RelayEvent(&msg);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n#endif // !_WIN32_WCE\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background painting needed (we do it all during WM_PAINT)\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(!m_bPaintLabel)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tpT->DoEraseBackground((HDC)wParam);\n\t\t\tpT->DoPaint((HDC)wParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(m_hWnd);\n\t\t\tpT->DoEraseBackground(dc.m_hDC);\n\t\t\tpT->DoPaint(dc.m_hDC);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bPaintLabel)\n\t\t\tInvalidate();\n\t\telse\n\t\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tif((m_lpstrHyperLink != NULL  || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))\n\t\t{\n\t\t\t::SetCursor(m_hCursor);\n\t\t\tif(IsUnderlineHover())\n\t\t\t{\n\t\t\t\tif(!m_bHover)\n\t\t\t\t{\n\t\t\t\t\tm_bHover = true;\n\t\t\t\t\tInvalidateRect(&m_rcLink);\n\t\t\t\t\tUpdateWindow();\n#ifndef _WIN32_WCE\n\t\t\t\t\tStartTrackMouseLeave();\n#endif // !_WIN32_WCE\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(IsUnderlineHover())\n\t\t\t{\n\t\t\t\tif(m_bHover)\n\t\t\t\t{\n\t\t\t\t\tm_bHover = false;\n\t\t\t\t\tInvalidateRect(&m_rcLink);\n\t\t\t\t\tUpdateWindow();\n\t\t\t\t}\n\t\t\t}\n\t\t\tbHandled = FALSE;\n\t\t}\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(IsUnderlineHover() && m_bHover)\n\t\t{\n\t\t\tm_bHover = false;\n\t\t\tInvalidateRect(&m_rcLink);\n\t\t\tUpdateWindow();\n\t\t}\n\t\treturn 0;\n\t}\n#endif // !_WIN32_WCE\n\n\tLRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\tif(::PtInRect(&m_rcLink, pt))\n\t\t{\n\t\t\tSetFocus();\n\t\t\tSetCapture();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(GetCapture() == m_hWnd)\n\t\t{\n\t\t\tReleaseCapture();\n\t\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\t\tif(::PtInRect(&m_rcLink, pt))\n\t\t\t{\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->Navigate();\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(wParam == VK_RETURN || wParam == VK_SPACE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Navigate();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn DLGC_WANTCHARS;\n\t}\n\n\tLRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tPOINT pt = { 0, 0 };\n\t\tGetCursorPos(&pt);\n\t\tScreenToClient(&pt);\n\t\tif((m_lpstrHyperLink != NULL  || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))\n\t\t{\n\t\t\treturn TRUE;\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn FALSE;\n\t}\n\n\tLRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tInvalidate();\n\t\tUpdateWindow();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)m_hFontNormal;\n\t}\n\n\tLRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_bInternalNormalFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFontNormal);\n\t\t\tm_bInternalNormalFont = false;\n\t\t}\n\n\t\tbool bCreateLinkFont = m_bInternalLinkFont;\n\n\t\tm_hFontNormal = (HFONT)wParam;\n\n\t\tif(bCreateLinkFont || IsAutoCreateLinkFont())\n\t\t\tCreateLinkFontFromNormal();\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcLabelRect();\n\n\t\tif((BOOL)lParam)\n\t\t{\n\t\t\tInvalidate();\n\t\t\tUpdateWindow();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\t// If the control is subclassed or superclassed, this message can cause\n\t\t// repainting without WM_PAINT. We don't use this state, so just do nothing.\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcLabelRect();\n\t\tpT->Invalidate();\n\t\treturn 0;\n\t}\n\n// Implementation\n\tvoid Init()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\t// Check if we should paint a label\n\t\tconst int cchBuff = 8;\n\t\tTCHAR szBuffer[cchBuff] = { 0 };\n\t\tif(::GetClassName(m_hWnd, szBuffer, cchBuff))\n\t\t{\n\t\t\tif(lstrcmpi(szBuffer, _T(\"static\")) == 0)\n\t\t\t{\n\t\t\t\tModifyStyle(0, SS_NOTIFY);   // we need this\n\t\t\t\tDWORD dwStyle = GetStyle() & 0x000000FF;\n#ifndef _WIN32_WCE\n\t\t\t\tif(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT || \n\t\t\t\t\t\tdwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME || \n\t\t\t\t\t\tdwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW || \n\t\t\t\t\t\tdwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE)\n#else // CE specific\n\t\t\t\tif(dwStyle == SS_ICON || dwStyle == SS_BITMAP)\n#endif // _WIN32_WCE\n\t\t\t\t\tm_bPaintLabel = false;\n\t\t\t}\n\t\t}\n\n\t\t// create or load a cursor\n#if (WINVER >= 0x0500) || defined(_WIN32_WCE)\n\t\tm_hCursor = ::LoadCursor(NULL, IDC_HAND);\n#else\n\t\tm_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane);\n#endif\n\t\tATLASSERT(m_hCursor != NULL);\n\n\t\t// set fonts\n\t\tif(m_bPaintLabel)\n\t\t{\n\t\t\tif(m_hFontNormal == NULL)\n\t\t\t{\n\t\t\t\tm_hFontNormal = AtlCreateControlFont();\n\t\t\t\tm_bInternalNormalFont = true;\n\t\t\t}\n\n\t\t\tif(m_hFontLink == NULL)\n\t\t\t\tCreateLinkFontFromNormal();\n\t\t}\n\n#ifndef _WIN32_WCE\n\t\t// create a tool tip\n\t\tm_tip.Create(m_hWnd);\n\t\tATLASSERT(m_tip.IsWindow());\n#endif // !_WIN32_WCE\n\n\t\t// set label (defaults to window text)\n\t\tif(m_lpstrLabel == NULL)\n\t\t{\n\t\t\tint nLen = GetWindowTextLength();\n\t\t\tif(nLen > 0)\n\t\t\t{\n\t\t\t\tATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]);\n\t\t\t\tif(m_lpstrLabel != NULL)\n\t\t\t\t\tATLVERIFY(GetWindowText(m_lpstrLabel, nLen + 1) > 0);\n\t\t\t}\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcLabelRect();\n\n\t\t// set hyperlink (defaults to label), or just activate tool tip if already set\n\t\tif(m_lpstrHyperLink == NULL && !IsCommandButton())\n\t\t{\n\t\t\tif(m_lpstrLabel != NULL)\n\t\t\t\tSetHyperLink(m_lpstrLabel);\n\t\t}\n#ifndef _WIN32_WCE\n\t\telse\n\t\t{\n\t\t\tm_tip.Activate(TRUE);\n\t\t\tm_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);\n\t\t}\n#endif // !_WIN32_WCE\n\n\t\t// set link colors\n\t\tif(m_bPaintLabel)\n\t\t{\n\t\t\tCRegKeyEx rk;\n\t\t\tLONG lRet = rk.Open(HKEY_CURRENT_USER, _T(\"Software\\\\Microsoft\\\\Internet Explorer\\\\Settings\"));\n\t\t\tif(lRet == ERROR_SUCCESS)\n\t\t\t{\n\t\t\t\tconst int cchValue = 12;\n\t\t\t\tTCHAR szValue[cchValue] = { 0 };\n\t\t\t\tULONG ulCount = cchValue;\n\t\t\t\tlRet = rk.QueryStringValue(_T(\"Anchor Color\"), szValue, &ulCount);\n\t\t\t\tif(lRet == ERROR_SUCCESS)\n\t\t\t\t{\n\t\t\t\t\tCOLORREF clr = pT->_ParseColorString(szValue);\n\t\t\t\t\tATLASSERT(clr != CLR_INVALID);\n\t\t\t\t\tif(clr != CLR_INVALID)\n\t\t\t\t\t\tm_clrLink = clr;\n\t\t\t\t}\n\n\t\t\t\tulCount = cchValue;\n\t\t\t\tlRet = rk.QueryStringValue(_T(\"Anchor Color Visited\"), szValue, &ulCount);\n\t\t\t\tif(lRet == ERROR_SUCCESS)\n\t\t\t\t{\n\t\t\t\t\tCOLORREF clr = pT->_ParseColorString(szValue);\n\t\t\t\t\tATLASSERT(clr != CLR_INVALID);\n\t\t\t\t\tif(clr != CLR_INVALID)\n\t\t\t\t\t\tm_clrVisited = clr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic COLORREF _ParseColorString(LPTSTR lpstr)\n\t{\n\t\tint c[3] = { -1, -1, -1 };\n\t\tLPTSTR p = NULL;\n\t\tfor(int i = 0; i < 2; i++)\n\t\t{\n\t\t\tfor(p = lpstr; *p != _T('\\0'); p = ::CharNext(p))\n\t\t\t{\n\t\t\t\tif(*p == _T(','))\n\t\t\t\t{\n\t\t\t\t\t*p = _T('\\0');\n\t\t\t\t\tc[i] = MinCrtHelper::_atoi(lpstr);\n\t\t\t\t\tlpstr = &p[1];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(c[i] == -1)\n\t\t\t\treturn CLR_INVALID;\n\t\t}\n\t\tif(*lpstr == _T('\\0'))\n\t\t\treturn CLR_INVALID;\n\t\tc[2] = MinCrtHelper::_atoi(lpstr);\n\n\t\treturn RGB(c[0], c[1], c[2]);\n\t}\n\n\tbool CalcLabelRect()\n\t{\n\t\tif(!::IsWindow(m_hWnd))\n\t\t\treturn false;\n\t\tif(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)\n\t\t\treturn false;\n\n\t\tCClientDC dc(m_hWnd);\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tm_rcLink = rcClient;\n\t\tif(!m_bPaintLabel)\n\t\t\treturn true;\n\n\t\tif(IsUsingTags())\n\t\t{\n\t\t\t// find tags and label parts\n\t\t\tLPTSTR lpstrLeft = NULL;\n\t\t\tint cchLeft = 0;\n\t\t\tLPTSTR lpstrLink = NULL;\n\t\t\tint cchLink = 0;\n\t\t\tLPTSTR lpstrRight = NULL;\n\t\t\tint cchRight = 0;\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);\n\t\t\tATLASSERT(lpstrLink != NULL);\n\t\t\tATLASSERT(cchLink > 0);\n\n\t\t\t// get label part rects\n\t\t\tHFONT hFontOld = dc.SelectFont(m_hFontNormal);\n\n\t\t\tUINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\n\t\t\tRECT rcLeft = rcClient;\n\t\t\tif(lpstrLeft != NULL)\n\t\t\t\tdc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);\n\n\t\t\tdc.SelectFont(m_hFontLink);\n\t\t\tRECT rcLink = rcClient;\n\t\t\tif(lpstrLeft != NULL)\n\t\t\t\trcLink.left = rcLeft.right;\n\t\t\tdc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);\n\n\t\t\tdc.SelectFont(hFontOld);\n\n\t\t\tm_rcLink = rcLink;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tHFONT hOldFont = NULL;\n\t\t\tif(m_hFontLink != NULL)\n\t\t\t\thOldFont = dc.SelectFont(m_hFontLink);\n\t\t\tLPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;\n\t\t\tDWORD dwStyle = GetStyle();\n\t\t\tUINT uFormat = DT_LEFT;\n\t\t\tif (dwStyle & SS_CENTER)\n\t\t\t\tuFormat = DT_CENTER;\n\t\t\telse if (dwStyle & SS_RIGHT)\n\t\t\t\tuFormat = DT_RIGHT;\n\t\t\tuFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\t\t\tdc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT);\n\t\t\tif(m_hFontLink != NULL)\n\t\t\t\tdc.SelectFont(hOldFont);\n\t\t\tif (dwStyle & SS_CENTER)\n\t\t\t{\n\t\t\t\tint dx = (rcClient.right - m_rcLink.right) / 2;\n\t\t\t\t::OffsetRect(&m_rcLink, dx, 0);\n\t\t\t}\n\t\t\telse if (dwStyle & SS_RIGHT)\n\t\t\t{\n\t\t\t\tint dx = rcClient.right - m_rcLink.right;\n\t\t\t\t::OffsetRect(&m_rcLink, dx, 0);\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tvoid CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const\n\t{\n\t\tlpstrLeft = NULL;\n\t\tcchLeft = 0;\n\t\tlpstrLink = NULL;\n\t\tcchLink = 0;\n\t\tlpstrRight = NULL;\n\t\tcchRight = 0;\n\n\t\tLPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;\n\t\tint cchText = lstrlen(lpstrText);\n\t\tbool bOutsideLink = true;\n\t\tfor(int i = 0; i < cchText; i++)\n\t\t{\n\t\t\tif(lpstrText[i] != _T('<'))\n\t\t\t\tcontinue;\n\n\t\t\tif(bOutsideLink)\n\t\t\t{\n\t\t\t\tif(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T(\"<A>\"), 3) == CSTR_EQUAL)\n\t\t\t\t{\n\t\t\t\t\tif(i > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tlpstrLeft = lpstrText;\n\t\t\t\t\t\tcchLeft = i;\n\t\t\t\t\t}\n\t\t\t\t\tlpstrLink = &lpstrText[i + 3];\n\t\t\t\t\tbOutsideLink = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T(\"</A>\"), 4) == CSTR_EQUAL)\n\t\t\t\t{\n\t\t\t\t\tcchLink = i - 3 - cchLeft;\n\t\t\t\t\tif(lpstrText[i + 4] != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tlpstrRight = &lpstrText[i + 4];\n\t\t\t\t\t\tcchRight = cchText - (i + 4);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tvoid DoEraseBackground(CDCHandle dc)\n\t{\n\t\tHBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd);\n\t\tif(hBrush != NULL)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\t\t\tdc.FillRect(&rect, hBrush);\n\t\t}\n\t}\n\n\tvoid DoPaint(CDCHandle dc)\n\t{\n\t\tif(IsUsingTags())\n\t\t{\n\t\t\t// find tags and label parts\n\t\t\tLPTSTR lpstrLeft = NULL;\n\t\t\tint cchLeft = 0;\n\t\t\tLPTSTR lpstrLink = NULL;\n\t\t\tint cchLink = 0;\n\t\t\tLPTSTR lpstrRight = NULL;\n\t\t\tint cchRight = 0;\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);\n\n\t\t\t// get label part rects\n\t\t\tRECT rcClient = { 0 };\n\t\t\tGetClientRect(&rcClient);\n\n\t\t\tdc.SetBkMode(TRANSPARENT);\n\t\t\tHFONT hFontOld = dc.SelectFont(m_hFontNormal);\n\n\t\t\tUINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\n\t\t\tif(lpstrLeft != NULL)\n\t\t\t\tdc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat);\n\n\t\t\tCOLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));\n\t\t\tif(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))\n\t\t\t\tdc.SelectFont(m_hFontLink);\n\t\t\telse\n\t\t\t\tdc.SelectFont(m_hFontNormal);\n\n\t\t\tdc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat);\n\n\t\t\tdc.SetTextColor(clrOld);\n\t\t\tdc.SelectFont(m_hFontNormal);\n\t\t\tif(lpstrRight != NULL)\n\t\t\t{\n\t\t\t\tRECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom };\n\t\t\t\tdc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat);\n\t\t\t}\n\n\t\t\tif(GetFocus() == m_hWnd)\n\t\t\t\tdc.DrawFocusRect(&m_rcLink);\n\n\t\t\tdc.SelectFont(hFontOld);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdc.SetBkMode(TRANSPARENT);\n\t\t\tCOLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));\n\n\t\t\tHFONT hFontOld = NULL;\n\t\t\tif(m_hFontLink != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))\n\t\t\t\thFontOld = dc.SelectFont(m_hFontLink);\n\t\t\telse\n\t\t\t\thFontOld = dc.SelectFont(m_hFontNormal);\n\n\t\t\tLPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;\n\n\t\t\tDWORD dwStyle = GetStyle();\n\t\t\tUINT uFormat = DT_LEFT;\n\t\t\tif (dwStyle & SS_CENTER)\n\t\t\t\tuFormat = DT_CENTER;\n\t\t\telse if (dwStyle & SS_RIGHT)\n\t\t\t\tuFormat = DT_RIGHT;\n\t\t\tuFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;\n\n\t\t\tdc.DrawText(lpstrText, -1, &m_rcLink, uFormat);\n\n\t\t\tif(GetFocus() == m_hWnd)\n\t\t\t\tdc.DrawFocusRect(&m_rcLink);\n\n\t\t\tdc.SetTextColor(clrOld);\n\t\t\tdc.SelectFont(hFontOld);\n\t\t}\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL StartTrackMouseLeave()\n\t{\n\t\tTRACKMOUSEEVENT tme = { 0 };\n\t\ttme.cbSize = sizeof(tme);\n\t\ttme.dwFlags = TME_LEAVE;\n\t\ttme.hwndTrack = m_hWnd;\n\t\treturn _TrackMouseEvent(&tme);\n\t}\n#endif // !_WIN32_WCE\n\n// Implementation helpers\n\tbool IsUnderlined() const\n\t{\n\t\treturn ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0);\n\t}\n\n\tbool IsNotUnderlined() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0);\n\t}\n\n\tbool IsUnderlineHover() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0);\n\t}\n\n\tbool IsCommandButton() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0);\n\t}\n\n\tbool IsNotifyButton() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON);\n\t}\n\n\tbool IsUsingTags() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_USETAGS) != 0);\n\t}\n\n\tbool IsUsingTagsBold() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD);\n\t}\n\n\tbool IsUsingToolTip() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0);\n\t}\n\n\tbool IsAutoCreateLinkFont() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT);\n\t}\n\n\tbool IsSingleLine() const\n\t{\n\t\treturn ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE);\n\t}\n};\n\nclass CHyperLink : public CHyperLinkImpl<CHyperLink>\n{\npublic:\n\tDECLARE_WND_CLASS(_T(\"WTL_HyperLink\"))\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWaitCursor - displays a wait cursor\n\nclass CWaitCursor\n{\npublic:\n// Data\n\tHCURSOR m_hWaitCursor;\n\tHCURSOR m_hOldCursor;\n\tbool m_bInUse;\n\n// Constructor/destructor\n\tCWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)\n\t{\n\t\tHINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance();\n\t\tm_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);\n\t\tATLASSERT(m_hWaitCursor != NULL);\n\n\t\tif(bSet)\n\t\t\tSet();\n\t}\n\n\t~CWaitCursor()\n\t{\n\t\tRestore();\n\t}\n\n// Methods\n\tbool Set()\n\t{\n\t\tif(m_bInUse)\n\t\t\treturn false;\n\t\tm_hOldCursor = ::SetCursor(m_hWaitCursor);\n\t\tm_bInUse = true;\n\t\treturn true;\n\t}\n\n\tbool Restore()\n\t{\n\t\tif(!m_bInUse)\n\t\t\treturn false;\n\t\t::SetCursor(m_hOldCursor);\n\t\tm_bInUse = false;\n\t\treturn true;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCustomWaitCursor - for custom and animated cursors\n\nclass CCustomWaitCursor : public CWaitCursor\n{\npublic:\n// Constructor/destructor\n\tCCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) : \n\t\t\tCWaitCursor(false, IDC_WAIT, true)\n\t{\n\t\tif(hInstance == NULL)\n\t\t\thInstance = ModuleHelper::GetResourceInstance();\n\t\tm_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);\n\n\t\tif(bSet)\n\t\t\tSet();\n\t}\n\n\t~CCustomWaitCursor()\n\t{\n\t\tRestore();\n#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))\n\t\t::DestroyCursor(m_hWaitCursor);\n#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMultiPaneStatusBarCtrl - Status Bar with multiple panes\n\ntemplate <class T, class TBase = CStatusBarCtrl>\nclass ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase >\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\n\n// Data\n\tenum { m_cxPaneMargin = 3 };\n\n\tint m_nPanes;\n\tint* m_pPane;\n\n// Constructor/destructor\n\tCMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL)\n\t{ }\n\n\t~CMultiPaneStatusBarCtrlImpl()\n\t{\n\t\tdelete [] m_pPane;\n\t}\n\n// Methods\n\tHWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)\n\t{\n#if (_MSC_VER >= 1300)\n\t\treturn ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase >   _baseClass;\n\t\treturn _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID);\n#endif // !(_MSC_VER >= 1300)\n\t}\n\n\tHWND 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)\n\t{\n\t\tconst int cchMax = 128;   // max text length is 127 for status bars (+1 for null)\n\t\tTCHAR szText[cchMax] = { 0 };\n\t\t::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);\n\t\treturn Create(hWndParent, szText, dwStyle, nID);\n\t}\n\n\tBOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPanes > 0);\n\n\t\tm_nPanes = nPanes;\n\t\tdelete [] m_pPane;\n\t\tm_pPane = NULL;\n\n\t\tATLTRY(m_pPane = new int[nPanes]);\n\t\tATLASSERT(m_pPane != NULL);\n\t\tif(m_pPane == NULL)\n\t\t\treturn FALSE;\n\n\t\tCTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tint* pPanesPos = buff.Allocate(nPanes);\n\t\tATLASSERT(pPanesPos != NULL);\n\t\tif(pPanesPos == NULL)\n\t\t\treturn FALSE;\n\n\t\tSecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int));\n\n\t\t// get status bar DC and set font\n\t\tCClientDC dc(m_hWnd);\n\t\tHFONT hOldFont = dc.SelectFont(GetFont());\n\n\t\t// get status bar borders\n\t\tint arrBorders[3] = { 0 };\n\t\tGetBorders(arrBorders);\n\n\t\tconst int cchBuff = 128;\n\t\tTCHAR szBuff[cchBuff] = { 0 };\n\t\tSIZE size = { 0, 0 };\n\t\tint cxLeft = arrBorders[0];\n\n\t\t// calculate right edge of each part\n\t\tfor(int i = 0; i < nPanes; i++)\n\t\t{\n\t\t\tif(pPanes[i] == ID_DEFAULT_PANE)\n\t\t\t{\n\t\t\t\t// make very large, will be resized later\n\t\t\t\tpPanesPos[i] = INT_MAX / 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);\n\t\t\t\tdc.GetTextExtent(szBuff, lstrlen(szBuff), &size);\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT;\n\t\t\t\tpPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin;\n\t\t\t}\n\t\t\tcxLeft = pPanesPos[i];\n\t\t}\n\n\t\tBOOL bRet = SetParts(nPanes, pPanesPos);\n\n\t\tif(bRet && bSetText)\n\t\t{\n\t\t\tfor(int i = 0; i < nPanes; i++)\n\t\t\t{\n\t\t\t\tif(pPanes[i] != ID_DEFAULT_PANE)\n\t\t\t\t{\n\t\t\t\t\t::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);\n\t\t\t\t\tSetPaneText(m_pPane[i], szBuff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdc.SelectFont(hOldFont);\n\t\treturn bRet;\n\t}\n\n\tbool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn false;\n\n\t\tint nLength = GetTextLength(nIndex, pnType);\n\t\tif(pcchLength != NULL)\n\t\t\t*pcchLength = nLength;\n\n\t\treturn true;\n\t}\n\n\tBOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\tint nLength = GetText(nIndex, lpstrText, pnType);\n\t\tif(pcchLength != NULL)\n\t\t\t*pcchLength = nLength;\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\treturn SetText(nIndex, lpstrText, nType);\n\t}\n\n\tBOOL GetPaneRect(int nPaneID, LPRECT lpRect) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\treturn GetRect(nIndex, lpRect);\n\t}\n\n\tBOOL SetPaneWidth(int nPaneID, int cxWidth)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPaneID != ID_DEFAULT_PANE);   // Can't resize this one\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\t// get pane positions\n\t\tCTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tint* pPanesPos = buff.Allocate(m_nPanes);\n\t\tif(pPanesPos == NULL)\n\t\t\treturn FALSE;\n\t\tGetParts(m_nPanes, pPanesPos);\n\t\t// calculate offset\n\t\tint cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]);\n\t\tint cxOff = cxWidth - cxPaneWidth;\n\t\t// find variable width pane\n\t\tint nDef = m_nPanes;\n\t\tfor(int i = 0; i < m_nPanes; i++)\n\t\t{\n\t\t\tif(m_pPane[i] == ID_DEFAULT_PANE)\n\t\t\t{\n\t\t\t\tnDef = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// resize\n\t\tif(nIndex < nDef)   // before default pane\n\t\t{\n\t\t\tfor(int i = nIndex; i < nDef; i++)\n\t\t\t\tpPanesPos[i] += cxOff;\n\t\t\t\t\n\t\t}\n\t\telse\t\t\t// after default one\n\t\t{\n\t\t\tfor(int i = nDef; i < nIndex; i++)\n\t\t\t\tpPanesPos[i] -= cxOff;\n\t\t}\n\t\t// set pane postions\n\t\treturn SetParts(m_nPanes, pPanesPos);\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tBOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\tGetTipText(nIndex, lpstrText, nSize);\n\t\treturn TRUE;\n\t}\n\n\tBOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\tSetTipText(nIndex, lpstrText);\n\t\treturn TRUE;\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))\n\tBOOL GetPaneIcon(int nPaneID, HICON& hIcon) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\thIcon = GetIcon(nIndex);\n\t\treturn TRUE;\n\t}\n\n\tBOOL SetPaneIcon(int nPaneID, HICON hIcon)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tint nIndex  = GetPaneIndexFromID(nPaneID);\n\t\tif(nIndex == -1)\n\t\t\treturn FALSE;\n\n\t\treturn SetIcon(nIndex, hIcon);\n\t}\n#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(wParam != SIZE_MINIMIZED && m_nPanes > 0)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdatePanesLayout();\n\t\t}\n\t\treturn lRet;\n\t}\n\n// Implementation\n\tBOOL UpdatePanesLayout()\n\t{\n\t\t// get pane positions\n\t\tCTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tint* pPanesPos = buff.Allocate(m_nPanes);\n\t\tATLASSERT(pPanesPos != NULL);\n\t\tif(pPanesPos == NULL)\n\t\t\treturn FALSE;\n\t\tint nRet = GetParts(m_nPanes, pPanesPos);\n\t\tATLASSERT(nRet == m_nPanes);\n\t\tif(nRet != m_nPanes)\n\t\t\treturn FALSE;\n\t\t// calculate offset\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tint cxOff = rcClient.right - pPanesPos[m_nPanes - 1];\n#ifndef _WIN32_WCE\n\t\t// Move panes left if size grip box is present\n\t\tif((GetStyle() & SBARS_SIZEGRIP) != 0)\n\t\t\tcxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE);\n#endif // !_WIN32_WCE\n\t\t// find variable width pane\n\t\tint i;\n\t\tfor(i = 0; i < m_nPanes; i++)\n\t\t{\n\t\t\tif(m_pPane[i] == ID_DEFAULT_PANE)\n\t\t\t\tbreak;\n\t\t}\n\t\t// resize all panes from the variable one to the right\n\t\tif((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1]))\n\t\t{\n\t\t\tfor(; i < m_nPanes; i++)\n\t\t\t\tpPanesPos[i] += cxOff;\n\t\t}\n\t\t// set pane postions\n\t\treturn SetParts(m_nPanes, pPanesPos);\n\t}\n\n\tint GetPaneIndexFromID(int nPaneID) const\n\t{\n\t\tfor(int i = 0; i < m_nPanes; i++)\n\t\t{\n\t\t\tif(m_pPane[i] == nPaneID)\n\t\t\t\treturn i;\n\t\t}\n\n\t\treturn -1;   // not found\n\t}\n};\n\nclass CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_MultiPaneStatusBar\"), GetWndClassName())\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPaneContainer - provides header with title and close button for panes\n\n// pane container extended styles\n#define PANECNT_NOCLOSEBUTTON   0x00000001\n#define PANECNT_VERTICAL        0x00000002\n#define PANECNT_FLATBORDER      0x00000004\n#define PANECNT_NOBORDER        0x00000008\n#define PANECNT_DIVIDER         0x00000010\n#define PANECNT_GRADIENT        0x00000020\n\n// Note: PANECNT_GRADIENT doesn't work with _ATL_NO_MSIMG\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T >\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, 0, -1)\n\n// Constants\n\tenum\n\t{\n\t\tm_cxyBorder = 2,\n\t\tm_cxyTextOffset = 4,\n\t\tm_cxyBtnOffset = 1,\n\n\t\tm_cchTitle = 80,\n\n\t\tm_cxImageTB = 13,\n\t\tm_cyImageTB = 11,\n\t\tm_cxyBtnAddTB = 7,\n\n\t\tm_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset,\n\n\t\tm_xBtnImageLeft = 6,\n\t\tm_yBtnImageTop = 5,\n\t\tm_xBtnImageRight = 12,\n\t\tm_yBtnImageBottom = 11,\n\n\t\tm_nCloseBtnID = ID_PANE_CLOSE\n\t};\n\n// Data members\n\tCToolBarCtrl m_tb;\n\tATL::CWindow m_wndClient;\n\tint m_cxyHeader;\n\tTCHAR m_szTitle[m_cchTitle];\n\tDWORD m_dwExtendedStyle;   // Pane container specific extended styles\n\tHFONT m_hFont;\n\tbool m_bInternalFont;\n\n\n// Constructor\n\tCPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false)\n\t{\n\t\tm_szTitle[0] = 0;\n\t}\n\n// Attributes\n\tDWORD GetPaneContainerExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\t\tif(m_hWnd != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tbool bUpdate = false;\n\n\t\t\tif(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0))   // add close button\n\t\t\t{\n\t\t\t\tpT->CreateCloseButton();\n\t\t\t\tbUpdate = true;\n\t\t\t}\n\t\t\telse if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0))   // remove close button\n\t\t\t{\n\t\t\t\tpT->DestroyCloseButton();\n\t\t\t\tbUpdate = true;\n\t\t\t}\n\n\t\t\tif((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL))   // change orientation\n\t\t\t{\n\t\t\t\tpT->CalcSize();\n\t\t\t\tbUpdate = true;\n\t\t\t}\n\n\t\t\tif((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) != \n\t\t\t   (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)))   // change border\n\t\t\t{\n\t\t\t\tbUpdate = true;\n\t\t\t}\n\n#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\t\t\tif((dwPrevStyle & PANECNT_GRADIENT) != (m_dwExtendedStyle & PANECNT_GRADIENT))   // change background\n\t\t\t{\n\t\t\t\tbUpdate = true;\n\t\t\t}\n#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\n\t\t\tif(bUpdate)\n\t\t\t\tpT->UpdateLayout();\n\t\t}\n\t\treturn dwPrevStyle;\n\t}\n\n\tHWND GetClient() const\n\t{\n\t\treturn m_wndClient;\n\t}\n\n\tHWND SetClient(HWND hWndClient)\n\t{\n\t\tHWND hWndOldClient = m_wndClient;\n\t\tm_wndClient = hWndClient;\n\t\tif(m_hWnd != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\t\treturn hWndOldClient;\n\t}\n\n\tBOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const\n\t{\n\t\tATLASSERT(lpstrTitle != NULL);\n\n\t\terrno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE);\n\n\t\treturn (nRet == 0 || nRet == STRUNCATE);\n\t}\n\n\tBOOL SetTitle(LPCTSTR lpstrTitle)\n\t{\n\t\tATLASSERT(lpstrTitle != NULL);\n\n\t\terrno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);\n\t\tbool bRet = (nRet == 0 || nRet == STRUNCATE);\n\t\tif(bRet && m_hWnd != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tint GetTitleLength() const\n\t{\n\t\treturn lstrlen(m_szTitle);\n\t}\n\n// Methods\n\tHWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,\n\t\t\tDWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tif(lpstrTitle != NULL)\n\t\t\tSecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);\n#if (_MSC_VER >= 1300)\n\t\treturn ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\treturn _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);\n#endif // !(_MSC_VER >= 1300)\n\t}\n\n\tHWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,\n\t\t\tDWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tif(uTitleID != 0U)\n\t\t\t::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle);\n#if (_MSC_VER >= 1300)\n\t\treturn ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\treturn _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);\n#endif // !(_MSC_VER >= 1300)\n\t}\n\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\t\t\tpT->UpdateLayout(rect.right, rect.bottom);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tBOOL EnableCloseButton(BOOL bEnable)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\treturn (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE;\n\t}\n\n\tvoid UpdateLayout()\n\t{\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout(rcClient.right, rcClient.bottom);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CPaneContainerImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tMESSAGE_HANDLER(WM_GETFONT, OnGetFont)\n\t\tMESSAGE_HANDLER(WM_SETFONT, OnSetFont)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_NOTIFY, OnNotify)\n\t\tMESSAGE_HANDLER(WM_COMMAND, OnCommand)\n\t\tFORWARD_NOTIFICATIONS()\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Init();\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_bInternalFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFont);\n\t\t\tm_hFont = NULL;\n\t\t\tm_bInternalFont = false;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_wndClient.m_hWnd != NULL)\n\t\t\tm_wndClient.SetFocus();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)m_hFont;\n\t}\n\n\tLRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_bInternalFont)\n\t\t{\n\t\t\t::DeleteObject(m_hFont);\n\t\t\tm_bInternalFont = false;\n\t\t}\n\n\t\tm_hFont = (HFONT)wParam;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcSize();\n\n\t\tif((BOOL)lParam != FALSE)\n\t\t\tpT->UpdateLayout();\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->DrawPaneTitleBackground((HDC)wParam);\n\n\t\treturn 1;\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tpT->DrawPaneTitle((HDC)wParam);\n\n\t\t\tif(m_wndClient.m_hWnd == NULL)   // no client window\n\t\t\t\tpT->DrawPane((HDC)wParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(m_hWnd);\n\t\t\tpT->DrawPaneTitle(dc.m_hDC);\n\n\t\t\tif(m_wndClient.m_hWnd == NULL)   // no client window\n\t\t\t\tpT->DrawPane(dc.m_hDC);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(m_tb.m_hWnd == NULL)\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;\n\t\tLPNMHDR lpnmh = (LPNMHDR)lParam;\n\t\tLRESULT lRet = 0;\n\n\t\t// pass toolbar custom draw notifications to the base class\n\t\tif(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd)\n\t\t\tlRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled);\n#ifndef _WIN32_WCE\n\t\t// tooltip notifications come with the tooltip window handle and button ID,\n\t\t// pass them to the parent if we don't handle them\n\t\telse if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID)\n\t\t\tbHandled = pT->GetToolTipText(lpnmh);\n#endif // !_WIN32_WCE\n\t\t// only let notifications not from the toolbar go to the parent\n\t\telse if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID)\n\t\t\tbHandled = FALSE;\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\t// if command comes from the close button, substitute HWND of the pane container instead\n\t\tif(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd)\n\t\t\treturn ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n// Custom draw overrides\n\tDWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_NOTIFYITEMDRAW;   // we need per-item notifications\n\t}\n\n\tDWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)\n\t{\n\t\treturn CDRF_NOTIFYPOSTPAINT;\n\t}\n\n\tDWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)\n\t{\n\t\tCDCHandle dc = lpNMCustomDraw->hdc;\n#if (_WIN32_IE >= 0x0400)\n\t\tRECT& rc = lpNMCustomDraw->rc;\n#else // !(_WIN32_IE >= 0x0400)\n\t\tRECT rc = { 0 };\n\t\tm_tb.GetItemRect(0, &rc);\n#endif // !(_WIN32_IE >= 0x0400)\n\n\t\tRECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 };\n\t\t::OffsetRect(&rcImage, rc.left, rc.top);\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tif((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0)\n\t\t{\n\t\t\tRECT rcShadow = rcImage;\n\t\t\t::OffsetRect(&rcShadow, 1, 1);\n\t\t\tCPen pen1;\n\t\t\tpen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));\n\t\t\tpT->DrawButtonImage(dc, rcShadow, pen1);\n\t\t\tCPen pen2;\n\t\t\tpen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));\n\t\t\tpT->DrawButtonImage(dc, rcImage, pen2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0)\n\t\t\t\t::OffsetRect(&rcImage, 1, 1);\n\t\t\tCPen pen;\n\t\t\tpen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT));\n\t\t\tpT->DrawButtonImage(dc, rcImage, pen);\n\t\t}\n\n\t\treturn CDRF_DODEFAULT;   // continue with the default item painting\n\t}\n\n// Implementation - overrideable methods\n\tvoid Init()\n\t{\n\t\tif(m_hFont == NULL)\n\t\t{\n\t\t\t// The same as AtlCreateControlFont() for horizontal pane\n#ifndef _WIN32_WCE\n\t\t\tLOGFONT lf = { 0 };\n\t\t\tATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);\n\t\t\tif(IsVertical())\n\t\t\t\tlf.lfEscapement = 900;   // 90 degrees\n\t\t\tm_hFont = ::CreateFontIndirect(&lf);\n#else // CE specific\n\t\t\tm_hFont = (HFONT)::GetStockObject(SYSTEM_FONT);\n\t\t\tif(IsVertical())\n\t\t\t{\n\t\t\t\tCLogFont lf(m_hFont);\n\t\t\t\tlf.lfEscapement = 900;   // 90 degrees\n\t\t\t\tm_hFont = ::CreateFontIndirect(&lf);\n\t\t\t}\n#endif // _WIN32_WCE\n\t\t\tm_bInternalFont = true;\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CalcSize();\n\n\t\tif((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)\n\t\t\tpT->CreateCloseButton();\n\t}\n\n\tvoid UpdateLayout(int cxWidth, int cyHeight)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tRECT rect = { 0 };\n\n\t\tif(IsVertical())\n\t\t{\n\t\t\t::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight);\n\t\t\tif(m_tb.m_hWnd != NULL)\n\t\t\t\tm_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\n\n\t\t\tif(m_wndClient.m_hWnd != NULL)\n\t\t\t\tm_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER);\n\t\t\telse\n\t\t\t\trect.right = cxWidth;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader);\n\t\t\tif(m_tb.m_hWnd != NULL)\n\t\t\t\tm_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\n\n\t\t\tif(m_wndClient.m_hWnd != NULL)\n\t\t\t\tm_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER);\n\t\t\telse\n\t\t\t\trect.bottom = cyHeight;\n\t\t}\n\n\t\tInvalidateRect(&rect);\n\t}\n\n\tvoid CreateCloseButton()\n\t{\n\t\tATLASSERT(m_tb.m_hWnd == NULL);\n\t\t// create toolbar for the \"x\" button\n\t\tm_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);\n\t\tATLASSERT(m_tb.IsWindow());\n\n\t\tif(m_tb.m_hWnd != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT;   // avoid level 4 warning\n\n\t\t\tm_tb.SetButtonStructSize();\n\n\t\t\tTBBUTTON tbbtn = { 0 };\n\t\t\ttbbtn.idCommand = pT->m_nCloseBtnID;\n\t\t\ttbbtn.fsState = TBSTATE_ENABLED;\n\t\t\ttbbtn.fsStyle = BTNS_BUTTON;\n\t\t\tm_tb.AddButtons(1, &tbbtn);\n\n\t\t\tm_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB);\n\t\t\tm_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB);\n\n\t\t\tif(IsVertical())\n\t\t\t\tm_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOACTIVATE);\n\t\t\telse\n\t\t\t\tm_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);\n\t\t}\n\t}\n\n\tvoid DestroyCloseButton()\n\t{\n\t\tif(m_tb.m_hWnd != NULL)\n\t\t\tm_tb.DestroyWindow();\n\t}\n\n\tvoid CalcSize()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tCFontHandle font = pT->GetTitleFont();\n\t\tif(font.IsNull())\n\t\t\tfont = (HFONT)::GetStockObject(SYSTEM_FONT);\n\t\tLOGFONT lf = { 0 };\n\t\tfont.GetLogFont(lf);\n\t\tif(IsVertical())\n\t\t{\n\t\t\tm_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset;\n\t\t\tint cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset + 1;\n\t\t\tm_cxyHeader = __max(cyFont, cyBtn);\n\t\t}\n\t}\n\n\tHFONT GetTitleFont() const\n\t{\n\t\treturn m_hFont;\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetToolTipText(LPNMHDR /*lpnmh*/)\n\t{\n\t\treturn FALSE;\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid DrawPaneTitle(CDCHandle dc)\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\n\t\tUINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST;\n\t\tif(IsVertical())\n\t\t{\n\t\t\trect.right = rect.left + m_cxyHeader;\n\t\t\tuBorder |= BF_BOTTOM;\n\t\t}\n\t\telse\n\t\t{\n\t\t\trect.bottom = rect.top + m_cxyHeader;\n\t\t\tuBorder |= BF_RIGHT;\n\t\t}\n\n\t\tif((m_dwExtendedStyle & PANECNT_NOBORDER) == 0)\n\t\t{\n\t\t\tif((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0)\n\t\t\t\tuBorder |= BF_FLAT;\n\t\t\tdc.DrawEdge(&rect, EDGE_ETCHED, uBorder);\n\t\t}\n\n\t\tif((m_dwExtendedStyle & PANECNT_DIVIDER) != 0)\n\t\t{\n\t\t\tuBorder = BF_FLAT | BF_ADJUST | (IsVertical() ? BF_RIGHT : BF_BOTTOM);\n\t\t\tdc.DrawEdge(&rect, BDR_SUNKENOUTER, uBorder);\n\t\t}\n\n\t\t// draw title text\n\t\tdc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));\n\t\tdc.SetBkMode(TRANSPARENT);\n\t\tT* pT = static_cast<T*>(this);\n\t\tHFONT hFontOld = dc.SelectFont(pT->GetTitleFont());\n#if defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS)\n\t\tconst UINT DT_END_ELLIPSIS = 0;\n#endif // defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS)\n\n\t\tif(IsVertical())\n\t\t{\n\t\t\trect.top += m_cxyTextOffset;\n\t\t\trect.bottom -= m_cxyTextOffset;\n\t\t\tif(m_tb.m_hWnd != NULL)\n\t\t\t\trect.top += m_cxToolBar;;\n\n\t\t\tRECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top };\n\t\t\tint cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT);\n\t\t\tRECT rcText = { 0 };\n\t\t\trcText.left = (rect.right - rect.left - cxFont) / 2;\n\t\t\trcText.right = rcText.left + (rect.bottom - rect.top);\n\t\t\trcText.top = rect.bottom;\n\t\t\trcText.bottom = rect.top;\n\t\t\tdc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);\n\t\t}\n\t\telse\n\t\t{\n\t\t\trect.left += m_cxyTextOffset;\n\t\t\trect.right -= m_cxyTextOffset;\n\t\t\tif(m_tb.m_hWnd != NULL)\n\t\t\t\trect.right -= m_cxToolBar;;\n\n\t\t\tdc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);\n\t\t}\n\n\t\tdc.SelectFont(hFontOld);\n\t}\n\n\tvoid DrawPaneTitleBackground(CDCHandle dc)\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\t\tif(IsVertical())\n\t\t\trect.right = m_cxyHeader;\n\t\telse\n\t\t\trect.bottom = m_cxyHeader;\n\n#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\t\tif((m_dwExtendedStyle & PANECNT_GRADIENT) != 0)\n\t\t\tdc.GradientFillRect(rect, ::GetSysColor(COLOR_WINDOW), ::GetSysColor(COLOR_3DFACE), IsVertical());\n\t\telse\n#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\t\t\tdc.FillRect(&rect, COLOR_3DFACE);\n\t}\n\n\t// called only if pane is empty\n\tvoid DrawPane(CDCHandle dc)\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\t\tif(IsVertical())\n\t\t\trect.left += m_cxyHeader;\n\t\telse\n\t\t\trect.top += m_cxyHeader;\n\t\tif((GetExStyle() & WS_EX_CLIENTEDGE) == 0)\n\t\t\tdc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);\n\t\tdc.FillRect(&rect, COLOR_APPWORKSPACE);\n\t}\n\n\t// drawing helper - draws \"x\" button image\n\tvoid DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen)\n\t{\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\t\tHPEN hPenOld = dc.SelectPen(hPen);\n\n\t\tdc.MoveTo(rcImage.left, rcImage.top);\n\t\tdc.LineTo(rcImage.right, rcImage.bottom);\n\t\tdc.MoveTo(rcImage.left + 1, rcImage.top);\n\t\tdc.LineTo(rcImage.right + 1, rcImage.bottom);\n\n\t\tdc.MoveTo(rcImage.left, rcImage.bottom - 1);\n\t\tdc.LineTo(rcImage.right, rcImage.top - 1);\n\t\tdc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);\n\t\tdc.LineTo(rcImage.right + 1, rcImage.top - 1);\n\n\t\tdc.SelectPen(hPenOld);\n#else // (_WIN32_WCE < 400)\n\t\trcImage;\n\t\thPen;\n\t\t// no support for the \"x\" button image\n#endif // (_WIN32_WCE < 400)\n\t}\n\n\tbool IsVertical() const\n\t{\n\t\treturn ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0);\n\t}\n};\n\nclass CPaneContainer : public CPaneContainerImpl<CPaneContainer>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_PaneContainer\"), 0, -1)\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CSortListViewCtrl - implements sorting for a listview control\n\n// sort listview extended styles\n#define SORTLV_USESHELLBITMAPS\t0x00000001\n\n// Notification sent to parent when sort column is changed by user clicking header.  \n#define SLVN_SORTCHANGED\tLVN_LAST\n\n// A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification\ntypedef struct tagNMSORTLISTVIEW\n{\n    NMHDR hdr;\n    int iNewSortColumn;\n    int iOldSortColumn;\n} NMSORTLISTVIEW, *LPNMSORTLISTVIEW;\n\n// Column sort types. Can be set on a per-column basis with the SetColumnSortType method.\nenum\n{\n\tLVCOLSORT_NONE,\n\tLVCOLSORT_TEXT,   // default\n\tLVCOLSORT_TEXTNOCASE,\n\tLVCOLSORT_LONG,\n\tLVCOLSORT_DOUBLE,\n\tLVCOLSORT_DECIMAL,\n\tLVCOLSORT_DATETIME,\n\tLVCOLSORT_DATE,\n\tLVCOLSORT_TIME,\n\tLVCOLSORT_CUSTOM,\n\tLVCOLSORT_LAST = LVCOLSORT_CUSTOM\n};\n\n\ntemplate <class T>\nclass CSortListViewImpl\n{\npublic:\n\tenum\n\t{\n\t\tm_cchCmpTextMax = 32, // overrideable\n\t\tm_cxSortImage = 16,\n\t\tm_cySortImage = 15,\n\t\tm_cxSortArrow = 11,\n\t\tm_cySortArrow = 6,\n\t\tm_iSortUp = 0,        // index of sort bitmaps\n\t\tm_iSortDown = 1,\n\t\tm_nShellSortUpID = 133\n\t};\n\n\t// passed to LVCompare functions as lParam1 and lParam2 \n\tstruct LVCompareParam\n\t{\n\t\tint iItem;\n\t\tDWORD_PTR dwItemData;\n\t\tunion\n\t\t{\n\t\t\tlong lValue;\n\t\t\tdouble dblValue;\n\t\t\tDECIMAL decValue;\n\t\t\tLPCTSTR pszValue;\n\t\t};\n\t};\n\t\n\t// passed to LVCompare functions as the lParamSort parameter\n\tstruct LVSortInfo\n\t{\n\t\tT* pT;\n\t\tint iSortCol;\n\t\tbool bDescending;\n\t};\n\n\tbool m_bSortDescending;\n\tbool m_bCommCtrl6;\n\tint m_iSortColumn;\n\tCBitmap m_bmSort[2];\n\tint m_fmtOldSortCol;\n\tHBITMAP m_hbmOldSortCol;\n\tDWORD m_dwSortLVExtendedStyle;\n\tATL::CSimpleArray<WORD> m_arrColSortType;\n\tbool m_bUseWaitCursor;\n\t\n\tCSortListViewImpl() :\n\t\t\tm_bSortDescending(false),\n\t\t\tm_bCommCtrl6(false),\n\t\t\tm_iSortColumn(-1), \n\t\t\tm_fmtOldSortCol(0),\n\t\t\tm_hbmOldSortCol(NULL),\n\t\t\tm_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS),\n\t\t\tm_bUseWaitCursor(true)\n\t{\n#ifndef _WIN32_WCE\n\t\tDWORD dwMajor = 0;\n\t\tDWORD dwMinor = 0;\n\t\tHRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);\n\t\tm_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6;\n#endif // !_WIN32_WCE\n\t}\n\t\n// Attributes\n\tvoid SetSortColumn(int iCol)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tCHeaderCtrl header = pT->GetHeader();\n\t\tATLASSERT(header.m_hWnd != NULL);\n\t\tATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize());\n\n\t\tint iOldSortCol = m_iSortColumn;\n\t\tm_iSortColumn = iCol;\n\t\tif(m_bCommCtrl6)\n\t\t{\n#ifndef HDF_SORTUP\n\t\t\tconst int HDF_SORTUP = 0x0400;\t\n#endif // HDF_SORTUP\n#ifndef HDF_SORTDOWN\n\t\t\tconst int HDF_SORTDOWN = 0x0200;\t\n#endif // HDF_SORTDOWN\n\t\t\tconst int nMask = HDF_SORTUP | HDF_SORTDOWN;\n\t\t\tHDITEM hditem = { HDI_FORMAT };\n\t\t\tif(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem))\n\t\t\t{\n\t\t\t\thditem.fmt &= ~nMask;\n\t\t\t\theader.SetItem(iOldSortCol, &hditem);\n\t\t\t}\n\t\t\tif(iCol >= 0 && header.GetItem(iCol, &hditem))\n\t\t\t{\n\t\t\t\thditem.fmt &= ~nMask;\n\t\t\t\thditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP;\n\t\t\t\theader.SetItem(iCol, &hditem);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif(m_bmSort[m_iSortUp].IsNull())\n\t\t\tpT->CreateSortBitmaps();\n\n\t\t// restore previous sort column's bitmap, if any, and format\n\t\tHDITEM hditem = { HDI_BITMAP | HDI_FORMAT };\n\t\tif(iOldSortCol != iCol && iOldSortCol >= 0)\n\t\t{\n\t\t\thditem.hbm = m_hbmOldSortCol;\n\t\t\thditem.fmt = m_fmtOldSortCol;\n\t\t\theader.SetItem(iOldSortCol, &hditem);\n\t\t}\n\n\t\t// save new sort column's bitmap and format, and add our sort bitmap\n\t\tif(iCol >= 0 && header.GetItem(iCol, &hditem))\n\t\t{\n\t\t\tif(iOldSortCol != iCol)\n\t\t\t{\n\t\t\t\tm_fmtOldSortCol = hditem.fmt;\n\t\t\t\tm_hbmOldSortCol = hditem.hbm;\n\t\t\t}\n\t\t\thditem.fmt &= ~HDF_IMAGE;\n\t\t\thditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;\n\t\t\tint i = m_bSortDescending ? m_iSortDown : m_iSortUp;\n\t\t\thditem.hbm = m_bmSort[i];\n\t\t\theader.SetItem(iCol, &hditem);\n\t\t}\n\t}\n\n\tint GetSortColumn() const\n\t{\n\t\treturn m_iSortColumn;\n\t}\n\n\tvoid SetColumnSortType(int iCol, WORD wType)\n\t{\n\t\tATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());\n\t\tATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST);\n\t\tm_arrColSortType[iCol] = wType;\n\t}\n\n\tWORD GetColumnSortType(int iCol) const\n\t{\n\t\tATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize());\n\t\treturn m_arrColSortType[iCol];\n\t}\n\n\tint GetColumnCount() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tCHeaderCtrl header = pT->GetHeader();\n\t\treturn header.m_hWnd != NULL ? header.GetItemCount() : 0;\n\t}\n\n\tbool IsSortDescending() const\n\t{\n\t\treturn m_bSortDescending;\n\t}\n\n\tDWORD GetSortListViewExtendedStyle() const\n\t{\n\t\treturn m_dwSortLVExtendedStyle;\n\t}\n\n\tDWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwSortLVExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwSortLVExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\t\treturn dwPrevStyle;\n\t}\n\n// Operations\n\tbool DoSortItems(int iCol, bool bDescending = false)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());\n\n\t\tWORD wType = m_arrColSortType[iCol];\n\t\tif(wType == LVCOLSORT_NONE)\n\t\t\treturn false;\n\n\t\tint nCount = pT->GetItemCount();\n\t\tif(nCount < 2)\n\t\t{\n\t\t\tm_bSortDescending = bDescending;\n\t\t\tSetSortColumn(iCol);\n\t\t\treturn true;\n\t\t}\n\n\t\tCWaitCursor waitCursor(false);\n\t\tif(m_bUseWaitCursor)\n\t\t\twaitCursor.Set();\n\n\t\tLVCompareParam* pParam = NULL;\n\t\tATLTRY(pParam = new LVCompareParam[nCount]);\n\t\tPFNLVCOMPARE pFunc = NULL;\n\t\tTCHAR pszTemp[pT->m_cchCmpTextMax] = { 0 };\n\t\tbool bStrValue = false;\n\n\t\tswitch(wType)\n\t\t{\n\t\tcase LVCOLSORT_TEXT:\n\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareText;\n\t\tcase LVCOLSORT_TEXTNOCASE:\n\t\t\tif(pFunc == NULL)\n\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase;\n\t\tcase LVCOLSORT_CUSTOM:\n\t\t\t{\n\t\t\t\tif(pFunc == NULL)\n\t\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareCustom;\n\n\t\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t\t{\n\t\t\t\t\tpParam[i].iItem = i;\n\t\t\t\t\tpParam[i].dwItemData = pT->GetItemData(i);\n\t\t\t\t\tpParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax];\n\t\t\t\t\tpT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax);\n\t\t\t\t\tpT->SetItemData(i, (DWORD_PTR)&pParam[i]);\n\t\t\t\t}\n\t\t\t\tbStrValue = true;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase LVCOLSORT_LONG:\n\t\t\t{\n\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareLong;\n\t\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t\t{\n\t\t\t\t\tpParam[i].iItem = i;\n\t\t\t\t\tpParam[i].dwItemData = pT->GetItemData(i);\n\t\t\t\t\tpT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);\n\t\t\t\t\tpParam[i].lValue = pT->StrToLong(pszTemp);\n\t\t\t\t\tpT->SetItemData(i, (DWORD_PTR)&pParam[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase LVCOLSORT_DOUBLE:\n\t\t\t{\n\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareDouble;\n\t\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t\t{\n\t\t\t\t\tpParam[i].iItem = i;\n\t\t\t\t\tpParam[i].dwItemData = pT->GetItemData(i);\n\t\t\t\t\tpT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);\n\t\t\t\t\tpParam[i].dblValue = pT->StrToDouble(pszTemp);\n\t\t\t\t\tpT->SetItemData(i, (DWORD_PTR)&pParam[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase LVCOLSORT_DECIMAL:\n\t\t\t{\n\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareDecimal;\n\t\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t\t{\n\t\t\t\t\tpParam[i].iItem = i;\n\t\t\t\t\tpParam[i].dwItemData = pT->GetItemData(i);\n\t\t\t\t\tpT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);\n\t\t\t\t\tpT->StrToDecimal(pszTemp, &pParam[i].decValue);\n\t\t\t\t\tpT->SetItemData(i, (DWORD_PTR)&pParam[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase LVCOLSORT_DATETIME:\n\t\tcase LVCOLSORT_DATE:\n\t\tcase LVCOLSORT_TIME:\n\t\t\t{\n\t\t\t\tpFunc = (PFNLVCOMPARE)pT->LVCompareDouble;\n\t\t\t\tDWORD dwFlags = LOCALE_NOUSEROVERRIDE;\n\t\t\t\tif(wType == LVCOLSORT_DATE)\n\t\t\t\t\tdwFlags |= VAR_DATEVALUEONLY;\n\t\t\t\telse if(wType == LVCOLSORT_TIME)\n\t\t\t\t\tdwFlags |= VAR_TIMEVALUEONLY;\n\t\t\t\tfor(int i = 0; i < nCount; i++)\n\t\t\t\t{\n\t\t\t\t\tpParam[i].iItem = i;\n\t\t\t\t\tpParam[i].dwItemData = pT->GetItemData(i);\n\t\t\t\t\tpT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);\n\t\t\t\t\tpParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags);\n\t\t\t\t\tpT->SetItemData(i, (DWORD_PTR)&pParam[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Unknown value for sort type in CSortListViewImpl::DoSortItems()\\n\"));\n\t\t\tbreak;\n\t\t} // switch(wType)\n\n\t\tATLASSERT(pFunc != NULL);\n\t\tLVSortInfo lvsi = { pT, iCol, bDescending };\n\t\tbool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE);\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tDWORD_PTR dwItemData = pT->GetItemData(i);\n\t\t\tLVCompareParam* p = (LVCompareParam*)dwItemData;\n\t\t\tATLASSERT(p != NULL);\n\t\t\tif(bStrValue)\n\t\t\t\tdelete [] (TCHAR*)p->pszValue;\n\t\t\tpT->SetItemData(i, p->dwItemData);\n\t\t}\n\t\tdelete [] pParam;\n\n\t\tif(bRet)\n\t\t{\n\t\t\tm_bSortDescending = bDescending;\n\t\t\tSetSortColumn(iCol);\n\t\t}\n\n\t\tif(m_bUseWaitCursor)\n\t\t\twaitCursor.Restore();\n\n\t\treturn bRet;\n\t}\n\n\tvoid CreateSortBitmaps()\n\t{\n\t\tif((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0)\n\t\t{\n\t\t\tbool bFree = false;\n\t\t\tLPCTSTR pszModule = _T(\"shell32.dll\"); \n\t\t\tHINSTANCE hShell = ::GetModuleHandle(pszModule);\n\n\t\t\tif (hShell == NULL)\t\t\n\t\t\t{\n\t\t\t\thShell = ::LoadLibrary(pszModule);\n\t\t\t\tbFree = true;\n\t\t\t}\n \n\t\t\tif (hShell != NULL)\n\t\t\t{\n\t\t\t\tbool bSuccess = true;\n\t\t\t\tfor(int i = m_iSortUp; i <= m_iSortDown; i++)\n\t\t\t\t{\n\t\t\t\t\tif(!m_bmSort[i].IsNull())\n\t\t\t\t\t\tm_bmSort[i].DeleteObject();\n\t\t\t\t\tm_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i), \n#ifndef _WIN32_WCE\n\t\t\t\t\t\tIMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);\n#else // CE specific\n\t\t\t\t\t\tIMAGE_BITMAP, 0, 0, 0);\n#endif // _WIN32_WCE\n\t\t\t\t\tif(m_bmSort[i].IsNull())\n\t\t\t\t\t{\n\t\t\t\t\t\tbSuccess = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(bFree)\n\t\t\t\t\t::FreeLibrary(hShell);\n\t\t\t\tif(bSuccess)\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tfor(int i = m_iSortUp; i <= m_iSortDown; i++)\n\t\t{\n\t\t\tif(!m_bmSort[i].IsNull())\n\t\t\t\tm_bmSort[i].DeleteObject();\n\n\t\t\tCDC dcMem;\n\t\t\tCClientDC dc(::GetDesktopWindow());\n\t\t\tdcMem.CreateCompatibleDC(dc.m_hDC);\n\t\t\tm_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage);\n\t\t\tHBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]);\n\t\t\tRECT rc = { 0, 0, m_cxSortImage, m_cySortImage };\n\t\t\tpT->DrawSortBitmap(dcMem.m_hDC, i, &rc);\n\t\t\tdcMem.SelectBitmap(hbmOld);\n\t\t\tdcMem.DeleteDC();\n\t\t}\n\t}\n\n\tvoid NotifyParentSortChanged(int iNewSortCol, int iOldSortCol)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tint nID = pT->GetDlgCtrlID();\n\t\tNMSORTLISTVIEW nm = { { pT->m_hWnd, (UINT_PTR)nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol };\n\t\t::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm);\n\t}\n\n// Overrideables\n\tint CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/)\n\t{\n\t\t// pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members.\n\t\t// If item1 > item2 return 1, if item1 < item2 return -1, else return 0.\n\t\treturn 0;\n\t}\n\n\tvoid DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc)\n\t{\n\t\tdc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE));\t\n\t\tHBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));\n\t\tCPen pen;\n\t\tpen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW));\n\t\tHPEN hpenOld = dc.SelectPen(pen);\n\t\tPOINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 };\n\t\tif(iBitmap == m_iSortUp)\n\t\t{\n\t\t\tPOINT pts[3] = \n\t\t\t{\n\t\t\t\t{ ptOrg.x + m_cxSortArrow / 2, ptOrg.y },\n\t\t\t\t{ ptOrg.x, ptOrg.y + m_cySortArrow - 1 }, \n\t\t\t\t{ ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 }\n\t\t\t};\n\t\t\tdc.Polygon(pts, 3);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tPOINT pts[3] = \n\t\t\t{\n\t\t\t\t{ ptOrg.x, ptOrg.y },\n\t\t\t\t{ ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 },\n\t\t\t\t{ ptOrg.x + m_cxSortArrow - 1, ptOrg.y }\n\t\t\t};\n\t\t\tdc.Polygon(pts, 3);\n\t\t}\n\t\tdc.SelectBrush(hbrOld);\n\t\tdc.SelectPen(hpenOld);\n\t}\n\n\tdouble DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags)\n\t{\n\t\tATLASSERT(lpstr != NULL);\n\t\tif(lpstr == NULL || lpstr[0] == _T('\\0'))\n\t\t\treturn 0;\n\n\t\tUSES_CONVERSION;\n\t\tHRESULT hRet = E_FAIL;\n\t\tDATE dRet = 0;\n\t\tif (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet)))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"VarDateFromStr failed with result of 0x%8.8X\\n\"), hRet);\n\t\t\tdRet = 0;\n\t\t}\n\t\treturn dRet;\n\t}\n\n\tlong StrToLong(LPCTSTR lpstr)\n\t{\n\t\tATLASSERT(lpstr != NULL);\n\t\tif(lpstr == NULL || lpstr[0] == _T('\\0'))\n\t\t\treturn 0;\n\t\t\n\t\tUSES_CONVERSION;\n\t\tHRESULT hRet = E_FAIL;\n\t\tlong lRet = 0;\n\t\tif (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet)))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"VarI4FromStr failed with result of 0x%8.8X\\n\"), hRet);\n\t\t\tlRet = 0;\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tdouble StrToDouble(LPCTSTR lpstr)\n\t{\n\t\tATLASSERT(lpstr != NULL);\n\t\tif(lpstr == NULL || lpstr[0] == _T('\\0'))\n\t\t\treturn 0;\n\n\t\tUSES_CONVERSION;\n\t\tHRESULT hRet = E_FAIL;\n\t\tdouble dblRet = 0;\n\t\tif (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet)))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"VarR8FromStr failed with result of 0x%8.8X\\n\"), hRet);\n\t\t\tdblRet = 0;\n\t\t}\n\t\treturn dblRet;\n\t}\n\n\tbool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal)\n\t{\n\t\tATLASSERT(lpstr != NULL);\n\t\tATLASSERT(pDecimal != NULL);\n\t\tif(lpstr == NULL || pDecimal == NULL)\n\t\t\treturn false;\n\n\t\tUSES_CONVERSION;\n\t\tHRESULT hRet = E_FAIL;\n\t\tif (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal)))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"VarDecFromStr failed with result of 0x%8.8X\\n\"), hRet);\n\t\t\tpDecimal->Lo64 = 0;\n\t\t\tpDecimal->Hi32 = 0;\n\t\t\tpDecimal->signscale = 0;\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n// Overrideable PFNLVCOMPARE functions\n\tstatic int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue);\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n\n\tstatic int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue);\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n\n\tstatic int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = 0;\n\t\tif(pParam1->lValue > pParam2->lValue)\n\t\t\tnRet = 1;\n\t\telse if(pParam1->lValue < pParam2->lValue)\n\t\t\tnRet = -1;\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n\n\tstatic int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = 0;\n\t\tif(pParam1->dblValue > pParam2->dblValue)\n\t\t\tnRet = 1;\n\t\telse if(pParam1->dblValue < pParam2->dblValue)\n\t\t\tnRet = -1;\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n\n\tstatic int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol);\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n\n#ifndef _WIN32_WCE\n\tstatic int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue);\n\t\tnRet--;\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n#else\n\t// Compare mantissas, ignore sign and scale\n\tstatic int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight)\n\t{\n\t\tif (decLeft.Hi32 < decRight.Hi32)\n\t\t{\n\t\t\treturn -1;\n\t\t}\n\t\tif (decLeft.Hi32 > decRight.Hi32)\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\t\t// Here, decLeft.Hi32 == decRight.Hi32\n\t\tif (decLeft.Lo64 < decRight.Lo64)\n\t\t{\n\t\t\treturn -1;\n\t\t}\n\t\tif (decLeft.Lo64 > decRight.Lo64)\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL\n\tstatic HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight)\n\t{\n\t\tstatic const ULONG powersOfTen[] =\n\t\t{\n\t\t\t10ul,\n\t\t\t100ul,\n\t\t\t1000ul,\n\t\t\t10000ul,\n\t\t\t100000ul,\n\t\t\t1000000ul,\n\t\t\t10000000ul,\n\t\t\t100000000ul,\n\t\t\t1000000000ul\n\t\t};\n\t\tstatic const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]);\n\t\tif (!pdecLeft || !pdecRight)\n\t\t{\n\t\t\treturn VARCMP_NULL;\n\t\t}\n\t\t\n\t\t// Degenerate case - at least one comparand is of the form\n\t\t// [+-]0*10^N (denormalized zero)\n\t\tbool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32);\n\t\tbool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32);\n\t\tif (bLeftZero && bRightZero)\n\t\t{\n\t\t\treturn VARCMP_EQ;\n\t\t}\n\t\tbool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0);\n\t\tbool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0);\n\t\tif (bLeftZero)\n\t\t{\n\t\t\treturn (bRightNeg ? VARCMP_GT : VARCMP_LT);\n\t\t}\n\t\t// This also covers the case where the comparands have different signs\n\t\tif (bRightZero || bLeftNeg != bRightNeg)\n\t\t{\n\t\t\treturn (bLeftNeg ? VARCMP_LT : VARCMP_GT);\n\t\t}\n\n\t\t// Here both comparands have the same sign and need to be compared\n\t\t// on mantissa and scale. The result is obvious when\n\t\t// 1. Scales are equal (then compare mantissas)\n\t\t// 2. A number with smaller scale is also the one with larger mantissa\n\t\t//    (then this number is obviously larger)\n\t\t// In the remaining case, we would multiply the number with smaller\n\t\t// scale by 10 and simultaneously increment its scale (which amounts to\n\t\t// adding trailing zeros after decimal point), until the numbers fall under\n\t\t// one of the two cases above\n\t\tDECIMAL temp;\n\t\tbool bInvert = bLeftNeg; // the final result needs to be inverted\n\t\tif (pdecLeft->scale < pdecRight->scale)\n\t\t{\n\t\t\ttemp = *pdecLeft;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttemp = *pdecRight;\n\t\t\tpdecRight = pdecLeft;\n\t\t\tbInvert = !bInvert;\n\t\t}\n\n\t\t// Now temp is the number with smaller (or equal) scale, and\n\t\t// we can modify it freely without touching original parameters\n\t\tint comp;\n\t\twhile ((comp = CompareMantissas(temp, *pdecRight)) < 0 &&\n\t\t\ttemp.scale < pdecRight->scale)\n\t\t{\n\t\t\t// Multiply by an appropriate power of 10\n\t\t\tint scaleDiff = pdecRight->scale - temp.scale;\n\t\t\tif (scaleDiff > largestPower)\n\t\t\t{\n\t\t\t\t// Keep the multiplier representable in 32bit\n\t\t\t\tscaleDiff = largestPower;\n\t\t\t}\n\t\t\tDWORDLONG power = powersOfTen[scaleDiff - 1];\n\t\t\t// Multiply temp's mantissa by power\n\t\t\tDWORDLONG product = temp.Lo32 * power;\n\t\t\tULONG carry = static_cast<ULONG>(product >> 32);\n\t\t\ttemp.Lo32  = static_cast<ULONG>(product);\n\t\t\tproduct = temp.Mid32 * power + carry;\n\t\t\tcarry = static_cast<ULONG>(product >> 32);\n\t\t\ttemp.Mid32 = static_cast<ULONG>(product);\n\t\t\tproduct = temp.Hi32 * power + carry;\n\t\t\tif (static_cast<ULONG>(product >> 32))\n\t\t\t{\n\t\t\t\t// Multiplication overflowed - pdecLeft is clearly larger\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttemp.Hi32 = static_cast<ULONG>(product);\n\t\t\ttemp.scale = (BYTE)(temp.scale + scaleDiff);\n\t\t}\n\t\tif (temp.scale < pdecRight->scale)\n\t\t{\n\t\t\tcomp = 1;\n\t\t}\n\t\tif (bInvert)\n\t\t{\n\t\t\tcomp = -comp;\n\t\t}\n\t\treturn (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ);\n\t}\n\n\tstatic int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)\n\t{\n\t\tATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL);\n\n\t\tLVCompareParam* pParam1 = (LVCompareParam*)lParam1;\n\t\tLVCompareParam* pParam2 = (LVCompareParam*)lParam2;\n\t\tLVSortInfo* pInfo = (LVSortInfo*)lParamSort;\n\t\t\n\t\tint nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue);\n\t\tnRet--;\n\t\treturn pInfo->bDescending ? -nRet : nRet;\n\t}\n#endif // !_WIN32_WCE\n\n\tBEGIN_MSG_MAP(CSortListViewImpl)\n\t\tMESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn)\n\t\tMESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn)\n\t\tNOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick)\n\t\tNOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\t\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);\n\t\tif(lRet == -1)\n\t\t\treturn -1;\n\n\t\tWORD wType = 0;\n\t\tm_arrColSortType.Add(wType);\n\t\tint nCount = m_arrColSortType.GetSize();\n\t\tATLASSERT(nCount == GetColumnCount());\n\n\t\tfor(int i = nCount - 1; i > lRet; i--)\n\t\t\tm_arrColSortType[i] = m_arrColSortType[i - 1];\n\t\tm_arrColSortType[(int)lRet] = LVCOLSORT_TEXT;\n\n\t\tif(lRet <= m_iSortColumn)\n\t\t\tm_iSortColumn++;\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\t\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);\n\t\tif(lRet == 0)\n\t\t\treturn 0;\n\n\t\tint iCol = (int)wParam; \n\t\tif(m_iSortColumn == iCol)\n\t\t\tm_iSortColumn = -1;\n\t\telse if(m_iSortColumn > iCol)\n\t\t\tm_iSortColumn--;\n\t\tm_arrColSortType.RemoveAt(iCol);\n\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tLPNMHEADER p = (LPNMHEADER)pnmh;\n\t\tif(p->iButton == 0)\n\t\t{\n\t\t\tint iOld = m_iSortColumn;\n\t\t\tbool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false;\n\t\t\tif(DoSortItems(p->iItem, bDescending))\n\t\t\t\tNotifyParentSortChanged(p->iItem, iOld);\t\t\t\t\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifndef _WIN32_WCE\n\t\tif(wParam == SPI_SETNONCLIENTMETRICS)\n\t\t\tGetSystemSettings();\n#else  // CE specific\n\t\twParam; // avoid level 4 warning\n\t\tGetSystemSettings();\n#endif // _WIN32_WCE\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tvoid GetSystemSettings()\n\t{\n\t\tif(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull())\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CreateSortBitmaps();\n\t\t\tif(m_iSortColumn != -1)\n\t\t\t\tSetSortColumn(m_iSortColumn);\n\t\t}\n\t}\n\n};\n\n\ntypedef ATL::CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_SHOWSELALWAYS , WS_EX_CLIENTEDGE>   CSortListViewCtrlTraits;\n\ntemplate <class T, class TBase = CListViewCtrl, class TWinTraits = CSortListViewCtrlTraits>\nclass ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl<T, TBase, TWinTraits>, public CSortListViewImpl<T>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())\n\n\tbool SortItems(int iCol, bool bDescending = false)\n\t{\n\t\treturn DoSortItems(iCol, bDescending);\n\t}\n\t\t\n\tBEGIN_MSG_MAP(CSortListViewCtrlImpl)\n\t\tMESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl<T>::OnInsertColumn)\n\t\tMESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl<T>::OnDeleteColumn)\n\t\tNOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl<T>::OnHeaderItemClick)\n\t\tNOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl<T>::OnHeaderItemClick)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl<T>::OnSettingChange)\n\tEND_MSG_MAP()\n};\n\nclass CSortListViewCtrl : public CSortListViewCtrlImpl<CSortListViewCtrl>\n{\npublic:\n\tDECLARE_WND_SUPERCLASS(_T(\"WTL_SortListViewCtrl\"), GetWndClassName())\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTabView - implements tab view window\n\n// TabView Notifications\n#define TBVN_PAGEACTIVATED   (0U-741)\n#define TBVN_CONTEXTMENU     (0U-742)\n\n// Notification data for TBVN_CONTEXTMENU\nstruct TBVCONTEXTMENUINFO\n{\n\tNMHDR hdr;\n\tPOINT pt;\n};\n\ntypedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO;\n\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE)\n\n// Declarations and enums\n\tstruct TABVIEWPAGE\n\t{\n\t\tHWND hWnd;\n\t\tLPTSTR lpstrTitle;\n\t\tLPVOID pData;\n\t};\n\n\tstruct TCITEMEXTRA\n\t{\n\t\tTCITEMHEADER tciheader;\n\t\tTABVIEWPAGE tvpage;\n\n\t\toperator LPTCITEM() { return (LPTCITEM)this; }\n\t};\n\n\tenum\n\t{\n\t\tm_nTabID = 1313,\n\t\tm_cxMoveMark = 6,\n\t\tm_cyMoveMark = 3,\n\t\tm_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1)\n\t};\n\n// Data members\n\tATL::CContainedWindowT<CTabCtrl> m_tab;\n\tint m_cyTabHeight;\n\n\tint m_nActivePage;\n\n\tint m_nInsertItem;\n\tPOINT m_ptStartDrag;\n\n\tCMenuHandle m_menu;\n\n\tint m_cchTabTextLength;\n\n\tint m_nMenuItemsCount;\n\n\tATL::CWindow m_wndTitleBar;\n\tLPTSTR m_lpstrTitleBarBase;\n\tint m_cchTitleBarLength;\n\n\tCImageList m_ilDrag;\n\n\tbool m_bDestroyPageOnRemove:1;\n\tbool m_bDestroyImageList:1;\n\tbool m_bActivePageMenuItem:1;\n\tbool m_bActiveAsDefaultMenuItem:1;\n\tbool m_bEmptyMenuItem:1;\n\tbool m_bWindowsMenuItem:1;\n\tbool m_bNoTabDrag:1;\n\t// internal\n\tbool m_bTabCapture:1;\n\tbool m_bTabDrag:1;\n\tbool m_bInternalFont:1;\n\n// Constructor/destructor\n\tCTabViewImpl() :\n\t\t\tm_nActivePage(-1), \n\t\t\tm_cyTabHeight(0), \n\t\t\tm_tab(this, 1), \n\t\t\tm_nInsertItem(-1), \n\t\t\tm_cchTabTextLength(30), \n\t\t\tm_nMenuItemsCount(10), \n\t\t\tm_lpstrTitleBarBase(NULL), \n\t\t\tm_cchTitleBarLength(100), \n\t\t\tm_bDestroyPageOnRemove(true), \n\t\t\tm_bDestroyImageList(true), \n\t\t\tm_bActivePageMenuItem(true), \n\t\t\tm_bActiveAsDefaultMenuItem(false), \n\t\t\tm_bEmptyMenuItem(false), \n\t\t\tm_bWindowsMenuItem(false), \n\t\t\tm_bNoTabDrag(false), \n\t\t\tm_bTabCapture(false), \n\t\t\tm_bTabDrag(false), \n\t\t\tm_bInternalFont(false)\n\t{\n\t\tm_ptStartDrag.x = 0;\n\t\tm_ptStartDrag.y = 0;\n\t}\n\n\t~CTabViewImpl()\n\t{\n\t\tdelete [] m_lpstrTitleBarBase;\n\t}\n\n// Message filter function - to be called from PreTranslateMessage of the main window\n\tBOOL PreTranslateMessage(MSG* pMsg)\n\t{\n\t\tif(IsWindow() == FALSE)\n\t\t\treturn FALSE;\n\n\t\tBOOL bRet = FALSE;\n\n\t\t// Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page)\n\t\tint nCount = GetPageCount();\n\t\tif(nCount > 0)\n\t\t{\n\t\t\tbool bControl = (::GetKeyState(VK_CONTROL) < 0);\n\t\t\tif((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl)\n\t\t\t{\n\t\t\t\tif(nCount > 1)\n\t\t\t\t{\n\t\t\t\t\tint nPage = m_nActivePage;\n\t\t\t\t\tbool bShift = (::GetKeyState(VK_SHIFT) < 0);\n\t\t\t\t\tif(bShift)\n\t\t\t\t\t\tnPage = (nPage > 0) ? (nPage - 1) : (nCount - 1);\n\t\t\t\t\telse\n\t\t\t\t\t\tnPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0;\n\n\t\t\t\t\tSetActivePage(nPage);\n\t\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\t\tpT->OnPageActivated(m_nActivePage);\n\t\t\t\t}\n\n\t\t\t\tbRet = TRUE;\n\t\t\t}\n\t\t}\n\n\t\t// If we are doing drag-drop, check for Escape key that cancels it\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\tif(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE)\n\t\t\t{\n\t\t\t\t::ReleaseCapture();\n\t\t\t\tbRet = TRUE;\n\t\t\t}\n\t\t}\n\n\t\t// Pass the message to the active page\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\tif(m_nActivePage != -1)\n\t\t\t\tbRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetPageCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_tab.GetItemCount();\n\t}\n\n\tint GetActivePage() const\n\t{\n\t\treturn m_nActivePage;\n\t}\n\n\tvoid SetActivePage(int nPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tSetRedraw(FALSE);\n\n\t\tif(m_nActivePage != -1)\n\t\t\t::ShowWindow(GetPageHWND(m_nActivePage), FALSE);\n\t\tm_nActivePage = nPage;\n\t\tm_tab.SetCurSel(m_nActivePage);\n\t\t::ShowWindow(GetPageHWND(m_nActivePage), TRUE);\n\n\t\tpT->UpdateLayout();\n\n\t\tSetRedraw(TRUE);\n\t\tRedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);\n\n\t\tif(::GetFocus() != m_tab.m_hWnd)\n\t\t\t::SetFocus(GetPageHWND(m_nActivePage));\n\n\t\tpT->UpdateTitleBar();\n\t\tpT->UpdateMenu();\n\t}\n\n\tHIMAGELIST GetImageList() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_tab.GetImageList();\n\t}\n\n\tHIMAGELIST SetImageList(HIMAGELIST hImageList)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn m_tab.SetImageList(hImageList);\n\t}\n\n\tvoid SetWindowMenu(HMENU hMenu)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tm_menu = hMenu;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateMenu();\n\t}\n\n\tvoid SetTitleBarWindow(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tdelete [] m_lpstrTitleBarBase;\n\t\tm_lpstrTitleBarBase = NULL;\n\n\t\tm_wndTitleBar = hWnd;\n\t\tif(hWnd == NULL)\n\t\t\treturn;\n\n\t\tint cchLen = m_wndTitleBar.GetWindowTextLength() + 1;\n\t\tATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]);\n\t\tif(m_lpstrTitleBarBase != NULL)\n\t\t{\n\t\t\tm_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen);\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateTitleBar();\n\t\t}\n\t}\n\n// Page attributes\n\tHWND GetPageHWND(int nPage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_PARAM;\n\t\tm_tab.GetItem(nPage, tcix);\n\n\t\treturn tcix.tvpage.hWnd;\n\t}\n\n\tLPCTSTR GetPageTitle(int nPage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_PARAM;\n\t\tif(m_tab.GetItem(nPage, tcix) == FALSE)\n\t\t\treturn NULL;\n\n\t\treturn tcix.tvpage.lpstrTitle;\n\t}\n\n\tbool SetPageTitle(int nPage, LPCTSTR lpstrTitle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tint cchBuff = lstrlen(lpstrTitle) + 1;\n\t\tLPTSTR lpstrBuff = NULL;\n\t\tATLTRY(lpstrBuff = new TCHAR[cchBuff]);\n\t\tif(lpstrBuff == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_PARAM;\n\t\tif(m_tab.GetItem(nPage, tcix) == FALSE)\n\t\t\treturn false;\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);\n\t\tif(lpstrTabText == NULL)\n\t\t\treturn false;\n\n\t\tdelete [] tcix.tvpage.lpstrTitle;\n\n\t\tpT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);\n\n\t\ttcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM;\n\t\ttcix.tciheader.pszText = lpstrTabText;\n\t\ttcix.tvpage.lpstrTitle = lpstrBuff;\n\t\tif(m_tab.SetItem(nPage, tcix) == FALSE)\n\t\t\treturn false;\n\n\t\tpT->UpdateTitleBar();\n\t\tpT->UpdateMenu();\n\n\t\treturn true;\n\t}\n\n\tLPVOID GetPageData(int nPage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_PARAM;\n\t\tm_tab.GetItem(nPage, tcix);\n\n\t\treturn tcix.tvpage.pData;\n\t}\n\n\tLPVOID SetPageData(int nPage, LPVOID pData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_PARAM;\n\t\tm_tab.GetItem(nPage, tcix);\n\t\tLPVOID pDataOld = tcix.tvpage.pData;\n\n\t\ttcix.tvpage.pData = pData;\n\t\tm_tab.SetItem(nPage, tcix);\n\n\t\treturn pDataOld;\n\t}\n\n\tint GetPageImage(int nPage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_IMAGE;\n\t\tm_tab.GetItem(nPage, tcix);\n\n\t\treturn tcix.tciheader.iImage;\n\t}\n\n\tint SetPageImage(int nPage, int nImage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_IMAGE;\n\t\tm_tab.GetItem(nPage, tcix);\n\t\tint nImageOld = tcix.tciheader.iImage;\n\n\t\ttcix.tciheader.iImage = nImage;\n\t\tm_tab.SetItem(nPage, tcix);\n\n\t\treturn nImageOld;\n\t}\n\n// Operations\n\tbool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)\n\t{\n\t\treturn InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData);\n\t}\n\n\tbool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage));\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tint cchBuff = lstrlen(lpstrTitle) + 1;\n\t\tLPTSTR lpstrBuff = NULL;\n\t\tATLTRY(lpstrBuff = new TCHAR[cchBuff]);\n\t\tif(lpstrBuff == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);\n\t\tif(lpstrTabText == NULL)\n\t\t\treturn false;\n\n\t\tpT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);\n\n\t\tSetRedraw(FALSE);\n\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;\n\t\ttcix.tciheader.pszText = lpstrTabText;\n\t\ttcix.tciheader.iImage = nImage;\n\t\ttcix.tvpage.hWnd = hWndView;\n\t\ttcix.tvpage.lpstrTitle = lpstrBuff;\n\t\ttcix.tvpage.pData = pData;\n\t\tint nItem = m_tab.InsertItem(nPage, tcix);\n\t\tif(nItem == -1)\n\t\t{\n\t\t\tdelete [] lpstrBuff;\n\t\t\tSetRedraw(TRUE);\n\t\t\treturn false;\n\t\t}\n\n\t\t// adjust active page index, if inserted before it\n\t\tif(nPage <= m_nActivePage)\n\t\t\tm_nActivePage++;\n\n\t\tSetActivePage(nItem);\n\t\tpT->OnPageActivated(m_nActivePage);\n\n\t\tif(GetPageCount() == 1)\n\t\t\tpT->ShowTabControl(true);\n\n\t\tpT->UpdateLayout();\n\n\t\tSetRedraw(TRUE);\n\t\tRedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);\n\n\t\treturn true;\n\t}\n\n\tvoid RemovePage(int nPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(IsValidPageIndex(nPage));\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tSetRedraw(FALSE);\n\n\t\tif(GetPageCount() == 1)\n\t\t\tpT->ShowTabControl(false);\n\n\t\tif(m_bDestroyPageOnRemove)\n\t\t\t::DestroyWindow(GetPageHWND(nPage));\n\t\telse\n\t\t\t::ShowWindow(GetPageHWND(nPage), FALSE);\n\t\tLPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage);\n\t\tdelete [] lpstrTitle;\n\n\t\tATLVERIFY(m_tab.DeleteItem(nPage) != FALSE);\n\n\t\tif(m_nActivePage == nPage)\n\t\t{\n\t\t\tm_nActivePage = -1;\n\n\t\t\tif(nPage > 0)\n\t\t\t{\n\t\t\t\tSetActivePage(nPage - 1);\n\t\t\t}\n\t\t\telse if(GetPageCount() > 0)\n\t\t\t{\n\t\t\t\tSetActivePage(nPage);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSetRedraw(TRUE);\n\t\t\t\tInvalidate();\n\t\t\t\tUpdateWindow();\n\t\t\t\tpT->UpdateTitleBar();\n\t\t\t\tpT->UpdateMenu();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage;\n\t\t\tm_nActivePage = -1;\n\t\t\tSetActivePage(nPage);\n\t\t}\n\n\t\tpT->OnPageActivated(m_nActivePage);\n\t}\n\n\tvoid RemoveAllPages()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tif(GetPageCount() == 0)\n\t\t\treturn;\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tSetRedraw(FALSE);\n\n\t\tpT->ShowTabControl(false);\n\n\t\tfor(int i = 0; i < GetPageCount(); i++)\n\t\t{\n\t\t\tif(m_bDestroyPageOnRemove)\n\t\t\t\t::DestroyWindow(GetPageHWND(i));\n\t\t\telse\n\t\t\t\t::ShowWindow(GetPageHWND(i), FALSE);\n\t\t\tLPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i);\n\t\t\tdelete [] lpstrTitle;\n\t\t}\n\t\tm_tab.DeleteAllItems();\n\n\t\tm_nActivePage = -1;\n\t\tpT->OnPageActivated(m_nActivePage);\n\n\t\tSetRedraw(TRUE);\n\t\tInvalidate();\n\t\tUpdateWindow();\n\n\t\tpT->UpdateTitleBar();\n\t\tpT->UpdateMenu();\n\t}\n\n\tint PageIndexFromHwnd(HWND hWnd) const\n\t{\n\t\tint nIndex = -1;\n\n\t\tfor(int i = 0; i < GetPageCount(); i++)\n\t\t{\n\t\t\tif(GetPageHWND(i) == hWnd)\n\t\t\t{\n\t\t\t\tnIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn nIndex;\n\t}\n\n\tvoid BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tCMenuHandle menu = hMenu;\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tint nFirstPos = 0;\n\n\t\t// Find first menu item in our range\n#ifndef _WIN32_WCE\n\t\tfor(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++)\n\t\t{\n\t\t\tUINT nID = menu.GetMenuItemID(nFirstPos);\n\t\t\tif((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST)\n\t\t\t\tbreak;\n\t\t}\n#else // CE specific\n\t\tfor(nFirstPos = 0; ; nFirstPos++)\n\t\t{\n\t\t\tCMenuItemInfo mii;\n\t\t\tmii.fMask = MIIM_ID;\n\t\t\tBOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii);\n\t\t\tif(bRet == FALSE)\n\t\t\t\tbreak;\n\t\t\tif((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST)\n\t\t\t\tbreak;\n\t\t}\n#endif // _WIN32_WCE\n\n\t\t// Remove all menu items for tab pages\n\t\tBOOL bRet = TRUE;\n\t\twhile(bRet != FALSE)\n\t\t\tbRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION);\n\n\t\t// Add separator if it's not already there\n\t\tint nPageCount = GetPageCount();\n\t\tif((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0))\n\t\t{\n\t\t\tCMenuItemInfo mii;\n\t\t\tmii.fMask = MIIM_TYPE;\n\t\t\tmenu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);\n\t\t\tif((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0))\n\t\t\t{\n\t\t\t\tmenu.AppendMenu(MF_SEPARATOR);\n\t\t\t\tnFirstPos++;\n\t\t\t}\n\t\t}\n\n\t\t// Add menu items for all pages\n\t\tif(nPageCount > 0)\n\t\t{\n\t\t\t// Append menu items for all pages\n\t\t\tconst int cchPrefix = 3;   // 2 digits + space\n\t\t\tnMenuItemsCount = __min(__min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax);\n\t\t\tATLASSERT(nMenuItemsCount < 100);   // 2 digits only\n\t\t\tif(nMenuItemsCount >= 100)\n\t\t\t\tnMenuItemsCount = 99;\n\n\t\t\tfor(int i = 0; i < nMenuItemsCount; i++)\n\t\t\t{\n\t\t\t\tLPCTSTR lpstrTitle = GetPageTitle(i);\n\t\t\t\tint nLen = lstrlen(lpstrTitle);\n\t\t\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\t\t\tLPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1);\n\t\t\t\tATLASSERT(lpstrText != NULL);\n\t\t\t\tif(lpstrText != NULL)\n\t\t\t\t{\n\t\t\t\t\tLPCTSTR lpstrFormat = (i < 9) ? _T(\"&%i %s\") : _T(\"%i %s\");\n\t\t\t\t\tSecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle);\n\t\t\t\t\tmenu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Mark active page\n\t\t\tif(bActivePageMenuItem && (m_nActivePage != -1))\n\t\t\t{\n#ifndef _WIN32_WCE\n\t\t\t\tif(bActiveAsDefaultMenuItem)\n\t\t\t\t{\n\t\t\t\t\tmenu.SetMenuDefaultItem((UINT)-1,  TRUE);\n\t\t\t\t\tmenu.SetMenuDefaultItem(nFirstPos + m_nActivePage,  TRUE);\n\t\t\t\t}\n\t\t\t\telse\n#else // CE specific\n\t\t\t\tbActiveAsDefaultMenuItem;   // avoid level 4 warning\n#endif // _WIN32_WCE\n\t\t\t\t{\n\t\t\t\t\tmenu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(bEmptyMenuItem)\n\t\t\t{\n\t\t\t\tmenu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText());\n\t\t\t\tmenu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED);\n\t\t\t}\n\n\t\t\t// Remove separator if nothing else is there\n\t\t\tif(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0))\n\t\t\t{\n\t\t\t\tCMenuItemInfo mii;\n\t\t\t\tmii.fMask = MIIM_TYPE;\n\t\t\t\tmenu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);\n\t\t\t\tif((mii.fType & MFT_SEPARATOR) != 0)\n\t\t\t\t\tmenu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION);\n\t\t\t}\n\t\t}\n\n\t\t// Add \"Windows...\" menu item\n\t\tif(bWindowsMenuItem)\n\t\t\tmenu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText());\n\t}\n\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->CreateTabControl();\n\t\t\tpT->UpdateLayout();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CTabViewImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tMESSAGE_HANDLER(WM_GETFONT, OnGetFont)\n\t\tMESSAGE_HANDLER(WM_SETFONT, OnSetFont)\n\t\tNOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged)\n\t\tNOTIFY_ID_HANDLER(m_nTabID, OnTabNotification)\n#ifndef _WIN32_WCE\n\t\tNOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo)\n#endif // !_WIN32_WCE\n\t\tFORWARD_NOTIFICATIONS()\n\tALT_MSG_MAP(1)   // tab control\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove)\n\t\tMESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp)\n\t\tMESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->CreateTabControl();\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tRemoveAllPages();\n\n\t\tif(m_bDestroyImageList)\n\t\t{\n\t\t\tCImageList il = m_tab.SetImageList(NULL);\n\t\t\tif(il.m_hImageList != NULL)\n\t\t\t\til.Destroy();\n\t\t}\n\n\t\tif(m_bInternalFont)\n\t\t{\n\t\t\tHFONT hFont = m_tab.GetFont();\n\t\t\tm_tab.SetFont(NULL, FALSE);\n\t\t\t::DeleteObject(hFont);\n\t\t\tm_bInternalFont = false;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_nActivePage != -1)\n\t\t\t::SetFocus(GetPageHWND(m_nActivePage));\n\t\treturn 0;\n\t}\n\n\tLRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn m_tab.SendMessage(WM_GETFONT);\n\t}\n\n\tLRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_bInternalFont)\n\t\t{\n\t\t\tHFONT hFont = m_tab.GetFont();\n\t\t\tm_tab.SetFont(NULL, FALSE);\n\t\t\t::DeleteObject(hFont);\n\t\t\tm_bInternalFont = false;\n\t\t}\n\n\t\tm_tab.SendMessage(WM_SETFONT, wParam, lParam);\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_cyTabHeight = pT->CalcTabHeight();\n\n\t\tif((BOOL)lParam != FALSE)\n\t\t\tpT->UpdateLayout();\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\t{\n\t\tSetActivePage(m_tab.GetCurSel());\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnPageActivated(m_nActivePage);\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\t{\n\t\t// nothing to do - this just blocks all tab control\n\t\t// notifications from being propagated further\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tLPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh;\n\t\tif(pTTDI->hdr.hwndFrom == m_tab.GetTooltips())\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateTooltipText(pTTDI);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 0;\n\t}\n#endif // !_WIN32_WCE\n\n// Tab control message handlers\n\tLRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(!m_bNoTabDrag && (m_tab.GetItemCount() > 1))\n\t\t{\n\t\t\tm_bTabCapture = true;\n\t\t\tm_tab.SetCapture();\n\n\t\t\tm_ptStartDrag.x = GET_X_LPARAM(lParam);\n\t\t\tm_ptStartDrag.y = GET_Y_LPARAM(lParam);\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(m_bTabCapture)\n\t\t{\n\t\t\tif(m_bTabDrag)\n\t\t\t{\n\t\t\t\tTCHITTESTINFO hti = { 0 };\n\t\t\t\thti.pt.x = GET_X_LPARAM(lParam);\n\t\t\t\thti.pt.y = GET_Y_LPARAM(lParam);\n\t\t\t\tint nItem = m_tab.HitTest(&hti);\n\t\t\t\tif(nItem != -1)\n\t\t\t\t\tMovePage(m_nActivePage, nItem);\n\t\t\t}\n\n\t\t\t::ReleaseCapture();\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bTabCapture)\n\t\t{\n\t\t\tm_bTabCapture = false;\n\n\t\t\tif(m_bTabDrag)\n\t\t\t{\n\t\t\t\tm_bTabDrag = false;\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->DrawMoveMark(-1);\n\n#ifndef _WIN32_WCE\n\t\t\t\tm_ilDrag.DragLeave(GetDesktopWindow());\n#endif // !_WIN32_WCE\n\t\t\t\tm_ilDrag.EndDrag();\n\n\t\t\t\tm_ilDrag.Destroy();\n\t\t\t\tm_ilDrag.m_hImageList = NULL;\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n\n\t\tif(m_bTabCapture)\n\t\t{\n\t\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\n\t\t\tif(!m_bTabDrag)\n\t\t\t{\n#ifndef _WIN32_WCE\n\t\t\t\tif(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) ||\n\t\t\t\t   abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG))\n#else // CE specific\n\t\t\t\tif(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 ||\n\t\t\t\t   abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4)\n#endif // _WIN32_WCE\n\t\t\t\t{\n\t\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\t\tpT->GenerateDragImage(m_nActivePage);\n\n\t\t\t\t\tint cxCursor = ::GetSystemMetrics(SM_CXCURSOR);\n\t\t\t\t\tint cyCursor = ::GetSystemMetrics(SM_CYCURSOR);\n\t\t\t\t\tm_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2));\n#ifndef _WIN32_WCE\n\t\t\t\t\tPOINT ptEnter = m_ptStartDrag;\n\t\t\t\t\tm_tab.ClientToScreen(&ptEnter);\n\t\t\t\t\tm_ilDrag.DragEnter(GetDesktopWindow(), ptEnter);\n#endif // !_WIN32_WCE\n\n\t\t\t\t\tm_bTabDrag = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(m_bTabDrag)\n\t\t\t{\n\t\t\t\tTCHITTESTINFO hti = { 0 };\n\t\t\t\thti.pt = pt;\n\t\t\t\tint nItem = m_tab.HitTest(&hti);\n\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->SetMoveCursor(nItem != -1);\n\n\t\t\t\tif(m_nInsertItem != nItem)\n\t\t\t\t\tpT->DrawMoveMark(nItem);\n\n\t\t\t\tm_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE);\n\t\t\t\tm_tab.ClientToScreen(&pt);\n\t\t\t\tm_ilDrag.DragMove(pt);\n\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tTCHITTESTINFO hti = { 0 };\n\t\thti.pt.x = GET_X_LPARAM(lParam);\n\t\thti.pt.y = GET_Y_LPARAM(lParam);\n\t\tint nItem = m_tab.HitTest(&hti);\n\t\tif(nItem != -1)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->OnContextMenu(nItem, hti.pt);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbool bShift = (::GetKeyState(VK_SHIFT) < 0);\n\t\tif(wParam == VK_F10 && bShift)\n\t\t{\n\t\t\tif(m_nActivePage != -1)\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\tm_tab.GetItemRect(m_nActivePage, &rect);\n\t\t\t\tPOINT pt = { rect.left, rect.bottom };\n\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\tpT->OnContextMenu(m_nActivePage, pt);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n// Implementation helpers\n\tbool IsValidPageIndex(int nPage) const\n\t{\n\t\treturn (nPage >= 0 && nPage < GetPageCount());\n\t}\n\n\tbool MovePage(int nMovePage, int nInsertBeforePage)\n\t{\n\t\tATLASSERT(IsValidPageIndex(nMovePage));\n\t\tATLASSERT(IsValidPageIndex(nInsertBeforePage));\n\n\t\tif(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage))\n\t\t\treturn false;\n\n\t\tif(nMovePage == nInsertBeforePage)\n\t\t\treturn true;   // nothing to do\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);\n\t\tif(lpstrTabText == NULL)\n\t\t\treturn false;\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;\n\t\ttcix.tciheader.pszText = lpstrTabText;\n\t\ttcix.tciheader.cchTextMax = m_cchTabTextLength + 1;\n\t\tBOOL bRet = m_tab.GetItem(nMovePage, tcix);\n\t\tATLASSERT(bRet != FALSE);\n\t\tif(bRet == FALSE)\n\t\t\treturn false;\n\n\t\tint nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage;\n\t\tint nNewItem = m_tab.InsertItem(nInsertItem, tcix);\n\t\tATLASSERT(nNewItem == nInsertItem);\n\t\tif(nNewItem != nInsertItem)\n\t\t{\n\t\t\tATLVERIFY(m_tab.DeleteItem(nNewItem));\n\t\t\treturn false;\n\t\t}\n\n\t\tif(nMovePage > nInsertBeforePage)\n\t\t\tATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE);\n\t\telse if(nMovePage < nInsertBeforePage)\n\t\t\tATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE);\n\n\t\tSetActivePage(nInsertBeforePage);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnPageActivated(m_nActivePage);\n\n\t\treturn true;\n\t}\n\n// Implementation overrideables\n\tbool CreateTabControl()\n\t{\n#ifndef _WIN32_WCE\n\t\tm_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID);\n#else // CE specific\n\t\tm_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID);\n#endif // _WIN32_WCE\n\t\tATLASSERT(m_tab.m_hWnd != NULL);\n\t\tif(m_tab.m_hWnd == NULL)\n\t\t\treturn false;\n\n\t\tm_tab.SetFont(AtlCreateControlFont());\n\t\tm_bInternalFont = true;\n\n\t\tm_tab.SetItemExtra(sizeof(TABVIEWPAGE));\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_cyTabHeight = pT->CalcTabHeight();\n\n\t\treturn true;\n\t}\n\n\tint CalcTabHeight()\n\t{\n\t\tint nCount = m_tab.GetItemCount();\n\t\tTCHAR szText[] = _T(\"NS\");\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_TEXT;\n\t\ttcix.tciheader.pszText = szText;\n\t\tint nIndex = m_tab.InsertItem(nCount, tcix);\n\n\t\tRECT rect = { 0, 0, 1000, 1000 };\n\t\tm_tab.AdjustRect(FALSE, &rect);\n\n\t\tRECT rcWnd = { 0, 0, 1000, rect.top };\n\t\t::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle());\n\n\t\tint nHeight = rcWnd.bottom - rcWnd.top;\n\n\t\tm_tab.DeleteItem(nIndex);\n\n\t\treturn nHeight;\n\t}\n\n\tvoid ShowTabControl(bool bShow)\n\t{\n\t\tm_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE);\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout();\n\t}\n\n\tvoid UpdateLayout()\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\n\t\tint cyOffset = 0;\n\t\tif(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))\n\t\t{\n\t\t\tm_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER);\n\t\t\tcyOffset = m_cyTabHeight;\n\t\t}\n\n\t\tif(m_nActivePage != -1)\n\t\t\t::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, cyOffset, rect.right - rect.left, rect.bottom - rect.top - cyOffset, SWP_NOZORDER);\n\t}\n\n\tvoid UpdateMenu()\n\t{\n\t\tif(m_menu.m_hMenu != NULL)\n\t\t\tBuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem);\n\t}\n\n\tvoid UpdateTitleBar()\n\t{\n\t\tif(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL)\n\t\t\treturn;   // nothing to do\n\n\t\tif(m_nActivePage != -1)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tLPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage);\n\t\t\tLPCTSTR lpstrDivider = pT->GetTitleDividerText();\n\t\t\tint cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1;\n\t\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\t\tLPTSTR lpstrPageTitle = buff.Allocate(cchBuffer);\n\t\t\tATLASSERT(lpstrPageTitle != NULL);\n\t\t\tif(lpstrPageTitle != NULL)\n\t\t\t{\n\t\t\t\tpT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1);\n\t\t\t\tSecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider);\n\t\t\t\tSecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlpstrPageTitle = m_lpstrTitleBarBase;\n\t\t\t}\n\n\t\t\tm_wndTitleBar.SetWindowText(lpstrPageTitle);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_wndTitleBar.SetWindowText(m_lpstrTitleBarBase);\n\t\t}\n\t}\n\n\tvoid DrawMoveMark(int nItem)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tif(m_nInsertItem != -1)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetMoveMarkRect(rect);\n\t\t\tm_tab.InvalidateRect(&rect);\n\t\t}\n\n\t\tm_nInsertItem = nItem;\n\n\t\tif(m_nInsertItem != -1)\n\t\t{\n\t\t\tCClientDC dc(m_tab.m_hWnd);\n\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetMoveMarkRect(rect);\n\n\t\t\tCPen pen;\n\t\t\tpen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT));\n\t\t\tCBrush brush;\n\t\t\tbrush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT));\n\n\t\t\tHPEN hPenOld = dc.SelectPen(pen);\n\t\t\tHBRUSH hBrushOld = dc.SelectBrush(brush);\n\n\t\t\tint x = rect.left;\n\t\t\tint y = rect.top;\n\t\t\tPOINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } };\n\t\t\tdc.Polygon(ptsTop, 3);\n\n\t\t\ty = rect.bottom - 1;\n\t\t\tPOINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } };\n\t\t\tdc.Polygon(ptsBottom, 3);\n\n\t\t\tdc.SelectPen(hPenOld);\n\t\t\tdc.SelectBrush(hBrushOld);\n\t\t}\n\t}\n\n\tvoid GetMoveMarkRect(RECT& rect) const\n\t{\n\t\tm_tab.GetClientRect(&rect);\n\n\t\tRECT rcItem = { 0 };\n\t\tm_tab.GetItemRect(m_nInsertItem, &rcItem);\n\n\t\tif(m_nInsertItem <= m_nActivePage)\n\t\t{\n\t\t\trect.left = rcItem.left - m_cxMoveMark / 2 - 1;\n\t\t\trect.right = rcItem.left + m_cxMoveMark / 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\trect.left = rcItem.right - m_cxMoveMark / 2 - 1;\n\t\t\trect.right = rcItem.right + m_cxMoveMark / 2;\n\t\t}\n\t}\n\n\tvoid SetMoveCursor(bool bCanMove)\n\t{\n\t\t::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO));\n\t}\n\n\tvoid GenerateDragImage(int nItem)\n\t{\n\t\tATLASSERT(IsValidPageIndex(nItem));\n\n#ifndef _WIN32_WCE\n\t\tRECT rcItem = { 0 };\n\t\tm_tab.GetItemRect(nItem, &rcItem);\n\t\t::InflateRect(&rcItem, 2, 2);   // make bigger to cover selected item\n#else // CE specific\n\t\tnItem;   // avoid level 4 warning\n\t\tRECT rcItem = { 0, 0, 40, 20 };\n#endif // _WIN32_WCE\n\n\t\tATLASSERT(m_ilDrag.m_hImageList == NULL);\n\t\tm_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1);\n\n\t\tCClientDC dc(m_hWnd);\n\t\tCDC dcMem;\n\t\tdcMem.CreateCompatibleDC(dc);\n\t\tATLASSERT(dcMem.m_hDC != NULL);\n\t\tdcMem.SetViewportOrg(-rcItem.left, -rcItem.top);\n\n\t\tCBitmap bmp;\n\t\tbmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top);\n\t\tATLASSERT(bmp.m_hBitmap != NULL);\n\n\t\tHBITMAP hBmpOld = dcMem.SelectBitmap(bmp);\n#ifndef _WIN32_WCE\n\t\tm_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC);\n#else // CE specific\n\t\tdcMem.Rectangle(&rcItem);\n#endif // _WIN32_WCE\n\t\tdcMem.SelectBitmap(hBmpOld);\n\n\t\tATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1);\n\t}\n\n\tvoid ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle)\n\t{\n\t\tif(lstrlen(lpstrTitle) >= cchShortTitle)\n\t\t{\n\t\t\tLPCTSTR lpstrEllipsis = _T(\"...\");\n\t\t\tint cchEllipsis = lstrlen(lpstrEllipsis);\n\t\t\tSecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1);\n\t\t\tSecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle);\n\t\t}\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid UpdateTooltipText(LPNMTTDISPINFO pTTDI)\n\t{\n\t\tATLASSERT(pTTDI != NULL);\n\t\tpTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom);\n\t}\n#endif // !_WIN32_WCE\n\n// Text for menu items and title bar - override to provide different strings\n\tstatic LPCTSTR GetEmptyListText()\n\t{\n\t\treturn _T(\"(Empty)\");\n\t}\n\n\tstatic LPCTSTR GetWindowsMenuItemText()\n\t{\n\t\treturn _T(\"&Windows...\");\n\t}\n\n\tstatic LPCTSTR GetTitleDividerText()\n\t{\n\t\treturn _T(\" - \");\n\t}\n\n// Notifications - override to provide different behavior\n\tvoid OnPageActivated(int nPage)\n\t{\n\t\tNMHDR nmhdr = { 0 };\n\t\tnmhdr.hwndFrom = m_hWnd;\n\t\tnmhdr.idFrom = nPage;\n\t\tnmhdr.code = TBVN_PAGEACTIVATED;\n\t\t::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);\n\t}\n\n\tvoid OnContextMenu(int nPage, POINT pt)\n\t{\n\t\tm_tab.ClientToScreen(&pt);\n\n\t\tTBVCONTEXTMENUINFO cmi = { 0 };\n\t\tcmi.hdr.hwndFrom = m_hWnd;\n\t\tcmi.hdr.idFrom = nPage;\n\t\tcmi.hdr.code = TBVN_CONTEXTMENU;\n\t\tcmi.pt = pt;\n\t\t::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi);\n\t}\n};\n\nclass CTabView : public CTabViewImpl<CTabView>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_TabView\"), 0, COLOR_APPWORKSPACE)\n};\n\n}; // namespace WTL\n\n#endif // __ATLCTRLX_H__\n"
  },
  {
    "path": "WTL/atlddx.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLDDX_H__\n#define __ATLDDX_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlddx.h requires atlapp.h to be included first\n#endif\n\n#if defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)\n\t#error Cannot use floating point DDX with _ATL_MIN_CRT defined\n#endif // defined(_ATL_USE_DDX_FLOAT) && defined(_ATL_MIN_CRT)\n\n#ifdef _ATL_USE_DDX_FLOAT\n  #include <float.h>\n#endif // _ATL_USE_DDX_FLOAT\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CWinDataExchange<T>\n\n\nnamespace WTL\n{\n\n// Constants\n#define DDX_LOAD\tFALSE\n#define DDX_SAVE\tTRUE\n\n// DDX map macros\n#define BEGIN_DDX_MAP(thisClass) \\\n\tBOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) \\\n\t{ \\\n\t\t(bSaveAndValidate); \\\n\t\t(nCtlID);\n\n#define DDX_TEXT(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_TEXT_LEN(nID, var, len) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Text(nID, var, sizeof(var), bSaveAndValidate, TRUE, len)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_INT(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Int(nID, var, TRUE, bSaveAndValidate)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_INT_RANGE(nID, var, min, max) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Int(nID, var, TRUE, bSaveAndValidate, TRUE, min, max)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_UINT(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Int(nID, var, FALSE, bSaveAndValidate)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_UINT_RANGE(nID, var, min, max) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Int(nID, var, FALSE, bSaveAndValidate, TRUE, min, max)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#ifdef _ATL_USE_DDX_FLOAT\n#define DDX_FLOAT(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Float(nID, var, bSaveAndValidate)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_FLOAT_RANGE(nID, var, min, max) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n#define DDX_FLOAT_P(nID, var, precision) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Float(nID, var, bSaveAndValidate, FALSE, 0, 0, precision)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n\n#define DDX_FLOAT_P_RANGE(nID, var, min, max, precision) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t{ \\\n\t\t\tif(!DDX_Float(nID, var, bSaveAndValidate, TRUE, min, max, precision)) \\\n\t\t\t\treturn FALSE; \\\n\t\t}\n#endif // _ATL_USE_DDX_FLOAT\n\n#define DDX_CONTROL(nID, obj) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t\tDDX_Control(nID, obj, bSaveAndValidate);\n\n#define DDX_CONTROL_HANDLE(nID, obj) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t\tDDX_Control_Handle(nID, obj, bSaveAndValidate);\n\n#define DDX_CHECK(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t\tDDX_Check(nID, var, bSaveAndValidate);\n\n#define DDX_RADIO(nID, var) \\\n\t\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\t\tDDX_Radio(nID, var, bSaveAndValidate);\n\n#define END_DDX_MAP() \\\n\t\treturn TRUE; \\\n\t}\n\n// DDX support for Tab, Combo, ListBox and ListView selection index\n// Note: Specialized versions require atlctrls.h to be included first\n#if (_MSC_VER >= 1300)\n\n#define DDX_INDEX(CtrlClass, nID, var) \\\n\tif(nCtlID == (UINT)-1 || nCtlID == nID) \\\n\t\tDDX_Index<CtrlClass>(nID, var, bSaveAndValidate);\n\n#ifdef __ATLCTRLS_H__\n  #define DDX_TAB_INDEX(nID, var)      DDX_INDEX(WTL::CTabCtrl, nID, var)\n  #ifndef WIN32_PLATFORM_WFSP   // No COMBOBOX on SmartPhones\n    #define DDX_COMBO_INDEX(nID, var)    DDX_INDEX(WTL::CComboBox, nID, var)\n  #endif\n  #define DDX_LISTBOX_INDEX(nID, var)  DDX_INDEX(WTL::CListBox, nID, var)\n  #define DDX_LISTVIEW_INDEX(nID, var) DDX_INDEX(WTL::CListViewCtrl, nID, var)\n#endif // __ATLCTRLS_H__\n\n#endif // (_MSC_VER >= 1300)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWinDataExchange - provides support for DDX\n\ntemplate <class T>\nclass CWinDataExchange\n{\npublic:\n// Data exchange method - override in your derived class\n\tBOOL DoDataExchange(BOOL /*bSaveAndValidate*/ = FALSE, UINT /*nCtlID*/ = (UINT)-1)\n\t{\n\t\t// this one should never be called, override it in\n\t\t// your derived class by implementing DDX map\n\t\tATLASSERT(FALSE);\n\t\treturn FALSE;\n\t}\n\n// Helpers for validation error reporting\n\tenum _XDataType\n\t{\n\t\tddxDataNull = 0,\n\t\tddxDataText = 1,\n\t\tddxDataInt = 2,\n\t\tddxDataFloat = 3,\n\t\tddxDataDouble = 4\n\t};\n\n\tstruct _XTextData\n\t{\n\t\tint nLength;\n\t\tint nMaxLength;\n\t};\n\n\tstruct _XIntData\n\t{\n\t\tlong nVal;\n\t\tlong nMin;\n\t\tlong nMax;\n\t};\n\n\tstruct _XFloatData\n\t{\n\t\tdouble nVal;\n\t\tdouble nMin;\n\t\tdouble nMax;\n\t};\n\n\tstruct _XData\n\t{\n\t\t_XDataType nDataType;\n\t\tunion\n\t\t{\n\t\t\t_XTextData textData;\n\t\t\t_XIntData intData;\n\t\t\t_XFloatData floatData;\n\t\t};\n\t};\n\n// Text exchange\n\tBOOL DDX_Text(UINT nID, LPTSTR lpstrText, int cbSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\n\t\tif(bSave)\n\t\t{\n\t\t\tHWND hWndCtrl = pT->GetDlgItem(nID);\n\t\t\tint nRetLen = ::GetWindowText(hWndCtrl, lpstrText, cbSize / sizeof(TCHAR));\n\t\t\tif(nRetLen < ::GetWindowTextLength(hWndCtrl))\n\t\t\t\tbSuccess = FALSE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));\n\t\t\tbSuccess = pT->SetDlgItemText(nID, lpstrText);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nLength > 0);\n\t\t\tif(lstrlen(lpstrText) > nLength)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataText };\n\t\t\t\tdata.textData.nLength = lstrlen(lpstrText);\n\t\t\t\tdata.textData.nMaxLength = nLength;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n\n\tBOOL DDX_Text(UINT nID, BSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\n\t\tif(bSave)\n\t\t{\n\t\t\tbSuccess = pT->GetDlgItemText(nID, bstrText);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUSES_CONVERSION;\n\t\t\tLPTSTR lpstrText = OLE2T(bstrText);\n\t\t\tATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));\n\t\t\tbSuccess = pT->SetDlgItemText(nID, lpstrText);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nLength > 0);\n\t\t\tif((int)::SysStringLen(bstrText) > nLength)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataText };\n\t\t\t\tdata.textData.nLength = (int)::SysStringLen(bstrText);\n\t\t\t\tdata.textData.nMaxLength = nLength;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n\n\tBOOL DDX_Text(UINT nID, ATL::CComBSTR& bstrText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\n\t\tif(bSave)\n\t\t{\n\t\t\tbSuccess = pT->GetDlgItemText(nID, (BSTR&)bstrText);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUSES_CONVERSION;\n\t\t\tLPTSTR lpstrText = OLE2T(bstrText);\n\t\t\tATLASSERT(!bValidate || (lstrlen(lpstrText) <= nLength));\n\t\t\tbSuccess = pT->SetDlgItemText(nID, lpstrText);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nLength > 0);\n\t\t\tif((int)bstrText.Length() > nLength)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataText };\n\t\t\t\tdata.textData.nLength = (int)bstrText.Length();\n\t\t\t\tdata.textData.nMaxLength = nLength;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL DDX_Text(UINT nID, _CSTRING_NS::CString& strText, int /*cbSize*/, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\n\t\tif(bSave)\n\t\t{\n\t\t\tHWND hWndCtrl = pT->GetDlgItem(nID);\n\t\t\tint nLen = ::GetWindowTextLength(hWndCtrl);\n\t\t\tint nRetLen = -1;\n\t\t\tLPTSTR lpstr = strText.GetBufferSetLength(nLen);\n\t\t\tif(lpstr != NULL)\n\t\t\t{\n\t\t\t\tnRetLen = ::GetWindowText(hWndCtrl, lpstr, nLen + 1);\n\t\t\t\tstrText.ReleaseBuffer();\n\t\t\t}\n\t\t\tif(nRetLen < nLen)\n\t\t\t\tbSuccess = FALSE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbSuccess = pT->SetDlgItemText(nID, strText);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nLength > 0);\n\t\t\tif(strText.GetLength() > nLength)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataText };\n\t\t\t\tdata.textData.nLength = strText.GetLength();\n\t\t\t\tdata.textData.nMaxLength = nLength;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n// Numeric exchange\n\ttemplate <class Type>\n\tBOOL DDX_Int(UINT nID, Type& nVal, BOOL bSigned, BOOL bSave, BOOL bValidate = FALSE, Type nMin = 0, Type nMax = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\n\t\tif(bSave)\n\t\t{\n\t\t\tnVal = (Type)pT->GetDlgItemInt(nID, &bSuccess, bSigned);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax));\n\t\t\tbSuccess = pT->SetDlgItemInt(nID, nVal, bSigned);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nMin != nMax);\n\t\t\tif(nVal < nMin || nVal > nMax)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataInt };\n\t\t\t\tdata.intData.nVal = (long)nVal;\n\t\t\t\tdata.intData.nMin = (long)nMin;\n\t\t\t\tdata.intData.nMax = (long)nMax;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n\n// Float exchange\n#ifdef _ATL_USE_DDX_FLOAT\n\tstatic BOOL _AtlSimpleFloatParse(LPCTSTR lpszText, double& d)\n\t{\n\t\tATLASSERT(lpszText != NULL);\n\t\twhile (*lpszText == _T(' ') || *lpszText == _T('\\t'))\n\t\t\tlpszText++;\n\n\t\tTCHAR chFirst = lpszText[0];\n\t\td = _tcstod(lpszText, (LPTSTR*)&lpszText);\n\t\tif (d == 0.0 && chFirst != _T('0'))\n\t\t\treturn FALSE;   // could not convert\n\t\twhile (*lpszText == _T(' ') || *lpszText == _T('\\t'))\n\t\t\tlpszText++;\n\n\t\tif (*lpszText != _T('\\0'))\n\t\t\treturn FALSE;   // not terminated properly\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL DDX_Float(UINT nID, float& nVal, BOOL bSave, BOOL bValidate = FALSE, float nMin = 0.F, float nMax = 0.F, int nPrecision = FLT_DIG)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\t\tconst int cchBuff = 32;\n\t\tTCHAR szBuff[cchBuff] = { 0 };\n\n\t\tif(bSave)\n\t\t{\n\t\t\tpT->GetDlgItemText(nID, szBuff, cchBuff);\n\t\t\tdouble d = 0;\n\t\t\tif(_AtlSimpleFloatParse(szBuff, d))\n\t\t\t\tnVal = (float)d;\n\t\t\telse\n\t\t\t\tbSuccess = FALSE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax));\n\t\t\tSecureHelper::sprintf_x(szBuff, cchBuff, _T(\"%.*g\"), nPrecision, nVal);\n\t\t\tbSuccess = pT->SetDlgItemText(nID, szBuff);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nMin != nMax);\n\t\t\tif(nVal < nMin || nVal > nMax)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataFloat };\n\t\t\t\tdata.floatData.nVal = (double)nVal;\n\t\t\t\tdata.floatData.nMin = (double)nMin;\n\t\t\t\tdata.floatData.nMax = (double)nMax;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n\n\tBOOL DDX_Float(UINT nID, double& nVal, BOOL bSave, BOOL bValidate = FALSE, double nMin = 0., double nMax = 0., int nPrecision = DBL_DIG)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bSuccess = TRUE;\n\t\tconst int cchBuff = 32;\n\t\tTCHAR szBuff[cchBuff] = { 0 };\n\n\t\tif(bSave)\n\t\t{\n\t\t\tpT->GetDlgItemText(nID, szBuff, cchBuff);\n\t\t\tdouble d = 0;\n\t\t\tif(_AtlSimpleFloatParse(szBuff, d))\n\t\t\t\tnVal = d;\n\t\t\telse\n\t\t\t\tbSuccess = FALSE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(!bValidate || (nVal >= nMin && nVal <= nMax));\n\t\t\tSecureHelper::sprintf_x(szBuff, cchBuff, _T(\"%.*g\"), nPrecision, nVal);\n\t\t\tbSuccess = pT->SetDlgItemText(nID, szBuff);\n\t\t}\n\n\t\tif(!bSuccess)\n\t\t{\n\t\t\tpT->OnDataExchangeError(nID, bSave);\n\t\t}\n\t\telse if(bSave && bValidate)   // validation\n\t\t{\n\t\t\tATLASSERT(nMin != nMax);\n\t\t\tif(nVal < nMin || nVal > nMax)\n\t\t\t{\n\t\t\t\t_XData data = { ddxDataFloat };\n\t\t\t\tdata.floatData.nVal = nVal;\n\t\t\t\tdata.floatData.nMin = nMin;\n\t\t\t\tdata.floatData.nMax = nMax;\n\t\t\t\tpT->OnDataValidateError(nID, bSave, data);\n\t\t\t\tbSuccess = FALSE;\n\t\t\t}\n\t\t}\n\t\treturn bSuccess;\n\t}\n#endif // _ATL_USE_DDX_FLOAT\n\n// Full control subclassing (for CWindowImpl derived controls)\n\ttemplate <class TControl>\n\tvoid DDX_Control(UINT nID, TControl& ctrl, BOOL bSave)\n\t{\n\t\tif(!bSave && ctrl.m_hWnd == NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tctrl.SubclassWindow(pT->GetDlgItem(nID));\n\t\t}\n\t}\n\n// Simple control attaching (for HWND wrapper controls)\n\ttemplate <class TControl>\n\tvoid DDX_Control_Handle(UINT nID, TControl& ctrl, BOOL bSave)\n\t{\n\t\tif(!bSave && ctrl.m_hWnd == NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tctrl = pT->GetDlgItem(nID);\n\t\t}\n\t}\n\n// Control state\n\tvoid DDX_Check(UINT nID, int& nValue, BOOL bSave)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hWndCtrl = pT->GetDlgItem(nID);\n\t\tif(bSave)\n\t\t{\n\t\t\tnValue = (int)::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L);\n\t\t\tATLASSERT(nValue >= 0 && nValue <= 2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(nValue < 0 || nValue > 2)\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ATL: Warning - dialog data checkbox value (%d) out of range.\\n\"), nValue);\n\t\t\t\tnValue = 0;  // default to off\n\t\t\t}\n\t\t\t::SendMessage(hWndCtrl, BM_SETCHECK, nValue, 0L);\n\t\t}\n\t}\n\n\t// variant that supports bool (checked/not-checked, no intermediate state)\n\tvoid DDX_Check(UINT nID, bool& bCheck, BOOL bSave)\n\t{\n\t\tint nValue = bCheck ? 1 : 0;\n\t\tDDX_Check(nID, nValue, bSave);\n\n\t\tif(bSave)\n\t\t{\n\t\t\tif(nValue == 2)\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ATL: Warning - checkbox state (%d) out of supported range.\\n\"), nValue);\n\t\t\tbCheck = (nValue == 1);\n\t\t}\n\t}\n\n\tvoid DDX_Radio(UINT nID, int& nValue, BOOL bSave)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hWndCtrl = pT->GetDlgItem(nID);\n\t\tATLASSERT(hWndCtrl != NULL);\n\n\t\t// must be first in a group of auto radio buttons\n\t\tATLASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);\n\t\tATLASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);\n\n\t\tif(bSave)\n\t\t\tnValue = -1;     // value if none found\n\n\t\t// walk all children in group\n\t\tint nButton = 0;\n\t\tdo\n\t\t{\n\t\t\tif(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)\n\t\t\t{\n\t\t\t\t// control in group is a radio button\n\t\t\t\tif(bSave)\n\t\t\t\t{\n\t\t\t\t\tif(::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tATLASSERT(nValue == -1);    // only set once\n\t\t\t\t\t\tnValue = nButton;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// select button\n\t\t\t\t\t::SendMessage(hWndCtrl, BM_SETCHECK, (nButton == nValue), 0L);\n\t\t\t\t}\n\t\t\t\tnButton++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ATL: Warning - skipping non-radio button in group.\\n\"));\n\t\t\t}\n\t\t\thWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);\n\t\t}\n\t\twhile (hWndCtrl != NULL && !(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));\n\t}\n\n// DDX support for Tab, Combo, ListBox and ListView selection index\n#if (_MSC_VER >= 1300)\n\ttemplate <class TCtrl>\n\tINT _getSel(TCtrl& tCtrl)\n\t{\n\t\treturn tCtrl.GetCurSel();\n\t}\n\n\ttemplate <class TCtrl>\n\tvoid _setSel(TCtrl& tCtrl, INT iSel)\n\t{\n\t\tif(iSel < 0)\n\t\t\ttCtrl.SetCurSel(-1);\n\t\telse\n\t\t\ttCtrl.SetCurSel(iSel);\n\t}\n\n#ifdef __ATLCTRLS_H__\n\t// ListViewCtrl specialization\n\ttemplate <>\n\tINT _getSel(WTL::CListViewCtrl& tCtrl)\n\t{\n\t\treturn tCtrl.GetSelectedIndex();\n\t}\n\n\ttemplate <>\n\tvoid _setSel(WTL::CListViewCtrl& tCtrl, INT iSel)\n\t{\n\t\tif(iSel < 0)\n\t\t\ttCtrl.SelectItem(-1);\n\t\telse\n\t\t\ttCtrl.SelectItem(iSel);\n\t}\n#endif // __ATLCTRLS_H__\n\n\ttemplate <class TCtrl>\n\tvoid DDX_Index(UINT nID, INT& nVal, BOOL bSave)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tTCtrl ctrl(pT->GetDlgItem(nID));\n\n\t\tif(bSave)\n\t\t\tnVal = _getSel(ctrl);\n\t\telse\n\t\t\t_setSel(ctrl, nVal);\n\t}\n#endif // (_MSC_VER >= 1300)\n\n// Overrideables\n\tvoid OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/)\n\t{\n\t\t// Override to display an error message\n\t\t::MessageBeep((UINT)-1);\n\t\tT* pT = static_cast<T*>(this);\n\t\t::SetFocus(pT->GetDlgItem(nCtrlID));\n\t}\n\n\tvoid OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/)\n\t{\n\t\t// Override to display an error message\n\t\t::MessageBeep((UINT)-1);\n\t\tT* pT = static_cast<T*>(this);\n\t\t::SetFocus(pT->GetDlgItem(nCtrlID));\n\t}\n};\n\n}; // namespace WTL\n\n#endif // __ATLDDX_H__\n"
  },
  {
    "path": "WTL/atldlgs.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLDLGS_H__\n#define __ATLDLGS_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atldlgs.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atldlgs.h requires atlwin.h to be included first\n#endif\n\n#include <commdlg.h>\n#include <shlobj.h>\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n  #include <shobjidl.h>\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CFileDialogImpl<T>\n// CFileDialog\n// CFileDialogEx\n// CMultiFileDialogImpl<T>\n// CMultiFileDialog\n// CShellFileDialogImpl<T>\n// CShellFileOpenDialogImpl<T>\n// CShellFileOpenDialog\n// CShellFileSaveDialogImpl<T>\n// CShellFileSaveDialog\n// CFolderDialogImpl<T>\n// CFolderDialog\n// CFontDialogImpl<T>\n// CFontDialog\n// CRichEditFontDialogImpl<T>\n// CRichEditFontDialog\n// CColorDialogImpl<T>\n// CColorDialog\n// CPrintDialogImpl<T>\n// CPrintDialog\n// CPrintDialogExImpl<T>\n// CPrintDialogEx\n// CPageSetupDialogImpl<T>\n// CPageSetupDialog\n// CFindReplaceDialogImpl<T>\n// CFindReplaceDialog\n//\n// CDialogBaseUnits\n// CMemDlgTemplate\n// CIndirectDialogImpl<T, TDlgTemplate, TBase>\n//\n// CPropertySheetWindow\n// CPropertySheetImpl<T, TBase>\n// CPropertySheet\n// CPropertyPageWindow\n// CPropertyPageImpl<T, TBase>\n// CPropertyPage<t_wDlgTemplateID>\n// CAxPropertyPageImpl<T, TBase>\n// CAxPropertyPage<t_wDlgTemplateID>\n//\n// CWizard97SheetWindow\n// CWizard97SheetImpl<T, TBase>\n// CWizard97Sheet\n// CWizard97PageWindow\n// CWizard97PageImpl<T, TBase>\n// CWizard97ExteriorPageImpl<T, TBase>\n// CWizard97InteriorPageImpl<T, TBase>\n//\n// CAeroWizardFrameWindow\n// CAeroWizardFrameImpl<T, TBase>\n// CAeroWizardFrame\n// CAeroWizardPageWindow\n// CAeroWizardPageImpl<T, TBase>\n// CAeroWizardPage<t_wDlgTemplateID>\n// CAeroWizardAxPageImpl<T, TBase>\n// CAeroWizardAxPage<t_wDlgTemplateID>\n//\n// CTaskDialogConfig\n// CTaskDialogImpl<T>\n// CTaskDialog\n//\n// Global functions:\n//   AtlTaskDialog()\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CFileDialogImpl - used for File Open or File Save As\n\n// compatibility with the old (vc6.0) headers\n#if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)\n  #ifndef CDSIZEOF_STRUCT\n    #define CDSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))\n  #endif\n  #define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)\n  #define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)\n  #ifdef UNICODE\n    #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400W\n  #else\n    #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400A\n  #endif // !UNICODE\n#endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)\n\n#if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM)\n  #define CDN_INCLUDEITEM         (CDN_FIRST - 0x0007)\n#endif\n\ntemplate <class T>\nclass ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase\n{\npublic:\n#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)\n\tOPENFILENAMEEX m_ofn;\n#else\n\tOPENFILENAME m_ofn;\n#endif\n\tBOOL m_bOpenFileDialog;            // TRUE for file open, FALSE for file save\n\tTCHAR m_szFileTitle[_MAX_FNAME];   // contains file title after return\n\tTCHAR m_szFileName[_MAX_PATH];     // contains full path name after return\n\n\tCFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs\n\t\t\tLPCTSTR lpszDefExt = NULL,\n\t\t\tLPCTSTR lpszFileName = NULL,\n\t\t\tDWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,\n\t\t\tLPCTSTR lpszFilter = NULL,\n\t\t\tHWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL\n\t\tm_szFileName[0] = _T('\\0');\n\t\tm_szFileTitle[0] = _T('\\0');\n\n\t\tm_bOpenFileDialog = bOpenFileDialog;\n\n#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)\n\t\tm_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME);\n#else\n\t\tm_ofn.lStructSize = sizeof(m_ofn);\n#endif\n\n#if (_WIN32_WINNT >= 0x0500)\n\t\t// adjust struct size if running on older version of Windows\n\t\tif(AtlIsOldWindows())\n\t\t{\n\t\t\tATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400);   // must be\n\t\t\tm_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;\n\t\t}\n#endif // (_WIN32_WINNT >= 0x0500)\n\t\tm_ofn.lpstrFile = m_szFileName;\n\t\tm_ofn.nMaxFile = _MAX_PATH;\n\t\tm_ofn.lpstrDefExt = lpszDefExt;\n\t\tm_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;\n\t\tm_ofn.nMaxFileTitle = _MAX_FNAME;\n#ifndef _WIN32_WCE\n\t\tm_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;\n#else // CE specific\n\t\tm_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;\n#endif // !_WIN32_WCE\n\t\tm_ofn.lpstrFilter = lpszFilter;\n\t\tm_ofn.hInstance = ModuleHelper::GetResourceInstance();\n\t\tm_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;\n\t\tm_ofn.hwndOwner = hWndParent;\n\n\t\t// setup initial file name\n\t\tif(lpszFileName != NULL)\n\t\tSecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);\n\t}\n\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);\n\t\tATLASSERT(m_ofn.lpfnHook != NULL);   // can still be a user hook\n\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\tif(m_ofn.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_ofn.hwndOwner = hWndParent;\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRetTh = m_thunk.Init(NULL, NULL);\n\t\tif(bRetTh == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);\n\n\t\tBOOL bRet;\n\t\tif(m_bOpenFileDialog)\n#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)\n\t\t\tbRet = ::GetOpenFileNameEx(&m_ofn);\n\t\telse\n\t\t\tbRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn);\n#else\n\t\t\tbRet = ::GetOpenFileName(&m_ofn);\n\t\telse\n\t\t\tbRet = ::GetSaveFileName(&m_ofn);\n#endif\n\n\t\tm_hWnd = NULL;\n\n\t\treturn bRet ? IDOK : IDCANCEL;\n\t}\n\n// Attributes\n\tATL::CWindow GetFileDialogWindow() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ATL::CWindow(GetParent());\n\t}\n\n\tint GetFilePath(LPTSTR lpstrFilePath, int nLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\treturn (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath);\n\t}\n\n\tint GetFolderIDList(LPVOID lpBuff, int nLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\treturn (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff);\n\t}\n\n\tint GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\treturn (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath);\n\t}\n\n\tint GetSpec(LPTSTR lpstrSpec, int nLength) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\treturn (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec);\n\t}\n\n\tvoid SetControlText(int nCtrlID, LPCTSTR lpstrText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\tGetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText);\n\t}\n\n\tvoid SetDefExt(LPCTSTR lpstrExt)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\tGetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt);\n\t}\n\n\tBOOL GetReadOnlyPref() const\t// return TRUE if readonly checked\n\t{\n\t\treturn ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE;\n\t}\n\n// Operations\n\tvoid HideControl(int nCtrlID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);\n\n\t\tGetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID);\n\t}\n\n// Special override for common dialogs\n\tBOOL EndDialog(INT_PTR /*nRetCode*/ = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tGetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0));\n\t\treturn TRUE;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CFileDialogImpl)\n\t\tNOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK)\n\t\tNOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange)\n\t\tNOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp)\n\t\tNOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone)\n\t\tNOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange)\n\t\tNOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation)\n\t\tNOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange)\n#ifndef _WIN32_WCE\n\t\tNOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem)\n#endif // !_WIN32_WCE\n\tEND_MSG_MAP()\n\n\tLRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn !pT->OnFileOK((LPOFNOTIFY)pnmh);\n\t}\n\n\tLRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnFolderChange((LPOFNOTIFY)pnmh);\n\t\treturn 0;\n\t}\n\n\tLRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnHelp((LPOFNOTIFY)pnmh);\n\t\treturn 0;\n\t}\n\n\tLRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnInitDone((LPOFNOTIFY)pnmh);\n\t\treturn 0;\n\t}\n\n\tLRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnSelChange((LPOFNOTIFY)pnmh);\n\t\treturn 0;\n\t}\n\n\tLRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->OnShareViolation((LPOFNOTIFY)pnmh);\n\t}\n\n\tLRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->OnTypeChange((LPOFNOTIFY)pnmh);\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->OnIncludeItem((LPOFNOTIFYEX)pnmh);\n\t}\n#endif // !_WIN32_WCE\n\n// Overrideables\n\tBOOL OnFileOK(LPOFNOTIFY /*lpon*/)\n\t{\n\t\treturn TRUE;\n\t}\n\n\tvoid OnFolderChange(LPOFNOTIFY /*lpon*/)\n\t{\n\t}\n\n\tvoid OnHelp(LPOFNOTIFY /*lpon*/)\n\t{\n\t}\n\n\tvoid OnInitDone(LPOFNOTIFY /*lpon*/)\n\t{\n\t}\n\n\tvoid OnSelChange(LPOFNOTIFY /*lpon*/)\n\t{\n\t}\n\n\tint OnShareViolation(LPOFNOTIFY /*lpon*/)\n\t{\n\t\treturn 0;\n\t}\n\n\tvoid OnTypeChange(LPOFNOTIFY /*lpon*/)\n\t{\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/)\n\t{\n\t\treturn TRUE;   // include item\n\t}\n#endif // !_WIN32_WCE\n};\n\nclass CFileDialog : public CFileDialogImpl<CFileDialog>\n{\npublic:\n\tCFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs\n\t\tLPCTSTR lpszDefExt = NULL,\n\t\tLPCTSTR lpszFileName = NULL,\n\t\tDWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,\n\t\tLPCTSTR lpszFilter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CFileDialogImpl<CFileDialog>(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)\n\t{ }\n\n\t// override base class map and references to handlers\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)\nclass CFileDialogEx : public CFileDialogImpl<CFileDialogEx>\n{\npublic:\n\tCFileDialogEx( // Supports only FileOpen\n\t\tLPCTSTR lpszDefExt = NULL,\n\t\tLPCTSTR lpszFileName = NULL,\n\t\tDWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,\n\t\tOFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW,\n\t\tOFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO,\t\t\n\t\tLPCTSTR lpszFilter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CFileDialogImpl<CFileDialogEx>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)\n\t{\n\t\tm_ofn.ExFlags = ExFlags;\n\t\tm_ofn.dwSortOrder = dwSortOrder;\n\t}\n\n\t// override base class map and references to handlers\n\tDECLARE_EMPTY_MSG_MAP()\n};\n#endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Multi File Dialog - Multi-select File Open dialog\n\n#ifndef _WIN32_WCE\n\n// The class dynamically resizes the buffer as the file selection changes\n// (as described in Knowledge Base article 131462). It also expands selected\n// shortcut files to take into account the full path of the target file.\n// Note that this doesn't work on Win9x for the old style dialogs, as well as\n// on NT for non-Unicode builds. \n\n#ifndef _WTL_FIXED_OFN_BUFFER_LENGTH\n  #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000\n#endif\n\ntemplate <class T>\nclass ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T >\n{\npublic:\n\tmutable LPCTSTR m_pNextFile; \n#ifndef _UNICODE\n\tbool m_bIsNT;\n#endif\n\n\tCMultiFileDialogImpl(\n\t\tLPCTSTR lpszDefExt = NULL,\n\t\tLPCTSTR lpszFileName = NULL,\n\t\tDWORD dwFlags = OFN_HIDEREADONLY,\n\t\tLPCTSTR lpszFilter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CFileDialogImpl<T>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent), \n\t\t  m_pNextFile(NULL)\n\t{\n\t\tm_ofn.Flags |= OFN_ALLOWMULTISELECT;   // Force multiple selection mode\n\n#ifndef _UNICODE\n#ifdef _versionhelpers_H_INCLUDED_\n\t\tOSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) };\n\t\tovi.dwPlatformId = VER_PLATFORM_WIN32_NT;\n\t\tDWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL);\n\t\tm_bIsNT = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE);\n#else // !_versionhelpers_H_INCLUDED_\n\t\tOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\t\t::GetVersionEx(&ovi);\n\t\tm_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT);\n#endif // _versionhelpers_H_INCLUDED_\n\t\tif (m_bIsNT)\n\t\t{\n\t\t\t// On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there \n\t\t\t// is absolutely nothing we can do except to start off with a large buffer.\n\t\t\tATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH));\n\t\t}\n#endif\n\t}\n\n\t~CMultiFileDialogImpl()\n\t{\n\t\tif (m_ofn.lpstrFile != m_szFileName)   // Free the buffer if we allocated it\n\t\t\tdelete[] m_ofn.lpstrFile;\n\t}\n\n// Operations\n\t// Get the directory that the files were chosen from.\n\t// The function returns the number of characters copied, not including the terminating zero. \n\t// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.\n\t// If the function fails, the return value is zero.\n\tint GetDirectory(LPTSTR pBuffer, int nBufLen) const\n\t{\n\t\tif (m_ofn.lpstrFile == NULL)\n\t\t\treturn 0;\n\n\t\tLPCTSTR pStr = m_ofn.lpstrFile;\n\t\tint nLength = lstrlen(pStr);\n\t\tif (pStr[nLength + 1] == 0)\n\t\t{\n\t\t\t// The OFN buffer contains a single item so extract its path.\n\t\t\tLPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\\\'));\n\t\t\tif (pSep != NULL)\n\t\t\t\tnLength = (int)(DWORD_PTR)(pSep - pStr);\n\t\t}\n\n\t\tint nRet = 0;\n\t\tif (pBuffer == NULL)   // If the buffer is NULL, return the required length\n\t\t{\n\t\t\tnRet = nLength + 1;\n\t\t}\n\t\telse if (nBufLen > nLength)\n\t\t{\n\t\t\tSecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength);\n\t\t\tnRet = nLength;\n\t\t}\n\n\t\treturn nRet;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tbool GetDirectory(_CSTRING_NS::CString& strDir) const\n\t{\n\t\tbool bRet = false;\n\n\t\tint nLength = GetDirectory(NULL, 0);\n\t\tif (nLength > 0)\n\t\t{\n\t\t\tbRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0);\n\t\t\tstrDir.ReleaseBuffer(nLength - 1);\n\t\t}\n\n\t\treturn bRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\t// Get the first filename as a pointer into the buffer.\n\tLPCTSTR GetFirstFileName() const\n\t{\n\t\tif (m_ofn.lpstrFile == NULL)\n\t\t\treturn NULL;\n\n\t\tm_pNextFile = NULL;   // Reset internal buffer pointer\n\n\t\tLPCTSTR pStr = m_ofn.lpstrFile;\n\t\tint nLength = lstrlen(pStr);\n\t\tif (pStr[nLength + 1] != 0)\n\t\t{\n\t\t\t// Multiple items were selected. The first string is the directory,\n\t\t\t// so skip forwards to the second string.\n\t\t\tpStr += nLength + 1;\n\n\t\t\t// Set up m_pNext so it points to the second item (or null).\n\t\t\tm_pNextFile = pStr;\n\t\t\tGetNextFileName();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// A single item was selected. Skip forward past the path.\n\t\t\tLPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\\\'));\n\t\t\tif (pSep != NULL)\n\t\t\t\tpStr = pSep + 1;\n\t\t}\n\n\t\treturn pStr;\n\t}\n\n\t// Get the next filename as a pointer into the buffer.\n\tLPCTSTR GetNextFileName() const\n\t{\n\t\tif (m_pNextFile == NULL)\n\t\t\treturn NULL;\n\n\t\tLPCTSTR pStr = m_pNextFile;\n\t\t// Set \"m_pNextFile\" to point to the next file name, or null if we \n\t\t// have reached the last file in the list.\n\t\tint nLength = lstrlen(pStr);\n\t\tm_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL;\n\n\t\treturn pStr;\n\t}\n\n\t// Get the first filename as a full path.\n\t// The function returns the number of characters copied, not including the terminating zero. \n\t// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.\n\t// If the function fails, the return value is zero.\n\tint GetFirstPathName(LPTSTR pBuffer, int nBufLen) const\n\t{\n\t\tLPCTSTR pStr = GetFirstFileName();\n\t\tint nLengthDir = GetDirectory(NULL, 0);\n\t\tif((pStr == NULL) || (nLengthDir == 0))\n\t\t\treturn 0;\n\n\t\t// Figure out the required length.\n\t\tint nLengthTotal = nLengthDir + lstrlen(pStr);\n\n\t\tint nRet = 0;\n\t\tif(pBuffer == NULL) // If the buffer is NULL, return the required length\n\t\t{\n\t\t\tnRet = nLengthTotal + 1;\n\t\t}\n\t\telse if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path\n\t\t{\t\t\n\t\t\tGetDirectory(pBuffer, nBufLen);\n\t\t\tSecureHelper::strcat_x(pBuffer, nBufLen, _T(\"\\\\\"));\n\t\t\tSecureHelper::strcat_x(pBuffer, nBufLen, pStr);\n\t\t\tnRet = nLengthTotal;\n\t\t}\n\n\t\treturn nRet;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tbool GetFirstPathName(_CSTRING_NS::CString& strPath) const\n\t{\n\t\tbool bRet = false;\n\n\t\tint nLength = GetFirstPathName(NULL, 0);\n\t\tif (nLength > 0)\n\t\t{\n\t\t\tbRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0);\n\t\t\tstrPath.ReleaseBuffer(nLength - 1);\n\t\t}\n\n\t\treturn bRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\t// Get the next filename as a full path.\n\t// The function returns the number of characters copied, not including the terminating zero. \n\t// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.\n\t// If the function fails, the return value is zero.\n\t// The internal position marker is moved forward only if the function succeeds and the buffer was large enough.\n\tint GetNextPathName(LPTSTR pBuffer, int nBufLen) const\n\t{\n\t\tif (m_pNextFile == NULL)\n\t\t\treturn 0;\n\n\t\tint nRet = 0;\n\t\tLPCTSTR pStr = m_pNextFile;\n\t\t// Does the filename contain a backslash?\n\t\tif (MinCrtHelper::_strrchr(pStr, _T('\\\\')) != NULL)\n\t\t{\n\t\t\t// Yes, so we'll assume it's a full path.\n\t\t\tint nLength = lstrlen(pStr);\n\n\t\t\tif (pBuffer == NULL) // If the buffer is NULL, return the required length\n\t\t\t{\n\t\t\t\tnRet = nLength + 1;\n\t\t\t}\n\t\t\telse if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename\n\t\t\t{\n\t\t\t\tSecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName());\n\t\t\t\tnRet = nBufLen;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The filename is relative, so construct the full path.\n\t\t\tint nLengthDir = GetDirectory(NULL, 0);\n\t\t\tif (nLengthDir > 0)\n\t\t\t{\n\t\t\t\t// Calculate the required space.\n\t\t\t\tint nLengthTotal = nLengthDir + lstrlen(pStr);\n\n\t\t\t\tif(pBuffer == NULL) // If the buffer is NULL, return the required length\n\t\t\t\t{\n\t\t\t\t\tnRet = nLengthTotal + 1;\n\t\t\t\t}\n\t\t\t\telse if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path\n\t\t\t\t{\n\t\t\t\t\tGetDirectory(pBuffer, nBufLen);\n\t\t\t\t\tSecureHelper::strcat_x(pBuffer, nBufLen, _T(\"\\\\\"));\n\t\t\t\t\tSecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName());\n\t\t\t\t\tnRet = nLengthTotal;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nRet;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tbool GetNextPathName(_CSTRING_NS::CString& strPath) const\n\t{\n\t\tbool bRet = false;\n\n\t\tint nLength = GetNextPathName(NULL, 0);\n\t\tif (nLength > 0)\n\t\t{\n\t\t\tbRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0);\n\t\t\tstrPath.ReleaseBuffer(nLength - 1);\n\t\t}\n\n\t\treturn bRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n// Implementation\n\tbool ResizeFilenameBuffer(DWORD dwLength)\n\t{\n\t\tif (dwLength > m_ofn.nMaxFile)\n\t\t{\n\t\t\t// Free the old buffer.\n\t\t\tif (m_ofn.lpstrFile != m_szFileName)\n\t\t\t{\n\t\t\t\tdelete[] m_ofn.lpstrFile;\n\t\t\t\tm_ofn.lpstrFile = NULL;\n\t\t\t\tm_ofn.nMaxFile = 0;\n\t\t\t}\n\n\t\t\t// Allocate the new buffer.\n\t\t\tLPTSTR lpstrBuff = NULL;\n\t\t\tATLTRY(lpstrBuff = new TCHAR[dwLength]);\n\t\t\tif (lpstrBuff != NULL)\n\t\t\t{\n\t\t\t\tm_ofn.lpstrFile = lpstrBuff;\n\t\t\t\tm_ofn.lpstrFile[0] = 0;\n\t\t\t\tm_ofn.nMaxFile = dwLength;\n\t\t\t}\n\t\t}\n\n\t\treturn (m_ofn.lpstrFile != NULL);\n\t}\n\n\tvoid OnSelChange(LPOFNOTIFY /*lpon*/)\n\t{\n#ifndef _UNICODE\n\t\t// There is no point resizing the buffer in ANSI builds running on NT.\n\t\tif (m_bIsNT)\n\t\t\treturn;\n#endif\n\n\t\t// Get the buffer length required to hold the spec.\n\t\tint nLength = GetSpec(NULL, 0);\n\t\tif (nLength <= 1)\n\t\t\treturn; // no files are selected, presumably\n\t\t\n\t\t// Add room for the directory, and an extra terminating zero.\n\t\tnLength += GetFolderPath(NULL, 0) + 1;\n\n\t\tif (!ResizeFilenameBuffer(nLength))\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn;\n\t\t}\n\n\t\t// If we are not following links then our work is done.\n\t\tif ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0)\n\t\t\treturn;\n\n\t\t// Get the file spec, which is the text in the edit control.\n\t\tif (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0)\n\t\t\treturn;\n\t\t\n\t\t// Get the ID-list of the current folder.\n\t\tint nBytes = GetFolderIDList(NULL, 0);\n#ifdef STRICT_TYPED_ITEMIDS\n\t\tCTempBuffer<ITEMIDLIST_RELATIVE> idlist;\n#else\n\t\tCTempBuffer<ITEMIDLIST> idlist;\n#endif\n\t\tidlist.AllocateBytes(nBytes);\n\t\tif ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0))\n\t\t\treturn;\n\n\t\t// First bind to the desktop folder, then to the current folder.\n\t\tATL::CComPtr<IShellFolder> pDesktop, pFolder;\n\t\tif (FAILED(::SHGetDesktopFolder(&pDesktop)))\n\t\t\treturn;\n\t\tif (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder)))\n\t\t\treturn;\n\n\t\t// Work through the file spec, looking for quoted filenames. If we find a shortcut file, then \n\t\t// we need to add enough extra buffer space to hold its target path.\n\t\tDWORD nExtraChars = 0;\n\t\tbool bInsideQuotes = false;\n\t\tLPCTSTR pAnchor = m_ofn.lpstrFile;\n\t\tLPCTSTR pChar = m_ofn.lpstrFile;\n\t\tfor ( ; *pChar; ++pChar)\n\t\t{\n\t\t\t// Look for quotation marks.\n\t\t\tif (*pChar == _T('\\\"'))\n\t\t\t{\n\t\t\t\t// We are either entering or leaving a passage of quoted text.\n\t\t\t\tbInsideQuotes = !bInsideQuotes;\n\n\t\t\t\t// Is it an opening or closing quote?\n\t\t\t\tif (bInsideQuotes)\n\t\t\t\t{\n\t\t\t\t\t// We found an opening quote, so set \"pAnchor\" to the following character.\n\t\t\t\t\tpAnchor = pChar + 1;\n\t\t\t\t}\n\t\t\t\telse // closing quote\n\t\t\t\t{\n\t\t\t\t\t// Each quoted entity should be shorter than MAX_PATH.\n\t\t\t\t\tif (pChar - pAnchor >= MAX_PATH)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t// Get the ID-list and attributes of the file.\n\t\t\t\t\tUSES_CONVERSION;\n\t\t\t\t\tint nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor);\n\t\t\t\t\tTCHAR szFileName[MAX_PATH] = { 0 };\n\t\t\t\t\tSecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength);\n#ifdef STRICT_TYPED_ITEMIDS\n\t\t\t\t\tPIDLIST_RELATIVE pidl = NULL;\n#else\n\t\t\t\t\tLPITEMIDLIST pidl = NULL;\n#endif\n\t\t\t\t\tDWORD dwAttrib = SFGAO_LINK;\n\t\t\t\t\tif (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib)))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Is it a shortcut file?\n\t\t\t\t\t\tif (dwAttrib & SFGAO_LINK)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Bind to its IShellLink interface.\n\t\t\t\t\t\t\tATL::CComPtr<IShellLink> pLink;\n\t\t\t\t\t\t\tif (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Get the shortcut's target path.\n\t\t\t\t\t\t\t\tTCHAR szPath[MAX_PATH] = { 0 };\n\t\t\t\t\t\t\t\tif (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0)))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// If the target path is longer than the shortcut name, then add on the number \n\t\t\t\t\t\t\t\t\t// of extra characters that are required.\n\t\t\t\t\t\t\t\t\tint nNewLength = lstrlen(szPath);\n\t\t\t\t\t\t\t\t\tif (nNewLength > nFileNameLength)\n\t\t\t\t\t\t\t\t\t\tnExtraChars += nNewLength - nFileNameLength;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Free the ID-list returned by ParseDisplayName.\n\t\t\t\t\t\t::CoTaskMemFree(pidl);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we need more space for shortcut targets, then reallocate.\n\t\tif (nExtraChars > 0)\n\t\t\tATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars));\n\t}\n};\n\nclass CMultiFileDialog : public CMultiFileDialogImpl<CMultiFileDialog>\n{\npublic:\n\tCMultiFileDialog(\n\t\tLPCTSTR lpszDefExt = NULL,\n\t\tLPCTSTR lpszFileName = NULL,\n\t\tDWORD dwFlags = OFN_HIDEREADONLY,\n\t\tLPCTSTR lpszFilter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CMultiFileDialogImpl<CMultiFileDialog>(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)\n\t{ }\n\n\tBEGIN_MSG_MAP(CMultiFileDialog)\n\t\tCHAIN_MSG_MAP(CMultiFileDialogImpl<CMultiFileDialog>)\n\tEND_MSG_MAP()\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Shell File Dialog - new Shell File Open and Save dialogs in Vista\n\n// Note: Use GetPtr() to access dialog interface methods.\n// Example:\n//\tCShellFileOpenDialog dlg;\n//\tdlg.GetPtr()->SetTitle(L\"MyFileOpenDialog\");\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n\n///////////////////////////////////////////////////////////////////////////////\n// CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl\n\ntemplate <class T>\nclass ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents\n{\npublic:\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tINT_PTR nRet = -1;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(pT->m_spFileDlg == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn nRet;\n\t\t}\n\n\t\tDWORD dwCookie = 0;\n\t\tpT->_Advise(dwCookie);\n\n\t\tHRESULT hRet = pT->m_spFileDlg->Show(hWndParent);\n\t\tif(SUCCEEDED(hRet))\n\t\t\tnRet = IDOK;\n\t\telse if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED))\n\t\t\tnRet = IDCANCEL;\n\t\telse\n\t\t\tATLASSERT(FALSE);   // error\n\n\t\tpT->_Unadvise(dwCookie);\n\n\t\treturn nRet;\n\t}\n\n\tbool IsNull() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\treturn (pT->m_spFileDlg == NULL);\n\t}\n\n// Operations - get file path after dialog returns\n\tHRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\n\t\tATL::CComPtr<IShellItem> spItem;\n\t\tHRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\thRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength);\n\n\t\treturn hRet;\n\t}\n\n\tHRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\n\t\tATL::CComPtr<IShellItem> spItem;\n\t\tHRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\thRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength);\n\n\t\treturn hRet;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tHRESULT GetFilePath(_CSTRING_NS::CString& strFilePath)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\n\t\tATL::CComPtr<IShellItem> spItem;\n\t\tHRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\thRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath);\n\n\t\treturn hRet;\n\t}\n\n\tHRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\n\t\tATL::CComPtr<IShellItem> spItem;\n\t\tHRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\thRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle);\n\n\t\treturn hRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n// Helpers for IShellItem\n\tstatic HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength)\n\t{\n\t\tATLASSERT(pShellItem != NULL);\n\n\t\tLPWSTR lpstrName = NULL;\n\t\tHRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t{\n\t\t\tif(lstrlenW(lpstrName) < cchLength)\n\t\t\t{\n\t\t\t\tSecureHelper::strcpyW_x(lpstr, cchLength, lpstrName);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\thRet = DISP_E_BUFFERTOOSMALL;\n\t\t\t}\n\n\t\t\t::CoTaskMemFree(lpstrName);\n\t\t}\n\n\t\treturn hRet;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tstatic HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str)\n\t{\n\t\tATLASSERT(pShellItem != NULL);\n\n\t\tLPWSTR lpstrName = NULL;\n\t\tHRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t{\n\t\t\tstr = lpstrName;\n\t\t\t::CoTaskMemFree(lpstrName);\n\t\t}\n\n\t\treturn hRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n// Implementation\n\tvoid _Advise(DWORD& dwCookie)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\t\tHRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie);\n\t\tATLVERIFY(SUCCEEDED(hRet));\n\t}\n\n\tvoid _Unadvise(DWORD dwCookie)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\t\tHRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie);\n\t\tATLVERIFY(SUCCEEDED(hRet));\n\t}\n\n\tvoid _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg != NULL);\n\n\t\tHRESULT hRet = E_FAIL;\n\n\t\tif(lpszFileName != NULL)\n\t\t{\n\t\t\thRet = pT->m_spFileDlg->SetFileName(lpszFileName);\n\t\t\tATLASSERT(SUCCEEDED(hRet));\n\t\t}\n\n\t\thRet = pT->m_spFileDlg->SetOptions(dwOptions);\n\t\tATLASSERT(SUCCEEDED(hRet));\n\n\t\tif(lpszDefExt != NULL)\n\t\t{\n\t\t\thRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt);\n\t\t\tATLASSERT(SUCCEEDED(hRet));\n\t\t}\n\n\t\tif(arrFilterSpec != NULL && uFilterSpecCount != 0U)\n\t\t{\n\t\t\thRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec);\n\t\t\tATLASSERT(SUCCEEDED(hRet));\n\t\t}\n\t}\n\n// Implementation - IUnknown interface\n\tSTDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)\n\t{\n\t\tif(ppvObject == NULL)\n\t\t\treturn E_POINTER;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents))\n\t\t{\n\t\t\t*ppvObject = (IFileDialogEvents*)pT;\n\t\t\t// AddRef() not needed\n\t\t\treturn S_OK;\n\t\t}\n\n\t\treturn E_NOINTERFACE;\n\t}\n\n\tvirtual ULONG STDMETHODCALLTYPE AddRef()\n\t{\n\t\treturn 1;\n\t}\n\n\tvirtual ULONG STDMETHODCALLTYPE Release()\n\t{\n\t\treturn 1;\n\t}\n\n// Implementation - IFileDialogEvents interface\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnFileOk();\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnFolderChanging(psiFolder);\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnFolderChange();\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnSelectionChange();\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnShareViolation(psi, pResponse);\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnTypeChange();\n\t}\n\n\tvirtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));\n\t\tpfd;   // avoid level 4 warning\n\t\treturn pT->OnOverwrite(psi, pResponse);\n\t}\n\n// Overrideables - Event handlers\n\tHRESULT OnFileOk()\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnFolderChanging(IShellItem* /*psiFolder*/)\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnFolderChange()\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnSelectionChange()\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/)\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnTypeChange()\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n\n\tHRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/)\n\t{\n\t\treturn E_NOTIMPL;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CShellFileOpenDialogImpl - implements new Shell File Open dialog\n\ntemplate <class T>\nclass ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T >\n{\npublic:\n\tATL::CComPtr<IFileOpenDialog> m_spFileDlg;\n\n\tCShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL, \n\t                         DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, \n\t                         LPCWSTR lpszDefExt = NULL, \n\t                         const COMDLG_FILTERSPEC* arrFilterSpec = NULL, \n\t                         UINT uFilterSpecCount = 0U)\n\t{\n\t\tHRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\t_Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);\n\t}\n\n\tIFileOpenDialog* GetPtr()\n\t{\n\t\treturn m_spFileDlg;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CShellFileOpenDialog - new Shell File Open dialog without events\n\nclass CShellFileOpenDialog : public CShellFileOpenDialogImpl<CShellFileOpenDialog>\n{\npublic:\n\tCShellFileOpenDialog(LPCWSTR lpszFileName = NULL, \n\t                     DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST, \n\t                     LPCWSTR lpszDefExt = NULL, \n\t                     const COMDLG_FILTERSPEC* arrFilterSpec = NULL, \n\t                     UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl<CShellFileOpenDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)\n\t{ }\n\n// Implementation (remove _Advise/_Unadvise code using template magic)\n\tvoid _Advise(DWORD& /*dwCookie*/)\n\t{ }\n\n\tvoid _Unadvise(DWORD /*dwCookie*/)\n\t{ }\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CShellFileSaveDialogImpl - implements new Shell File Save dialog\n\ntemplate <class T>\nclass ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T >\n{\npublic:\n\tATL::CComPtr<IFileSaveDialog> m_spFileDlg;\n\n\tCShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL, \n\t                         DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, \n\t                         LPCWSTR lpszDefExt = NULL, \n\t                         const COMDLG_FILTERSPEC* arrFilterSpec = NULL, \n\t                         UINT uFilterSpecCount = 0U)\n\t{\n\t\tHRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog);\n\n\t\tif(SUCCEEDED(hRet))\n\t\t\t_Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);\n\t}\n\n\tIFileSaveDialog* GetPtr()\n\t{\n\t\treturn m_spFileDlg;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CShellFileSaveDialog - new Shell File Save dialog without events\n\nclass CShellFileSaveDialog : public CShellFileSaveDialogImpl<CShellFileSaveDialog>\n{\npublic:\n\tCShellFileSaveDialog(LPCWSTR lpszFileName = NULL, \n\t                     DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT, \n\t                     LPCWSTR lpszDefExt = NULL, \n\t                     const COMDLG_FILTERSPEC* arrFilterSpec = NULL, \n\t                     UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl<CShellFileSaveDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)\n\t{ }\n\n// Implementation (remove _Advise/_Unadvise code using template magic)\n\tvoid _Advise(DWORD& /*dwCookie*/)\n\t{ }\n\n\tvoid _Unadvise(DWORD /*dwCookie*/)\n\t{ }\n};\n\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFolderDialogImpl - used for browsing for a folder\n\n#ifndef _WIN32_WCE\n\ntemplate <class T>\nclass ATL_NO_VTABLE CFolderDialogImpl\n{\npublic:\n\tBROWSEINFO m_bi;\n\tLPCTSTR m_lpstrInitialFolder;\n\tLPCITEMIDLIST m_pidlInitialSelection;\n\tbool m_bExpandInitialSelection;\n\tTCHAR m_szFolderDisplayName[MAX_PATH];\n\tTCHAR m_szFolderPath[MAX_PATH];\n#ifdef STRICT_TYPED_ITEMIDS\n\tPIDLIST_ABSOLUTE m_pidlSelected;\n#else\n\tLPITEMIDLIST m_pidlSelected;\n#endif\n\tHWND m_hWnd;   // used only in the callback function\n\n// Constructor\n\tCFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : \n\t\t\tm_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL)\n\t{\n\t\tmemset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL\n\n\t\tm_bi.hwndOwner = hWndParent;\n\t\tm_bi.pidlRoot = NULL;\n\t\tm_bi.pszDisplayName = m_szFolderDisplayName;\n\t\tm_bi.lpszTitle = lpstrTitle;\n\t\tm_bi.ulFlags = uFlags;\n\t\tm_bi.lpfn = BrowseCallbackProc;\n\t\tm_bi.lParam = (LPARAM)static_cast<T*>(this);\n\n\t\tm_szFolderPath[0] = 0;\n\t\tm_szFolderDisplayName[0] = 0;\n\t}\n\n\t~CFolderDialogImpl()\n\t{\n\t\t::CoTaskMemFree(m_pidlSelected);\n\t}\n\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tif(m_bi.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_bi.hwndOwner = hWndParent;\n\n\t\t// Clear out any previous results\n\t\tm_szFolderPath[0] = 0;\n\t\tm_szFolderDisplayName[0] = 0;\n\t\t::CoTaskMemFree(m_pidlSelected);\n\n\t\tINT_PTR nRet = IDCANCEL;\n\t\tm_pidlSelected = ::SHBrowseForFolder(&m_bi);\n\n\t\tif(m_pidlSelected != NULL)\n\t\t{\n\t\t\tnRet = IDOK;\n\n\t\t\t// If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path.\n\t\t\t// Otherwise, the caller must handle the ID-list directly.\n\t\t\tif((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0)\n\t\t\t{\n\t\t\t\tif(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE)\n\t\t\t\t\tnRet = IDCANCEL;\n\t\t\t}\n\t\t}\n\n\t\treturn nRet;\n\t}\n\n\t// Methods to call before DoModal\n\tvoid SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true)\n\t{\n\t\t// lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified\n\t\tm_lpstrInitialFolder = lpstrInitialFolder;\n\t\tm_bExpandInitialSelection = bExpand;\n\t}\n\n\tvoid SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true)\n\t{\n\t\tm_pidlInitialSelection = pidl;\n\t\tm_bExpandInitialSelection = bExpand;\n\t}\n\n#ifdef STRICT_TYPED_ITEMIDS\n\tvoid SetRootFolder(PCIDLIST_ABSOLUTE pidl)\n#else\n\tvoid SetRootFolder(LPCITEMIDLIST pidl)\n#endif\n\t{\n\t\tm_bi.pidlRoot = pidl;\n\t}\n\n\t// Methods to call after DoModal\n\tLPITEMIDLIST GetSelectedItem(bool bDetach = false)\n\t{\n\t\tLPITEMIDLIST pidl = m_pidlSelected;\n\t\tif(bDetach)\n\t\t\tm_pidlSelected = NULL;\n\n\t\treturn pidl;\n\t}\n\n\tLPCTSTR GetFolderPath() const\n\t{\n\t\treturn m_szFolderPath;\n\t}\n\n\tLPCTSTR GetFolderDisplayName() const\n\t{\n\t\treturn m_szFolderDisplayName;\n\t}\n\n\tint GetFolderImageIndex() const\n\t{\n\t\treturn m_bi.iImage;\n\t}\n\n// Callback function and overrideables\n\tstatic int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)\n\t{\n#ifndef BFFM_VALIDATEFAILED\n  #ifdef UNICODE\n\t\tconst int BFFM_VALIDATEFAILED = 4;\n  #else\n\t\tconst int BFFM_VALIDATEFAILED = 3;\n  #endif\n#endif // !BFFM_VALIDATEFAILED\n#ifndef BFFM_IUNKNOWN\n\t\tconst int BFFM_IUNKNOWN = 5;\n#endif // !BFFM_IUNKNOWN\n#ifndef BIF_NEWDIALOGSTYLE\n\t\tconst UINT BIF_NEWDIALOGSTYLE = 0x0040;\n#endif // !BIF_NEWDIALOGSTYLE\n\n\t\tint nRet = 0;\n\t\tT* pT = (T*)lpData;\n\t\tbool bClear = false;\n\t\tif(pT->m_hWnd == NULL)\n\t\t{\n\t\t\tpT->m_hWnd = hWnd;\n\t\t\tbClear = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(pT->m_hWnd == hWnd);\n\t\t}\n\n\t\tswitch(uMsg)\n\t\t{\n\t\tcase BFFM_INITIALIZED:\n\t\t\t// Set initial selection\n\t\t\t// Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder\n\t\t\tif(pT->m_pidlInitialSelection != NULL)\n\t\t\t\tpT->SetSelection(pT->m_pidlInitialSelection);\n\t\t\telse if(pT->m_lpstrInitialFolder != NULL)\n\t\t\t\tpT->SetSelection(pT->m_lpstrInitialFolder);\n\n\t\t\t// Expand initial selection if appropriate\n\t\t\tif(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0))\n\t\t\t{\n\t\t\t\tif(pT->m_pidlInitialSelection != NULL)\n\t\t\t\t\tpT->SetExpanded(pT->m_pidlInitialSelection);\n\t\t\t\telse if(pT->m_lpstrInitialFolder != NULL)\n\t\t\t\t\tpT->SetExpanded(pT->m_lpstrInitialFolder);\n\t\t\t}\n\t\t\tpT->OnInitialized();\n\t\t\tbreak;\n\t\tcase BFFM_SELCHANGED:\n\t\t\tpT->OnSelChanged((LPITEMIDLIST)lParam);\n\t\t\tbreak;\n\t\tcase BFFM_VALIDATEFAILED:\n\t\t\tnRet = pT->OnValidateFailed((LPCTSTR)lParam);\n\t\t\tbreak;\n\t\tcase BFFM_IUNKNOWN:\n\t\t\tpT->OnIUnknown((IUnknown*)lParam);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Unknown message received in CFolderDialogImpl::BrowseCallbackProc\\n\"));\n\t\t\tbreak;\n\t\t}\n\n\t\tif(bClear)\n\t\t\tpT->m_hWnd = NULL;\n\t\treturn nRet;\n\t}\n\n\tvoid OnInitialized()\n\t{\n\t}\n\n\tvoid OnSelChanged(LPITEMIDLIST /*pItemIDList*/)\n\t{\n\t}\n\n\tint OnValidateFailed(LPCTSTR /*lpstrFolderPath*/)\n\t{\n\t\treturn 1;   // 1=continue, 0=EndDialog\n\t}\n\n\tvoid OnIUnknown(IUnknown* /*pUnknown*/)\n\t{\n\t}\n\n\t// Commands - valid to call only from handlers\n\tvoid EnableOK(BOOL bEnable)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable);\n\t}\n\n\tvoid SetSelection(LPCITEMIDLIST pItemIDList)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList);\n\t}\n\n\tvoid SetSelection(LPCTSTR lpstrFolderPath)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath);\n\t}\n\n\tvoid SetStatusText(LPCTSTR lpstrText)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText);\n\t}\n\n\tvoid SetOKText(LPCTSTR lpstrOKText)\n\t{\n#ifndef BFFM_SETOKTEXT\n\t\tconst UINT BFFM_SETOKTEXT = WM_USER + 105;\n#endif\n\t\tATLASSERT(m_hWnd != NULL);\n\t\tUSES_CONVERSION;\n\t\tLPCWSTR lpstr = T2CW(lpstrOKText);\n\t\t::SendMessage(m_hWnd, BFFM_SETOKTEXT, 0, (LPARAM)lpstr);\n\t}\n\n\tvoid SetExpanded(LPCITEMIDLIST pItemIDList)\n\t{\n#ifndef BFFM_SETEXPANDED\n\t\tconst UINT BFFM_SETEXPANDED = WM_USER + 106;\n#endif\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList);\n\t}\n\n\tvoid SetExpanded(LPCTSTR lpstrFolderPath)\n\t{\n#ifndef BFFM_SETEXPANDED\n\t\tconst UINT BFFM_SETEXPANDED = WM_USER + 106;\n#endif\n\t\tATLASSERT(m_hWnd != NULL);\n\t\tUSES_CONVERSION;\n\t\tLPCWSTR lpstr = T2CW(lpstrFolderPath);\n\t\t::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr);\n\t}\n};\n\nclass CFolderDialog : public CFolderDialogImpl<CFolderDialog>\n{\npublic:\n\tCFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS)\n\t\t: CFolderDialogImpl<CFolderDialog>(hWndParent, lpstrTitle, uFlags)\n\t{ }\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCommonDialogImplBase - base class for common dialog classes\n\nclass ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase\n{\npublic:\n\tstatic UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tif(uMsg != WM_INITDIALOG)\n\t\t\treturn 0;\n\t\tCCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();\n\t\tATLASSERT(pT != NULL);\n\t\tATLASSERT(pT->m_hWnd == NULL);\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\t// subclass dialog's window\n\t\tif(!pT->SubclassWindow(hWnd))\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Subclassing a common dialog failed\\n\"));\n\t\t\treturn 0;\n\t\t}\n\t\t// check message map for WM_INITDIALOG handler\n\t\tLRESULT lRes = 0;\n\t\tif(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)\n\t\t\treturn 0;\n\t\treturn lRes;\n\t}\n\n// Special override for common dialogs\n\tBOOL EndDialog(INT_PTR /*nRetCode*/ = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tSendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));\n\t\treturn TRUE;\n\t}\n\n// Implementation - try to override these, to prevent errors\n\tHWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID)\n\t{\n\t\tATLASSERT(FALSE);   // should not be called\n\t\treturn NULL;\n\t}\n\n\tstatic LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)\n\t{\n\t\tATLASSERT(FALSE);   // should not be called\n\t\treturn 0;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFontDialogImpl - font selection dialog\n\n#ifndef _WIN32_WCE\n\ntemplate <class T>\nclass ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase\n{\npublic:\n\tenum { _cchStyleName = 64 };\n\n\tCHOOSEFONT m_cf;\n\tTCHAR m_szStyleName[_cchStyleName];  // contains style name after return\n\tLOGFONT m_lf;                        // default LOGFONT to store the info\n\n// Constructors\n\tCFontDialogImpl(LPLOGFONT lplfInitial = NULL,\n\t\t\tDWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,\n\t\t\tHDC hDCPrinter = NULL,\n\t\t\tHWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_cf, 0, sizeof(m_cf));\n\t\tmemset(&m_lf, 0, sizeof(m_lf));\n\t\tmemset(&m_szStyleName, 0, sizeof(m_szStyleName));\n\n\t\tm_cf.lStructSize = sizeof(m_cf);\n\t\tm_cf.hwndOwner = hWndParent;\n\t\tm_cf.rgbColors = RGB(0, 0, 0);\n\t\tm_cf.lpszStyle = (LPTSTR)&m_szStyleName;\n\t\tm_cf.Flags = dwFlags | CF_ENABLEHOOK;\n\t\tm_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc;\n\n\t\tif(lplfInitial != NULL)\n\t\t{\n\t\t\tm_cf.lpLogFont = lplfInitial;\n\t\t\tm_cf.Flags |= CF_INITTOLOGFONTSTRUCT;\n\t\t\tm_lf = *lplfInitial;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_cf.lpLogFont = &m_lf;\n\t\t}\n\n\t\tif(hDCPrinter != NULL)\n\t\t{\n\t\t\tm_cf.hDC = hDCPrinter;\n\t\t\tm_cf.Flags |= CF_PRINTERFONTS;\n\t\t}\n\t}\n\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0);\n\t\tATLASSERT(m_cf.lpfnHook != NULL);   // can still be a user hook\n\n\t\tif(m_cf.hwndOwner == NULL)          // set only if not specified before\n\t\t\tm_cf.hwndOwner = hWndParent;\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRetTh = m_thunk.Init(NULL, NULL);\n\t\tif(bRetTh == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);\n\n\t\tBOOL bRet = ::ChooseFont(&m_cf);\n\n\t\tm_hWnd = NULL;\n\n\t\tif(bRet)   // copy logical font from user's initialization buffer (if needed)\n\t\t\tSecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf));\n\n\t\treturn bRet ? IDOK : IDCANCEL;\n\t}\n\n\t// works only when the dialog is dislayed or after\n\tvoid GetCurrentFont(LPLOGFONT lplf) const\n\t{\n\t\tATLASSERT(lplf != NULL);\n\n\t\tif(m_hWnd != NULL)\n\t\t\t::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf);\n\t\telse\n\t\t\t*lplf = m_lf;\n\t}\n\n\t// works only when the dialog is dislayed or before\n#ifndef _WIN32_WCE\n\tvoid SetLogFont(LPLOGFONT lplf)\n\t{\n\t\tATLASSERT(lplf != NULL);\n#ifndef WM_CHOOSEFONT_SETLOGFONT\n\t\tconst UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101);\n#endif\n\t\tif(m_hWnd != NULL)\n\t\t{\n\t\t\t::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_lf = *lplf;\n\t\t\tm_cf.Flags |= CF_INITTOLOGFONTSTRUCT;\n\t\t}\n\t}\n\n\tvoid SetFlags(DWORD dwFlags)\n\t{\n#ifndef WM_CHOOSEFONT_SETFLAGS\n\t\tconst UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102);\n#endif\n\t\tif(m_hWnd != NULL)\n\t\t{\n\t\t\tCHOOSEFONT cf = { sizeof(CHOOSEFONT) };\n\t\t\tcf.Flags = dwFlags;\n\t\t\t::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_cf.Flags = dwFlags;\n\t\t}\n\t}\n#endif // !_WIN32_WCE\n\n\t// Helpers for parsing information after successful return\n\tLPCTSTR GetFaceName() const   // return the face name of the font\n\t{\n\t\treturn (LPCTSTR)m_cf.lpLogFont->lfFaceName;\n\t}\n\n\tLPCTSTR GetStyleName() const  // return the style name of the font\n\t{\n\t\treturn m_cf.lpszStyle;\n\t}\n\n\tint GetSize() const           // return the pt size of the font\n\t{\n\t\treturn m_cf.iPointSize;\n\t}\n\n\tCOLORREF GetColor() const     // return the color of the font\n\t{\n\t\treturn m_cf.rgbColors;\n\t}\n\n\tint GetWeight() const         // return the chosen font weight\n\t{\n\t\treturn (int)m_cf.lpLogFont->lfWeight;\n\t}\n\n\tBOOL IsStrikeOut() const      // return TRUE if strikeout\n\t{\n\t\treturn (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE;\n\t}\n\n\tBOOL IsUnderline() const      // return TRUE if underline\n\t{\n\t\treturn (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE;\n\t}\n\n\tBOOL IsBold() const           // return TRUE if bold font\n\t{\n\t\treturn (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE;\n\t}\n\n\tBOOL IsItalic() const         // return TRUE if italic font\n\t{\n\t\treturn m_cf.lpLogFont->lfItalic ? TRUE : FALSE;\n\t}\n};\n\nclass CFontDialog : public CFontDialogImpl<CFontDialog>\n{\npublic:\n\tCFontDialog(LPLOGFONT lplfInitial = NULL,\n\t\tDWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,\n\t\tHDC hDCPrinter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CFontDialogImpl<CFontDialog>(lplfInitial, dwFlags, hDCPrinter, hWndParent)\n\t{ }\n\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRichEditFontDialogImpl - font selection for the Rich Edit ctrl\n\n#if defined(_RICHEDIT_) && !defined(_WIN32_WCE)\n\ntemplate <class T>\nclass ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T >\n{\npublic:\n\tCRichEditFontDialogImpl(const CHARFORMAT& charformat,\n\t\t\tDWORD dwFlags = CF_SCREENFONTS,\n\t\t\tHDC hDCPrinter = NULL,\n\t\t\tHWND hWndParent = NULL)\n\t\t\t: CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent)\n\t{\n\t\tm_cf.Flags |= CF_INITTOLOGFONTSTRUCT;\n\t\tm_cf.Flags |= FillInLogFont(charformat);\n\t\tm_cf.lpLogFont = &m_lf;\n\n\t\tif((charformat.dwMask & CFM_COLOR) != 0)\n\t\t\tm_cf.rgbColors = charformat.crTextColor;\n\t}\n\n\tvoid GetCharFormat(CHARFORMAT& cf) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tcf.dwEffects = 0;\n\t\tcf.dwMask = 0;\n\t\tif((m_cf.Flags & CF_NOSTYLESEL) == 0)\n\t\t{\n\t\t\tcf.dwMask |= CFM_BOLD | CFM_ITALIC;\n\t\t\tcf.dwEffects |= IsBold() ? CFE_BOLD : 0;\n\t\t\tcf.dwEffects |= IsItalic() ? CFE_ITALIC : 0;\n\t\t}\n\t\tif((m_cf.Flags & CF_NOSIZESEL) == 0)\n\t\t{\n\t\t\tcf.dwMask |= CFM_SIZE;\n\t\t\t// GetSize() returns in tenths of points so mulitply by 2 to get twips\n\t\t\tcf.yHeight = GetSize() * 2;\n\t\t}\n\n\t\tif((m_cf.Flags & CF_NOFACESEL) == 0)\n\t\t{\n\t\t\tcf.dwMask |= CFM_FACE;\n\t\t\tcf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily;\n#if (_RICHEDIT_VER >= 0x0200)\n\t\t\tSecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName());\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t\t\tSecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName()));\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\t\t}\n\n\t\tif((m_cf.Flags & CF_EFFECTS) != 0)\n\t\t{\n\t\t\tcf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;\n\t\t\tcf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0;\n\t\t\tcf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0;\n\t\t\tcf.crTextColor = GetColor();\n\t\t}\n\t\tif((m_cf.Flags & CF_NOSCRIPTSEL) == 0)\n\t\t{\n\t\t\tcf.bCharSet = m_cf.lpLogFont->lfCharSet;\n\t\t\tcf.dwMask |= CFM_CHARSET;\n\t\t}\n\t\tcf.yOffset = 0;\n\t}\n\n\tDWORD FillInLogFont(const CHARFORMAT& cf)\n\t{\n\t\tUSES_CONVERSION;\n\t\tDWORD dwFlags = 0;\n\t\tif((cf.dwMask & CFM_SIZE) != 0)\n\t\t{\n\t\t\tHDC hDC = ::CreateDC(_T(\"DISPLAY\"), NULL, NULL, NULL);\n\t\t\tLONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY);\n\t\t\tm_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440);\n\t\t}\n\t\telse\n\t\t\tm_lf.lfHeight = 0;\n\n\t\tm_lf.lfWidth = 0;\n\t\tm_lf.lfEscapement = 0;\n\t\tm_lf.lfOrientation = 0;\n\n\t\tif((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD))\n\t\t{\n\t\t\tm_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL;\n\t\t\tm_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdwFlags |= CF_NOSTYLESEL;\n\t\t\tm_lf.lfWeight = FW_DONTCARE;\n\t\t\tm_lf.lfItalic = FALSE;\n\t\t}\n\n\t\tif((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR))\n\t\t{\n\t\t\tdwFlags |= CF_EFFECTS;\n\t\t\tm_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE);\n\t\t\tm_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_lf.lfUnderline = (BYTE)FALSE;\n\t\t\tm_lf.lfStrikeOut = (BYTE)FALSE;\n\t\t}\n\n\t\tif((cf.dwMask & CFM_CHARSET) != 0)\n\t\t\tm_lf.lfCharSet = cf.bCharSet;\n\t\telse\n\t\t\tdwFlags |= CF_NOSCRIPTSEL;\n\t\tm_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;\n\t\tm_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;\n\t\tm_lf.lfQuality = DEFAULT_QUALITY;\n\t\tif((cf.dwMask & CFM_FACE) != 0)\n\t\t{\n\t\t\tm_lf.lfPitchAndFamily = cf.bPitchAndFamily;\n#if (_RICHEDIT_VER >= 0x0200)\n\t\t\tSecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName);\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t\t\tSecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName));\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;\n\t\t\tm_lf.lfFaceName[0] = (TCHAR)0;\n\t\t}\n\t\treturn dwFlags;\n\t}\n};\n\nclass CRichEditFontDialog : public CRichEditFontDialogImpl<CRichEditFontDialog>\n{\npublic:\n\tCRichEditFontDialog(const CHARFORMAT& charformat,\n\t\tDWORD dwFlags = CF_SCREENFONTS,\n\t\tHDC hDCPrinter = NULL,\n\t\tHWND hWndParent = NULL)\n\t\t: CRichEditFontDialogImpl<CRichEditFontDialog>(charformat, dwFlags, hDCPrinter, hWndParent)\n\t{ }\n\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CColorDialogImpl - color selection\n\n#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))\n\n#ifdef _WIN32_WCE\n  #pragma comment(lib, \"commdlg.lib\")\n\n  #ifndef SETRGBSTRING\n    #define SETRGBSTRING _T(\"commdlg_SetRGBColor\")\n  #endif\n\n  #ifndef COLOROKSTRING\n    #define COLOROKSTRING _T(\"commdlg_ColorOK\")\n  #endif\n#endif\n\ntemplate <class T>\nclass ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase\n{\npublic:\n\tCHOOSECOLOR m_cc;\n\n// Constructor\n\tCColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_cc, 0, sizeof(m_cc));\n\n\t\tm_cc.lStructSize = sizeof(m_cc);\n\t\tm_cc.lpCustColors = GetCustomColors();\n\t\tm_cc.hwndOwner = hWndParent;\n\t\tm_cc.Flags = dwFlags | CC_ENABLEHOOK;\n\t\tm_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc;\n\n\t\tif(clrInit != 0)\n\t\t{\n\t\t\tm_cc.rgbResult = clrInit;\n\t\t\tm_cc.Flags |= CC_RGBINIT;\n\t\t}\n\t}\n\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0);\n\t\tATLASSERT(m_cc.lpfnHook != NULL);   // can still be a user hook\n\n\t\tif(m_cc.hwndOwner == NULL)          // set only if not specified before\n\t\t\tm_cc.hwndOwner = hWndParent;\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRetTh = m_thunk.Init(NULL, NULL);\n\t\tif(bRetTh == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);\n\n\t\tBOOL bRet = ::ChooseColor(&m_cc);\n\n\t\tm_hWnd = NULL;\n\n\t\treturn bRet ? IDOK : IDCANCEL;\n\t}\n\n\t// Set the current color while dialog is displayed\n\tvoid SetCurrentColor(COLORREF clr)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tSendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr);\n\t}\n\n\t// Get the selected color after DoModal returns, or in OnColorOK\n\tCOLORREF GetColor() const\n\t{\n\t\treturn m_cc.rgbResult;\n\t}\n\n// Special override for the color dialog\n\tstatic UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tif(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage())\n\t\t\treturn 0;\n\n\t\tLPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam;\n\t\tCCommonDialogImplBase* pT = NULL;\n\n\t\tif(uMsg == WM_INITDIALOG)\n\t\t{\n\t\t\tpT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();\n\t\t\tlpCC->lCustData = (LPARAM)pT;\n\t\t\tATLASSERT(pT != NULL);\n\t\t\tATLASSERT(pT->m_hWnd == NULL);\n\t\t\tATLASSERT(::IsWindow(hWnd));\n\t\t\t// subclass dialog's window\n\t\t\tif(!pT->SubclassWindow(hWnd))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Subclassing a Color common dialog failed\\n\"));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\telse if(uMsg == _GetColorOKMessage())\n\t\t{\n\t\t\tpT = (CCommonDialogImplBase*)lpCC->lCustData;\n\t\t\tATLASSERT(pT != NULL);\n\t\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn 0;\n\t\t}\n\n\t\t// pass to the message map\n\t\tLRESULT lRes = 0;\n\t\tif(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)\n\t\t\treturn 0;\n\n\t\treturn lRes;\n\t}\n\n// Helpers\n\tstatic COLORREF* GetCustomColors()\n\t{\n\t\tstatic COLORREF rgbCustomColors[16] =\n\t\t{\n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t\tRGB(255, 255, 255), RGB(255, 255, 255), \n\t\t};\n\n\t\treturn rgbCustomColors;\n\t}\n\n\tstatic UINT _GetSetRGBMessage()\n\t{\n\t\tstatic UINT uSetRGBMessage = 0;\n\t\tif(uSetRGBMessage == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uSetRGBMessage == 0)\n\t\t\t\tuSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING);\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uSetRGBMessage != 0);\n\t\treturn uSetRGBMessage;\n\t}\n\n\tstatic UINT _GetColorOKMessage()\n\t{\n\t\tstatic UINT uColorOKMessage = 0;\n\t\tif(uColorOKMessage == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uColorOKMessage == 0)\n\t\t\t\tuColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING);\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uColorOKMessage != 0);\n\t\treturn uColorOKMessage;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CColorDialogImpl)\n\t\tMESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK)\n\tEND_MSG_MAP()\n\n\tLRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->OnColorOK();\n\t}\n\n// Overrideable\n\tBOOL OnColorOK()        // validate color\n\t{\n\t\treturn FALSE;\n\t}\n};\n\nclass CColorDialog : public CColorDialogImpl<CColorDialog>\n{\npublic:\n\tCColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)\n\t\t: CColorDialogImpl<CColorDialog>(clrInit, dwFlags, hWndParent)\n\t{ }\n\n\t// override base class map and references to handlers\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrintDialogImpl - used for Print... and PrintSetup...\n\n#ifndef _WIN32_WCE\n\n// global helper\nstatic inline HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode)\n{\n\tif(hDevNames == NULL)\n\t\treturn NULL;\n\n\tLPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames);\n\tLPDEVMODE  lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL;\n\n\tif(lpDevNames == NULL)\n\t\treturn NULL;\n\n\tHDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset,\n\t\t\t\t\t  (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset,\n\t\t\t\t\t  (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset,\n\t\t\t\t\t  lpDevMode);\n\n\t::GlobalUnlock(hDevNames);\n\tif(hDevMode != NULL)\n\t\t::GlobalUnlock(hDevMode);\n\treturn hDC;\n}\n\n#pragma warning(push)\n#pragma warning(disable: 4512)   // assignment operator could not be generated\n\ntemplate <class T>\nclass ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase\n{\npublic:\n\t// print dialog parameter block (note this is a reference)\n\tPRINTDLG& m_pd;\n\n// Constructors\n\tCPrintDialogImpl(BOOL bPrintSetupOnly = FALSE,\t// TRUE for Print Setup, FALSE for Print Dialog\n\t\t\tDWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,\n\t\t\tHWND hWndParent = NULL)\n\t\t\t: m_pd(m_pdActual)\n\t{\n\t\tmemset(&m_pdActual, 0, sizeof(m_pdActual));\n\n\t\tm_pd.lStructSize = sizeof(m_pdActual);\n\t\tm_pd.hwndOwner = hWndParent;\n\t\tm_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);\n\t\tm_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc;\n\t\tm_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc;\n\n\t\tif(bPrintSetupOnly)\n\t\t\tm_pd.Flags |= PD_PRINTSETUP;\n\t\telse\n\t\t\tm_pd.Flags |= PD_RETURNDC;\n\n\t\tm_pd.Flags &= ~PD_RETURNIC; // do not support information context\n\t}\n\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0);\n\t\tATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0);\n\t\tATLASSERT(m_pd.lpfnPrintHook != NULL);   // can still be a user hook\n\t\tATLASSERT(m_pd.lpfnSetupHook != NULL);   // can still be a user hook\n\t\tATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this\n\n\t\tif(m_pd.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_pd.hwndOwner = hWndParent;\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRetTh = m_thunk.Init(NULL, NULL);\n\t\tif(bRetTh == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);\n\n\t\tBOOL bRet = ::PrintDlg(&m_pd);\n\n\t\tm_hWnd = NULL;\n\n\t\treturn bRet ? IDOK : IDCANCEL;\n\t}\n\n\t// GetDefaults will not display a dialog but will get device defaults\n\tBOOL GetDefaults()\n\t{\n\t\tm_pd.Flags |= PD_RETURNDEFAULT;\n\t\tATLASSERT(m_pd.hDevMode == NULL);    // must be NULL\n\t\tATLASSERT(m_pd.hDevNames == NULL);   // must be NULL\n\n\t\treturn ::PrintDlg(&m_pd);\n\t}\n\n\t// Helpers for parsing information after successful return num. copies requested\n\tint GetCopies() const\n\t{\n\t\tif((m_pd.Flags & PD_USEDEVMODECOPIES) != 0)\n\t\t{\n\t\t\tLPDEVMODE lpDevMode = GetDevMode();\n\t\t\treturn (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;\n\t\t}\n\n\t\treturn m_pd.nCopies;\n\t}\n\n\tBOOL PrintCollate() const       // TRUE if collate checked\n\t{\n\t\treturn ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintSelection() const     // TRUE if printing selection\n\t{\n\t\treturn ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintAll() const           // TRUE if printing all pages\n\t{\n\t\treturn (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintRange() const         // TRUE if printing page range\n\t{\n\t\treturn ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintToFile() const        // TRUE if printing to a file\n\t{\n\t\treturn ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;\n\t}\n\n\tint GetFromPage() const         // starting page if valid\n\t{\n\t\treturn PrintRange() ? m_pd.nFromPage : -1;\n\t}\n\n\tint GetToPage() const           // ending page if valid\n\t{\n\t\treturn PrintRange() ? m_pd.nToPage : -1;\n\t}\n\n\tLPDEVMODE GetDevMode() const    // return DEVMODE\n\t{\n\t\tif(m_pd.hDevMode == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPDEVMODE)::GlobalLock(m_pd.hDevMode);\n\t}\n\n\tLPCTSTR GetDriverName() const   // return driver name\n\t{\n\t\tif(m_pd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wDriverOffset;\n\t}\n\n\tLPCTSTR GetDeviceName() const   // return device name\n\t{\n\t\tif(m_pd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wDeviceOffset;\n\t}\n\n\tLPCTSTR GetPortName() const     // return output port name\n\t{\n\t\tif(m_pd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wOutputOffset;\n\t}\n\n\tHDC GetPrinterDC() const        // return HDC (caller must delete)\n\t{\n\t\tATLASSERT((m_pd.Flags & PD_RETURNDC) != 0);\n\t\treturn m_pd.hDC;\n\t}\n\n\t// This helper creates a DC based on the DEVNAMES and DEVMODE structures.\n\t// This DC is returned, but also stored in m_pd.hDC as though it had been\n\t// returned by CommDlg.  It is assumed that any previously obtained DC\n\t// has been/will be deleted by the user.  This may be\n\t// used without ever invoking the print/print setup dialogs.\n\tHDC CreatePrinterDC()\n\t{\n\t\tm_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode);\n\t\treturn m_pd.hDC;\n\t}\n\n// Implementation\n\tPRINTDLG m_pdActual; // the Print/Print Setup need to share this\n\n\t// The following handle the case of print setup... from the print dialog\n\tCPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit)\n\t{ }\n\n\tBEGIN_MSG_MAP(CPrintDialogImpl)\n#ifdef psh1\n\t\tCOMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed\n#else // !psh1\n\t\tCOMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h\n#endif // !psh1\n\tEND_MSG_MAP()\n\n\tLRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)\n\t{\n\t\tT dlgSetup(m_pd);\n\t\tModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);\n\t\treturn DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl);\n\t}\n};\n\nclass CPrintDialog : public CPrintDialogImpl<CPrintDialog>\n{\npublic:\n\tCPrintDialog(BOOL bPrintSetupOnly = FALSE,\n\t\tDWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,\n\t\tHWND hWndParent = NULL)\n\t\t: CPrintDialogImpl<CPrintDialog>(bPrintSetupOnly, dwFlags, hWndParent)\n\t{ }\n\n\tCPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl<CPrintDialog>(pdInit)\n\t{ }\n};\n\n#pragma warning(pop)\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrintDialogExImpl - new print dialog for Windows 2000\n\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\n}; // namespace WTL\n\n#include <atlcom.h>\n\nextern \"C\" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};\nextern \"C\" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};\n\nnamespace WTL\n{\n\ntemplate <class T>\nclass ATL_NO_VTABLE CPrintDialogExImpl : \n\t\t\t\tpublic ATL::CWindow,\n\t\t\t\tpublic ATL::CMessageMap,\n\t\t\t\tpublic IPrintDialogCallback,\n\t\t\t\tpublic ATL::IObjectWithSiteImpl< T >\n{\npublic:\n\tPRINTDLGEX m_pdex;\n\n// Constructor\n\tCPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,\n\t\t\t\tHWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_pdex, 0, sizeof(m_pdex));\n\n\t\tm_pdex.lStructSize = sizeof(PRINTDLGEX);\n\t\tm_pdex.hwndOwner = hWndParent;\n\t\tm_pdex.Flags = dwFlags;\n\t\tm_pdex.nStartPage = START_PAGE_GENERAL;\n\t\t// callback object will be set in DoModal\n\n\t\tm_pdex.Flags &= ~PD_RETURNIC; // do not support information context\n\t}\n\n// Operations\n\tHRESULT DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\t\tATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this\n\n\t\tif(m_pdex.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_pdex.hwndOwner = hWndParent;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT;\n\n\t\tHRESULT hResult = ::PrintDlgEx(&m_pdex);\n\n\t\tm_hWnd = NULL;\n\n\t\treturn hResult;\n\t}\n\n\tBOOL EndDialog(INT_PTR /*nRetCode*/ = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tSendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));\n\t\treturn TRUE;\n\t}\n\n\t// GetDefaults will not display a dialog but will get device defaults\n\tHRESULT GetDefaults()\n\t{\n\t\tATLASSERT(m_pdex.hDevMode == NULL);    // must be NULL\n\t\tATLASSERT(m_pdex.hDevNames == NULL);   // must be NULL\n\n\t\tif(m_pdex.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_pdex.hwndOwner = ::GetActiveWindow();\n\n\t\tm_pdex.Flags |= PD_RETURNDEFAULT;\n\t\tHRESULT hRet = ::PrintDlgEx(&m_pdex);\n\t\tm_pdex.Flags &= ~PD_RETURNDEFAULT;\n\n\t\treturn hRet;\n\t}\n\n\t// Helpers for parsing information after successful return num. copies requested\n\tint GetCopies() const\n\t{\n\t\tif((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0)\n\t\t{\n\t\t\tLPDEVMODE lpDevMode = GetDevMode();\n\t\t\treturn (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;\n\t\t}\n\n\t\treturn m_pdex.nCopies;\n\t}\n\n\tBOOL PrintCollate() const       // TRUE if collate checked\n\t{\n\t\treturn ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintSelection() const     // TRUE if printing selection\n\t{\n\t\treturn ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintAll() const           // TRUE if printing all pages\n\t{\n\t\treturn (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintRange() const         // TRUE if printing page range\n\t{\n\t\treturn ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL PrintToFile() const        // TRUE if printing to a file\n\t{\n\t\treturn ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;\n\t}\n\n\tLPDEVMODE GetDevMode() const    // return DEVMODE\n\t{\n\t\tif(m_pdex.hDevMode == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPDEVMODE)::GlobalLock(m_pdex.hDevMode);\n\t}\n\n\tLPCTSTR GetDriverName() const   // return driver name\n\t{\n\t\tif(m_pdex.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wDriverOffset;\n\t}\n\n\tLPCTSTR GetDeviceName() const   // return device name\n\t{\n\t\tif(m_pdex.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wDeviceOffset;\n\t}\n\n\tLPCTSTR GetPortName() const     // return output port name\n\t{\n\t\tif(m_pdex.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);\n\t\tif(lpDev == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPCTSTR)lpDev + lpDev->wOutputOffset;\n\t}\n\n\tHDC GetPrinterDC() const        // return HDC (caller must delete)\n\t{\n\t\tATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0);\n\t\treturn m_pdex.hDC;\n\t}\n\n\t// This helper creates a DC based on the DEVNAMES and DEVMODE structures.\n\t// This DC is returned, but also stored in m_pdex.hDC as though it had been\n\t// returned by CommDlg.  It is assumed that any previously obtained DC\n\t// has been/will be deleted by the user.  This may be\n\t// used without ever invoking the print/print setup dialogs.\n\tHDC CreatePrinterDC()\n\t{\n\t\tm_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode);\n\t\treturn m_pdex.hDC;\n\t}\n\n// Implementation - interfaces\n\n// IUnknown\n\tSTDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)\n\t{\n\t\tif(ppvObject == NULL)\n\t\t\treturn E_POINTER;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback))\n\t\t{\n\t\t\t*ppvObject = (IPrintDialogCallback*)pT;\n\t\t\t// AddRef() not needed\n\t\t\treturn S_OK;\n\t\t}\n\t\telse if(IsEqualGUID(riid, IID_IObjectWithSite))\n\t\t{\n\t\t\t*ppvObject = (IObjectWithSite*)pT;\n\t\t\t// AddRef() not needed\n\t\t\treturn S_OK;\n\t\t}\n\n\t\treturn E_NOINTERFACE;\n\t}\n\n\tvirtual ULONG STDMETHODCALLTYPE AddRef()\n\t{\n\t\treturn 1;\n\t}\n\n\tvirtual ULONG STDMETHODCALLTYPE Release()\n\t{\n\t\treturn 1;\n\t}\n\n// IPrintDialogCallback\n\tSTDMETHOD(InitDone)()\n\t{\n\t\treturn S_FALSE;\n\t}\n\n\tSTDMETHOD(SelectionChange)()\n\t{\n\t\treturn S_FALSE;\n\t}\n\n\tSTDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)\n\t{\n\t\t// set up m_hWnd the first time\n\t\tif(m_hWnd == NULL)\n\t\t\tAttach(hWnd);\n\n\t\t// call message map\n\t\tHRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE;\n\t\tif(hRet == S_OK && uMsg == WM_NOTIFY)   // return in DWLP_MSGRESULT\n\t\t\t::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult);\n\n\t\tif(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE)\n\t\t\thRet = S_FALSE;\n\n\t\treturn hRet;\n\t}\n};\n\nclass CPrintDialogEx : public CPrintDialogExImpl<CPrintDialogEx>\n{\npublic:\n\tCPrintDialogEx(\n\t\tDWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,\n\t\tHWND hWndParent = NULL)\n\t\t: CPrintDialogExImpl<CPrintDialogEx>(dwFlags, hWndParent)\n\t{ }\n\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPageSetupDialogImpl - Page Setup dialog\n\n#ifndef _WIN32_WCE\n\ntemplate <class T>\nclass ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase\n{\npublic:\n\tPAGESETUPDLG m_psd;\n\tATL::CWndProcThunk m_thunkPaint;\n\n// Constructors\n\tCPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_psd, 0, sizeof(m_psd));\n\n\t\tm_psd.lStructSize = sizeof(m_psd);\n\t\tm_psd.hwndOwner = hWndParent;\n\t\tm_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK);\n\t\tm_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc;\n\t\tm_thunkPaint.Init((WNDPROC)T::PaintHookProc, this);\n#if (_ATL_VER >= 0x0700)\n\t\tm_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC();\n#else\n\t\tm_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk);\n#endif\n\t}\n\n\tDECLARE_EMPTY_MSG_MAP()\n\n// Attributes\n\tLPDEVMODE GetDevMode() const    // return DEVMODE\n\t{\n\t\tif(m_psd.hDevMode == NULL)\n\t\t\treturn NULL;\n\n\t\treturn (LPDEVMODE)::GlobalLock(m_psd.hDevMode);\n\t}\n\n\tLPCTSTR GetDriverName() const   // return driver name\n\t{\n\t\tif(m_psd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);\n\t\treturn (LPCTSTR)lpDev + lpDev->wDriverOffset;\n\t}\n\n\tLPCTSTR GetDeviceName() const   // return device name\n\t{\n\t\tif(m_psd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);\n\t\treturn (LPCTSTR)lpDev + lpDev->wDeviceOffset;\n\t}\n\n\tLPCTSTR GetPortName() const     // return output port name\n\t{\n\t\tif(m_psd.hDevNames == NULL)\n\t\t\treturn NULL;\n\n\t\tLPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);\n\t\treturn (LPCTSTR)lpDev + lpDev->wOutputOffset;\n\t}\n\n\tHDC CreatePrinterDC()\n\t{\n\t\treturn _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode);\n\t}\n\n\tSIZE GetPaperSize() const\n\t{\n\t\tSIZE size = { m_psd.ptPaperSize.x, m_psd.ptPaperSize.y };\n\t\treturn size;\n\t}\n\n\tvoid GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const\n\t{\n\t\tif(lpRectMargins != NULL)\n\t\t\t*lpRectMargins = m_psd.rtMargin;\n\t\tif(lpRectMinMargins != NULL)\n\t\t\t*lpRectMinMargins = m_psd.rtMinMargin;\n\t}\n\n// Operations\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0);\n\t\tATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0);\n\t\tATLASSERT(m_psd.lpfnPageSetupHook != NULL);   // can still be a user hook\n\t\tATLASSERT(m_psd.lpfnPagePaintHook != NULL);   // can still be a user hook\n\n\t\tif(m_psd.hwndOwner == NULL)   // set only if not specified before\n\t\t\tm_psd.hwndOwner = hWndParent;\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRetTh = m_thunk.Init(NULL, NULL);\n\t\tif(bRetTh == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);\n\n\t\tBOOL bRet = ::PageSetupDlg(&m_psd);\n\n\t\tm_hWnd = NULL;\n\n\t\treturn bRet ? IDOK : IDCANCEL;\n\t}\n\n// Implementation\n\tstatic UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tT* pT = (T*)hWnd;\n\t\tUINT_PTR uRet = 0;\n\t\tswitch(uMsg)\n\t\t{\n\t\tcase WM_PSD_PAGESETUPDLG:\n\t\t\tuRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam);\n\t\t\tbreak;\n\t\tcase WM_PSD_FULLPAGERECT:\n\t\tcase WM_PSD_MINMARGINRECT:\n\t\tcase WM_PSD_MARGINRECT:\n\t\tcase WM_PSD_GREEKTEXTRECT:\n\t\tcase WM_PSD_ENVSTAMPRECT:\n\t\tcase WM_PSD_YAFULLPAGERECT:\n\t\t\tuRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CPageSetupDialogImpl::PaintHookProc - unknown message received\\n\"));\n\t\t\tbreak;\n\t\t}\n\t\treturn uRet;\n\t}\n\n// Overridables\n\tUINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/)\n\t{\n\t\t// return 1 to prevent any more drawing\n\t\treturn 0;\n\t}\n\n\tUINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/)\n\t{\n\t\treturn 0; // do the default\n\t}\n};\n\nclass CPageSetupDialog : public CPageSetupDialogImpl<CPageSetupDialog>\n{\npublic:\n\tCPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)\n\t\t: CPageSetupDialogImpl<CPageSetupDialog>(dwFlags, hWndParent)\n\t{ }\n\n\t// override PaintHookProc and references to handlers\n\tstatic UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM)\n\t{\n\t\treturn 0;\n\t}\n};\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFindReplaceDialogImpl - Find/FindReplace modeless dialogs\n\n#ifndef _WIN32_WCE\n\ntemplate <class T>\nclass ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase\n{\npublic:\n\tenum { _cchFindReplaceBuffer = 128 };\n\n\tFINDREPLACE m_fr;\n\tTCHAR m_szFindWhat[_cchFindReplaceBuffer];\n\tTCHAR m_szReplaceWith[_cchFindReplaceBuffer];\n\n// Constructors\n\tCFindReplaceDialogImpl()\n\t{\n\t\tmemset(&m_fr, 0, sizeof(m_fr));\n\t\tm_szFindWhat[0] = _T('\\0');\n\t\tm_szReplaceWith[0] = _T('\\0');\n\n\t\tm_fr.lStructSize = sizeof(m_fr);\n\t\tm_fr.Flags = FR_ENABLEHOOK;\n\t\tm_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc;\n\t\tm_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat;\n\t\tm_fr.wFindWhatLen = _cchFindReplaceBuffer;\n\t\tm_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith;\n\t\tm_fr.wReplaceWithLen = _cchFindReplaceBuffer;\n\t}\n\n\t// Note: You must allocate the object on the heap.\n\t//       If you do not, you must override OnFinalMessage()\n\tvirtual void OnFinalMessage(HWND /*hWnd*/)\n\t{\n\t\tdelete this;\n\t}\n\n\tHWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace\n\t\t\tLPCTSTR lpszFindWhat,\n\t\t\tLPCTSTR lpszReplaceWith = NULL,\n\t\t\tDWORD dwFlags = FR_DOWN,\n\t\t\tHWND hWndParent = NULL)\n\t{\n\t\tATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0);\n\t\tATLASSERT(m_fr.lpfnHook != NULL);\n\n\t\tm_fr.Flags |= dwFlags;\n\n\t\tif(hWndParent == NULL)\n\t\t\tm_fr.hwndOwner = ::GetActiveWindow();\n\t\telse\n\t\t\tm_fr.hwndOwner = hWndParent;\n\t\tATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog\n\n\t\tif(lpszFindWhat != NULL)\n\t\t\tSecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE);\n\n\t\tif(lpszReplaceWith != NULL)\n\t\t\tSecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE);\n\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn NULL;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);\n\n\t\tHWND hWnd = NULL;\n\t\tif(bFindDialogOnly)\n\t\t\thWnd = ::FindText(&m_fr);\n\t\telse\n\t\t\thWnd = ::ReplaceText(&m_fr);\n\n\t\tATLASSERT(m_hWnd == hWnd);\n\t\treturn hWnd;\n\t}\n\n\tstatic const UINT GetFindReplaceMsg()\n\t{\n\t\tstatic const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);\n\t\treturn nMsgFindReplace;\n\t}\n\t// call while handling FINDMSGSTRING registered message\n\t// to retreive the object\n\tstatic T* PASCAL GetNotifier(LPARAM lParam)\n\t{\n\t\tATLASSERT(lParam != NULL);\n\t\tT* pDlg = (T*)(lParam - offsetof(T, m_fr));\n\t\treturn pDlg;\n\t}\n\n// Operations\n\t// Helpers for parsing information after successful return\n\tLPCTSTR GetFindString() const    // get find string\n\t{\n\t\treturn (LPCTSTR)m_fr.lpstrFindWhat;\n\t}\n\n\tLPCTSTR GetReplaceString() const // get replacement string\n\t{\n\t\treturn (LPCTSTR)m_fr.lpstrReplaceWith;\n\t}\n\n\tBOOL SearchDown() const          // TRUE if search down, FALSE is up\n\t{\n\t\treturn ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL FindNext() const            // TRUE if command is find next\n\t{\n\t\treturn ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL MatchCase() const           // TRUE if matching case\n\t{\n\t\treturn ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL MatchWholeWord() const      // TRUE if matching whole words only\n\t{\n\t\treturn ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL ReplaceCurrent() const      // TRUE if replacing current string\n\t{\n\t\treturn ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL ReplaceAll() const          // TRUE if replacing all occurrences\n\t{\n\t\treturn ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE;\n\t}\n\n\tBOOL IsTerminating() const       // TRUE if terminating dialog\n\t{\n\t\treturn ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ;\n\t}\n};\n\nclass CFindReplaceDialog : public CFindReplaceDialogImpl<CFindReplaceDialog>\n{\npublic:\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n#endif // !_WIN32_WCE\n\n\n/////////////////////////////////////////////////////////////////////////\n// CDialogBaseUnits - Dialog Units helper\n//\n\nclass CDialogBaseUnits\n{\npublic:\n\tSIZE m_sizeUnits;\n\n// Constructors\n\tCDialogBaseUnits()\n\t{\n\t\t// The base units of the out-dated System Font\n\t\tLONG nDlgBaseUnits = ::GetDialogBaseUnits();\n\t\tm_sizeUnits.cx = LOWORD(nDlgBaseUnits);\n\t\tm_sizeUnits.cy = HIWORD(nDlgBaseUnits);\n\t}\n\n\tCDialogBaseUnits(HWND hWnd)\n\t{\n\t\tif(!InitDialogBaseUnits(hWnd)) {\n\t\t\tLONG nDlgBaseUnits = ::GetDialogBaseUnits();\n\t\t\tm_sizeUnits.cx = LOWORD(nDlgBaseUnits);\n\t\t\tm_sizeUnits.cy = HIWORD(nDlgBaseUnits);\n\t\t}\n\t}\n\n\tCDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)\n\t{\n\t\tif(!InitDialogBaseUnits(hFont, hWnd)) {\n\t\t\tLONG nDlgBaseUnits = ::GetDialogBaseUnits();\n\t\t\tm_sizeUnits.cx = LOWORD(nDlgBaseUnits);\n\t\t\tm_sizeUnits.cy = HIWORD(nDlgBaseUnits);\n\t\t}\n\t}\n\n\tCDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)\n\t{\n\t\tif(!InitDialogBaseUnits(lf, hWnd)) {\n\t\t\tLONG nDlgBaseUnits = ::GetDialogBaseUnits();\n\t\t\tm_sizeUnits.cx = LOWORD(nDlgBaseUnits);\n\t\t\tm_sizeUnits.cy = HIWORD(nDlgBaseUnits);\n\t\t}\n\t}\n\n// Operations\n\tBOOL InitDialogBaseUnits(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tRECT rc = { 0, 0, 4, 8 };\n\t\tif(!::MapDialogRect(hWnd, &rc)) return FALSE;\n\t\tm_sizeUnits.cx = rc.right;\n\t\tm_sizeUnits.cy = rc.bottom;\n\t\treturn TRUE;\n\t}\n\n\tBOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)\n\t{\n\t\tCFont font;\n\t\tfont.CreateFontIndirect(&lf);\n\t\tif(font.IsNull()) return FALSE;\n\t\treturn InitDialogBaseUnits(font, hWnd);\n\t}\n\n\tBOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)\n\t{\n\t\tATLASSERT(hFont != NULL);\n\t\tCWindowDC dc = hWnd;\n\t\tTEXTMETRIC tmText = { 0 };\n\t\tSIZE sizeText = { 0 };\n\t\tHFONT hFontOld = dc.SelectFont(hFont);\n\t\tdc.GetTextMetrics(&tmText);\n\t\tm_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading;\n\t\tdc.GetTextExtent(_T(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\"), 52, &sizeText);\n\t\tm_sizeUnits.cx = (sizeText.cx + 26) / 52;\n\t\tdc.SelectFont(hFontOld);\n\t\treturn TRUE;\n\t}\n\n\tSIZE GetDialogBaseUnits() const\n\t{\n\t\treturn m_sizeUnits;\n\t}\n\n\tINT MapDialogPixelsX(INT x) const\n\t{\n\t\treturn ::MulDiv(x, 4, m_sizeUnits.cx);  // Pixels X to DLU\n\t}\n\n\tINT MapDialogPixelsY(INT y) const\n\t{\n\t\treturn ::MulDiv(y, 8, m_sizeUnits.cy);  // Pixels Y to DLU\n\t}\n\n\tPOINT MapDialogPixels(POINT pt) const\n\t{\n\t\tPOINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) };\n\t\treturn out;\n\t}\n\n\tSIZE MapDialogPixels(SIZE input) const\n\t{\n\t\tSIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) };\n\t\treturn out;\n\t}\n\n\tRECT MapDialogPixels(const RECT& input) const\n\t{\n\t\tRECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) };\n\t\treturn out;\n\t}\n\n\tINT MapDialogUnitsX(INT x) const\n\t{\n\t\treturn ::MulDiv(x, m_sizeUnits.cx, 4);  // DLU to Pixels X\n\t}\n\n\tINT MapDialogUnitsY(INT y) const\n\t{\n\t\treturn ::MulDiv(y, m_sizeUnits.cy, 8);  // DLU to Pixels Y\n\t}\n\n\tPOINT MapDialogUnits(POINT pt) const\n\t{\n\t\tPOINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) };\n\t\treturn out;\n\t}\n\n\tSIZE MapDialogUnits(SIZE input) const\n\t{\n\t\tSIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) };\n\t\treturn out;\n\t}\n\n\tRECT MapDialogUnits(const RECT& input) const\n\t{\n\t\tRECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) };\n\t\treturn out;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX\n\n#if (_ATL_VER >= 0x800)\n  typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX;\n  typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX;\n#else // (_ATL_VER >= 0x800)\n  typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX;\n  #pragma pack(push, 4)\n  struct DLGITEMTEMPLATEEX\n  {\n\tDWORD helpID;\n\tDWORD exStyle;\n\tDWORD style;\n\tshort x;\n\tshort y;\n\tshort cx;\n\tshort cy;\n\tDWORD id;\n  };\n  #pragma pack(pop)\n#endif // (_ATL_VER >= 0x800)\n\n\ntemplate <class TWinTraits>\nclass CMemDlgTemplateT\n{\npublic:\n\tenum StdCtrlType\n\t{\n\t\tCTRL_BUTTON    = 0x0080,\n\t\tCTRL_EDIT      = 0x0081,\n\t\tCTRL_STATIC    = 0x0082,\n\t\tCTRL_LISTBOX   = 0x0083,\n\t\tCTRL_SCROLLBAR = 0x0084,\n\t\tCTRL_COMBOBOX  = 0x0085\n\t};\n\n\tHANDLE m_hData;\n\tLPBYTE m_pData;\n\tLPBYTE m_pPtr;\n\tSIZE_T m_cAllocated;\n\n\tCMemDlgTemplateT() : m_hData(NULL), m_pData(NULL), m_pPtr(NULL), m_cAllocated(0)\n\t{ }\n\n\t~CMemDlgTemplateT()\n\t{\n\t\tReset();\n\t}\n\n\tbool IsValid() const\n\t{\n\t\treturn (m_pData != NULL);\n\t}\n\n\tbool IsTemplateEx() const\n\t{\n\t\treturn (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF);\n\t}\n\n\tLPDLGTEMPLATE GetTemplatePtr()\n\t{\n\t\treturn reinterpret_cast<LPDLGTEMPLATE>(m_pData);\n\t}\n\n\tDLGTEMPLATEEX* GetTemplateExPtr()\n\t{\n\t\treturn reinterpret_cast<DLGTEMPLATEEX*>(m_pData);\n\t}\n\n\tvoid Reset()\n\t{\n\t\tif (IsValid()) {\n#ifndef UNDER_CE\n\t\t\t::GlobalUnlock(m_pData);\n#endif\n\t\t\tATLVERIFY(::GlobalFree(m_hData) == NULL);\n\t\t}\n\n\t\tm_hData = NULL;\n\t\tm_pData = NULL;\n\t\tm_pPtr = NULL;\n\t\tm_cAllocated = 0;\n\t}\n\n\tvoid Create(bool bDlgEx, LPCTSTR lpszCaption, const RECT& rc, DWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t            LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,\n\t            ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)\n\t{\n\t\tCreate(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,\n\t\t\tlpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr);\n\t}\n\n\tvoid Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t            LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,\n\t            ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)\n\t{\n\t\t// Should have DS_SETFONT style to set the dialog font name and size\n\t\tif (lpstrFontName != NULL)\n\t\t{\n\t\t\tdwStyle |= DS_SETFONT;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdwStyle &= ~DS_SETFONT;\n\t\t}\n\n\t\tif (bDlgEx)\n\t\t{\n\t\t\tDLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight};\n\t\t\tAddData(&dlg, sizeof(dlg));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight};\n\t\t\tAddData(&dlg, sizeof(dlg));\n\t\t}\n\n#ifndef _WIN32_WCE\n\t\tif (Menu.m_lpstr == NULL)\n\t\t{\n\t\t\tWORD menuData = 0;\n\t\t\tAddData(&menuData, sizeof(WORD));\n\t\t}\n\t\telse if (IS_INTRESOURCE(Menu.m_lpstr))\n\t\t{\n\t\t\tWORD menuData[] = { 0xFFFF, LOWORD(Menu.m_lpstr) };\n\t\t\tAddData(menuData, sizeof(menuData));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddString(Menu.m_lpstr);\n\t\t}\n#else // _WIN32_WCE\n\t\t// Windows CE doesn't support the addition of menus to a dialog box\n\t\tATLASSERT(Menu.m_lpstr == NULL);\n\t\tMenu.m_lpstr;   // avoid level 4 warning\n\t\tWORD menuData = 0;\n\t\tAddData(&menuData, sizeof(WORD));\n#endif // _WIN32_WCE\n\n\t\tif (ClassName.m_lpstr == NULL)\n\t\t{\n\t\t\tWORD classData = 0;\n\t\t\tAddData(&classData, sizeof(WORD));\n\t\t}\n\t\telse if (IS_INTRESOURCE(ClassName.m_lpstr))\n\t\t{\n\t\t\tWORD classData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) };\n\t\t\tAddData(classData, sizeof(classData));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddString(ClassName.m_lpstr);\n\t\t}\n\n\t\t// Set dialog caption\n\t\tAddString(lpszCaption);\n\n\t\tif (lpstrFontName != NULL)\n\t\t{\n\t\t\tAddData(&wFontSize, sizeof(wFontSize));\n\n\t\t\tif (bDlgEx)\n\t\t\t{\n\t\t\t\tAddData(&wWeight, sizeof(wWeight));\n\t\t\t\tAddData(&bItalic, sizeof(bItalic));\n\t\t\t\tAddData(&bCharset, sizeof(bCharset));\n\t\t\t}\n\n\t\t\tAddString(lpstrFontName);\n\t\t}\n\t}\n\n\tvoid AddControl(ATL::_U_STRINGorID ClassName, WORD wId, const RECT& rc, DWORD dwStyle, DWORD dwExStyle,\n\t                ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)\n\t{\n\t\tAddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,\n\t\t\tText.m_lpstr, pCreationData, nCreationData, dwHelpID);\n\t}\n\n\tvoid AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle,\n\t                ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)\n\t{\n\t\tATLASSERT(IsValid());\n\n\t\t// DWORD align data\n\t\tconst DWORD_PTR dwDwordAlignBits = sizeof(DWORD) - 1;\n\t\tm_pPtr = (LPBYTE)(((DWORD_PTR)m_pPtr + dwDwordAlignBits) & (~dwDwordAlignBits));\n\n\t\tif (IsTemplateEx())\n\t\t{\n\t\t\tDLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData;\n\t\t\tdlg->cDlgItems++;\n\n\t\t\tDLGITEMTEMPLATEEX item = {dwHelpID, TWinTraits::GetWndExStyle(0) | dwExStyle, TWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId};\n\t\t\tAddData(&item, sizeof(item));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData;\n\t\t\tdlg->cdit++;\n\n\t\t\tDLGITEMTEMPLATE item = {TWinTraits::GetWndStyle(0) | dwStyle, TWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId};\n\t\t\tAddData(&item, sizeof(item));\n\t\t}\n\n\t\tATLASSERT(ClassName.m_lpstr != NULL);\n\t\tif (IS_INTRESOURCE(ClassName.m_lpstr))\n\t\t{\n\t\t\tWORD wData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) };\n\t\t\tAddData(wData, sizeof(wData));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddString(ClassName.m_lpstr);\n\t\t}\n\n\t\tif (Text.m_lpstr == NULL)\n\t\t{\n\t\t\tWORD classData = 0;\n\t\t\tAddData(&classData, sizeof(WORD));\n\t\t}\n\t\telse if (IS_INTRESOURCE(Text.m_lpstr))\n\t\t{\n\t\t\tWORD wData[] = { 0xFFFF, LOWORD(Text.m_lpstr) };\n\t\t\tAddData(wData, sizeof(wData));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddString(Text.m_lpstr);\n\t\t}\n\n\t\tAddData(&nCreationData, sizeof(nCreationData));\n\n\t\tif ((nCreationData != 0))\n\t\t{\n\t\t\tATLASSERT(pCreationData != NULL);\n\t\t\tAddData(pCreationData, nCreationData * sizeof(WORD));\n\t\t}\n\t}\n\n\tvoid AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight,\n\t                   DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)\n\t{\n\t\tAddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID);\n\t}\n\n\tvoid AddData(LPCVOID pData, size_t nData)\n\t{\n\t\tATLASSERT(pData != NULL);\n\n\t\tconst SIZE_T ALLOCATION_INCREMENT = 1024;\n\n\t\tif (m_pData == NULL)\n\t\t{\n\t\t\tm_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;\n\t\t\tm_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated);\n\t\t\tATLASSERT(m_hData != NULL);\n#ifndef UNDER_CE\n\t\t\tm_pPtr = m_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));\n#else\n\t\t\tm_pPtr = m_pData = static_cast<LPBYTE>(m_hData);\n#endif\n\t\t\tATLASSERT(m_pData != NULL);\n\t\t}\n\t\telse if (((m_pPtr - m_pData) + nData) > m_cAllocated)\n\t\t{\n\t\t\tSIZE_T ptrPos = (m_pPtr - m_pData);\n\t\t\tm_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;\n#ifndef UNDER_CE\n\t\t\t::GlobalUnlock(m_pData);\n#endif\n\t\t\tm_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT);\n\t\t\tATLASSERT(m_hData != NULL);\n#ifndef UNDER_CE\n\t\t\tm_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));\n#else\n\t\t\tm_pData = static_cast<LPBYTE>(m_hData);\n#endif\n\t\t\tATLASSERT(m_pData != NULL);\n\t\t\tm_pPtr = m_pData + ptrPos;\n\t\t}\n\n\t\tSecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData);\n\n\t\tm_pPtr += nData;\n\t}\n\n\tvoid AddString(LPCTSTR lpszStr)\n\t{\n\t\tif (lpszStr == NULL)\n\t\t{\n\t\t\tWCHAR szEmpty = 0;\n\t\t\tAddData(&szEmpty, sizeof(szEmpty));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tUSES_CONVERSION;\n\t\t\tLPCWSTR lpstr = T2CW(lpszStr);\n\t\t\tint nSize = lstrlenW(lpstr) + 1;\n\t\t\tAddData(lpstr, nSize * sizeof(WCHAR));\n\t\t}\n\t}\n};\n\ntypedef CMemDlgTemplateT<ATL::CControlWinTraits>\tCMemDlgTemplate;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Dialog and control macros for indirect dialogs\n\n// for DLGTEMPLATE\n#define BEGIN_DIALOG(x, y, width, height) \\\n\tvoid DoInitTemplate() \\\n\t{ \\\n\t\tbool bExTemplate = false; \\\n\t\tshort nX = x, nY = y, nWidth = width, nHeight = height; \\\n\t\tLPCTSTR szCaption = NULL; \\\n\t\tDWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \\\n\t\tDWORD dwExStyle = 0; \\\n\t\tLPCTSTR szFontName = NULL; \\\n\t\tWORD wFontSize = 0; \\\n\t\tWORD wWeight = 0; \\\n\t\tBYTE bItalic = 0; \\\n\t\tBYTE bCharset = 0; \\\n\t\tDWORD dwHelpID = 0; \\\n\t\tATL::_U_STRINGorID Menu = 0U; \\\n\t\tATL::_U_STRINGorID ClassName = 0U;\n\n// for DLGTEMPLATEEX\n#define BEGIN_DIALOG_EX(x, y, width, height, helpID) \\\n\tvoid DoInitTemplate() \\\n\t{ \\\n\t\tbool bExTemplate = true; \\\n\t\tshort nX = x, nY = y, nWidth = width, nHeight = height; \\\n\t\tLPCTSTR szCaption = NULL; \\\n\t\tDWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \\\n\t\tDWORD dwExStyle = 0; \\\n\t\tLPCTSTR szFontName = NULL; \\\n\t\tWORD wFontSize = 0; \\\n\t\tWORD wWeight = 0; \\\n\t\tBYTE bItalic = 0; \\\n\t\tBYTE bCharset = 0; \\\n\t\tDWORD dwHelpID = helpID; \\\n\t\tATL::_U_STRINGorID Menu = 0U; \\\n\t\tATL::_U_STRINGorID ClassName = 0U;\n\n#define END_DIALOG() \\\n\t\tm_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \\\n\t};\n\n#define DIALOG_CAPTION(caption) \\\n\t\tszCaption = caption;\n#define DIALOG_STYLE(style) \\\n\t\tdwStyle = style;\n#define DIALOG_EXSTYLE(exStyle) \\\n\t\tdwExStyle = exStyle;\n#define DIALOG_FONT(pointSize, typeFace) \\\n\t\twFontSize = pointSize; \\\n\t\tszFontName = typeFace;\n#define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \\\n\t\tATLASSERT(bExTemplate); \\\n\t\twFontSize = pointsize; \\\n\t\tszFontName = typeface; \\\n\t\twWeight = weight; \\\n\t\tbItalic = italic; \\\n\t\tbCharset = charset;\n#define DIALOG_MENU(menuName) \\\n\t\tMenu = menuName;\n#define DIALOG_CLASS(className) \\\n\t\tClassName = className;\n\n#define BEGIN_CONTROLS_MAP() \\\n\tvoid DoInitControls() \\\n\t{\n\n#define END_CONTROLS_MAP() \\\n\t};\n\n\n#define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0);\n#define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0);\n#define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0);\n#define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);\n#ifndef _WIN32_WCE\n#define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0);\n#endif // !_WIN32_WCE\n#define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);\n#define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);\n#define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);\n#define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0);\n#define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0);\n#define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0);\n#define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \\\n\tm_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0);\n#define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \\\n\tm_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0);\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CIndirectDialogImpl - dialogs with template in memory\n\ntemplate <class T, class TDlgTemplate = CMemDlgTemplate, class TBase = ATL::CWindow>\nclass ATL_NO_VTABLE CIndirectDialogImpl : public ATL::CDialogImpl< T, TBase >\n{\npublic:\n\tenum { IDD = 0 };   // no dialog template resource\n\n\tTDlgTemplate m_Template;\n\n\tvoid CreateTemplate()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->DoInitTemplate();\n\t\tpT->DoInitControls();\n\t}\n\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_hWnd == NULL);\n\n\t\tif(!m_Template.IsValid())\n\t\t\tCreateTemplate();\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT);\n\n#ifdef _DEBUG\n\t\tm_bModal = true;\n#endif // _DEBUG\n\n\t\treturn ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);\n\t}\n\n\tHWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->m_hWnd == NULL);\n\n\t\tif(!m_Template.IsValid())\n\t\t\tCreateTemplate();\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE) \n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn NULL;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT);\n\n#ifdef _DEBUG\n\t\tm_bModal = false;\n#endif // _DEBUG\n\n\t\tHWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);\n\t\tATLASSERT(m_hWnd == hWnd);\n\n\t\treturn hWnd;\n\t}\n\n\t// for CComControl\n\tHWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)\n\t{\n\t\treturn Create(hWndParent, dwInitParam);\n\t}\n\n\tvoid DoInitTemplate() \n\t{\n\t\tATLASSERT(FALSE);   // MUST be defined in derived class\n\t}\n\n\tvoid DoInitControls() \n\t{\n\t\tATLASSERT(FALSE);   // MUST be defined in derived class\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPropertySheetWindow - client side for a property sheet\n\nclass CPropertySheetWindow : public ATL::CWindow\n{\npublic:\n// Constructors\n\tCPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)\n\t{ }\n\n\tCPropertySheetWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tint GetPageCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHWND hWndTabCtrl = GetTabControl();\n\t\tATLASSERT(hWndTabCtrl != NULL);\n\t\treturn (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);\n\t}\n\n\tHWND GetActivePage() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);\n\t}\n\n\tint GetActiveIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tHWND hWndTabCtrl = GetTabControl();\n\t\tATLASSERT(hWndTabCtrl != NULL);\n\t\treturn (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);\n\t}\n\n\tBOOL SetActivePage(int nPageIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L);\n\t}\n\n\tBOOL SetActivePage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hPage != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage);\n\t}\n\n\tBOOL SetActivePageByID(int nPageID)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID);\n\t}\n\n\tvoid SetTitle(LPCTSTR lpszText, UINT nStyle = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid\n\t\tATLASSERT(lpszText != NULL);\n\t\t::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText);\n\t}\n\n\tHWND GetTabControl() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);\n\t}\n\n\tvoid SetFinishText(LPCTSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);\n\t}\n\n\tvoid SetWizardButtons(DWORD dwFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);\n\t}\n\n// Operations\n\tBOOL AddPage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hPage != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);\n\t}\n\n\tBOOL AddPage(LPCPROPSHEETPAGE pPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pPage != NULL);\n\t\tHPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);\n\t\tif(hPage == NULL)\n\t\t\treturn FALSE;\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hPage != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);\n\t}\n\n\tBOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pPage != NULL);\n\t\tHPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);\n\t\tif(hPage == NULL)\n\t\t\treturn FALSE;\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);\n\t}\n\n\tBOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hPage != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);\n\t}\n\n\tBOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pPage != NULL);\n\t\tHPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);\n\t\tif(hPage == NULL)\n\t\t\treturn FALSE;\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid RemovePage(int nPageIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L);\n\t}\n\n\tvoid RemovePage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(hPage != NULL);\n\t\t::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage);\n\t}\n\n\tBOOL PressButton(int nButton)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);\n\t}\n\n\tBOOL Apply()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L);\n\t}\n\n\tvoid CancelToClose()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L);\n\t}\n\n\tvoid SetModified(HWND hWndPage, BOOL bChanged = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(::IsWindow(hWndPage));\n\t\tUINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED;\n\t\t::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L);\n\t}\n\n\tLRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam);\n\t}\n\n\tvoid RebootSystem()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L);\n\t}\n\n\tvoid RestartWindows()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L);\n\t}\n\n\tBOOL IsDialogMessage(LPMSG lpMsg)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg);\n\t}\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tint HwndToIndex(HWND hWnd) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L);\n\t}\n\n\tHWND IndexToHwnd(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L);\n\t}\n\n\tint PageToIndex(HPROPSHEETPAGE hPage) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage);\n\t}\n\n\tHPROPSHEETPAGE IndexToPage(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L);\n\t}\n\n\tint IdToIndex(int nID) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID);\n\t}\n\n\tint IndexToId(int nIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L);\n\t}\n\n\tint GetResult() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L);\n\t}\n\n\tBOOL RecalcPageSizes()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L);\n\t}\n\n\tvoid SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle);\n\t}\n\n\tvoid SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n// Implementation - override to prevent usage\n\tHWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn NULL;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CPropertySheetImpl - implements a property sheet\n\ntemplate <class T, class TBase = CPropertySheetWindow>\nclass ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase >\n{\npublic:\n\tPROPSHEETHEADER m_psh;\n\tATL::CSimpleArray<HPROPSHEETPAGE> m_arrPages;\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific\n  #ifndef PROPSHEET_LINK_SIZE\n\t#define PROPSHEET_LINK_SIZE 128\n  #endif // PROPSHEET_LINK_SIZE\n\tTCHAR m_szLink[PROPSHEET_LINK_SIZE];\n\tstatic LPCTSTR m_pszTitle;\n\tstatic LPCTSTR m_pszLink;\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) \n\n// Construction/Destruction\n\tCPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)\n\t{\n\t\tmemset(&m_psh, 0, sizeof(PROPSHEETHEADER));\n\t\tm_psh.dwSize = sizeof(PROPSHEETHEADER);\n\t\tm_psh.dwFlags = PSH_USECALLBACK;\n\t\tm_psh.hInstance = ModuleHelper::GetResourceInstance();\n\t\tm_psh.phpage = NULL;   // will be set later\n\t\tm_psh.nPages = 0;      // will be set later\n\t\tm_psh.pszCaption = title.m_lpstr;\n\t\tm_psh.nStartPage = uStartPage;\n\t\tm_psh.hwndParent = hWndParent;   // if NULL, will be set in DoModal/Create\n\t\tm_psh.pfnCallback = T::PropSheetCallback;\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific \n\t\tm_psh.dwFlags |= PSH_MAXIMIZE;\n\t\tm_szLink[0] = 0;\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)\n\t}\n\n\t~CPropertySheetImpl()\n\t{\n\t\tif(m_arrPages.GetSize() > 0)   // sheet never created, destroy all pages\n\t\t{\n\t\t\tfor(int i = 0; i < m_arrPages.GetSize(); i++)\n\t\t\t\t::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]);\n\t\t}\n\t}\n\n// Callback function and overrideables\n\tstatic int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)\n\t{\n\t\tlParam;   // avoid level 4 warning\n\t\tint nRet = 0;\n\n\t\tif(uMsg == PSCB_INITIALIZED)\n\t\t{\n\t\t\tATLASSERT(hWnd != NULL);\n\t\t\tT* pT = (T*)ModuleHelper::ExtractCreateWndData();\n\t\t\t// subclass the sheet window\n\t\t\tpT->SubclassWindow(hWnd);\n\t\t\t// remove page handles array\n\t\t\tpT->_CleanUpPages();\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific\n\t\t\tm_pszTitle = pT->m_psh.pszCaption;\n\t\t\tif(*pT->m_szLink != 0)\n\t\t\t\tm_pszLink = pT->m_szLink;\n#endif  // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific\n\n\t\t\tpT->OnSheetInitialized();\n\t\t}\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg\n\t\telse\n\t\t{\n\t\t\tswitch(uMsg)\n\t\t\t{\n\t\t\tcase PSCB_GETVERSION :\n\t\t\t\tnRet = COMCTL32_VERSION;\n\t\t\t\tbreak;\n\t\t\tcase PSCB_GETTITLE :\n\t\t\t\tif(m_pszTitle != NULL)\n\t\t\t\t{\n\t\t\t\t\tlstrcpy((LPTSTR)lParam, m_pszTitle);\n\t\t\t\t\tm_pszTitle = NULL;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase PSCB_GETLINKTEXT:\n\t\t\t\tif(m_pszLink != NULL)\n\t\t\t\t{\n\t\t\t\t\tlstrcpy((LPTSTR)lParam, m_pszLink);\n\t\t\t\t\tm_pszLink = NULL;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) \n\n\t\treturn nRet;\n\t}\n\n\tvoid OnSheetInitialized()\n\t{\n\t}\n\n// Create method\n\tHWND Create(HWND hWndParent = NULL)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\n\t\tm_psh.dwFlags |= PSH_MODELESS;\n\t\tif(m_psh.hwndParent == NULL)\n\t\t\tm_psh.hwndParent = hWndParent;\n\t\tm_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();\n\t\tm_psh.nPages = m_arrPages.GetSize();\n\n\t\tT* pT = static_cast<T*>(this);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = pT->m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn NULL;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);\n\n\t\tHWND hWnd = (HWND)::PropertySheet(&m_psh);\n\t\t_CleanUpPages();   // ensure clean-up, required if call failed\n\n\t\tATLASSERT(m_hWnd == hWnd);\n\n\t\treturn hWnd;\n\t}\n\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\n\t\tm_psh.dwFlags &= ~PSH_MODELESS;\n\t\tif(m_psh.hwndParent == NULL)\n\t\t\tm_psh.hwndParent = hWndParent;\n\t\tm_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();\n\t\tm_psh.nPages = m_arrPages.GetSize();\n\n\t\tT* pT = static_cast<T*>(this);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = pT->m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn -1;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);\n\n\t\tINT_PTR nRet = ::PropertySheet(&m_psh);\n\t\t_CleanUpPages();   // ensure clean-up, required if call failed\n\n\t\treturn nRet;\n\t}\n\n\t// implementation helper - clean up pages array\n\tvoid _CleanUpPages()\n\t{\n\t\tm_psh.nPages = 0;\n\t\tm_psh.phpage = NULL;\n\t\tm_arrPages.RemoveAll();\n\t}\n\n// Attributes (extended overrides of client class methods)\n// These now can be called before the sheet is created\n// Note: Calling these after the sheet is created gives unpredictable results\n\tint GetPageCount() const\n\t{\n\t\tif(m_hWnd == NULL)   // not created yet\n\t\t\treturn m_arrPages.GetSize();\n\t\treturn TBase::GetPageCount();\n\t}\n\n\tint GetActiveIndex() const\n\t{\n\t\tif(m_hWnd == NULL)   // not created yet\n\t\t\treturn m_psh.nStartPage;\n\t\treturn TBase::GetActiveIndex();\n\t}\n\n\tHPROPSHEETPAGE GetPage(int nPageIndex) const\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\treturn (HPROPSHEETPAGE)m_arrPages[nPageIndex];\n\t}\n\n\tint GetPageIndex(HPROPSHEETPAGE hPage) const\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\treturn m_arrPages.Find((HPROPSHEETPAGE&)hPage);\n\t}\n\n\tBOOL SetActivePage(int nPageIndex)\n\t{\n\t\tif(m_hWnd == NULL)   // not created yet\n\t\t{\n\t\t\tATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize());\n\t\t\tm_psh.nStartPage = nPageIndex;\n\t\t\treturn TRUE;\n\t\t}\n\t\treturn TBase::SetActivePage(nPageIndex);\n\t}\n\n\tBOOL SetActivePage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(hPage != NULL);\n\t\tif (m_hWnd == NULL)   // not created yet\n\t\t{\n\t\t\tint nPageIndex = GetPageIndex(hPage);\n\t\t\tif(nPageIndex == -1)\n\t\t\t\treturn FALSE;\n\n\t\t\treturn SetActivePage(nPageIndex);\n\t\t}\n\t\treturn TBase::SetActivePage(hPage);\n\n\t}\n\n\tvoid SetTitle(LPCTSTR lpszText, UINT nStyle = 0)\n\t{\n\t\tATLASSERT((nStyle & ~PSH_PROPTITLE) == 0);   // only PSH_PROPTITLE is valid\n\t\tATLASSERT(lpszText != NULL);\n\n\t\tif(m_hWnd == NULL)\n\t\t{\n\t\t\t// set internal state\n\t\t\tm_psh.pszCaption = lpszText;   // must exist until sheet is created\n\t\t\tm_psh.dwFlags &= ~PSH_PROPTITLE;\n\t\t\tm_psh.dwFlags |= nStyle;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// set external state\n\t\t\tTBase::SetTitle(lpszText, nStyle);\n\t\t}\n\t}\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field\t\n\tvoid SetLinkText(LPCTSTR lpszText)\n\t{\n\t\tATLASSERT(lpszText != NULL);\n\t\tATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE);\n\t\tlstrcpy(m_szLink, lpszText);\n\t}\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) \n\n\tvoid SetWizardMode()\n\t{\n\t\tm_psh.dwFlags |= PSH_WIZARD;\n\t}\n\n\tvoid EnableHelp()\n\t{\n\t\tm_psh.dwFlags |= PSH_HASHELP;\n\t}\n\n// Operations\n\tBOOL AddPage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(hPage != NULL);\n\t\tBOOL bRet = FALSE;\n\t\tif(m_hWnd != NULL)\n\t\t\tbRet = TBase::AddPage(hPage);\n\t\telse\t// sheet not created yet, use internal data\n\t\t\tbRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage);\n\t\treturn bRet;\n\t}\n\n\tBOOL AddPage(LPCPROPSHEETPAGE pPage)\n\t{\n\t\tATLASSERT(pPage != NULL);\n\t\tHPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);\n\t\tif(hPage == NULL)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = AddPage(hPage);\n\t\tif(!bRet)\n\t\t\t::DestroyPropertySheetPage(hPage);\n\t\treturn bRet;\n\t}\n\n\tBOOL RemovePage(HPROPSHEETPAGE hPage)\n\t{\n\t\tATLASSERT(hPage != NULL);\n\t\tif (m_hWnd == NULL)   // not created yet\n\t\t{\n\t\t\tint nPage = GetPageIndex(hPage);\n\t\t\tif(nPage == -1)\n\t\t\t\treturn FALSE;\n\t\t\treturn RemovePage(nPage);\n\t\t}\n\t\tTBase::RemovePage(hPage);\n\t\treturn TRUE;\n\n\t}\n\n\tBOOL RemovePage(int nPageIndex)\n\t{\n\t\tBOOL bRet = TRUE;\n\t\tif(m_hWnd != NULL)\n\t\t\tTBase::RemovePage(nPageIndex);\n\t\telse\t// sheet not created yet, use internal data\n\t\t\tbRet = m_arrPages.RemoveAt(nPageIndex);\n\t\treturn bRet;\n\t}\n\n#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\tvoid SetHeader(LPCTSTR szbmHeader)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\n\t\tm_psh.dwFlags &= ~PSH_WIZARD;\n\t\tm_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97);\n\t\tm_psh.pszbmHeader = szbmHeader;\n\t}\n\n\tvoid SetHeader(HBITMAP hbmHeader)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\n\t\tm_psh.dwFlags &= ~PSH_WIZARD;\n\t\tm_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97);\n\t\tm_psh.hbmHeader = hbmHeader;\n\t}\n\n\tvoid SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\n\t\tm_psh.dwFlags &= ~PSH_WIZARD;\n\t\tm_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97;\n\t\tm_psh.pszbmWatermark = szbmWatermark;\n\n\t\tif (hplWatermark != NULL)\n\t\t{\n\t\t\tm_psh.dwFlags |= PSH_USEHPLWATERMARK;\n\t\t\tm_psh.hplWatermark = hplWatermark;\n\t\t}\n\t}\n\n\tvoid SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\n\t\tm_psh.dwFlags &= ~PSH_WIZARD;\n\t\tm_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97);\n\t\tm_psh.hbmWatermark = hbmWatermark;\n\n\t\tif (hplWatermark != NULL)\n\t\t{\n\t\t\tm_psh.dwFlags |= PSH_USEHPLWATERMARK;\n\t\t\tm_psh.hplWatermark = hplWatermark;\n\t\t}\n\t}\n\n\tvoid StretchWatermark(bool bStretchWatermark)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tif (bStretchWatermark)\n\t\t\tm_psh.dwFlags |= PSH_STRETCHWATERMARK;\n\t\telse\n\t\t\tm_psh.dwFlags &= ~PSH_STRETCHWATERMARK;\n\t}\n#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CPropertySheetImpl)\n\t\tMESSAGE_HANDLER(WM_COMMAND, OnCommand)\n\t\tMESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRet = DefWindowProc(uMsg, wParam, lParam);\n\t\tif(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) &&\n\t\t   ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))\n\t\t\tDestroyWindow();\n\t\treturn lRet;\n\t}\n\n\tLRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE))\n\t\t\tSendMessage(WM_CLOSE);\n\t\telse\n\t\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n};\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers\ntemplate < class T, class TBase >\nLPCWSTR CPropertySheetImpl<T,TBase>::m_pszTitle = NULL;\ntemplate < class T, class TBase>\nLPCWSTR CPropertySheetImpl<T,TBase>::m_pszLink = NULL;\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)\n\n// for non-customized sheets\nclass CPropertySheet : public CPropertySheetImpl<CPropertySheet>\n{\npublic:\n\tCPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)\n\t\t: CPropertySheetImpl<CPropertySheet>(title, uStartPage, hWndParent)\n\t{ }\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPropertyPageWindow - client side for a property page\n\nclass CPropertyPageWindow : public ATL::CWindow\n{\npublic:\n// Constructors\n\tCPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)\n\t{ }\n\n\tCPropertyPageWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tCPropertySheetWindow GetPropertySheet() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CPropertySheetWindow(GetParent());\n\t}\n\n// Operations\n\tBOOL Apply()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\treturn GetPropertySheet().Apply();\n\t}\n\n\tvoid CancelToClose()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetPropertySheet().CancelToClose();\n\t}\n\n\tvoid SetModified(BOOL bChanged = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetPropertySheet().SetModified(m_hWnd, bChanged);\n\t}\n\n\tLRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\treturn GetPropertySheet().QuerySiblings(wParam, lParam);\n\t}\n\n\tvoid RebootSystem()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetPropertySheet().RebootSystem();\n\t}\n\n\tvoid RestartWindows()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetPropertySheet().RestartWindows();\n\t}\n\n\tvoid SetWizardButtons(DWORD dwFlags)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetPropertySheet().SetWizardButtons(dwFlags);\n\t}\n\n// Implementation - overrides to prevent usage\n\tHWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn NULL;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CPropertyPageImpl - implements a property page\n\ntemplate <class T, class TBase = CPropertyPageWindow>\nclass ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase >\n{\npublic:\n\tPROPSHEETPAGE m_psp;\n\n\toperator PROPSHEETPAGE*() { return &m_psp; }\n\n// Construction\n\tCPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL)\n\t{\n\t\t// initialize PROPSHEETPAGE struct\n\t\tmemset(&m_psp, 0, sizeof(PROPSHEETPAGE));\n\t\tm_psp.dwSize = sizeof(PROPSHEETPAGE);\n\t\tm_psp.dwFlags = PSP_USECALLBACK;\n\t\tm_psp.hInstance = ModuleHelper::GetResourceInstance();\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD);\n\t\tm_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;\n\t\tm_psp.pfnCallback = T::PropPageCallback;\n\t\tm_psp.lParam = (LPARAM)pT;\n\n\t\tif(title.m_lpstr != NULL)\n\t\t\tSetTitle(title);\n\t}\n\n// Callback function and overrideables\n\tstatic UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)\n\t{\n\t\thWnd;   // avoid level 4 warning\n\t\tATLASSERT(hWnd == NULL);\n\t\tT* pT = (T*)ppsp->lParam;\n\t\tUINT uRet = 0;\n\n\t\tswitch(uMsg)\n\t\t{\n\t\tcase PSPCB_CREATE:\n\t\t\t{\n\t\t\t\tATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT;\n\t\t\t\tModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage);\n\t\t\t\tuRet = pT->OnPageCreate() ? 1 : 0;\n\t\t\t}\n\t\t\tbreak;\n#if (_WIN32_IE >= 0x0500)\n\t\tcase PSPCB_ADDREF:\n\t\t\tpT->OnPageAddRef();\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0500)\n\t\tcase PSPCB_RELEASE:\n\t\t\tpT->OnPageRelease();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\treturn uRet;\n\t}\n\n\tbool OnPageCreate()\n\t{\n\t\treturn true;   // true - allow page to be created, false - prevent creation\n\t}\n\n#if (_WIN32_IE >= 0x0500)\n\tvoid OnPageAddRef()\n\t{\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n\n\tvoid OnPageRelease()\n\t{\n\t}\n\n// Create method\n\tHPROPSHEETPAGE Create()\n\t{\n\t\treturn ::CreatePropertySheetPage(&m_psp);\n\t}\n\n// Attributes\n\tvoid SetTitle(ATL::_U_STRINGorID title)\n\t{\n\t\tm_psp.pszTitle = title.m_lpstr;\n\t\tm_psp.dwFlags |= PSP_USETITLE;\n\t}\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tvoid SetHeaderTitle(LPCTSTR lpstrHeaderTitle)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tm_psp.dwFlags |= PSP_USEHEADERTITLE;\n\t\tm_psp.pszHeaderTitle = lpstrHeaderTitle;\n\t}\n\n\tvoid SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tm_psp.dwFlags |= PSP_USEHEADERSUBTITLE;\n\t\tm_psp.pszHeaderSubTitle = lpstrHeaderSubTitle;\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n// Operations\n\tvoid EnableHelp()\n\t{\n\t\tm_psp.dwFlags |= PSP_HASHELP;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CPropertyPageImpl)\n\t\tMESSAGE_HANDLER(WM_NOTIFY, OnNotify)\n\tEND_MSG_MAP()\n\n\t// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification\n\t// handlers that return direct values without any restrictions\n\tLRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n#ifndef _WIN32_WCE\n\t\t// This notification is sometimes received on Windows CE after the window is already destroyed\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#endif\n\t\tNMHDR* pNMHDR = (NMHDR*)lParam;\n\n\t\t// don't handle messages not from the page/sheet itself\n\t\tif(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n#ifdef _WIN32_WCE\n\t\tATLASSERT(::IsWindow(m_hWnd));\n#endif\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tLRESULT lResult = 0;\n\t\tswitch(pNMHDR->code)\n\t\t{\n#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS\n\t\tcase PSN_SETACTIVE:\n\t\t\tlResult = pT->OnSetActive();\n\t\t\tbreak;\n\t\tcase PSN_KILLACTIVE:\n\t\t\tlResult = pT->OnKillActive();\n\t\t\tbreak;\n\t\tcase PSN_APPLY:\n\t\t\tlResult = pT->OnApply();\n\t\t\tbreak;\n\t\tcase PSN_RESET:\n\t\t\tpT->OnReset();\n\t\t\tbreak;\n\t\tcase PSN_QUERYCANCEL:\n\t\t\tlResult = pT->OnQueryCancel();\n\t\t\tbreak;\n\t\tcase PSN_WIZNEXT:\n\t\t\tlResult = pT->OnWizardNext();\n\t\t\tbreak;\n\t\tcase PSN_WIZBACK:\n\t\t\tlResult = pT->OnWizardBack();\n\t\t\tbreak;\n\t\tcase PSN_WIZFINISH:\n\t\t\tlResult = pT->OnWizardFinish();\n\t\t\tbreak;\n\t\tcase PSN_HELP:\n\t\t\tpT->OnHelp();\n\t\t\tbreak;\n#ifndef _WIN32_WCE\n#if (_WIN32_IE >= 0x0400)\n\t\tcase PSN_GETOBJECT:\n\t\t\tif(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))\n\t\t\t\tbHandled = FALSE;\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0500)\n\t\tcase PSN_TRANSLATEACCELERATOR:\n\t\t\t{\n\t\t\t\tLPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;\n\t\t\t\tlResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase PSN_QUERYINITIALFOCUS:\n\t\t\t{\n\t\t\t\tLPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;\n\t\t\t\tlResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);\n\t\t\t}\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_WIN32_WCE\n\n#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n\t\tcase PSN_SETACTIVE:\n\t\t\tlResult = pT->OnSetActive() ? 0 : -1;\n\t\t\tbreak;\n\t\tcase PSN_KILLACTIVE:\n\t\t\tlResult = !pT->OnKillActive();\n\t\t\tbreak;\n\t\tcase PSN_APPLY:\n\t\t\tlResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;\n\t\t\tbreak;\n\t\tcase PSN_RESET:\n\t\t\tpT->OnReset();\n\t\t\tbreak;\n\t\tcase PSN_QUERYCANCEL:\n\t\t\tlResult = !pT->OnQueryCancel();\n\t\t\tbreak;\n\t\tcase PSN_WIZNEXT:\n\t\t\tlResult = pT->OnWizardNext();\n\t\t\tbreak;\n\t\tcase PSN_WIZBACK:\n\t\t\tlResult = pT->OnWizardBack();\n\t\t\tbreak;\n\t\tcase PSN_WIZFINISH:\n\t\t\tlResult = !pT->OnWizardFinish();\n\t\t\tbreak;\n\t\tcase PSN_HELP:\n\t\t\tpT->OnHelp();\n\t\t\tbreak;\n#ifndef _WIN32_WCE\n#if (_WIN32_IE >= 0x0400)\n\t\tcase PSN_GETOBJECT:\n\t\t\tif(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))\n\t\t\t\tbHandled = FALSE;\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0500)\n\t\tcase PSN_TRANSLATEACCELERATOR:\n\t\t\t{\n\t\t\t\tLPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;\n\t\t\t\tlResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase PSN_QUERYINITIALFOCUS:\n\t\t\t{\n\t\t\t\tLPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;\n\t\t\t\tlResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);\n\t\t\t}\n\t\t\tbreak;\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_WIN32_WCE\n\n#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n\t\tdefault:\n\t\t\tbHandled = FALSE;   // not handled\n\t\t}\n\n\t\treturn lResult;\n\t}\n\n// Overridables\n\t// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification\n\t// handlers that return direct values without any restrictions\n#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS\n\tint OnSetActive()\n\t{\n\t\t// 0 = allow activate\n\t\t// -1 = go back that was active\n\t\t// page ID = jump to page\n\t\treturn 0;\n\t}\n\n\tBOOL OnKillActive()\n\t{\n\t\t// FALSE = allow deactivate\n\t\t// TRUE = prevent deactivation\n\t\treturn FALSE;\n\t}\n\n\tint OnApply()\n\t{\n\t\t// PSNRET_NOERROR = apply OK\n\t\t// PSNRET_INVALID = apply not OK, return to this page\n\t\t// PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus\n\t\treturn PSNRET_NOERROR;\n\t}\n\n\tvoid OnReset()\n\t{\n\t}\n\n\tBOOL OnQueryCancel()\n\t{\n\t\t// FALSE = allow cancel\n\t\t// TRUE = prevent cancel\n\t\treturn FALSE;\n\t}\n\n\tint OnWizardBack()\n\t{\n\t\t// 0  = goto previous page\n\t\t// -1 = prevent page change\n\t\t// >0 = jump to page by dlg ID\n\t\treturn 0;\n\t}\n\n\tint OnWizardNext()\n\t{\n\t\t// 0  = goto next page\n\t\t// -1 = prevent page change\n\t\t// >0 = jump to page by dlg ID\n\t\treturn 0;\n\t}\n\n\tINT_PTR OnWizardFinish()\n\t{\n\t\t// FALSE = allow finish\n\t\t// TRUE = prevent finish\n\t\t// HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only)\n\t\treturn FALSE;\n\t}\n\n\tvoid OnHelp()\n\t{\n\t}\n\n#ifndef _WIN32_WCE\n#if (_WIN32_IE >= 0x0400)\n\tBOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)\n\t{\n\t\treturn FALSE;   // not processed\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500)\n\tint OnTranslateAccelerator(LPMSG /*lpMsg*/)\n\t{\n\t\t// PSNRET_NOERROR - message not handled\n\t\t// PSNRET_MESSAGEHANDLED - message handled\n\t\treturn PSNRET_NOERROR;\n\t}\n\n\tHWND OnQueryInitialFocus(HWND /*hWndFocus*/)\n\t{\n\t\t// NULL = set focus to default control\n\t\t// HWND = set focus to HWND\n\t\treturn NULL;\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_WIN32_WCE\n\n#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n\tBOOL OnSetActive()\n\t{\n\t\treturn TRUE;\n\t}\n\n\tBOOL OnKillActive()\n\t{\n\t\treturn TRUE;\n\t}\n\n\tBOOL OnApply()\n\t{\n\t\treturn TRUE;\n\t}\n\n\tvoid OnReset()\n\t{\n\t}\n\n\tBOOL OnQueryCancel()\n\t{\n\t\treturn TRUE;    // ok to cancel\n\t}\n\n\tint OnWizardBack()\n\t{\n\t\t// 0  = goto previous page\n\t\t// -1 = prevent page change\n\t\t// >0 = jump to page by dlg ID\n\t\treturn 0;\n\t}\n\n\tint OnWizardNext()\n\t{\n\t\t// 0  = goto next page\n\t\t// -1 = prevent page change\n\t\t// >0 = jump to page by dlg ID\n\t\treturn 0;\n\t}\n\n\tBOOL OnWizardFinish()\n\t{\n\t\treturn TRUE;\n\t}\n\n\tvoid OnHelp()\n\t{\n\t}\n\n#ifndef _WIN32_WCE\n#if (_WIN32_IE >= 0x0400)\n\tBOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)\n\t{\n\t\treturn FALSE;   // not processed\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500)\n\tBOOL OnTranslateAccelerator(LPMSG /*lpMsg*/)\n\t{\n\t\treturn FALSE;   // not translated\n\t}\n\n\tHWND OnQueryInitialFocus(HWND /*hWndFocus*/)\n\t{\n\t\treturn NULL;   // default\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_WIN32_WCE\n\n#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n};\n\n// for non-customized pages\ntemplate <WORD t_wDlgTemplateID>\nclass CPropertyPage : public CPropertyPageImpl<CPropertyPage<t_wDlgTemplateID> >\n{\npublic:\n\tenum { IDD = t_wDlgTemplateID };\n\n\tCPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<CPropertyPage>(title)\n\t{ }\n\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CAxPropertyPageImpl - property page that hosts ActiveX controls\n\n#ifndef _ATL_NO_HOSTING\n\n// Note: You must #include <atlhost.h> to use these classes\n\ntemplate <class T, class TBase = CPropertyPageWindow>\nclass ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase >\n{\npublic:\n// Data members\n\tHGLOBAL m_hInitData;\n\tHGLOBAL m_hDlgRes;\n\tHGLOBAL m_hDlgResSplit;\n\n// Constructor/destructor\n\tCAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : \n\t\t\tCPropertyPageImpl< T, TBase >(title),\n\t\t\tm_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\n\t\t// initialize ActiveX hosting and modify dialog template\n\t\tATL::AtlAxWinInit();\n\n\t\tHINSTANCE hInstance = ModuleHelper::GetResourceInstance();\n\t\tLPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD);\n\t\tHRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG);\n\t\tif(hDlg != NULL)\n\t\t{\n\t\t\tHRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT);\n\n\t\t\tBYTE* pInitData = NULL;\n\t\t\tif(hDlgInit != NULL)\n\t\t\t{\n\t\t\t\tm_hInitData = ::LoadResource(hInstance, hDlgInit);\n\t\t\t\tpInitData = (BYTE*)::LockResource(m_hInitData);\n\t\t\t}\n\n\t\t\tm_hDlgRes = ::LoadResource(hInstance, hDlg);\n\t\t\tDLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes);\n\t\t\tLPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData);\n\t\t\tif(lpDialogTemplate != pDlg)\n\t\t\t\tm_hDlgResSplit = GlobalHandle(lpDialogTemplate);\n\n\t\t\t// set up property page to use in-memory dialog template\n\t\t\tif(lpDialogTemplate != NULL)\n\t\t\t{\n\t\t\t\tm_psp.dwFlags |= PSP_DLGINDIRECT;\n\t\t\t\tm_psp.pResource = lpDialogTemplate;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tATLASSERT(FALSE && _T(\"CAxPropertyPageImpl - ActiveX initializtion failed!\"));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tATLASSERT(FALSE && _T(\"CAxPropertyPageImpl - Cannot find dialog template!\"));\n\t\t}\n\t}\n\n\t~CAxPropertyPageImpl()\n\t{\n\t\tif(m_hInitData != NULL)\n\t\t{\n\t\t\tUnlockResource(m_hInitData);\n\t\t\tFreeResource(m_hInitData);\n\t\t}\n\t\tif(m_hDlgRes != NULL)\n\t\t{\n\t\t\tUnlockResource(m_hDlgRes);\n\t\t\tFreeResource(m_hDlgRes);\n\t\t}\n\t\tif(m_hDlgResSplit != NULL)\n\t\t{\n\t\t\t::GlobalFree(m_hDlgResSplit);\n\t\t}\n\t}\n\n// Methods\n\t// call this one to handle keyboard message for ActiveX controls\n\tBOOL PreTranslateMessage(LPMSG pMsg)\n\t{\n\t\tif ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&\n\t\t   (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))\n\t\t\treturn FALSE;\n\t\t// find a direct child of the dialog from the window that has focus\n\t\tHWND hWndCtl = ::GetFocus();\n\t\tif (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd)\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\thWndCtl = ::GetParent(hWndCtl);\n\t\t\t}\n\t\t\twhile (::GetParent(hWndCtl) != m_hWnd);\n\t\t}\n\t\t// give controls a chance to translate this message\n\t\treturn (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg);\n\t}\n\n// Overridables\n#if (_WIN32_IE >= 0x0500)\n\t// new default implementation for ActiveX hosting pages\n#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS\n\tint OnTranslateAccelerator(LPMSG lpMsg)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;\n\t}\n#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n\tBOOL OnTranslateAccelerator(LPMSG lpMsg)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn pT->PreTranslateMessage(lpMsg);\n\t}\n#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS\n#endif // (_WIN32_IE >= 0x0500)\n\n// Support for new stuff in ATL7\n#if (_ATL_VER >= 0x0700)\n\tint GetIDD()\n\t{\n\t\treturn( static_cast<T*>(this)->IDD );\n\t}\n\n\tvirtual DLGPROC GetDialogProc()\n\t{\n\t\treturn DialogProc;\n\t}\n\n\tstatic INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tCAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd;\n\t\tif (uMsg == WM_INITDIALOG)\n\t\t{\n\t\t\tHRESULT hr;\n\t\t\tif (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD())))\n\t\t\t{\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn FALSE;\n\t\t\t}\n\t\t}\n\t\treturn CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam);\n\t}\n\n// ActiveX controls creation\n\tvirtual HRESULT CreateActiveXControls(UINT nID)\n\t{\n\t\t// Load dialog template and InitData\n\t\tHRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT);\n\t\tBYTE* pInitData = NULL;\n\t\tHGLOBAL hData = NULL;\n\t\tHRESULT hr = S_OK;\n\t\tif (hDlgInit != NULL)\n\t\t{\n\t\t\thData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit);\n\t\t\tif (hData != NULL)\n\t\t\t\tpInitData = (BYTE*) ::LockResource(hData);\n\t\t}\n\n\t\tHRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG);\n\t\tif (hDlg != NULL)\n\t\t{\n\t\t\tHGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg);\n\t\t\tDLGTEMPLATE* pDlg = NULL;\n\t\t\tif (hResource != NULL)\n\t\t\t{\n\t\t\t\tpDlg = (DLGTEMPLATE*) ::LockResource(hResource);\n\t\t\t\tif (pDlg != NULL)\n\t\t\t\t{\n\t\t\t\t\t// Get first control on the template\n\t\t\t\t\tBOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg);\n\t\t\t\t\tWORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg);\n\n\t\t\t\t\t// Get first control on the dialog\n\t\t\t\t\tDLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg);\n\t\t\t\t\tHWND hWndPrev = GetWindow(GW_CHILD);\n\n\t\t\t\t\t// Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order)\n\t\t\t\t\tfor (WORD nItem = 0; nItem < nItems; nItem++)\n\t\t\t\t\t{\n\t\t\t\t\t\tDWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id;\n\t\t\t\t\t\tif (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tBYTE* pData = NULL;\n\t\t\t\t\t\t\tDWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData);\n\t\t\t\t\t\t\tATL::CComPtr<IStream> spStream;\n\t\t\t\t\t\t\tif (dwLen != 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tHGLOBAL h = GlobalAlloc(GHND, dwLen);\n\t\t\t\t\t\t\t\tif (h != NULL)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tBYTE* pBytes = (BYTE*) GlobalLock(h);\n\t\t\t\t\t\t\t\t\tBYTE* pSource = pData; \n\t\t\t\t\t\t\t\t\tSecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen);\n\t\t\t\t\t\t\t\t\tGlobalUnlock(h);\n\t\t\t\t\t\t\t\t\tCreateStreamOnHGlobal(h, TRUE, &spStream);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thr = E_OUTOFMEMORY;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tATL::CComBSTR bstrLicKey;\n\t\t\t\t\t\t\thr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str);\n\t\t\t\t\t\t\tif (SUCCEEDED(hr))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tATL::CAxWindow2 wnd;\n\t\t\t\t\t\t\t\t// Get control caption.\n\t\t\t\t\t\t\t\tLPWSTR pszClassName = \n\t\t\t\t\t\t\t\t\tbDialogEx ? \n\t\t\t\t\t\t\t\t\t\t(LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) :\n\t\t\t\t\t\t\t\t\t\t(LPWSTR)(pItem + 1);\n\t\t\t\t\t\t\t\t// Get control rect.\n\t\t\t\t\t\t\t\tRECT rect = { 0 };\n\t\t\t\t\t\t\t\trect.left = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : pItem->x;\n\t\t\t\t\t\t\t\trect.top = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : pItem->y;\n\t\t\t\t\t\t\t\trect.right = rect.left + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : pItem->cx);\n\t\t\t\t\t\t\t\trect.bottom = rect.top + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : pItem->cy);\n\n\t\t\t\t\t\t\t\t// Convert from dialog units to screen units\n\t\t\t\t\t\t\t\tMapDialogRect(&rect);\n\n\t\t\t\t\t\t\t\t// Create AxWindow with a NULL caption.\n\t\t\t\t\t\t\t\twnd.Create(m_hWnd, \n\t\t\t\t\t\t\t\t\t&rect, \n\t\t\t\t\t\t\t\t\tNULL, \n\t\t\t\t\t\t\t\t\t(bDialogEx ? \n\t\t\t\t\t\t\t\t\t\t((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : \n\t\t\t\t\t\t\t\t\t\tpItem->style) | WS_TABSTOP, \n\t\t\t\t\t\t\t\t\tbDialogEx ? \n\t\t\t\t\t\t\t\t\t\t((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : \n\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\tbDialogEx ? \n\t\t\t\t\t\t\t\t\t\t((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : \n\t\t\t\t\t\t\t\t\t\tpItem->id,\n\t\t\t\t\t\t\t\t\tNULL);\n\n\t\t\t\t\t\t\t\tif (wnd != NULL)\n\t\t\t\t\t\t\t\t{\n#ifndef _WIN32_WCE\n\t\t\t\t\t\t\t\t\t// Set the Help ID\n\t\t\t\t\t\t\t\t\tif (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0)\n\t\t\t\t\t\t\t\t\t\twnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID);\n#endif // !_WIN32_WCE\n\t\t\t\t\t\t\t\t\t// Try to create the ActiveX control.\n\t\t\t\t\t\t\t\t\thr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey);\n\t\t\t\t\t\t\t\t\tif (FAILED(hr))\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t// Set the correct tab position.\n\t\t\t\t\t\t\t\t\tif (nItem == 0)\n\t\t\t\t\t\t\t\t\t\thWndPrev = HWND_TOP;\n\t\t\t\t\t\t\t\t\twnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);\n\t\t\t\t\t\t\t\t\thWndPrev = wnd;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thr = ATL::AtlHresultFromLastError();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (nItem != 0)\n\t\t\t\t\t\t\t\thWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thr = ATL::AtlHresultFromLastError();\n\t\t\t}\n\t\t\telse\n\t\t\t\thr = ATL::AtlHresultFromLastError();\n\t\t}\n\t\treturn hr;\n\t}\n\n// Event handling support\n\tHRESULT AdviseSinkMap(bool bAdvise)\n\t{\n\t\tif(!bAdvise && m_hWnd == NULL)\n\t\t{\n\t\t\t// window is gone, controls are already unadvised\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\\n\"));\n\t\t\treturn S_OK;\n\t\t}\n\t\tHRESULT hRet = E_NOTIMPL;\n\t\t__if_exists(T::_GetSinkMapFinder)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\thRet = AtlAdviseSinkMap(pT, bAdvise);\n\t\t}\n\t\treturn hRet;\n\t}\n\n// Message map and handlers\n\ttypedef CPropertyPageImpl< T, TBase>   _baseClass;\n\tBEGIN_MSG_MAP(CAxPropertyPageImpl)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\t// initialize controls in dialog with DLGINIT resource section\n\t\tExecuteDlgInit(static_cast<T*>(this)->IDD);\n\t\tAdviseSinkMap(true);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tAdviseSinkMap(false);\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n#endif // (_ATL_VER >= 0x0700)\n};\n\n// for non-customized pages\ntemplate <WORD t_wDlgTemplateID>\nclass CAxPropertyPage : public CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >\n{\npublic:\n\tenum { IDD = t_wDlgTemplateID };\n\n\tCAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl<CAxPropertyPage>(title)\n\t{ }\n\n#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)\n\t// not empty so we handle accelerators/create controls\n\tBEGIN_MSG_MAP(CAxPropertyPage)\n\t\tCHAIN_MSG_MAP(CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >)\n\tEND_MSG_MAP()\n#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))\n\tDECLARE_EMPTY_MSG_MAP()\n#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))\n};\n\n#endif // _ATL_NO_HOSTING\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Wizard97 Support\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n// Sample wizard dialog resources:\n//\n// IDD_WIZ97_INTERIOR_BLANK DIALOG  0, 0, 317, 143\n// STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION\n// CAPTION \"Wizard97 Property Page - Interior\"\n// FONT 8, \"MS Shell Dlg\"\n// BEGIN\n// END\n//\n// IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193\n// STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\n// CAPTION \"Wizard97 Property Page - Welcome/Complete\"\n// FONT 8, \"MS Shell Dlg\", 0, 0, 0x0\n// BEGIN\n//    LTEXT           \"Welcome to the X Wizard\",IDC_WIZ97_EXTERIOR_TITLE,115,8,\n//                    195,24\n//    LTEXT           \"Wizard Explanation\\r\\n(The height of the static text should be in multiples of 8 dlus)\",\n//                    IDC_STATIC,115,40,195,16\n//    LTEXT           \"h\",IDC_WIZ97_BULLET1,118,64,8,8\n//    LTEXT           \"List Item 1 (the h is turned into a bullet)\",IDC_STATIC,\n//                    127,63,122,8\n//    LTEXT           \"h\",IDC_WIZ97_BULLET2,118,79,8,8\n//    LTEXT           \"List Item 2. Keep 7 dlus between paragraphs\",IDC_STATIC,\n//                    127,78,33,8\n//    CONTROL         \"&Do not show this Welcome page again\",\n//                    IDC_WIZ97_WELCOME_NOTAGAIN,\"Button\",BS_AUTOCHECKBOX | \n//                    WS_TABSTOP,115,169,138,10\n// END\n//\n// GUIDELINES DESIGNINFO \n// BEGIN\n//    IDD_WIZ97_INTERIOR_BLANK, DIALOG\n//    BEGIN\n//        LEFTMARGIN, 7\n//        RIGHTMARGIN, 310\n//        VERTGUIDE, 21\n//        VERTGUIDE, 31\n//        VERTGUIDE, 286\n//        VERTGUIDE, 296\n//        TOPMARGIN, 7\n//        BOTTOMMARGIN, 136\n//        HORZGUIDE, 8\n//    END\n//\n//    IDD_WIZ97_EXTERIOR_BLANK, DIALOG\n//    BEGIN\n//        RIGHTMARGIN, 310\n//        VERTGUIDE, 115\n//        VERTGUIDE, 118\n//        VERTGUIDE, 127\n//        TOPMARGIN, 7\n//        BOTTOMMARGIN, 186\n//        HORZGUIDE, 8\n//        HORZGUIDE, 32\n//        HORZGUIDE, 40\n//        HORZGUIDE, 169\n//    END\n// END\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet\n\nclass CWizard97SheetWindow : public CPropertySheetWindow\n{\npublic:\n// Constructors\n\tCWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)\n\t{ }\n\n\tCWizard97SheetWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Operations\n\tHFONT GetExteriorPageTitleFont(void)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L);\n\t}\n\n\tHFONT GetBulletFont(void)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L);\n\t}\n\n// Helpers\n\tstatic UINT GetMessage_GetExteriorPageTitleFont()\n\t{\n\t\tstatic UINT uGetExteriorPageTitleFont = 0;\n\t\tif(uGetExteriorPageTitleFont == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uGetExteriorPageTitleFont == 0)\n\t\t\t\tuGetExteriorPageTitleFont = ::RegisterWindowMessage(_T(\"GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12\"));\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uGetExteriorPageTitleFont != 0);\n\t\treturn uGetExteriorPageTitleFont;\n\t}\n\n\tstatic UINT GetMessage_GetBulletFont()\n\t{\n\t\tstatic UINT uGetBulletFont = 0;\n\t\tif(uGetBulletFont == 0)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(uGetBulletFont == 0)\n\t\t\t\tuGetBulletFont = ::RegisterWindowMessage(_T(\"GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5\"));\n\n\t\t\tlock.Unlock();\n\t\t}\n\t\tATLASSERT(uGetBulletFont != 0);\n\t\treturn uGetBulletFont;\n\t}\n\n// Implementation - override to prevent usage\n\tHWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn NULL;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97SheetImpl - implements a Wizard 97 style wizard sheet\n\ntemplate <class T, class TBase = CWizard97SheetWindow>\nclass ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase >\n{\nprotected:\n// Typedefs\n\ttypedef CWizard97SheetImpl< T, TBase > thisClass;\n\ttypedef CPropertySheetImpl< T, TBase > baseClass;\n\n// Member variables\n\tCFont m_fontExteriorPageTitle;   // Welcome and Completion page title font\n\tCFont m_fontBullet;              // Bullet font (used on static text 'h' to produce a small bullet)\n\tbool m_bReceivedFirstSizeMessage;   \n\npublic:\n\tCWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :\n\t\t\tbaseClass(title, uStartPage, hWndParent),\n\t\t\tm_bReceivedFirstSizeMessage(false)\n\t{\n\t\tm_psh.dwFlags &= ~(PSH_NOCONTEXTHELP);\n\t\tm_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE);\n\n\t\tm_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP);\n\t\tm_psh.dwFlags |= PSH_WIZARD97;\n\n\t\tbaseClass::SetHeader(headerBitmap.m_lpstr);\n\t\tbaseClass::SetWatermark(watermarkBitmap.m_lpstr);\n\t}\n\n// Overrides from base class\n\tvoid OnSheetInitialized()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->_InitializeFonts();\n\n\t\t// We'd like to center the wizard here, but its too early.\n\t\t// Instead, we'll do CenterWindow upon our first WM_SIZE message\n\t}\n\n// Initialization\n\tvoid _InitializeFonts()\n\t{\n\t\t// Setup the Title and Bullet Font\n\t\t// (Property pages can send the \"get external page title font\" and \"get bullet font\" messages)\n\t\t// The derived class needs to do the actual SetFont for the dialog items)\n\n\t\tCFontHandle fontThisDialog = this->GetFont();\n\t\tCClientDC dcScreen(NULL);\n\n\t\tLOGFONT titleLogFont = {0};\n\t\tLOGFONT bulletLogFont = {0};\n\t\tfontThisDialog.GetLogFont(&titleLogFont);\n\t\tfontThisDialog.GetLogFont(&bulletLogFont);\n\n\t\t// The Wizard 97 Spec recommends to do the Title Font\n\t\t// as Verdana Bold, 12pt.\n\t\ttitleLogFont.lfCharSet = DEFAULT_CHARSET;\n\t\ttitleLogFont.lfWeight = FW_BOLD;\n\t\tSecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T(\"Verdana Bold\"));\n\t\tINT titleFontPointSize = 12;\n\t\ttitleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);\n\t\tm_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont);\n\n\t\t// The Wizard 97 Spec recommends to do Bullets by having\n\t\t// static text of \"h\" in the Marlett font.\n\t\tbulletLogFont.lfCharSet = DEFAULT_CHARSET;\n\t\tbulletLogFont.lfWeight = FW_NORMAL;\n\t\tSecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T(\"Marlett\"));\n\t\tINT bulletFontSize = 8;\n\t\tbulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);\n\t\tm_fontBullet.CreateFontIndirect(&bulletLogFont);\n\t}\n\n// Message Handling\n\tBEGIN_MSG_MAP(thisClass)\n\t\tMESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont)\n\t\tMESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tCHAIN_MSG_MAP(baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)(HFONT)m_fontExteriorPageTitle;\n\t}\n\n\tLRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn (LRESULT)(HFONT)m_fontBullet;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(!m_bReceivedFirstSizeMessage)\n\t\t{\n\t\t\tm_bReceivedFirstSizeMessage = true;\n\t\t\tthis->CenterWindow();\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n};\n\n// for non-customized sheets\nclass CWizard97Sheet : public CWizard97SheetImpl<CWizard97Sheet>\n{\nprotected:\n// Typedefs\n\ttypedef CWizard97Sheet thisClass;\n\ttypedef CWizard97SheetImpl<CWizard97Sheet> baseClass;\n\npublic:\n\tCWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :\n\t\tbaseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent)\n\t{ }\n\n\tBEGIN_MSG_MAP(thisClass)\n\t\tCHAIN_MSG_MAP(baseClass)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97PageWindow - client side for a Wizard 97 style wizard page\n\n#define WIZARD97_EXTERIOR_CXDLG 317\n#define WIZARD97_EXTERIOR_CYDLG 193\n\n#define WIZARD97_INTERIOR_CXDLG 317\n#define WIZARD97_INTERIOR_CYDLG 143\n\nclass CWizard97PageWindow : public CPropertyPageWindow\n{\npublic:\n// Constructors\n\tCWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)\n\t{ }\n\n\tCWizard97PageWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tCWizard97SheetWindow GetPropertySheet() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn CWizard97SheetWindow(GetParent());\n\t}\n\n// Operations\n\tHFONT GetExteriorPageTitleFont(void)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn GetPropertySheet().GetExteriorPageTitleFont();\n\t}\n\n\tHFONT GetBulletFont(void)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn GetPropertySheet().GetBulletFont();\n\t}\n\n// Implementation - overrides to prevent usage\n\tHWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn NULL;\n\t}\n\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97PageImpl - implements a Wizard 97 style wizard page\n\ntemplate <class T, class TBase = CWizard97PageWindow>\nclass ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase >\n{\nprotected:\n// Typedefs\n\ttypedef CWizard97PageImpl< T, TBase > thisClass;\n\ttypedef CPropertyPageImpl< T, TBase > baseClass;\n\npublic:\n\tCWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)\n\t{ }\n\n// Message Handling\n\tBEGIN_MSG_MAP(thisClass)\n\t\tCHAIN_MSG_MAP(baseClass)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page\n\ntemplate <class T, class TBase = CWizard97PageWindow>\nclass ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase >\n{\nprotected:\n// Typedefs\n\ttypedef CWizard97ExteriorPageImpl< T, TBase > thisClass;\n\ttypedef CPropertyPageImpl< T, TBase > baseClass;\n\npublic:\n// Constructors\n\tCWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)\n\t{\n\t\tm_psp.dwFlags |= PSP_HASHELP;\n\t\tm_psp.dwFlags |= PSP_HIDEHEADER;\n\t}\n\n// Message Handling\n\tBEGIN_MSG_MAP(thisClass)\n\t\tCHAIN_MSG_MAP(baseClass)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page\n\ntemplate <class T, class TBase = CWizard97PageWindow>\nclass ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase >\n{\nprotected:\n// Typedefs\n\ttypedef CWizard97InteriorPageImpl< T, TBase > thisClass;\n\ttypedef CPropertyPageImpl< T, TBase > baseClass;\n\npublic:\n// Constructors\n\tCWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)\n\t{\n\t\tm_psp.dwFlags |= PSP_HASHELP;\n\t\tm_psp.dwFlags &= ~PSP_HIDEHEADER;\n\t\tm_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;\n\n\t\t// Be sure to have the derived class define this in the constructor.\n\t\t// We'll default it to something obvious in case its forgotten.\n\t\tbaseClass::SetHeaderTitle(_T(\"Call SetHeaderTitle in Derived Class\"));\n\t\tbaseClass::SetHeaderSubTitle(_T(\"Call SetHeaderSubTitle in the constructor of the Derived Class.\"));\n\t}\n\n// Message Handling\n\tBEGIN_MSG_MAP(thisClass)\n\t\tCHAIN_MSG_MAP(baseClass)\n\tEND_MSG_MAP()\n};\n\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Aero Wizard support\n\n#if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardFrameWindow - client side for an Aero Wizard frame window\n\nclass CAeroWizardFrameWindow : public CPropertySheetWindow\n{\npublic:\n// Constructors\n\tCAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)\n\t{ }\n\n\tCAeroWizardFrameWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Operations - new, Aero Wizard only\n\tvoid SetNextText(LPCWSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText);\n\t}\n\n\tvoid ShowWizardButtons(DWORD dwButtons, DWORD dwStates)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);\n\t}\n\n\tvoid EnableWizardButtons(DWORD dwButtons, DWORD dwStates)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);\n\t}\n\n\tvoid SetButtonText(DWORD dwButton, LPCWSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardFrameImpl - implements an Aero Wizard frame\n\ntemplate <class T, class TBase = CAeroWizardFrameWindow>\nclass ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl<T, TBase >\n{\npublic:\n// Constructor\n\tCAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) :\n\t\tCPropertySheetImpl<T, TBase >(title, uStartPage, hWndParent)\n\t{\n\t\tm_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD;\n\t}\n\n// Operations\n\tvoid EnableResizing()\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tm_psh.dwFlags |= PSH_RESIZABLE;\n\t}\n\n\tvoid UseHeaderBitmap()\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tm_psh.dwFlags |= PSH_HEADERBITMAP;\n\t}\n\n\tvoid SetNoMargin()\n\t{\n\t\tATLASSERT(m_hWnd == NULL);   // can't do this after it's created\n\t\tm_psh.dwFlags |= PSH_NOMARGIN;\n\t}\n\n// Override to prevent use\n\tHWND Create(HWND /*hWndParent*/ = NULL)\n\t{\n\t\tATLASSERT(FALSE);   // not supported for Aero Wizard\n\t\treturn NULL;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardFrame - for non-customized frames\n\nclass CAeroWizardFrame : public CAeroWizardFrameImpl<CAeroWizardFrame>\n{\npublic:\n\tCAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)\n\t\t: CAeroWizardFrameImpl<CAeroWizardFrame>(title, uStartPage, hWndParent)\n\t{ }\n\n\tBEGIN_MSG_MAP(CAeroWizardFrame)\n\t\tMESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl<CAeroWizardFrame>::OnCommand)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardPageWindow - client side for an Aero Wizard page\n\nclass CAeroWizardPageWindow : public CPropertyPageWindow\n{\npublic:\n// Constructors\n\tCAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)\n\t{ }\n\n\tCAeroWizardPageWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Attributes\n\tCAeroWizardFrameWindow GetAeroWizardFrame() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t// This is not really top-level frame window, but it processes all frame messages\n\t\treturn CAeroWizardFrameWindow(GetParent());\n\t}\n\n// Operations - new, Aero Wizard only\n\tvoid SetNextText(LPCWSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetAeroWizardFrame().SetNextText(lpszText);\n\t}\n\n\tvoid ShowWizardButtons(DWORD dwButtons, DWORD dwStates)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates);\n\t}\n\n\tvoid EnableWizardButtons(DWORD dwButtons, DWORD dwStates)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates);\n\t}\n\n\tvoid SetButtonText(DWORD dwButton, LPCWSTR lpszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetParent() != NULL);\n\t\tGetAeroWizardFrame().SetButtonText(dwButton, lpszText);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardPageImpl - implements an Aero Wizard page\n\ntemplate <class T, class TBase = CAeroWizardPageWindow>\nclass ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl<T, TBase >\n{\npublic:\n\tCAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<T, TBase >(title)\n\t{ }\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardPage - for non-customized pages\n\ntemplate <WORD t_wDlgTemplateID>\nclass CAeroWizardPage : public CAeroWizardPageImpl<CAeroWizardPage<t_wDlgTemplateID> >\n{\npublic:\n\tenum { IDD = t_wDlgTemplateID };\n\n\tCAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl<CAeroWizardPage>(title)\n\t{ }\n\n\tDECLARE_EMPTY_MSG_MAP()\n};\n\n\n#ifndef _ATL_NO_HOSTING\n\n// Note: You must #include <atlhost.h> to use these classes\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls\n\ntemplate <class T, class TBase = CAeroWizardPageWindow>\nclass ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase >\n{\npublic:\n\tCAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title)\n\t{ }\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroWizardAxPage - for non-customized pages\n\ntemplate <WORD t_wDlgTemplateID>\nclass CAeroWizardAxPage : public CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >\n{\npublic:\n\tenum { IDD = t_wDlgTemplateID };\n\n\tCAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl<CAeroWizardAxPage>(title)\n\t{ }\n\n#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)\n\t// not empty so we handle accelerators/create controls\n\tBEGIN_MSG_MAP(CAeroWizardAxPage)\n\t\tCHAIN_MSG_MAP(CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >)\n\tEND_MSG_MAP()\n#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))\n\tDECLARE_EMPTY_MSG_MAP()\n#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))\n};\n\n#endif // _ATL_NO_HOSTING\n\n#endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// TaskDialog support\n\n#if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)\n\n///////////////////////////////////////////////////////////////////////////////\n// AtlTaskDialog - support for TaskDialog() function\n\ninline int AtlTaskDialog(HWND hWndParent, \n                         ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText, \n                         TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL)\n{\n\tint nRet = -1;\n\n#ifdef _WTL_TASKDIALOG_DIRECT\n\tUSES_CONVERSION;\n\tHRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), \n\t\tIS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), \n\t\tIS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), \n\t\tIS_INTRESOURCE(ContentText.m_lpstr) ?  (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), \n\t\tdwCommonButtons, \n\t\tIS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),\n\t\t&nRet);\n\tATLVERIFY(SUCCEEDED(hRet));\n#else\n\t// This allows apps to run on older versions of Windows\n\ttypedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton);\n\n\tHMODULE m_hCommCtrlDLL = ::LoadLibrary(_T(\"comctl32.dll\"));\n\tif(m_hCommCtrlDLL != NULL)\n\t{\n\t\tPFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, \"TaskDialog\");\n\t\tif(pfnTaskDialog != NULL)\n\t\t{\n\t\t\tUSES_CONVERSION;\n\t\t\tHRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(), \n\t\t\t\tIS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr), \n\t\t\t\tIS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr), \n\t\t\t\tIS_INTRESOURCE(ContentText.m_lpstr) ?  (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr), \n\t\t\t\tdwCommonButtons, \n\t\t\t\tIS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),\n\t\t\t\t&nRet);\n\t\t\tATLVERIFY(SUCCEEDED(hRet));\n\t\t}\n\n\t\t::FreeLibrary(m_hCommCtrlDLL);\n\t}\n#endif\n\n\treturn nRet;\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTaskDialogConfig - TASKDIALOGCONFIG wrapper\n\nclass CTaskDialogConfig : public TASKDIALOGCONFIG\n{\npublic:\n// Constructor\n\tCTaskDialogConfig()\n\t{\n\t\tInit();\n\t}\n\n\tvoid Init()\n\t{\n\t\tmemset(this, 0, sizeof(TASKDIALOGCONFIG));   // initialize structure to 0/NULL\n\t\tthis->cbSize = sizeof(TASKDIALOGCONFIG);\n\t\tthis->hInstance = ModuleHelper::GetResourceInstance();\n\t}\n\n// Operations - setting values\n\t// common buttons\n\tvoid SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtonsArg)\n\t{\n\t\tthis->dwCommonButtons = dwCommonButtonsArg;\n\t}\n\n\t// window title text\n\tvoid SetWindowTitle(UINT nID)\n\t{\n\t\tthis->pszWindowTitle = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetWindowTitle(LPCWSTR lpstrWindowTitle)\n\t{\n\t\tthis->pszWindowTitle = lpstrWindowTitle;\n\t}\n\n\t// main icon\n\tvoid SetMainIcon(HICON hIcon)\n\t{\n\t\tthis->dwFlags |= TDF_USE_HICON_MAIN;\n\t\tthis->hMainIcon = hIcon;\n\t}\n\n\tvoid SetMainIcon(UINT nID)\n\t{\n\t\tthis->dwFlags &= ~TDF_USE_HICON_MAIN;\n\t\tthis->pszMainIcon = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetMainIcon(LPCWSTR lpstrMainIcon)\n\t{\n\t\tthis->dwFlags &= ~TDF_USE_HICON_MAIN;\n\t\tthis->pszMainIcon = lpstrMainIcon;\n\t}\n\n\t// main instruction text\n\tvoid SetMainInstructionText(UINT nID)\n\t{\n\t\tthis->pszMainInstruction = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetMainInstructionText(LPCWSTR lpstrMainInstruction)\n\t{\n\t\tthis->pszMainInstruction = lpstrMainInstruction;\n\t}\n\n\t// content text\n\tvoid SetContentText(UINT nID)\n\t{\n\t\tthis->pszContent = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetContentText(LPCWSTR lpstrContent)\n\t{\n\t\tthis->pszContent = lpstrContent;\n\t}\n\n\t// buttons\n\tvoid SetButtons(const TASKDIALOG_BUTTON* pButtonsArg, UINT cButtonsArg, int nDefaultButtonArg = 0)\n\t{\n\t\tthis->pButtons = pButtonsArg;\n\t\tthis->cButtons = cButtonsArg;\n\t\tif(nDefaultButtonArg != 0)\n\t\t\tthis->nDefaultButton = nDefaultButtonArg;\n\t}\n\n\tvoid SetDefaultButton(int nDefaultButtonArg)\n\t{\n\t\tthis->nDefaultButton = nDefaultButtonArg;\n\t}\n\n\t// radio buttons\n\tvoid SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtonsArg, UINT cRadioButtonsArg, int nDefaultRadioButtonArg = 0)\n\t{\n\t\tthis->pRadioButtons = pRadioButtonsArg;\n\t\tthis->cRadioButtons = cRadioButtonsArg;\n\t\tif(nDefaultRadioButtonArg != 0)\n\t\t\tthis->nDefaultRadioButton = nDefaultRadioButtonArg;\n\t}\n\n\tvoid SetDefaultRadioButton(int nDefaultRadioButtonArg)\n\t{\n\t\tthis->nDefaultRadioButton = nDefaultRadioButtonArg;\n\t}\n\n\t// verification text\n\tvoid SetVerificationText(UINT nID)\n\t{\n\t\tthis->pszVerificationText = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetVerificationText(LPCWSTR lpstrVerificationText)\n\t{\n\t\tthis->pszVerificationText = lpstrVerificationText;\n\t}\n\n\t// expanded information text\n\tvoid SetExpandedInformationText(UINT nID)\n\t{\n\t\tthis->pszExpandedInformation = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)\n\t{\n\t\tthis->pszExpandedInformation = lpstrExpandedInformation;\n\t}\n\n\t// expanded control text\n\tvoid SetExpandedControlText(UINT nID)\n\t{\n\t\tthis->pszExpandedControlText = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetExpandedControlText(LPCWSTR lpstrExpandedControlText)\n\t{\n\t\tthis->pszExpandedControlText = lpstrExpandedControlText;\n\t}\n\n\t// collapsed control text\n\tvoid SetCollapsedControlText(UINT nID)\n\t{\n\t\tthis->pszCollapsedControlText = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)\n\t{\n\t\tthis->pszCollapsedControlText = lpstrCollapsedControlText;\n\t}\n\n\t// footer icon\n\tvoid SetFooterIcon(HICON hIcon)\n\t{\n\t\tthis->dwFlags |= TDF_USE_HICON_FOOTER;\n\t\tthis->hFooterIcon = hIcon;\n\t}\n\n\tvoid SetFooterIcon(UINT nID)\n\t{\n\t\tthis->dwFlags &= ~TDF_USE_HICON_FOOTER;\n\t\tthis->pszFooterIcon = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetFooterIcon(LPCWSTR lpstrFooterIcon)\n\t{\n\t\tthis->dwFlags &= ~TDF_USE_HICON_FOOTER;\n\t\tthis->pszFooterIcon = lpstrFooterIcon;\n\t}\n\n\t// footer text\n\tvoid SetFooterText(UINT nID)\n\t{\n\t\tthis->pszFooter = MAKEINTRESOURCEW(nID);\n\t}\n\n\tvoid SetFooterText(LPCWSTR lpstrFooterText)\n\t{\n\t\tthis->pszFooter = lpstrFooterText;\n\t}\n\n\t// width (in DLUs)\n\tvoid SetWidth(UINT cxWidthArg)\n\t{\n\t\tthis->cxWidth = cxWidthArg;\n\t}\n\n\t// modify flags\n\tvoid ModifyFlags(DWORD dwRemove, DWORD dwAdd)\n\t{\n\t\tthis->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTaskDialogImpl - implements a Task Dialog\n\ntemplate <class T>\nclass ATL_NO_VTABLE CTaskDialogImpl\n{\npublic:\n\tCTaskDialogConfig m_tdc;\n\tHWND m_hWnd;   // used only in callback functions\n\n// Constructor\n\tCTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL)\n\t{\n\t\tm_tdc.hwndParent = hWndParent;\n\t\tm_tdc.pfCallback = T::TaskDialogCallback;\n\t\tm_tdc.lpCallbackData = (LONG_PTR)static_cast<T*>(this);\n\t}\n\n// Operations\n\tHRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL)\n\t{\n\t\tif(m_tdc.hwndParent == NULL)\n\t\t\tm_tdc.hwndParent = hWndParent;\n\n#ifdef _WTL_TASKDIALOG_DIRECT\n\t\treturn ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);\n#else\n\n\t\t// This allows apps to run on older versions of Windows\n\t\ttypedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked);\n\n\t\tHRESULT hRet = E_UNEXPECTED;\n\t\tHMODULE m_hCommCtrlDLL = ::LoadLibrary(_T(\"comctl32.dll\"));\n\t\tif(m_hCommCtrlDLL != NULL)\n\t\t{\n\t\t\tPFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, \"TaskDialogIndirect\");\n\t\t\tif(pfnTaskDialogIndirect != NULL)\n\t\t\t\thRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);\n\n\t\t\t::FreeLibrary(m_hCommCtrlDLL);\n\t\t}\n\n\t\treturn hRet;\n#endif\n\t}\n\n// Operations - setting values of TASKDIALOGCONFIG\n\t// common buttons\n\tvoid SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)\n\t{\tm_tdc.SetCommonButtons(dwCommonButtons); }\n\t// window title text\n\tvoid SetWindowTitle(UINT nID)\n\t{\tm_tdc.SetWindowTitle(nID); }\n\tvoid SetWindowTitle(LPCWSTR lpstrWindowTitle)\n\t{\tm_tdc.SetWindowTitle(lpstrWindowTitle); }\n\t// main icon\n\tvoid SetMainIcon(HICON hIcon)\n\t{\tm_tdc.SetMainIcon(hIcon); }\n\tvoid SetMainIcon(UINT nID)\n\t{\tm_tdc.SetMainIcon(nID); }\n\tvoid SetMainIcon(LPCWSTR lpstrMainIcon)\n\t{\tm_tdc.SetMainIcon(lpstrMainIcon); }\n\t// main instruction text\n\tvoid SetMainInstructionText(UINT nID)\n\t{\tm_tdc.SetMainInstructionText(nID); }\n\tvoid SetMainInstructionText(LPCWSTR lpstrMainInstruction)\n\t{\tm_tdc.SetMainInstructionText(lpstrMainInstruction); }\n\t// content text\n\tvoid SetContentText(UINT nID)\n\t{\tm_tdc.SetContentText(nID); }\n\tvoid SetContentText(LPCWSTR lpstrContent)\n\t{\tm_tdc.SetContentText(lpstrContent); }\n\t// buttons\n\tvoid SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)\n\t{\tm_tdc.SetButtons(pButtons, cButtons, nDefaultButton); }\n\tvoid SetDefaultButton(int nDefaultButton)\n\t{\tm_tdc.SetDefaultButton(nDefaultButton); }\n\t// radio buttons\n\tvoid SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)\n\t{\tm_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); }\n\tvoid SetDefaultRadioButton(int nDefaultRadioButton)\n\t{\tm_tdc.SetDefaultRadioButton(nDefaultRadioButton); }\n\t// verification text\n\tvoid SetVerificationText(UINT nID)\n\t{\tm_tdc.SetVerificationText(nID); }\n\tvoid SetVerificationText(LPCWSTR lpstrVerificationText)\n\t{\tm_tdc.SetVerificationText(lpstrVerificationText); }\n\t// expanded information text\n\tvoid SetExpandedInformationText(UINT nID)\n\t{\tm_tdc.SetExpandedInformationText(nID); }\n\tvoid SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)\n\t{\tm_tdc.SetExpandedInformationText(lpstrExpandedInformation); }\n\t// expanded control text\n\tvoid SetExpandedControlText(UINT nID)\n\t{\tm_tdc.SetExpandedControlText(nID); }\n\tvoid SetExpandedControlText(LPCWSTR lpstrExpandedControlText)\n\t{\tm_tdc.SetExpandedControlText(lpstrExpandedControlText); }\n\t// collapsed control text\n\tvoid SetCollapsedControlText(UINT nID)\n\t{\tm_tdc.SetCollapsedControlText(nID); }\n\tvoid SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)\n\t{\tm_tdc.SetCollapsedControlText(lpstrCollapsedControlText); }\n\t// footer icon\n\tvoid SetFooterIcon(HICON hIcon)\n\t{\tm_tdc.SetFooterIcon(hIcon); }\n\tvoid SetFooterIcon(UINT nID)\n\t{\tm_tdc.SetFooterIcon(nID); }\n\tvoid SetFooterIcon(LPCWSTR lpstrFooterIcon)\n\t{\tm_tdc.SetFooterIcon(lpstrFooterIcon); }\n\t// footer text\n\tvoid SetFooterText(UINT nID)\n\t{\tm_tdc.SetFooterText(nID); }\n\tvoid SetFooterText(LPCWSTR lpstrFooterText)\n\t{\tm_tdc.SetFooterText(lpstrFooterText); }\n\t// width (in DLUs)\n\tvoid SetWidth(UINT cxWidth)\n\t{\tm_tdc.SetWidth(cxWidth); }\n\t// modify flags\n\tvoid ModifyFlags(DWORD dwRemove, DWORD dwAdd)\n\t{\tm_tdc.ModifyFlags(dwRemove, dwAdd); }\n\n// Implementation\n\tstatic HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData)\n\t{\n\t\tT* pT = (T*)lpRefData;\n\t\tATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd);\n\n\t\tBOOL bRet = FALSE;\n\t\tswitch(uMsg)\n\t\t{\n\t\tcase TDN_DIALOG_CONSTRUCTED:\n\t\t\tpT->m_hWnd = hWnd;\n\t\t\tpT->OnDialogConstructed();\n\t\t\tbreak;\n\t\tcase TDN_CREATED:\n\t\t\tpT->OnCreated();\n\t\t\tbreak;\n\t\tcase TDN_BUTTON_CLICKED:\n\t\t\tbRet = pT->OnButtonClicked((int)wParam);\n\t\t\tbreak;\n\t\tcase TDN_RADIO_BUTTON_CLICKED:\n\t\t\tpT->OnRadioButtonClicked((int)wParam);\n\t\t\tbreak;\n\t\tcase TDN_HYPERLINK_CLICKED:\n\t\t\tpT->OnHyperlinkClicked((LPCWSTR)lParam);\n\t\t\tbreak;\n\t\tcase TDN_EXPANDO_BUTTON_CLICKED:\n\t\t\tpT->OnExpandoButtonClicked((wParam != 0));\n\t\t\tbreak;\n\t\tcase TDN_VERIFICATION_CLICKED:\n\t\t\tpT->OnVerificationClicked((wParam != 0));\n\t\t\tbreak;\n\t\tcase TDN_HELP:\n\t\t\tpT->OnHelp();\n\t\t\tbreak;\n\t\tcase TDN_TIMER:\n\t\t\tbRet = pT->OnTimer((DWORD)wParam);\n\t\t\tbreak;\n\t\tcase TDN_NAVIGATED:\n\t\t\tpT->OnNavigated();\n\t\t\tbreak;\n\t\tcase TDN_DESTROYED:\n\t\t\tpT->OnDestroyed();\n\t\t\tpT->m_hWnd = NULL;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Unknown notification received in CTaskDialogImpl::TaskDialogCallback\\n\"));\n\t\t\tbreak;\n\t\t}\n\n\t\treturn (bRet != FALSE) ? S_OK : S_FALSE;\n\t}\n\n// Overrideables - notification handlers\n\tvoid OnDialogConstructed()\n\t{\n\t}\n\n\tvoid OnCreated()\n\t{\n\t}\n\n\tBOOL OnButtonClicked(int /*nButton*/)\n\t{\n\t\treturn FALSE;   // don't prevent dialog to close\n\t}\n\n\tvoid OnRadioButtonClicked(int /*nRadioButton*/)\n\t{\n\t}\n\n\tvoid OnHyperlinkClicked(LPCWSTR /*pszHREF*/)\n\t{\n\t}\n\n\tvoid OnExpandoButtonClicked(bool /*bExpanded*/)\n\t{\n\t}\n\n\tvoid OnVerificationClicked(bool /*bChecked*/)\n\t{\n\t}\n\n\tvoid OnHelp()\n\t{\n\t}\n\n\tBOOL OnTimer(DWORD /*dwTickCount*/)\n\t{\n\t\treturn FALSE;   // don't reset counter\n\t}\n\n\tvoid OnNavigated()\n\t{\n\t}\n\n\tvoid OnDestroyed()\n\t{\n\t}\n\n// Commands - valid to call only from handlers\n\tvoid NavigatePage(TASKDIALOGCONFIG& tdc)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\n\t\ttdc.cbSize = sizeof(TASKDIALOGCONFIG);\n\t\tif(tdc.hwndParent == NULL)\n\t\t\ttdc.hwndParent = m_tdc.hwndParent;\n\t\ttdc.pfCallback = m_tdc.pfCallback;\n\t\ttdc.lpCallbackData = m_tdc.lpCallbackData;\n\t\t(TASKDIALOGCONFIG)m_tdc = tdc;\n\n\t\t::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc);\n\t}\n\n\t// modify TASKDIALOGCONFIG values, then call this to update task dialog\n\tvoid NavigatePage()\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc);\n\t}\n\n\tvoid ClickButton(int nButton)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L);\n\t}\n\n\tvoid SetMarqueeProgressBar(BOOL bMarquee)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L);\n\t}\n\n\tBOOL SetProgressBarState(int nNewState)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L);\n\t}\n\n\tDWORD SetProgressBarRange(int nMinRange, int nMaxRange)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\treturn (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange));\n\t}\n\n\tint SetProgressBarPos(int nNewPos)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\treturn (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L);\n\t}\n\n\tBOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\treturn (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed);\n\t}\n\n\tvoid SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText);\n\t}\n\n\tvoid ClickRadioButton(int nRadioButton)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L);\n\t}\n\n\tvoid EnableButton(int nButton, BOOL bEnable)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable);\n\t}\n\n\tvoid EnableRadioButton(int nButton, BOOL bEnable)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable);\n\t}\n\n\tvoid ClickVerification(BOOL bCheck, BOOL bFocus)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus);\n\t}\n\n\tvoid UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText);\n\t}\n\n\tvoid SetButtonElevationRequiredState(int nButton, BOOL bElevation)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n\t\t::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation);\n\t}\n\n\tvoid UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n#ifdef _DEBUG\n\t\tif(element == TDIE_ICON_MAIN)\n\t\t\tATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0);\n\t\telse if(element == TDIE_ICON_FOOTER)\n\t\t\tATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0);\n#endif // _DEBUG\n\t\t::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon);\n\t}\n\n\tvoid UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon)\n\t{\n\t\tATLASSERT(m_hWnd != NULL);\n#ifdef _DEBUG\n\t\tif(element == TDIE_ICON_MAIN)\n\t\t\tATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0);\n\t\telse if(element == TDIE_ICON_FOOTER)\n\t\t\tATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0);\n#endif // _DEBUG\n\t\t::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTaskDialog - for non-customized task dialogs\n\nclass CTaskDialog : public CTaskDialogImpl<CTaskDialog>\n{\npublic:\n\tCTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl<CTaskDialog>(hWndParent)\n\t{\n\t\tm_tdc.pfCallback = NULL;\n\t}\n};\n\n#endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)\n\n}; // namespace WTL\n\n#endif // __ATLDLGS_H__\n"
  },
  {
    "path": "WTL/atldwm.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLDWM_H__\n#define __ATLDWM_H__\n\n#pragma once\n\n#ifdef _WIN32_WCE\n\t#error atldwm.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLAPP_H__\n\t#error atldwm.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atldwm.h requires atlwin.h to be included first\n#endif\n\n#if (_WIN32_WINNT < 0x0600)\n\t#error atldwm.h requires _WIN32_WINNT >= 0x0600\n#endif\n\n#ifndef _DWMAPI_H_\n  #include <dwmapi.h>\n#endif\n#pragma comment(lib, \"dwmapi.lib\")\n\n// Note: To create an application that also runs on older versions of Windows,\n// use delay load of dwmapi.dll and ensure that no calls to the DWM API are\n// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, \n// and add dwmapi.dll in the Linker.Input.Delay Loaded DLLs section of the \n// project properties.\n#if (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD)\n  #pragma comment(lib, \"delayimp.lib\")\n  #pragma comment(linker, \"/delayload:dwmapi.dll\")\n#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_DWMAPI_DELAYLOAD)\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CDwm\n// CDwmImpl<T, TBase>\n// CDwmWindowT<TBase> - CDwmWindow\n// CDwmThumbnailT<t_bManaged, TBase>\n// CDwmThumbnail\n// CDwmThumbnailHandle\n// CAeroControlImpl\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CDwm - wrapper for DWM handle\n\nclass CDwm\n{\npublic:\n// Data members\n\tstatic int m_nIsDwmSupported;\n\n// Constructor\n\tCDwm()\n\t{\n\t\tIsDwmSupported();\n\t}\n\n// Dwm support helper\n\tstatic bool IsDwmSupported()\n\t{\n\t\tif(m_nIsDwmSupported == -1)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CDwm::IsDwmSupported.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif(m_nIsDwmSupported == -1)\n\t\t\t{\n\t\t\t\tHMODULE hDwmDLL = ::LoadLibrary(_T(\"dwmapi.dll\"));\n\t\t\t\tm_nIsDwmSupported = (hDwmDLL != NULL) ? 1 : 0;\n\t\t\t\tif(hDwmDLL != NULL)\n\t\t\t\t\t::FreeLibrary(hDwmDLL);\n\t\t\t}\n\n\t\t\tlock.Unlock();\n\t\t}\n\n\t\tATLASSERT(m_nIsDwmSupported != -1);\n\t\treturn (m_nIsDwmSupported == 1);\n\t}\n\n// Operations\n\tBOOL DwmIsCompositionEnabled() const\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn FALSE;\n\n\t\tBOOL bRes = FALSE;\n\t\treturn (SUCCEEDED(::DwmIsCompositionEnabled(&bRes)) && bRes) ? TRUE : FALSE;\n\t}\n\n\tBOOL DwmEnableComposition(UINT fEnable)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn FALSE;\n\n\t\treturn SUCCEEDED(::DwmEnableComposition(fEnable)) ? TRUE : FALSE;\n\t}\n\n\tBOOL DwmEnableMMCSS(BOOL fEnableMMCSS)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn FALSE;\n\n\t\treturn SUCCEEDED(::DwmEnableMMCSS(fEnableMMCSS)) ? TRUE : FALSE;\n\t}\n\n\tHRESULT DwmGetColorizationColor(DWORD* pcrColorization, BOOL* pfOpaqueBlend)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\treturn ::DwmGetColorizationColor(pcrColorization, pfOpaqueBlend);\n\t}\n\n\tHRESULT DwmFlush()\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\treturn ::DwmFlush();\n\t}\n};\n\n__declspec(selectany) int CDwm::m_nIsDwmSupported = -1;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDwmImpl - DWM window support\n\ntemplate <class T, class TBase = CDwm>\nclass CDwmImpl : public TBase\n{\npublic:\n\tHRESULT DwmEnableBlurBehindWindow(const DWM_BLURBEHIND* pBB)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmEnableBlurBehindWindow(pT->m_hWnd, pBB);\n\t}\n\n\tHRESULT DwmExtendFrameIntoClientArea(const MARGINS* pMargins)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmExtendFrameIntoClientArea(pT->m_hWnd, pMargins);\n\t}\n\n\tHRESULT DwmExtendFrameIntoEntireClientArea()\n\t{\n\t\tMARGINS margins = { -1 };\n\t\treturn DwmExtendFrameIntoClientArea(&margins);\n\t}\n\n\tHRESULT DwmGetCompositionTimingInfo(DWM_TIMING_INFO* pTimingInfo)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmGetCompositionTimingInfo(pT->m_hWnd, pTimingInfo);\n\t}\n\n\tHRESULT DwmGetWindowAttribute(DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmGetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute);\n\t}\n\n\tHRESULT DwmModifyPreviousDxFrameDuration(INT cRefreshes, BOOL fRelative)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmModifyPreviousDxFrameDuration(pT->m_hWnd, cRefreshes, fRelative);\n\t}\n\n\tHRESULT DwmSetDxFrameDuration(INT cRefreshes)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmSetDxFrameDuration(pT->m_hWnd, cRefreshes);\n\t}\n\n\tHRESULT DwmSetPresentParameters(DWM_PRESENT_PARAMETERS* pPresentParams)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmSetPresentParameters(pT->m_hWnd, pPresentParams);\n\t}\n\n\tHRESULT DwmSetWindowAttribute(DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmSetWindowAttribute(pT->m_hWnd, dwAttribute, pvAttribute, cbAttribute);\n\t}\n\n\tHRESULT DwmAttachMilContent()\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmAttachMilContent(pT->m_hWnd);\n\t}\n\n\tHRESULT DwmDetachMilContent()\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DwmDetachMilContent(pT->m_hWnd);\n\t}\n};\n\ntemplate <class TBase>\nclass CDwmWindowT : public TBase, public CDwmImpl<CDwmWindowT< TBase > >\n{\npublic:\n\tCDwmWindowT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCDwmWindowT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n};\n\ntypedef CDwmWindowT<ATL::CWindow>\tCDwmWindow;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDwmThumbnail - provides DWM thumbnail support\n\ntemplate <bool t_bManaged, class TBase = CDwm>\nclass CDwmThumbnailT : public TBase\n{\npublic:\n// Data members\n\tHTHUMBNAIL m_hThumbnail;\n\n// Constructor\n\tCDwmThumbnailT(HTHUMBNAIL hThumbnail = NULL) : m_hThumbnail(hThumbnail)\n\t{ }\n\n\t~CDwmThumbnailT()\n\t{\n\t\tif(t_bManaged && (m_hThumbnail != NULL))\n\t\t\tUnregister();\n\t}\n\n// Operations\n\tCDwmThumbnailT<t_bManaged, TBase>& operator =(HTHUMBNAIL hThumbnail)\n\t{\n\t\tAttach(hThumbnail);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HTHUMBNAIL hThumbnailNew)\n\t{\n\t\tif(t_bManaged && m_hThumbnail != NULL && m_hThumbnail != hThumbnailNew)\n\t\t\tUnregister();\n\t\tm_hThumbnail = hThumbnailNew;\n\t}\n\n\tHTHUMBNAIL Detach()\n\t{\n\t\tHTHUMBNAIL hThumbnail = m_hThumbnail;\n\t\tm_hThumbnail = NULL;\n\t\treturn hThumbnail;\n\t}\n\n\tHRESULT Register(HWND hwndDestination, HWND hwndSource)\n\t{\n\t\tATLASSERT(::IsWindow(hwndDestination));\n\t\tATLASSERT(::IsWindow(hwndSource));\n\t\tATLASSERT(m_hThumbnail==NULL);\n\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\treturn ::DwmRegisterThumbnail(hwndDestination, hwndSource, &m_hThumbnail);\n\t}\n\n\tHRESULT Unregister()\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\t\tif(m_hThumbnail == NULL)\n\t\t\treturn S_FALSE;\n\n\t\tHRESULT Hr = ::DwmUnregisterThumbnail(m_hThumbnail);\n\t\tif(SUCCEEDED(Hr))\n\t\t\tm_hThumbnail = NULL;\n\n\t\treturn Hr;\n\t}\n\n\toperator HTHUMBNAIL() const { return m_hThumbnail; }\n\n\tbool IsNull() const { return (m_hThumbnail == NULL); }\n\n\tHRESULT UpdateProperties(const DWM_THUMBNAIL_PROPERTIES* ptnProperties)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tATLASSERT(m_hThumbnail != NULL);\n\t\treturn ::DwmUpdateThumbnailProperties(m_hThumbnail, ptnProperties);\n\t}\n\n// Attributes\n\tHRESULT QuerySourceSize(PSIZE pSize)\n\t{\n\t\tif(!IsDwmSupported())\n\t\t\treturn E_NOTIMPL;\n\n\t\tATLASSERT(m_hThumbnail != NULL);\n\t\treturn ::DwmQueryThumbnailSourceSize(m_hThumbnail, pSize);\n\t}\n};\n\ntypedef CDwmThumbnailT<true, CDwm> CDwmThumbnail;\ntypedef CDwmThumbnailT<false, CDwm> CDwmThumbnailHandle;\n\n\n#ifdef __ATLTHEME_H__\n\n///////////////////////////////////////////////////////////////////////////////\n// CAeroControlImpl - Base class for controls on Glass\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass CAeroControlImpl : public CThemeImpl<T>,\n                         public CBufferedPaintImpl<T>,\n                         public ATL::CWindowImpl<T, TBase, TWinTraits>\n{\npublic:\n\ttypedef CThemeImpl<T> _themeClass;\n\ttypedef CBufferedPaintImpl<T> _baseClass;\n\ttypedef ATL::CWindowImpl<T, TBase, TWinTraits> _windowClass;\n\n\tCAeroControlImpl()\n\t{\n\t\tm_PaintParams.dwFlags = BPPF_ERASE;\n\t}\n\n\tstatic LPCWSTR GetThemeName()\n\t{\n#ifdef _UNICODE\n\t\treturn TBase::GetWndClassName();\n#else\n\t\tATLASSERT(!_T(\"Return UNICODE string of window classname / theme class\"));\n\t\treturn NULL;\n#endif // _UNICODE\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CAeroControlImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnActivate)\n\t\tCHAIN_MSG_MAP(_themeClass)\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Init();\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(IsThemingSupported())\n\t\t\tInvalidate(FALSE);\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n// Operations\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tBOOL bRet = _windowClass::SubclassWindow(hWnd);\n\t\tif(bRet)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n// Implementation\n\tLRESULT DefWindowProc()\n\t{\n\t\tconst ATL::_ATL_MSG* pMsg = m_pCurrentMsg;\n\t\tLRESULT lRes = 0;\n\t\tif(pMsg != NULL)\n\t\t\tlRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);\n\n\t\treturn lRes;\n\t}\n\n\tLRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLRESULT lRes = 0;\n\t\tif(::DwmDefWindowProc(pT->m_hWnd, uMsg, wParam, lParam, &lRes) != FALSE)\n\t\t\treturn lRes;\n\n\t\treturn _windowClass::DefWindowProc(uMsg, wParam, lParam);\n\t}\n\n\tvoid DoBufferedPaint(HDC hDC, RECT& rcPaint)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tHDC hDCPaint = NULL;\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tm_BufferedPaint.Begin(hDC, &rcClient, m_dwFormat, &m_PaintParams, &hDCPaint);\n\t\tATLASSERT(hDCPaint != NULL);\n\t\tpT->DoAeroPaint(hDCPaint, rcClient, rcPaint);\n\t\tm_BufferedPaint.End();\n\t}\n\n\tvoid DoPaint(HDC /*hdc*/, RECT& /*rcClient*/)\n\t{\n\t\tDefWindowProc();\n\t}\n\n// Overridables\n\tvoid Init()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tSetThemeClassList(pT->GetThemeName());\n\t\tif(m_lpstrThemeClassList != NULL)\n\t\t\tOpenThemeData();\n\t}\n\n\tvoid DoAeroPaint(HDC hDC, RECT& /*rcClient*/, RECT& rcPaint)\n\t{\n\t\tDefWindowProc(WM_PAINT, (WPARAM) hDC, 0L);\n\t\tm_BufferedPaint.MakeOpaque(&rcPaint);\n\t}\n};\n\n#endif // __ATLTHEME_H__\n\n}; // namespace WTL\n\n#endif // __ATLDWM_H__\n"
  },
  {
    "path": "WTL/atlfind.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLFIND_H__\n#define __ATLFIND_H__\n\n#pragma once\n\n#ifdef _WIN32_WCE\n\t#error atlfind.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLCTRLS_H__\n\t#error atlfind.h requires atlctrls.h to be included first\n#endif\n\n#ifndef __ATLDLGS_H__\n\t#error atlfind.h requires atldlgs.h to be included first\n#endif\n\n#if !((defined(__ATLMISC_H__) && defined(_WTL_USE_CSTRING)) || defined(__ATLSTR_H__))\n\t#error atlfind.h requires CString (either from ATL's atlstr.h or WTL's atlmisc.h with _WTL_USE_CSTRING)\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CEditFindReplaceImplBase<T, TFindReplaceDialog>\n// CEditFindReplaceImpl<T, TFindReplaceDialog>\n// CRichEditFindReplaceImpl<T, TFindReplaceDialog>\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CEditFindReplaceImplBase - Base class for mixin classes that\n// help implement Find/Replace for CEdit or CRichEditCtrl based window classes.\n\ntemplate <class T, class TFindReplaceDialog = CFindReplaceDialog>\nclass CEditFindReplaceImplBase\n{\nprotected:\n// Typedefs\n\ttypedef CEditFindReplaceImplBase<T, TFindReplaceDialog> thisClass;\n\n// Data members\n\tTFindReplaceDialog* m_pFindReplaceDialog;\n\t_CSTRING_NS::CString m_sFindNext, m_sReplaceWith;\n\tBOOL m_bFindOnly, m_bFirstSearch, m_bMatchCase, m_bWholeWord, m_bFindDown;\n\tLONG m_nInitialSearchPos;\n\tHCURSOR m_hOldCursor;\n\n// Enumerations\n\tenum TranslationTextItem\n\t{\n\t\teText_OnReplaceAllMessage   = 0,\n\t\teText_OnReplaceAllTitle     = 1,\n\t\teText_OnTextNotFoundMessage = 2,\n\t\teText_OnTextNotFoundTitle   = 3\n\t};\n\npublic:\n// Constructors\n\tCEditFindReplaceImplBase() :\n\t\tm_pFindReplaceDialog(NULL),\n\t\tm_bFindOnly(TRUE),\n\t\tm_bFirstSearch(TRUE),\n\t\tm_bMatchCase(FALSE),\n\t\tm_bWholeWord(FALSE),\n\t\tm_bFindDown(TRUE),\n\t\tm_nInitialSearchPos(0),\n\t\tm_hOldCursor(NULL)\n\t{\n\t}\n\n// Message Handlers\n\tBEGIN_MSG_MAP(thisClass)\n\tALT_MSG_MAP(1)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(TFindReplaceDialog::GetFindReplaceMsg(), OnFindReplaceCmd)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_FIND, OnEditFind)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_REPEAT, OnEditRepeat)\n\t\tCOMMAND_ID_HANDLER(ID_EDIT_REPLACE, OnEditReplace)\n\tEND_MSG_MAP()\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_pFindReplaceDialog != NULL)\n\t\t{\n\t\t\tm_pFindReplaceDialog->SendMessage(WM_CLOSE);\n\t\t\tATLASSERT(m_pFindReplaceDialog == NULL);\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnFindReplaceCmd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tTFindReplaceDialog* pDialog = TFindReplaceDialog::GetNotifier(lParam);\n\t\tif(pDialog == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\t::MessageBeep(MB_ICONERROR);\n\t\t\treturn 1;\n\t\t}\n\t\tATLASSERT(pDialog == m_pFindReplaceDialog);\n\n\t\tLPFINDREPLACE findReplace = (LPFINDREPLACE)lParam;\n\t\tif((m_pFindReplaceDialog != NULL) && (findReplace != NULL))\n\t\t{\n\t\t\tif(pDialog->FindNext())\n\t\t\t{\n\t\t\t\tpT->OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(),\n\t\t\t\t\tpDialog->MatchCase(), pDialog->MatchWholeWord());\n\t\t\t}\n\t\t\telse if(pDialog->ReplaceCurrent())\n\t\t\t{\n\t\t\t\tpT->OnReplaceSel(pDialog->GetFindString(),\n\t\t\t\t\tpDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(),\n\t\t\t\t\tpDialog->GetReplaceString());\n\t\t\t}\n\t\t\telse if(pDialog->ReplaceAll())\n\t\t\t{\n\t\t\t\tpT->OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),\n\t\t\t\t\tpDialog->MatchCase(), pDialog->MatchWholeWord());\n\t\t\t}\n\t\t\telse if(pDialog->IsTerminating())\n\t\t\t{\n\t\t\t\t// Dialog is going away (but hasn't gone away yet)\n\t\t\t\t// OnFinalMessage will \"delete this\"\n\t\t\t\tpT->OnTerminatingFindReplaceDialog(m_pFindReplaceDialog);\n\t\t\t\tm_pFindReplaceDialog = NULL;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditFind(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->FindReplace(TRUE);\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditRepeat(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\t// If the user is holding down SHIFT when hitting F3, we'll\n\t\t// search in reverse. Otherwise, we'll search forward.\n\t\t// (be sure to have an accelerator mapped to ID_EDIT_REPEAT\n\t\t// for both F3 and Shift+F3)\n\t\tm_bFindDown = !((::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000);\n\n\t\tif(m_sFindNext.IsEmpty())\n\t\t{\n\t\t\tpT->FindReplace(TRUE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))\n\t\t\t\tpT->TextNotFound(m_sFindNext);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEditReplace(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tDWORD style = pT->GetStyle();\n\t\tif((style & ES_READONLY) != ES_READONLY)\n\t\t{\n\t\t\tpT->FindReplace(FALSE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Don't allow replace when the edit control is read only\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n// Operations (overrideable)\n\tTFindReplaceDialog* CreateFindReplaceDialog(BOOL bFindOnly, // TRUE for Find, FALSE for FindReplace\n\t\t\tLPCTSTR lpszFindWhat,\n\t\t\tLPCTSTR lpszReplaceWith = NULL,\n\t\t\tDWORD dwFlags = FR_DOWN,\n\t\t\tHWND hWndParent = NULL)\n\t{\n\t\t// You can override all of this in a derived class\n\n\t\tTFindReplaceDialog* findReplaceDialog = new TFindReplaceDialog();\n\t\tif(findReplaceDialog == NULL)\n\t\t{\n\t\t\t::MessageBeep(MB_ICONHAND);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tHWND hWndFindReplace = findReplaceDialog->Create(bFindOnly,\n\t\t\t\tlpszFindWhat, lpszReplaceWith, dwFlags, hWndParent);\n\t\t\tif(hWndFindReplace == NULL)\n\t\t\t{\n\t\t\t\tdelete findReplaceDialog;\n\t\t\t\tfindReplaceDialog = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfindReplaceDialog->SetActiveWindow();\n\t\t\t\tfindReplaceDialog->ShowWindow(SW_SHOW);\n\t\t\t}\n\t\t}\n\n\t\treturn findReplaceDialog;\n\t}\n\n\tvoid AdjustDialogPosition(HWND hWndDialog)\n\t{\n\t\tATLASSERT((hWndDialog != NULL) && ::IsWindow(hWndDialog));\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tLONG nStartChar = 0, nEndChar = 0;\n\t\t// Send EM_GETSEL so we can use both Edit and RichEdit\n\t\t// (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)\n\t\t::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);\n\t\tPOINT point = pT->PosFromChar(nStartChar);\n\t\t::ClientToScreen(pT->GetParent(), &point);\n\t\tCRect rect;\n\t\t::GetWindowRect(hWndDialog, &rect);\n\t\tif(rect.PtInRect(point))\n\t\t{\n\t\t\tif(point.y > rect.Height())\n\t\t\t{\n\t\t\t\trect.OffsetRect(0, point.y - rect.bottom - 20);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tint nVertExt = GetSystemMetrics(SM_CYSCREEN);\n\t\t\t\tif(point.y + rect.Height() < nVertExt)\n\t\t\t\t\trect.OffsetRect(0, 40 + point.y - rect.top);\n\t\t\t}\n\n\t\t\t::MoveWindow(hWndDialog, rect.left, rect.top, rect.Width(), rect.Height(), TRUE);\n\t\t}\n\t}\n\n\tDWORD GetFindReplaceDialogFlags(void) const\n\t{\n\t\tDWORD dwFlags = 0;\n\t\tif(m_bFindDown)\n\t\t\tdwFlags |= FR_DOWN;\n\t\tif(m_bMatchCase)\n\t\t\tdwFlags |= FR_MATCHCASE;\n\t\tif(m_bWholeWord)\n\t\t\tdwFlags |= FR_WHOLEWORD;\n\n\t\treturn dwFlags;\n\t}\n\n\tvoid FindReplace(BOOL bFindOnly)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_bFirstSearch = TRUE;\n\t\tif(m_pFindReplaceDialog != NULL)\n\t\t{\n\t\t\tif(m_bFindOnly == bFindOnly)\n\t\t\t{\n\t\t\t\tm_pFindReplaceDialog->SetActiveWindow();\n\t\t\t\tm_pFindReplaceDialog->ShowWindow(SW_SHOW);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_pFindReplaceDialog->SendMessage(WM_CLOSE);\n\t\t\t\tATLASSERT(m_pFindReplaceDialog == NULL);\n\t\t\t}\n\t\t}\n\n\t\tATLASSERT(m_pFindReplaceDialog == NULL);\n\n\t\t_CSTRING_NS::CString findNext;\n\t\tpT->GetSelText(findNext);\n\t\t// if selection is empty or spans multiple lines use old find text\n\t\tif(findNext.IsEmpty() || (findNext.FindOneOf(_T(\"\\n\\r\")) != -1))\n\t\t\tfindNext = m_sFindNext;\n\t\t_CSTRING_NS::CString replaceWith = m_sReplaceWith;\n\t\tDWORD dwFlags = pT->GetFindReplaceDialogFlags();\n\n\t\tm_pFindReplaceDialog = pT->CreateFindReplaceDialog(bFindOnly,\n\t\t\tfindNext, replaceWith, dwFlags, pT->operator HWND());\n\t\tATLASSERT(m_pFindReplaceDialog != NULL);\n\t\tif(m_pFindReplaceDialog != NULL)\n\t\t\tm_bFindOnly = bFindOnly;\n\t}\n\n\tBOOL SameAsSelected(LPCTSTR lpszCompare, BOOL bMatchCase, BOOL /*bWholeWord*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\t// check length first\n\t\tsize_t nLen = lstrlen(lpszCompare);\n\t\tLONG nStartChar = 0, nEndChar = 0;\n\t\t// Send EM_GETSEL so we can use both Edit and RichEdit\n\t\t// (CEdit::GetSel uses int&, and CRichEditCtrlT::GetSel uses LONG&)\n\t\t::SendMessage(pT->m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);\n\t\tif(nLen != (size_t)(nEndChar - nStartChar))\n\t\t\treturn FALSE;\n\n\t\t// length is the same, check contents\n\t\t_CSTRING_NS::CString selectedText;\n\t\tpT->GetSelText(selectedText);\n\n\t\treturn (bMatchCase && selectedText.Compare(lpszCompare) == 0) ||\n\t\t\t(!bMatchCase && selectedText.CompareNoCase(lpszCompare) == 0);\n\t}\n\n\tvoid TextNotFound(LPCTSTR lpszFind)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_bFirstSearch = TRUE;\n\t\tpT->OnTextNotFound(lpszFind);\n\t}\n\n\t_CSTRING_NS::CString GetTranslationText(enum TranslationTextItem eItem) const\n\t{\n\t\t_CSTRING_NS::CString text;\n\t\tswitch(eItem)\n\t\t{\n\t\tcase eText_OnReplaceAllMessage:\n\t\t\ttext = _T(\"Replaced %d occurances of \\\"%s\\\" with \\\"%s\\\"\");\n\t\t\tbreak;\n\t\tcase eText_OnReplaceAllTitle:\n\t\t\ttext = _T(\"Replace All\");\n\t\t\tbreak;\n\t\tcase eText_OnTextNotFoundMessage:\n\t\t\ttext = _T(\"Unable to find the text \\\"%s\\\"\");\n\t\t\tbreak;\n\t\tcase eText_OnTextNotFoundTitle:\n\t\t\ttext = _T(\"Text not found\");\n\t\t\tbreak;\n\t\t}\n\n\t\treturn text;\n\t}\n\n// Overrideable Handlers\n\tvoid OnFindNext(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tm_sFindNext = lpszFind;\n\t\tm_bMatchCase = bMatchCase;\n\t\tm_bWholeWord = bWholeWord;\n\t\tm_bFindDown = bFindDown;\n\n\t\tif(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))\n\t\t\tpT->TextNotFound(m_sFindNext);\n\t\telse\n\t\t\tpT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());\n\t}\n\n\tvoid OnReplaceSel(LPCTSTR lpszFind, BOOL bFindDown, BOOL bMatchCase, BOOL bWholeWord, LPCTSTR lpszReplace)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tm_sFindNext = lpszFind;\n\t\tm_sReplaceWith = lpszReplace;\n\t\tm_bMatchCase = bMatchCase;\n\t\tm_bWholeWord = bWholeWord;\n\t\tm_bFindDown = bFindDown;\n\n\t\tif(pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))\n\t\t\tpT->ReplaceSel(m_sReplaceWith);\n\n\t\tif(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))\n\t\t\tpT->TextNotFound(m_sFindNext);\n\t\telse\n\t\t\tpT->AdjustDialogPosition(m_pFindReplaceDialog->operator HWND());\n\t}\n\n\tvoid OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bMatchCase, BOOL bWholeWord)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tm_sFindNext = lpszFind;\n\t\tm_sReplaceWith = lpszReplace;\n\t\tm_bMatchCase = bMatchCase;\n\t\tm_bWholeWord = bWholeWord;\n\t\tm_bFindDown = TRUE;\n\n\t\t// no selection or different than what looking for\n\t\tif(!pT->SameAsSelected(m_sFindNext, m_bMatchCase, m_bWholeWord))\n\t\t{\n\t\t\tif(!pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown))\n\t\t\t{\n\t\t\t\tpT->TextNotFound(m_sFindNext);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tpT->OnReplaceAllCoreBegin();\n\n\t\tint replaceCount=0;\n\t\tdo\n\t\t{\n\t\t\t++replaceCount;\n\t\t\tpT->ReplaceSel(m_sReplaceWith);\n\t\t} while(pT->FindTextSimple(m_sFindNext, m_bMatchCase, m_bWholeWord, m_bFindDown));\n\n\t\tpT->OnReplaceAllCoreEnd(replaceCount);\n\t}\n\n\tvoid OnReplaceAllCoreBegin()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tm_hOldCursor = ::SetCursor(::LoadCursor(NULL, IDC_WAIT));\n\n\t\tpT->HideSelection(TRUE, FALSE);\n\n\t}\n\n\tvoid OnReplaceAllCoreEnd(int replaceCount)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->HideSelection(FALSE, FALSE);\n\n\t\t::SetCursor(m_hOldCursor);\n\n\t\t_CSTRING_NS::CString message = pT->GetTranslationText(eText_OnReplaceAllMessage);\n\t\tif(message.GetLength() > 0)\n\t\t{\n\t\t\t_CSTRING_NS::CString formattedMessage;\n\t\t\tformattedMessage.Format(message, replaceCount, (LPCTSTR)m_sFindNext, (LPCTSTR)m_sReplaceWith);\n\t\t\tif(m_pFindReplaceDialog != NULL)\n\t\t\t{\n\t\t\t\tm_pFindReplaceDialog->MessageBox(formattedMessage,\n\t\t\t\t\tpT->GetTranslationText(eText_OnReplaceAllTitle),\n\t\t\t\t\tMB_OK | MB_ICONINFORMATION | MB_APPLMODAL);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpT->MessageBox(formattedMessage,\n\t\t\t\t\tpT->GetTranslationText(eText_OnReplaceAllTitle),\n\t\t\t\t\tMB_OK | MB_ICONINFORMATION | MB_APPLMODAL);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid OnTextNotFound(LPCTSTR lpszFind)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\t_CSTRING_NS::CString message = pT->GetTranslationText(eText_OnTextNotFoundMessage);\n\t\tif(message.GetLength() > 0)\n\t\t{\n\t\t\t_CSTRING_NS::CString formattedMessage;\n\t\t\tformattedMessage.Format(message, lpszFind);\n\t\t\tif(m_pFindReplaceDialog != NULL)\n\t\t\t{\n\t\t\t\tm_pFindReplaceDialog->MessageBox(formattedMessage,\n\t\t\t\t\tpT->GetTranslationText(eText_OnTextNotFoundTitle),\n\t\t\t\t\tMB_OK | MB_ICONINFORMATION | MB_APPLMODAL);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpT->MessageBox(formattedMessage,\n\t\t\t\t\tpT->GetTranslationText(eText_OnTextNotFoundTitle),\n\t\t\t\t\tMB_OK | MB_ICONINFORMATION | MB_APPLMODAL);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t::MessageBeep(MB_ICONHAND);\n\t\t}\n\t}\n\n\tvoid OnTerminatingFindReplaceDialog(TFindReplaceDialog*& /*findReplaceDialog*/)\n\t{\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CEditFindReplaceImpl - Mixin class for implementing Find/Replace for CEdit\n// based window classes.\n\n// Chain to CEditFindReplaceImpl message map. Your class must also derive from CEdit.\n// Example:\n// class CMyEdit : public CWindowImpl<CMyEdit, CEdit>,\n//                 public CEditFindReplaceImpl<CMyEdit>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyEdit)\n//              // your handlers...\n//              CHAIN_MSG_MAP_ALT(CEditFindReplaceImpl<CMyEdit>, 1)\n//      END_MSG_MAP()\n//      // other stuff...\n// };\n\ntemplate <class T, class TFindReplaceDialog = CFindReplaceDialog>\nclass CEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>\n{\nprotected:\n\ttypedef CEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;\n\ttypedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;\n\n// Data members\n\tLPTSTR m_pShadowBuffer;     // Special shadow buffer only used in some cases.\n\tUINT m_nShadowSize;\n\tint m_bShadowBufferNeeded;  // TRUE, FALSE, < 0 => Need to check\n\npublic:\n// Constructors\n\tCEditFindReplaceImpl() :\n\t\tm_pShadowBuffer(NULL),\n\t\tm_nShadowSize(0),\n\t\tm_bShadowBufferNeeded(-1)\n\t{\n\t}\n\n\tvirtual ~CEditFindReplaceImpl()\n\t{\n\t\tif(m_pShadowBuffer != NULL)\n\t\t{\n\t\t\tdelete [] m_pShadowBuffer;\n\t\t\tm_pShadowBuffer = NULL;\n\t\t}\n\t}\n\n// Message Handlers\n\tBEGIN_MSG_MAP(thisClass)\n\tALT_MSG_MAP(1)\n\t\tCHAIN_MSG_MAP_ALT(baseClass, 1)\n\tEND_MSG_MAP()\n\n// Operations\n\t// Supported only for RichEdit, so this does nothing for Edit\n\tvoid HideSelection(BOOL /*bHide*/ = TRUE, BOOL /*bChangeStyle*/ = FALSE)\n\t{\n\t}\n\n// Operations (overrideable)\n\tBOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tATLASSERT(lpszFind != NULL);\n\t\tATLASSERT(*lpszFind != _T('\\0'));\n\n\t\tUINT nLen = pT->GetBufferLength();\n\t\tint nStartChar = 0, nEndChar = 0;\n\t\tpT->GetSel(nStartChar, nEndChar);\n\t\tUINT nStart = nStartChar;\n\t\tint iDir = bFindDown ? +1 : -1;\n\n\t\t// can't find a match before the first character\n\t\tif((nStart == 0) && (iDir < 0))\n\t\t\treturn FALSE;\n\n\t\tLPCTSTR lpszText = pT->LockBuffer();\n\n\t\tbool isDBCS = false;\n#ifdef _MBCS\n\t\tCPINFO info = { 0 };\n\t\t::GetCPInfo(::GetOEMCP(), &info);\n\t\tisDBCS = (info.MaxCharSize > 1);\n#endif\n\n\t\tif(iDir < 0)\n\t\t{\n\t\t\t// always go back one for search backwards\n\t\t\tnStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));\n\t\t}\n\t\telse if((nStartChar != nEndChar) && (pT->SameAsSelected(lpszFind, bMatchCase, bWholeWord)))\n\t\t{\n\t\t\t// easy to go backward/forward with SBCS\n#ifndef _UNICODE\n\t\t\tif(::IsDBCSLeadByte(lpszText[nStart]))\n\t\t\t\tnStart++;\n#endif\n\t\t\tnStart += iDir;\n\t\t}\n\n\t\t// handle search with nStart past end of buffer\n\t\tUINT nLenFind = ::lstrlen(lpszFind);\n\t\tif((nStart + nLenFind - 1) >= nLen)\n\t\t{\n\t\t\tif((iDir < 0) && (nLen >= nLenFind))\n\t\t\t{\n\t\t\t\tif(isDBCS)\n\t\t\t\t{\n\t\t\t\t\t// walk back to previous character n times\n\t\t\t\t\tnStart = nLen;\n\t\t\t\t\tint n = nLenFind;\n\t\t\t\t\twhile(n--)\n\t\t\t\t\t{\n\t\t\t\t\t\tnStart -= int((lpszText + nStart) - ::CharPrev(lpszText, lpszText + nStart));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// single-byte character set is easy and fast\n\t\t\t\t\tnStart = nLen - nLenFind;\n\t\t\t\t}\n\t\t\t\tATLASSERT((nStart + nLenFind - 1) <= nLen);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpT->UnlockBuffer();\n\t\t\t\treturn FALSE;\n\t\t\t}\n\t\t}\n\n\t\t// start the search at nStart\n\t\tLPCTSTR lpsz = lpszText + nStart;\n\t\ttypedef int (WINAPI* CompareProc)(LPCTSTR str1, LPCTSTR str2);\n\t\tCompareProc pfnCompare = bMatchCase ? lstrcmp : lstrcmpi;\n\n\t\tif(isDBCS)\n\t\t{\n\t\t\t// double-byte string search\n\t\t\tLPCTSTR lpszStop = NULL;\n\t\t\tif(iDir > 0)\n\t\t\t{\n\t\t\t\t// start at current and find _first_ occurrance\n\t\t\t\tlpszStop = lpszText + nLen - nLenFind + 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// start at top and find _last_ occurrance\n\t\t\t\tlpszStop = lpsz;\n\t\t\t\tlpsz = lpszText;\n\t\t\t}\n\n\t\t\tLPCTSTR lpszFound = NULL;\n\t\t\twhile(lpsz <= lpszStop)\n\t\t\t{\n#ifndef _UNICODE\n\t\t\t\tif(!bMatchCase || (*lpsz == *lpszFind && (!::IsDBCSLeadByte(*lpsz) || lpsz[1] == lpszFind[1])))\n#else\n\t\t\t\tif(!bMatchCase || (*lpsz == *lpszFind && lpsz[1] == lpszFind[1]))\n#endif\n\t\t\t\t{\n\t\t\t\t\tLPTSTR lpch = (LPTSTR)(lpsz + nLenFind);\n\t\t\t\t\tTCHAR chSave = *lpch;\n\t\t\t\t\t*lpch = _T('\\0');\n\t\t\t\t\tint nResult = (*pfnCompare)(lpsz, lpszFind);\n\t\t\t\t\t*lpch = chSave;\n\t\t\t\t\tif(nResult == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tlpszFound = lpsz;\n\t\t\t\t\t\tif(iDir > 0)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlpsz = ::CharNext(lpsz);\n\t\t\t}\n\t\t\tpT->UnlockBuffer();\n\n\t\t\tif(lpszFound != NULL)\n\t\t\t{\n\t\t\t\tint n = (int)(lpszFound - lpszText);\n\t\t\t\tpT->SetSel(n, n + nLenFind);\n\t\t\t\treturn TRUE;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// single-byte string search\n\t\t\tUINT nCompare = 0;\n\t\t\tif(iDir < 0)\n\t\t\t\tnCompare = (UINT)(lpsz - lpszText) + 1;\n\t\t\telse\n\t\t\t\tnCompare = nLen - (UINT)(lpsz - lpszText) - nLenFind + 1;\n\n\t\t\twhile(nCompare > 0)\n\t\t\t{\n\t\t\t\tATLASSERT(lpsz >= lpszText);\n\t\t\t\tATLASSERT((lpsz + nLenFind - 1) <= (lpszText + nLen - 1));\n\n\t\t\t\tLPSTR lpch = (LPSTR)(lpsz + nLenFind);\n\t\t\t\tchar chSave = *lpch;\n\t\t\t\t*lpch = '\\0';\n\t\t\t\tint nResult = (*pfnCompare)(lpsz, lpszFind);\n\t\t\t\t*lpch = chSave;\n\t\t\t\tif(nResult == 0)\n\t\t\t\t{\n\t\t\t\t\tpT->UnlockBuffer();\n\t\t\t\t\tint n = (int)(lpsz - lpszText);\n\t\t\t\t\tpT->SetSel(n, n + nLenFind);\n\t\t\t\t\treturn TRUE;\n\t\t\t\t}\n\n\t\t\t\t// restore character at end of search\n\t\t\t\t*lpch = chSave;\n\n\t\t\t\t// move on to next substring\n\t\t\t\tnCompare--;\n\t\t\t\tlpsz += iDir;\n\t\t\t}\n\t\t\tpT->UnlockBuffer();\n\t\t}\n\n\t\treturn FALSE;\n\t}\n\n\tLPCTSTR LockBuffer() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(pT->m_hWnd != NULL);\n\n\t\tBOOL useShadowBuffer = pT->UseShadowBuffer();\n\t\tif(useShadowBuffer)\n\t\t{\n\t\t\tif((m_pShadowBuffer == NULL) || pT->GetModify())\n\t\t\t{\n\t\t\t\tATLASSERT((m_pShadowBuffer != NULL) || (m_nShadowSize == 0));\n\t\t\t\tUINT nSize = pT->GetWindowTextLength() + 1;\n\t\t\t\tif(nSize > m_nShadowSize)\n\t\t\t\t{\n\t\t\t\t\t// need more room for shadow buffer\n\t\t\t\t\tT* pThisNoConst = const_cast<T*>(pT);\n\t\t\t\t\tdelete[] m_pShadowBuffer;\n\t\t\t\t\tpThisNoConst->m_pShadowBuffer = NULL;\n\t\t\t\t\tpThisNoConst->m_nShadowSize = 0;\n\t\t\t\t\tpThisNoConst->m_pShadowBuffer = new TCHAR[nSize];\n\t\t\t\t\tpThisNoConst->m_nShadowSize = nSize;\n\t\t\t\t}\n\n\t\t\t\t// update the shadow buffer with GetWindowText\n\t\t\t\tATLASSERT(m_nShadowSize >= nSize);\n\t\t\t\tATLASSERT(m_pShadowBuffer != NULL);\n\t\t\t\tpT->GetWindowText(m_pShadowBuffer, nSize);\n\t\t\t}\n\n\t\t\treturn m_pShadowBuffer;\n\t\t}\n\n\t\tHLOCAL hLocal = pT->GetHandle();\n\t\tATLASSERT(hLocal != NULL);\n\t\tLPCTSTR lpszText = (LPCTSTR)::LocalLock(hLocal);\n\t\tATLASSERT(lpszText != NULL);\n\n\t\treturn lpszText;\n\t}\n\n\tvoid UnlockBuffer() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(pT->m_hWnd != NULL);\n\n\t\tBOOL useShadowBuffer = pT->UseShadowBuffer();\n\t\tif(!useShadowBuffer)\n\t\t{\n\t\t\tHLOCAL hLocal = pT->GetHandle();\n\t\t\tATLASSERT(hLocal != NULL);\n\t\t\t::LocalUnlock(hLocal);\n\t\t}\n\t}\n\n\tUINT GetBufferLength() const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(pT->m_hWnd != NULL);\n\n\t\tUINT nLen = 0;\n\t\tLPCTSTR lpszText = pT->LockBuffer();\n\t\tif(lpszText != NULL)\n\t\t\tnLen = ::lstrlen(lpszText);\n\t\tpT->UnlockBuffer();\n\n\t\treturn nLen;\n\t}\n\n\tLONG EndOfLine(LPCTSTR lpszText, UINT nLen, UINT nIndex) const\n\t{\n\t\tLPCTSTR lpsz = lpszText + nIndex;\n\t\tLPCTSTR lpszStop = lpszText + nLen;\n\t\twhile(lpsz < lpszStop && *lpsz != _T('\\r'))\n\t\t\t++lpsz;\n\t\treturn LONG(lpsz - lpszText);\n\t}\n\n\tLONG GetSelText(_CSTRING_NS::CString& strText) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\n\t\tint nStartChar = 0, nEndChar = 0;\n\t\tpT->GetSel(nStartChar, nEndChar);\n\t\tATLASSERT((UINT)nEndChar <= pT->GetBufferLength());\n\t\tLPCTSTR lpszText = pT->LockBuffer();\n\t\tLONG nLen = pT->EndOfLine(lpszText, nEndChar, nStartChar) - nStartChar;\n\t\tSecureHelper::memcpy_x(strText.GetBuffer(nLen), nLen * sizeof(TCHAR), lpszText + nStartChar, nLen * sizeof(TCHAR));\n\t\tstrText.ReleaseBuffer(nLen);\n\t\tpT->UnlockBuffer();\n\n\t\treturn nLen;\n\t}\n\n\tBOOL UseShadowBuffer(void) const\n\t{\n\t\tconst T* pT = static_cast<const T*>(this);\n\n\t\tif(pT->m_bShadowBufferNeeded < 0)\n\t\t{\n\t\t\tT* pThisNoConst = const_cast<T*>(pT);\n\n#ifdef _versionhelpers_H_INCLUDED_\n\t\t\tOSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) };\n\t\t\tovi.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;\n\t\t\tDWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL);\n\t\t\tbool bWin9x = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE);\n#else // !_versionhelpers_H_INCLUDED_\n\t\t\tOSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };\n\t\t\t::GetVersionEx(&ovi);\n\n\t\t\tbool bWin9x = (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);\n#endif // _versionhelpers_H_INCLUDED_\n\t\t\tif(bWin9x)\n\t\t\t{\n\t\t\t\t// Windows 95, 98, ME\n\t\t\t\t// Under Win9x, it is necessary to maintain a shadow buffer.\n\t\t\t\t// It is only updated when the control contents have been changed.\n\t\t\t\tpThisNoConst->m_bShadowBufferNeeded = TRUE;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Windows NT, 2000, XP, etc.\n\t\t\t\tpThisNoConst->m_bShadowBufferNeeded = FALSE;\n\n#ifndef _UNICODE\n\t\t\t\t// On Windows XP (or later), if common controls version 6 is in use\n\t\t\t\t// (such as via theming), then EM_GETHANDLE will always return a UNICODE string.\n\t\t\t\t// If theming is enabled and Common Controls version 6 is in use,\n\t\t\t\t// you're really not suppose to superclass or subclass common controls\n\t\t\t\t// with an ANSI windows procedure (so its best to only theme if you use UNICODE).\n\t\t\t\t// Using a shadow buffer uses GetWindowText instead, so it solves\n\t\t\t\t// this problem for us (although it makes it a little less efficient).\n\n#ifdef _versionhelpers_H_INCLUDED_\n\t\t\t\tif(::IsWindowsXPOrGreater())\n#else // !_versionhelpers_H_INCLUDED_\n\t\t\t\tif ((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))\n#endif // _versionhelpers_H_INCLUDED_\n\t\t\t\t{\n\t\t\t\t\tDWORD dwMajor = 0, dwMinor = 0;\n\t\t\t\t\tHRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);\n\t\t\t\t\tif(SUCCEEDED(hRet))\n\t\t\t\t\t{\n\t\t\t\t\t\tif(dwMajor >= 6)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpThisNoConst->m_bShadowBufferNeeded = TRUE;\n\n\t\t\t\t\t\t\tATLTRACE2(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\"));\n\t\t\t\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"If you use common controls version 6 or later, you should only do so for UNICODE builds.\\r\\n\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n#endif // !_UNICODE\n\t\t\t}\n\t\t}\n\n\t\treturn (pT->m_bShadowBufferNeeded != FALSE);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRichEditFindReplaceImpl - Mixin class for implementing Find/Replace for CRichEditCtrl\n// based window classes.\n\n// Chain to CRichEditFindReplaceImpl message map. Your class must also derive from CRichEditCtrl.\n// Example:\n// class CMyRichEdit : public CWindowImpl<CMyRichEdit, CRichEditCtrl>,\n//                     public CRichEditFindReplaceImpl<CMyRichEdit>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyRichEdit)\n//              // your handlers...\n//              CHAIN_MSG_MAP_ALT(CRichEditFindReplaceImpl<CMyRichEdit>, 1)\n//      END_MSG_MAP()\n//      // other stuff...\n// };\n\ntemplate <class T, class TFindReplaceDialog = CFindReplaceDialog>\nclass CRichEditFindReplaceImpl : public CEditFindReplaceImplBase<T, TFindReplaceDialog>\n{\nprotected:\n\ttypedef CRichEditFindReplaceImpl<T, TFindReplaceDialog> thisClass;\n\ttypedef CEditFindReplaceImplBase<T, TFindReplaceDialog> baseClass;\n\npublic:\n\tBEGIN_MSG_MAP(thisClass)\n\tALT_MSG_MAP(1)\n\t\tCHAIN_MSG_MAP_ALT(baseClass, 1)\n\tEND_MSG_MAP()\n\n// Operations (overrideable)\n\tBOOL FindTextSimple(LPCTSTR lpszFind, BOOL bMatchCase, BOOL bWholeWord, BOOL bFindDown = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tATLASSERT(lpszFind != NULL);\n\t\tFINDTEXTEX ft = { 0 };\n\n\t\tpT->GetSel(ft.chrg);\n\t\tif(m_bFirstSearch)\n\t\t{\n\t\t\tif(bFindDown)\n\t\t\t\tm_nInitialSearchPos = ft.chrg.cpMin;\n\t\t\telse\n\t\t\t\tm_nInitialSearchPos = ft.chrg.cpMax;\n\t\t\tm_bFirstSearch = FALSE;\n\t\t}\n\n#if (_RICHEDIT_VER >= 0x0200)\n\t\tft.lpstrText = (LPTSTR)lpszFind;\n#else // !(_RICHEDIT_VER >= 0x0200)\n\t\tUSES_CONVERSION;\n\t\tft.lpstrText = T2A((LPTSTR)lpszFind);\n#endif // !(_RICHEDIT_VER >= 0x0200)\n\n\t\tif(ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection\n\t\t{\n\t\t\tif(bFindDown)\n\t\t\t{\n\t\t\t\tft.chrg.cpMin++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// won't wraparound backwards\n\t\t\t\tft.chrg.cpMin = __max(ft.chrg.cpMin, 0);\n\t\t\t}\n\t\t}\n\n\t\tDWORD dwFlags = bMatchCase ? FR_MATCHCASE : 0;\n\t\tdwFlags |= bWholeWord ? FR_WHOLEWORD : 0;\n\n\t\tft.chrg.cpMax = pT->GetTextLength() + m_nInitialSearchPos;\n\n\t\tif(bFindDown)\n\t\t{\n\t\t\tif(m_nInitialSearchPos >= 0)\n\t\t\t\tft.chrg.cpMax = pT->GetTextLength();\n\n\t\t\tdwFlags |= FR_DOWN;\n\t\t\tATLASSERT(ft.chrg.cpMax >= ft.chrg.cpMin);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(m_nInitialSearchPos >= 0)\n\t\t\t\tft.chrg.cpMax = 0;\n\n\t\t\tdwFlags &= ~FR_DOWN;\n\t\t\tATLASSERT(ft.chrg.cpMax <= ft.chrg.cpMin);\n\t\t}\n\n\t\tBOOL bRet = FALSE;\n\t\tif(pT->FindAndSelect(dwFlags, ft) != -1)\n\t\t{\n\t\t\tbRet = TRUE;   // we found the text\n\t\t}\n\t\telse if(m_nInitialSearchPos > 0)\n\t\t{\n\t\t\t// if the original starting point was not the beginning\n\t\t\t// of the buffer and we haven't already been here\n\t\t\tif(bFindDown)\n\t\t\t{\n\t\t\t\tft.chrg.cpMin = 0;\n\t\t\t\tft.chrg.cpMax = m_nInitialSearchPos;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tft.chrg.cpMin = pT->GetTextLength();\n\t\t\t\tft.chrg.cpMax = m_nInitialSearchPos;\n\t\t\t}\n\t\t\tm_nInitialSearchPos = m_nInitialSearchPos - pT->GetTextLength();\n\n\t\t\tbRet = (pT->FindAndSelect(dwFlags, ft) != -1) ? TRUE : FALSE;\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tlong FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLONG index = pT->FindText(dwFlags, ft);\n\t\tif(index != -1) // i.e. we found something\n\t\t\tpT->SetSel(ft.chrgText);\n\n\t\treturn index;\n\t}\n};\n\n}; // namespace WTL\n\n#endif // __ATLFIND_H__\n"
  },
  {
    "path": "WTL/atlframe.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLFRAME_H__\n#define __ATLFRAME_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlframe.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlframe.h requires atlwin.h to be included first\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CFrameWindowImpl<T, TBase, TWinTraits>\n// CMDIWindow\n// CMDIFrameWindowImpl<T, TBase, TWinTraits>\n// CMDIChildWindowImpl<T, TBase, TWinTraits>\n// COwnerDraw<T>\n// CUpdateUIBase\n// CUpdateUI<T>\n// CDynamicUpdateUI<T>\n// CAutoUpdateUI<T>\n// CDialogResize<T>\n// CDoubleBufferImpl<T>\n// CDoubleBufferWindowImpl<T, TBase, TWinTraits>\n//\n// Global functions:\n//   AtlCreateSimpleToolBar()\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CFrameWndClassInfo - Manages frame window Windows class information\n\nclass CFrameWndClassInfo\n{\npublic:\n#ifndef _WIN32_WCE\n\tenum { cchAutoName = 5 + sizeof(void*) * 2 };   // sizeof(void*) * 2 is the number of digits %p outputs\n\tWNDCLASSEX m_wc;\n#else // CE specific\n\tenum { cchAutoName = MAX_PATH };   // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string.\n\tWNDCLASS m_wc;\n#endif // !_WIN32_WCE\n\tLPCTSTR m_lpszOrigName;\n\tWNDPROC pWndProc;\n\tLPCTSTR m_lpszCursorID;\n\tBOOL m_bSystemCursor;\n\tATOM m_atom;\n\tTCHAR m_szAutoName[cchAutoName];\n\tUINT m_uCommonResourceID;\n\n#ifndef _WIN32_WCE\n\tATOM Register(WNDPROC* pProc)\n\t{\n\t\tif (m_atom == 0)\n\t\t{\n\t\t\tCWindowCreateCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(m_atom == 0)\n\t\t\t{\n\t\t\t\tHINSTANCE hInst = ModuleHelper::GetModuleInstance();\n\n\t\t\t\tif (m_lpszOrigName != NULL)\n\t\t\t\t{\n\t\t\t\t\tATLASSERT(pProc != NULL);\n\t\t\t\t\tLPCTSTR lpsz = m_wc.lpszClassName;\n\t\t\t\t\tWNDPROC proc = m_wc.lpfnWndProc;\n\n\t\t\t\t\tWNDCLASSEX wc = { sizeof(WNDCLASSEX) };\n\t\t\t\t\t// try process local class first\n\t\t\t\t\tif(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))\n\t\t\t\t\t{\n\t\t\t\t\t\t// try global class\n\t\t\t\t\t\tif(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlock.Unlock();\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm_wc = wc;\n\t\t\t\t\tpWndProc = m_wc.lpfnWndProc;\n\t\t\t\t\tm_wc.lpszClassName = lpsz;\n\t\t\t\t\tm_wc.lpfnWndProc = proc;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tm_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);\n\t\t\t\t}\n\n\t\t\t\tm_wc.hInstance = hInst;\n\t\t\t\tm_wc.style &= ~CS_GLOBALCLASS;   // we don't register global classes\n\t\t\t\tif (m_wc.lpszClassName == NULL)\n\t\t\t\t{\n#if (_WIN32_WINNT >= 0x0500) || defined(_WIN64)\n\t\t\t\t\tSecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T(\"ATL:%p\"), &m_wc);\n#else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))\n\t\t\t\t\tSecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T(\"ATL:%8.8X\"), (DWORD_PTR)&m_wc);\n#endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))\n\t\t\t\t\tm_wc.lpszClassName = m_szAutoName;\n\t\t\t\t}\n\n\t\t\t\tWNDCLASSEX wcTemp = m_wc;\n\t\t\t\tm_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);\n\t\t\t\tif (m_atom == 0)\n\t\t\t\t{\n\t\t\t\t\tif(m_uCommonResourceID != 0)   // use it if not zero\n\t\t\t\t\t{\n\t\t\t\t\t\tm_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), \n\t\t\t\t\t\t\tMAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, \n\t\t\t\t\t\t\t::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);\n\t\t\t\t\t\tm_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), \n\t\t\t\t\t\t\tMAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, \n\t\t\t\t\t\t\t::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);\n\t\t\t\t\t}\n\t\t\t\t\tm_atom = ::RegisterClassEx(&m_wc);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlock.Unlock();\n\t\t}\n\n\t\tif (m_lpszOrigName != NULL)\n\t\t{\n\t\t\tATLASSERT(pProc != NULL);\n\t\t\tATLASSERT(pWndProc != NULL);\n\t\t\t*pProc = pWndProc;\n\t\t}\n\n\t\treturn m_atom;\n\t}\n#else // CE specific\n\tATOM Register(WNDPROC* pProc)\n\t{\n\t\tif (m_atom == 0)\n\t\t{\n\t\t\tCWindowCreateCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(m_atom == 0)\n\t\t\t{\n\t\t\t\tHINSTANCE hInst = ModuleHelper::GetModuleInstance();\n\n\t\t\t\tif (m_lpszOrigName != NULL)\n\t\t\t\t{\n\t\t\t\t\tATLASSERT(pProc != NULL);\n\t\t\t\t\tLPCTSTR lpsz = m_wc.lpszClassName;\n\t\t\t\t\tWNDPROC proc = m_wc.lpfnWndProc;\n\n\t\t\t\t\tWNDCLASS wc = { 0 };\n\t\t\t\t\t// try process local class first\n\t\t\t\t\tif(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))\n\t\t\t\t\t{\n\t\t\t\t\t\t// try global class\n\t\t\t\t\t\tif(!::GetClassInfo(NULL, m_lpszOrigName, &wc))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlock.Unlock();\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tm_wc = wc;\n\t\t\t\t\tpWndProc = m_wc.lpfnWndProc;\n\t\t\t\t\tm_wc.lpszClassName = lpsz;\n\t\t\t\t\tm_wc.lpfnWndProc = proc;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if defined(GWES_CURSOR) || defined(GWES_MCURSOR)\n\t\t\t\t\tm_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);\n#else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))\n\t\t\t\t\tm_wc.hCursor = NULL;\n#endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))\n\t\t\t\t}\n\n\t\t\t\tm_wc.hInstance = hInst;\n\t\t\t\tm_wc.style &= ~CS_GLOBALCLASS;   // we don't register global classes\n\t\t\t\tif (m_wc.lpszClassName == NULL)\n\t\t\t\t{\n\t\t\t\t\twsprintf(m_szAutoName, _T(\"ATL:%8.8X\"), (DWORD_PTR)&m_wc);\n\t\t\t\t\tm_wc.lpszClassName = m_szAutoName;\n\t\t\t\t}\n\n\t\t\t\tWNDCLASS wcTemp = m_wc;\n\t\t\t\tm_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);\n\t\t\t\tif (m_atom == 0)\n\t\t\t\t{\n\t\t\t\t\tif(m_uCommonResourceID != 0)   // use it if not zero\n\t\t\t\t\t\tm_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), \n\t\t\t\t\t\t\tMAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, \n\t\t\t\t\t\t\t::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);\n\t\t\t\t\tm_atom = ::RegisterClass(&m_wc);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlock.Unlock();\n\t\t}\n\n\t\tif (m_lpszOrigName != NULL)\n\t\t{\n\t\t\tATLASSERT(pProc != NULL);\n\t\t\tATLASSERT(pWndProc != NULL);\n\t\t\t*pProc = pWndProc;\n\t\t}\n\n\t\treturn m_atom;\n\t}\n#endif // _WIN32_WCE\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Macros for declaring frame window WNDCLASS\n\n#ifndef _WIN32_WCE\n\n#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ sizeof(WNDCLASSEX), 0, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \\\n\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ sizeof(WNDCLASSEX), style, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \\\n\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ sizeof(WNDCLASSEX), 0, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \\\n\t\tOrigWndClassName, NULL, NULL, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#else // CE specific\n\n#define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ 0, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \\\n\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ style, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \\\n\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \\\nstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n{ \\\n\tstatic WTL::CFrameWndClassInfo wc = \\\n\t{ \\\n\t\t{ NULL, StartWindowProc, \\\n\t\t  0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \\\n\t\tOrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t}; \\\n\treturn wc; \\\n}\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFrameWindowImpl\n\n// Client window command chaining macro (only for frame windows)\n#define CHAIN_CLIENT_COMMANDS() \\\n\tif(uMsg == WM_COMMAND && m_hWndClient != NULL) \\\n\t\t::SendMessage(m_hWndClient, uMsg, wParam, lParam);\n\n// standard toolbar styles\n#define ATL_SIMPLE_TOOLBAR_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)\n// toolbar in a rebar pane\n#define ATL_SIMPLE_TOOLBAR_PANE_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)\n// standard rebar styles\n#if (_WIN32_IE >= 0x0400)\n  #define ATL_SIMPLE_REBAR_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)\n#else\n  #define ATL_SIMPLE_REBAR_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS)\n#endif // !(_WIN32_IE >= 0x0400)\n// rebar without borders\n#if (_WIN32_IE >= 0x0400)\n  #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)\n#else\n  #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \\\n\t(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER)\n#endif // !(_WIN32_IE >= 0x0400)\n\n// command bar support\n#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)\n\n#define CBRM_GETCMDBAR\t\t\t(WM_USER + 301) // returns command bar HWND\n#define CBRM_GETMENU\t\t\t(WM_USER + 302) // returns loaded or attached menu\n#define CBRM_TRACKPOPUPMENU\t\t(WM_USER + 303) // displays a popup menu\n\nstruct _AtlFrameWnd_CmdBarPopupMenu\n{\n\tint cbSize;\n\tHMENU hMenu;\n\tUINT uFlags;\n\tint x;\n\tint y;\n\tLPTPMPARAMS lptpm;\n};\n\n#define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu\n\n#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)\n\n\ntemplate <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>\nclass ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits >\n{\npublic:\n\tDECLARE_FRAME_WND_CLASS(NULL, 0)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tstruct _ChevronMenuInfo\n\t{\n\t\tHMENU hMenu;\n\t\tLPNMREBARCHEVRON lpnm;\n\t\tbool bCmdBar;\n\t};\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\n// Data members\n\tHWND m_hWndToolBar;\n\tHWND m_hWndStatusBar;\n\tHWND m_hWndClient;\n\n#ifdef _WIN32_WCE\n\tHWND m_hWndCECommandBar;\n#endif // _WIN32_WCE\n\n\tHACCEL m_hAccel;\n\n// Constructor\n\tCFrameWindowImplBase() : \n\t\tm_hWndToolBar(NULL), \n\t\tm_hWndStatusBar(NULL), \n\t\tm_hWndClient(NULL), \n#ifdef _WIN32_WCE\n\t\tm_hWndCECommandBar(NULL),\n#endif // _WIN32_WCE\n\t\tm_hAccel(NULL)\n\t{ }\n\n// Methods\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)\n\t{\n\t\tATLASSERT(m_hWnd == NULL);\n\n#if (_ATL_VER >= 0x0800)\n\t\t// Allocate the thunk structure here, where we can fail gracefully.\n\t\tBOOL bRet = m_thunk.Init(NULL, NULL);\n\t\tif(bRet == FALSE)\n\t\t{\n\t\t\t::SetLastError(ERROR_OUTOFMEMORY);\n\t\t\treturn NULL;\n\t\t}\n#endif // (_ATL_VER >= 0x0800)\n\n\t\tif(atom == 0)\n\t\t\treturn NULL;\n\n\t\tModuleHelper::AddCreateWndData(&m_thunk.cd, this);\n\n\t\tif(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD))\n\t\t\tMenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;\n\t\tif(rect.m_lpRect == NULL)\n\t\t\trect.m_lpRect = &TBase::rcDefault;\n\n\t\tHWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,\n\t\t\tdwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,\n\t\t\trect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,\n\t\t\tModuleHelper::GetModuleInstance(), lpCreateParam);\n\n\t\tATLASSERT(hWnd == NULL || m_hWnd == hWnd);\n\n\t\treturn hWnd;\n\t}\n\n\tstatic HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, \n\t\t\tDWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tHINSTANCE hInst = ModuleHelper::GetResourceInstance();\n\t\tHRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);\n\t\tif (hRsrc == NULL)\n\t\t\treturn NULL;\n\n\t\tHGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);\n\t\tif (hGlobal == NULL)\n\t\t\treturn NULL;\n\n\t\t_AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);\n\t\tif (pData == NULL)\n\t\t\treturn NULL;\n\t\tATLASSERT(pData->wVersion == 1);\n\n\t\tWORD* pItems = pData->items();\n\t\tint nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);\n\t\tCTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tTBBUTTON* pTBBtn = buff.Allocate(nItems);\n\t\tATLASSERT(pTBBtn != NULL);\n\t\tif(pTBBtn == NULL)\n\t\t\treturn NULL;\n\n\t\tconst int cxSeparator = 8;\n\n\t\t// set initial separator (half width)\n\t\tif(bInitialSeparator)\n\t\t{\n\t\t\tpTBBtn[0].iBitmap = cxSeparator / 2;\n\t\t\tpTBBtn[0].idCommand = 0;\n\t\t\tpTBBtn[0].fsState = 0;\n\t\t\tpTBBtn[0].fsStyle = BTNS_SEP;\n\t\t\tpTBBtn[0].dwData = 0;\n\t\t\tpTBBtn[0].iString = 0;\n\t\t}\n\n\t\tint nBmp = 0;\n\t\tfor(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)\n\t\t{\n\t\t\tif(pItems[i] != 0)\n\t\t\t{\n\t\t\t\tpTBBtn[j].iBitmap = nBmp++;\n\t\t\t\tpTBBtn[j].idCommand = pItems[i];\n\t\t\t\tpTBBtn[j].fsState = TBSTATE_ENABLED;\n\t\t\t\tpTBBtn[j].fsStyle = BTNS_BUTTON;\n\t\t\t\tpTBBtn[j].dwData = 0;\n\t\t\t\tpTBBtn[j].iString = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpTBBtn[j].iBitmap = cxSeparator;\n\t\t\t\tpTBBtn[j].idCommand = 0;\n\t\t\t\tpTBBtn[j].fsState = 0;\n\t\t\t\tpTBBtn[j].fsStyle = BTNS_SEP;\n\t\t\t\tpTBBtn[j].dwData = 0;\n\t\t\t\tpTBBtn[j].iString = 0;\n\t\t\t}\n\t\t}\n\n#ifndef _WIN32_WCE\n\t\tHWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);\n\t\tif(hWnd == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn NULL;\n\t\t}\n#else // CE specific\n\t\tdwStyle;\n\t\tnID;\n\t\t// The toolbar must go onto the existing CommandBar or MenuBar\n\t\tHWND hWnd = hWndParent;\n#endif // _WIN32_WCE\n\n\t\t::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);\n\n\t\t// check if font is taller than our bitmaps\n\t\tCFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);\n\t\tif(font.IsNull())\n\t\t\tfont = (HFONT)::GetStockObject(SYSTEM_FONT);\n\t\tLOGFONT lf = { 0 };\n\t\tfont.GetLogFont(lf);\n\t\tWORD cyFontHeight = (WORD)abs(lf.lfHeight);\n\n#ifndef _WIN32_WCE\n\t\tWORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID);\n\t\tif(bitsPerPixel > 4)\n\t\t{\n\t\t\tCOLORREF crMask = CLR_DEFAULT;\n\t\t\tif(bitsPerPixel == 32)\n\t\t\t{\n\t\t\t\t// 32-bit color bitmap with alpha channel (valid for Windows XP and later)\n\t\t\t\tcrMask = CLR_NONE;\n\t\t\t}\n\t\t\tHIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);\n\t\t\tATLASSERT(hImageList != NULL);\n\t\t\t::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList);\n\t\t}\n\t\telse\n#endif // !_WIN32_WCE\n\t\t{\n\t\t\tTBADDBITMAP tbab = { 0 };\n\t\t\ttbab.hInst = hInst;\n\t\t\ttbab.nID = nResourceID;\n\t\t\t::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);\n\t\t}\n\n\t\t::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);\n\t\t::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight)));\n\t\tconst int cxyButtonMargin = 7;\n\t\t::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin));\n\n\t\treturn hWnd;\n\t}\n\n#ifndef _WIN32_WCE\n\tstatic HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\t// Ensure style combinations for proper rebar painting\n\t\tif(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER)\n\t\t\tdwStyle &= ~WS_BORDER;\n\t\telse if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))\n\t\t\tdwStyle |= CCS_NODIVIDER;\n\n\t\t// Create rebar window\n\t\tHWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);\n\t\tif(hWndReBar == NULL)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Failed to create rebar.\\n\"));\n\t\t\treturn NULL;\n\t\t}\n\n\t\t// Initialize and send the REBARINFO structure\n\t\tREBARINFO rbi = { sizeof(REBARINFO), 0 };\n\t\tif(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Failed to initialize rebar.\\n\"));\n\t\t\t::DestroyWindow(hWndReBar);\n\t\t\treturn NULL;\n\t\t}\n\n\t\treturn hWndReBar;\n\t}\n\n\tBOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tATLASSERT(!::IsWindow(m_hWndToolBar));\n\t\tm_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID);\n\t\treturn (m_hWndToolBar != NULL);\n\t}\n\n\tstatic BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(hWndReBar));   // must be already created\n#ifdef _DEBUG\n\t\t// block - check if this is really a rebar\n\t\t{\n\t\t\tTCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 };\n\t\t\t::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));\n\t\t\tATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);\n\t\t}\n#endif // _DEBUG\n\t\tATLASSERT(::IsWindow(hWndBand));   // must be already created\n\n\t\t// Get number of buttons on the toolbar\n\t\tint nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);\n\n\t\t// Set band info structure\n\t\tREBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };\n#if (_WIN32_IE >= 0x0400)\n\t\trbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;\n#else\n\t\trbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE;\n#endif // !(_WIN32_IE >= 0x0400)\n\t\tif(lpstrTitle != NULL)\n\t\t\trbBand.fMask |= RBBIM_TEXT;\n\t\trbBand.fStyle = RBBS_CHILDEDGE;\n#if (_WIN32_IE >= 0x0500)\n\t\tif(nBtnCount > 0)   // add chevron style for toolbar with buttons\n\t\t\trbBand.fStyle |= RBBS_USECHEVRON;\n#endif // (_WIN32_IE >= 0x0500)\n\t\tif(bNewRow)\n\t\t\trbBand.fStyle |= RBBS_BREAK;\n\n\t\trbBand.lpText = (LPTSTR)lpstrTitle;\n\t\trbBand.hwndChild = hWndBand;\n\t\tif(nID == 0)   // calc band ID\n\t\t\tnID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);\n\t\trbBand.wID = nID;\n\n\t\t// Calculate the size of the band\n\t\tBOOL bRet = FALSE;\n\t\tRECT rcTmp = { 0 };\n\t\tif(nBtnCount > 0)\n\t\t{\n\t\t\tbRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);\n\t\t\tATLASSERT(bRet);\n\t\t\trbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;\n\t\t\trbBand.cyMinChild = rcTmp.bottom - rcTmp.top;\n\t\t\tif(bFullWidthAlways)\n\t\t\t{\n\t\t\t\trbBand.cxMinChild = rbBand.cx;\n\t\t\t}\n\t\t\telse if(lpstrTitle == NULL)\n\t\t\t{\n\t\t\t\tbRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t\trbBand.cxMinChild = rcTmp.right;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\trbBand.cxMinChild = 0;\n\t\t\t}\n\t\t}\n\t\telse\t// no buttons, either not a toolbar or really has no buttons\n\t\t{\n\t\t\tbRet = ::GetWindowRect(hWndBand, &rcTmp);\n\t\t\tATLASSERT(bRet);\n\t\t\trbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);\n\t\t\trbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0;\n\t\t\trbBand.cyMinChild = rcTmp.bottom - rcTmp.top;\n\t\t}\n\n#if (_WIN32_IE >= 0x0400)\n\t\trbBand.cxIdeal = rbBand.cx;\n#endif // (_WIN32_IE >= 0x0400)\n\n\t\t// Add the band\n\t\tLRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);\n\t\tif(lRes == 0)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Failed to add a band to the rebar.\\n\"));\n\t\t\treturn FALSE;\n\t\t}\n\n#if (_WIN32_IE >= 0x0501)\n\t\tDWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L);\n\t\t::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS);\n#endif // (_WIN32_IE >= 0x0501)\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndToolBar));   // must be an existing rebar\n\t\tATLASSERT(::IsWindow(hWndBand));        // must be created\n\t\treturn AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);\n\t}\n\n#if (_WIN32_IE >= 0x0400)\n\tvoid SizeSimpleReBarBands()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndToolBar));   // must be an existing rebar\n\n\t\tint nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);\n\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tREBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };\n\t\t\trbBand.fMask = RBBIM_SIZE;\n\t\t\tBOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);\n\t\t\tATLASSERT(bRet);\n\t\t\tRECT rect = { 0 };\n\t\t\t::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);\n\t\t\trbBand.cx += rect.left + rect.right;\n\t\t\tbRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);\n\t\t\tATLASSERT(bRet);\n\t\t}\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n#endif // _WIN32_WCE\n\n#ifndef _WIN32_WCE\n\tBOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)\n#else // CE specific\n\tBOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)\n#endif // _WIN32_WCE\n\t{\n\t\tATLASSERT(!::IsWindow(m_hWndStatusBar));\n\t\tm_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);\n\t\treturn (m_hWndStatusBar != NULL);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)\n#else // CE specific\n\tBOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)\n#endif // _WIN32_WCE\n\t{\n\t\tconst int cchMax = 128;   // max text length is 127 for status bars (+1 for null)\n\t\tTCHAR szText[cchMax] = { 0 };\n\t\t::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);\n\t\treturn CreateSimpleStatusBar(szText, dwStyle, nID);\n\t}\n\n#ifdef _WIN32_WCE\n\tBOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1)\n\t{\n\t\tATLASSERT(m_hWndCECommandBar == NULL);\n\t\tATLASSERT(m_hWndToolBar == NULL);\n\n\t\tm_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID);\n\t\tif(m_hWndCECommandBar == NULL)\n\t\t\treturn FALSE;\n\n\t\tm_hWndToolBar = m_hWndCECommandBar;\n\n\t\tBOOL bRet = TRUE;\n\n\t\tif(pszMenu != NULL)\n\t\t\tbRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton);\n\n\t\tbRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0);\n\n\t\treturn bRet;\n\t}\n\n#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)\n\tBOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0)\n\t{\n\t\tATLASSERT(m_hWndCECommandBar == NULL);\n\n\t\tSHMENUBARINFO mbi = { 0 };\n\t\tmbi.cbSize = sizeof(mbi);\n\t\tmbi.hwndParent = m_hWnd;\n\t\tmbi.dwFlags = dwFlags;\n\t\tmbi.nToolBarId = nToolBarId;\n\t\tmbi.hInstRes  = ModuleHelper::GetResourceInstance();\n\t\tmbi.nBmpId = nBmpId;\n\t\tmbi.cBmpImages = cBmpImages;\n\t\tmbi.hwndMB = NULL;   // This gets set by SHCreateMenuBar\n\n\t\tBOOL bRet = ::SHCreateMenuBar(&mbi);\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tm_hWndCECommandBar = mbi.hwndMB;\n\t\t\tSizeToMenuBar();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tvoid SizeToMenuBar()   // for menu bar only\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(::IsWindow(m_hWndCECommandBar));\n\n\t\tRECT rect = { 0 };\n\t\tGetWindowRect(&rect);\n\t\tRECT rectMB = { 0 };\n\t\t::GetWindowRect(m_hWndCECommandBar, &rectMB);\n\t\tint cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top;\n\t\tSetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE);\n\t}\n#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)\n#endif // _WIN32_WCE\n\n\tvoid UpdateLayout(BOOL bResizeBars = TRUE)\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\n\t\t// position bars and offset their dimensions\n\t\tUpdateBarsPosition(rect, bResizeBars);\n\n\t\t// resize client window\n\t\tif(m_hWndClient != NULL)\n\t\t\t::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,\n\t\t\t\trect.right - rect.left, rect.bottom - rect.top,\n\t\t\t\tSWP_NOZORDER | SWP_NOACTIVATE);\n\t}\n\n\tvoid UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)\n\t{\n\t\t// resize toolbar\n\t\tif(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))\n\t\t{\n\t\t\tif(bResizeBars != FALSE)\n\t\t\t{\n\t\t\t\t::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);\n\t\t\t\t::InvalidateRect(m_hWndToolBar, NULL, TRUE);\n\t\t\t}\n\t\t\tRECT rectTB = { 0 };\n\t\t\t::GetWindowRect(m_hWndToolBar, &rectTB);\n\t\t\trect.top += rectTB.bottom - rectTB.top;\n\t\t}\n\n\t\t// resize status bar\n\t\tif(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))\n\t\t{\n\t\t\tif(bResizeBars != FALSE)\n\t\t\t\t::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);\n\t\t\tRECT rectSB = { 0 };\n\t\t\t::GetWindowRect(m_hWndStatusBar, &rectSB);\n\t\t\trect.bottom -= rectSB.bottom - rectSB.top;\n\t\t}\n\t}\n\n\tBOOL PreTranslateMessage(MSG* pMsg)\n\t{\n\t\tif(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))\n\t\t\treturn TRUE;\n\t\treturn FALSE;\n\t}\n\n\tBEGIN_MSG_MAP(CFrameWindowImplBase)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n#ifndef _WIN32_WCE\n\t\tNOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)\n\t\tNOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)\n#endif // !_WIN32_WCE\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_hWndClient != NULL)   // view will paint itself instead\n\t\t\treturn 1;\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n\n\t\tif(m_hWndStatusBar == NULL)\n\t\t\treturn 1;\n\n\t\tWORD wFlags = HIWORD(wParam);\n\t\tif(wFlags == 0xFFFF && lParam == NULL)   // menu closing\n\t\t{\n\t\t\t::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst int cchBuff = 256;\n\t\t\tTCHAR szBuff[cchBuff] = { 0 };\n\t\t\tif(!(wFlags & MF_POPUP))\n\t\t\t{\n\t\t\t\tWORD wID = LOWORD(wParam);\n\t\t\t\t// check for special cases\n\t\t\t\tif(wID >= 0xF000 && wID < 0xF1F0)   // system menu IDs\n\t\t\t\t\twID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);\n\t\t\t\telse if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST)   // MRU items\n\t\t\t\t\twID = ATL_IDS_MRU_FILE;\n\t\t\t\telse if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD)   // MDI child windows\n\t\t\t\t\twID = ATL_IDS_MDICHILD;\n\n\t\t\t\tint nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff);\n\t\t\t\tfor(int i = 0; i < nRet; i++)\n\t\t\t\t{\n\t\t\t\t\tif(szBuff[i] == _T('\\n'))\n\t\t\t\t\t{\n\t\t\t\t\t\tszBuff[i] = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);\n\t\t\t::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);\n\t\t}\n\n\t\treturn 1;\n\t}\n#endif // !_WIN32_WCE\n\n\tLRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)\n\t{\n\t\tif(m_hWndClient != NULL)\n\t\t\t::SetFocus(m_hWndClient);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)\n\t{\n\t\tif((GetStyle() & (WS_CHILD | WS_POPUP)) == 0)\n\t\t\t::PostQuitMessage(1);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tLPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;\n\t\tif((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))\n\t\t{\n\t\t\tconst int cchBuff = 256;\n\t\t\tchar szBuff[cchBuff] = { 0 };\n\t\t\tint nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);\n\t\t\tfor(int i = 0; i < nRet; i++)\n\t\t\t{\n\t\t\t\tif(szBuff[i] == '\\n')\n\t\t\t\t{\n\t\t\t\t\tSecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n#if (_WIN32_IE >= 0x0300)\n\t\t\tif(nRet > 0)   // string was loaded, save it\n\t\t\t\tpDispInfo->uFlags |= TTF_DI_SETITEM;\n#endif // (_WIN32_IE >= 0x0300)\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)\n\t{\n\t\tLPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;\n\t\tif((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))\n\t\t{\n\t\t\tconst int cchBuff = 256;\n\t\t\twchar_t szBuff[cchBuff] = { 0 };\n\t\t\tint nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);\n\t\t\tfor(int i = 0; i < nRet; i++)\n\t\t\t{\n\t\t\t\tif(szBuff[i] == L'\\n')\n\t\t\t\t{\n\t\t\t\t\tSecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n#if (_WIN32_IE >= 0x0300)\n\t\t\tif(nRet > 0)   // string was loaded, save it\n\t\t\t\tpDispInfo->uFlags |= TTF_DI_SETITEM;\n#endif // (_WIN32_IE >= 0x0300)\n\t\t}\n\n\t\treturn 0;\n\t}\n#endif // !_WIN32_WCE\n\n// Implementation - chevron menu support\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tbool PrepareChevronMenu(_ChevronMenuInfo& cmi)\n\t{\n\t\t// get rebar and toolbar\n\t\tREBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };\n\t\trbbi.fMask = RBBIM_CHILD;\n\t\tBOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);\n\t\tATLASSERT(bRet);\n\n\t\t// assume the band is a toolbar\n\t\tATL::CWindow wnd = rbbi.hwndChild;\n\t\tint nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);\n\t\tif(nCount <= 0)   // probably not a toolbar\n\t\t\treturn false;\n\n\t\t// check if it's a command bar\n\t\tCMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);\n\t\tcmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);\n\n\t\t// build a menu from hidden items\n\t\tCMenuHandle menu;\n\t\tbRet = menu.CreatePopupMenu();\n\t\tATLASSERT(bRet);\n\t\tRECT rcClient = { 0 };\n\t\tbRet = wnd.GetClientRect(&rcClient);\n\t\tATLASSERT(bRet);\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tTBBUTTON tbb = { 0 };\n\t\t\tbRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);\n\t\t\tATLASSERT(bRet);\n\t\t\t// skip hidden buttons\n\t\t\tif((tbb.fsState & TBSTATE_HIDDEN) != 0)\n\t\t\t\tcontinue;\n\t\t\tRECT rcButton = { 0 };\n\t\t\tbRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);\n\t\t\tATLASSERT(bRet);\n\t\t\tbool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);\n\t\t\tif((rcButton.right > rcClient.right) || (rcButton.bottom > rcClient.bottom))\n\t\t\t{\n\t\t\t\tif(tbb.fsStyle & BTNS_SEP)\n\t\t\t\t{\n\t\t\t\t\tif(menu.GetMenuItemCount() > 0)\n\t\t\t\t\t\tmenu.AppendMenu(MF_SEPARATOR);\n\t\t\t\t}\n\t\t\t\telse if(cmi.bCmdBar)\n\t\t\t\t{\n\t\t\t\t\tconst int cchBuff = 200;\n\t\t\t\t\tTCHAR szBuff[cchBuff] = { 0 };\n\t\t\t\t\tCMenuItemInfo mii;\n\t\t\t\t\tmii.fMask = MIIM_TYPE | MIIM_SUBMENU;\n\t\t\t\t\tmii.dwTypeData = szBuff;\n\t\t\t\t\tmii.cch = cchBuff;\n\t\t\t\t\tbRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t\t// Note: CmdBar currently supports only drop-down items\n\t\t\t\t\tATLASSERT(::IsMenu(mii.hSubMenu));\n\t\t\t\t\tbRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// get button's text\n\t\t\t\t\tconst int cchBuff = 200;\n\t\t\t\t\tTCHAR szBuff[cchBuff] = { 0 };\n\t\t\t\t\tLPCTSTR lpstrText = szBuff;\n\t\t\t\t\tTBBUTTONINFO tbbi = { 0 };\n\t\t\t\t\ttbbi.cbSize = sizeof(TBBUTTONINFO);\n\t\t\t\t\ttbbi.dwMask = TBIF_TEXT;\n\t\t\t\t\ttbbi.pszText = szBuff;\n\t\t\t\t\ttbbi.cchText = cchBuff;\n\t\t\t\t\tif((wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1) || (szBuff[0] == 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t// no text for this button, try a resource string\n\t\t\t\t\t\tlpstrText = _T(\"\");\n\t\t\t\t\t\tint nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff);\n\t\t\t\t\t\tfor(int n = 0; n < nRet; n++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(szBuff[n] == _T('\\n'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlpstrText = &szBuff[n + 1];\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(menu.GetMenuItemCount() == 0)   // no hidden buttons after all\n\t\t{\n\t\t\tmenu.DestroyMenu();\n\t\t\t::MessageBeep((UINT)-1);\n\t\t\treturn false;\n\t\t}\n\n\t\tcmi.hMenu = menu;\n\t\treturn true;\n\t}\n\n\tvoid DisplayChevronMenu(_ChevronMenuInfo& cmi)\n\t{\n#ifndef TPM_VERPOSANIMATION\n\t\tconst UINT TPM_VERPOSANIMATION = 0x1000L;   // Menu animation flag\n#endif\n\t\t// convert chevron rect to screen coordinates\n\t\tATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;\n\t\tPOINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom };\n\t\twndFrom.MapWindowPoints(NULL, &pt, 1);\n\t\tRECT rc = cmi.lpnm->rc;\n\t\twndFrom.MapWindowPoints(NULL, &rc);\n\t\t// set up flags and rect\n\t\tUINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);\n\t\tTPMPARAMS TPMParams = { 0 };\n\t\tTPMParams.cbSize = sizeof(TPMPARAMS);\n\t\tTPMParams.rcExclude = rc;\n\t\t// check if this window has a command bar\n\t\tHWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);\n\t\tif(::IsWindow(hWndCmdBar))\n\t\t{\n\t\t\tCBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams };\n\t\t\t::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCMenuHandle menu = cmi.hMenu;\n\t\t\tmenu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams);\n\t\t}\n\t}\n\n\tvoid CleanupChevronMenu(_ChevronMenuInfo& cmi)\n\t{\n\t\tCMenuHandle menu = cmi.hMenu;\n\t\t// if menu is from a command bar, detach submenus so they are not destroyed\n\t\tif(cmi.bCmdBar)\n\t\t{\n\t\t\tfor(int i = menu.GetMenuItemCount() - 1; i >=0; i--)\n\t\t\t\tmenu.RemoveMenu(i, MF_BYPOSITION);\n\t\t}\n\t\t// destroy menu\n\t\tmenu.DestroyMenu();\n\t\t// convert chevron rect to screen coordinates\n\t\tATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;\n\t\tRECT rc = cmi.lpnm->rc;\n\t\twndFrom.MapWindowPoints(NULL, &rc);\n\t\t// eat next message if click is on the same button\n\t\tMSG msg = { 0 };\n\t\tif(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt))\n\t\t\t::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n};\n\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>\nclass ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >\n{\npublic:\n\tHWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tHMENU hMenu = NULL, LPVOID lpCreateParam = NULL)\n\t{\n\t\tATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);\n\n\t\tdwStyle = T::GetWndStyle(dwStyle);\n\t\tdwExStyle = T::GetWndExStyle(dwExStyle);\n\n\t\tif(rect.m_lpRect == NULL)\n\t\t\trect.m_lpRect = &TBase::rcDefault;\n\n\t\treturn CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);\n\t}\n\n\tHWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tconst int cchName = 256;\n\t\tTCHAR szWindowName[cchName] = { 0 };\n#ifndef _WIN32_WCE\n\t\t::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);\n\t\tHMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));\n#else // CE specific\n\t\t::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);\n\n\t\t// This always needs to be NULL for Windows CE.\n\t\t// Frame Window menus have to go onto the CommandBar.\n\t\t// Use CreateSimpleCECommandBar\n\t\tHMENU hMenu = NULL;\n#endif // _WIN32_WCE\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);\n\n\t\tif(hWnd != NULL)\n\t\t\tm_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));\n\n\t\treturn hWnd;\n\t}\n\n\tBOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tif(nResourceID == 0)\n\t\t\tnResourceID = T::GetWndClassInfo().m_uCommonResourceID;\n#ifndef _WIN32_WCE\n\t\tATLASSERT(!::IsWindow(m_hWndToolBar));\n\t\tm_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);\n\t\treturn (m_hWndToolBar != NULL);\n#else // CE specific\n\t\tHWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);\n\t\treturn (hWnd != NULL);\n#endif // _WIN32_WCE\n\t}\n\n#ifdef _WIN32_WCE\n\t// CE specific variant that returns the handle of the toolbar\n\tHWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tif(nResourceID == 0)\n\t\t\tnResourceID = T::GetWndClassInfo().m_uCommonResourceID;\n\n\t\treturn T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);\n\t}\n#endif // _WIN32_WCE\n\n// message map and handlers\n\ttypedef CFrameWindowImplBase< TBase, TWinTraits >   _baseClass;\n\n\tBEGIN_MSG_MAP(CFrameWindowImpl)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\t\tNOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)\n#endif // (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\t\tNOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n#endif // !_ATL_NO_REBAR_SUPPORT\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam != SIZE_MINIMIZED)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\tLRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout(FALSE);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n\tLRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\t_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };\n\t\tif(!pT->PrepareChevronMenu(cmi))\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\t\t// display a popup menu with hidden items\n\t\tpT->DisplayChevronMenu(cmi);\n\t\t// cleanup\n\t\tpT->CleanupChevronMenu(cmi);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)\n#endif // !_ATL_NO_REBAR_SUPPORT\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// AtlCreateSimpleToolBar - helper for creating simple toolbars\n\n#ifndef _WIN32_WCE\n\ninline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, \n\t\tDWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n{\n\treturn CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID);\n}\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMDIWindow\n\n#ifndef _WIN32_WCE\n\n#ifndef _WTL_MDIWINDOWMENU_TEXT\n#define _WTL_MDIWINDOWMENU_TEXT\t_T(\"&Window\")\n#endif\n\nclass CMDIWindow : public ATL::CWindow\n{\npublic:\n// Data members\n\tHWND m_hWndMDIClient;\n\tHMENU m_hMenu;\n\n// Constructors\n\tCMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL)\n\t{ }\n\n\tCMDIWindow& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// Operations\n\tHWND MDIGetActive(BOOL* lpbMaximized = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\treturn (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);\n\t}\n\n\tvoid MDIActivate(HWND hWndChildToActivate)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\tATLASSERT(::IsWindow(hWndChildToActivate));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);\n\t}\n\n\tvoid MDINext(HWND hWndChild, BOOL bPrevious = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\tATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);\n\t}\n\n\tvoid MDIMaximize(HWND hWndChildToMaximize)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\tATLASSERT(::IsWindow(hWndChildToMaximize));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);\n\t}\n\n\tvoid MDIRestore(HWND hWndChildToRestore)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\tATLASSERT(::IsWindow(hWndChildToRestore));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);\n\t}\n\n\tvoid MDIDestroy(HWND hWndChildToDestroy)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\tATLASSERT(::IsWindow(hWndChildToDestroy));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);\n\t}\n\n\tBOOL MDICascade(UINT uFlags = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\treturn (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);\n\t}\n\n\tBOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\treturn (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);\n\t}\n\n\tvoid MDIIconArrange()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\t::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);\n\t}\n\n\tHMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\treturn (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);\n\t}\n\n\tHMENU MDIRefreshMenu()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\t\treturn (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);\n\t}\n\n// Additional operations\n\tstatic HMENU GetStandardWindowMenu(HMENU hMenu)\n\t{\n\t\tint nCount = ::GetMenuItemCount(hMenu);\n\t\tif(nCount == -1)\n\t\t\treturn NULL;\n\t\tint nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);\n\t\tif(nLen == 0)\n\t\t\treturn NULL;\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpszText = buff.Allocate(nLen + 1);\n\t\tif(lpszText == NULL)\n\t\t\treturn NULL;\n\t\tif(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)\n\t\t\treturn NULL;\n\t\tif(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0)\n\t\t\treturn NULL;\n\t\treturn ::GetSubMenu(hMenu, nCount - 2);\n\t}\n\n\tvoid SetMDIFrameMenu()\n\t{\n\t\tHMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);\n\t\tMDISetMenu(m_hMenu, hWindowMenu);\n\t\tMDIRefreshMenu();\n\t\t::DrawMenuBar(GetMDIFrame());\n\t}\n\n\tHWND GetMDIFrame() const\n\t{\n\t\treturn ::GetParent(m_hWndMDIClient);\n\t}\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMDIFrameWindowImpl\n\n#ifndef _WIN32_WCE\n\n// MDI child command chaining macro (only for MDI frame windows)\n#define CHAIN_MDI_CHILD_COMMANDS() \\\n\tif(uMsg == WM_COMMAND) \\\n\t{ \\\n\t\tHWND hWndChild = MDIGetActive(); \\\n\t\tif(hWndChild != NULL) \\\n\t\t\t::SendMessage(hWndChild, uMsg, wParam, lParam); \\\n\t}\n\ntemplate <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>\nclass ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >\n{\npublic:\n\tHWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tHMENU hMenu = NULL, LPVOID lpCreateParam = NULL)\n\t{\n\t\tm_hMenu = hMenu;\n\t\tATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);\n\n\t\tdwStyle = T::GetWndStyle(dwStyle);\n\t\tdwExStyle = T::GetWndExStyle(dwExStyle);\n\n\t\tif(rect.m_lpRect == NULL)\n\t\t\trect.m_lpRect = &TBase::rcDefault;\n\n\t\treturn CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);\n\t}\n\n\tHWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tconst int cchName = 256;\n\t\tTCHAR szWindowName[cchName] = { 0 };\n\t\t::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);\n\t\tHMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);\n\n\t\tif(hWnd != NULL)\n\t\t\tm_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));\n\n\t\treturn hWnd;\n\t}\n\n\tBOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tATLASSERT(!::IsWindow(m_hWndToolBar));\n\t\tif(nResourceID == 0)\n\t\t\tnResourceID = T::GetWndClassInfo().m_uCommonResourceID;\n\t\tm_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);\n\t\treturn (m_hWndToolBar != NULL);\n\t}\n\n\tvirtual WNDPROC GetWindowProc()\n\t{\n\t\treturn MDIFrameWindowProc;\n\t}\n\n\tstatic LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tCMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;\n\t\t// set a ptr to this message and save the old value\n#if (_ATL_VER >= 0x0700)\n\t\tATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);\n\t\tconst ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;\n#else // !(_ATL_VER >= 0x0700)\n\t\tMSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };\n\t\tconst MSG* pOldMsg = pThis->m_pCurrentMsg;\n#endif // !(_ATL_VER >= 0x0700)\n\t\tpThis->m_pCurrentMsg = &msg;\n\t\t// pass to the message map to process\n\t\tLRESULT lRes = 0;\n\t\tBOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);\n\t\t// restore saved value for the current message\n\t\tATLASSERT(pThis->m_pCurrentMsg == &msg);\n\t\tpThis->m_pCurrentMsg = pOldMsg;\n\t\t// do the default processing if message was not handled\n\t\tif(!bRet)\n\t\t{\n\t\t\tif(uMsg != WM_NCDESTROY)\n\t\t\t{\n\t\t\t\tlRes = pThis->DefWindowProc(uMsg, wParam, lParam);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// unsubclass, if needed\n\t\t\t\tLONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);\n\t\t\t\tlRes = pThis->DefWindowProc(uMsg, wParam, lParam);\n\t\t\t\tif(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)\n\t\t\t\t\t::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);\n#if (_ATL_VER >= 0x0700)\n\t\t\t\t// mark window as destryed\n\t\t\t\tpThis->m_dwState |= WINSTATE_DESTROYED;\n#else // !(_ATL_VER >= 0x0700)\n\t\t\t\t// clear out window handle\n\t\t\t\tHWND hWnd = pThis->m_hWnd;\n\t\t\t\tpThis->m_hWnd = NULL;\n\t\t\t\t// clean up after window is destroyed\n\t\t\t\tpThis->OnFinalMessage(hWnd);\n#endif // !(_ATL_VER >= 0x0700)\n\t\t\t}\n\t\t}\n#if (_ATL_VER >= 0x0700)\n\t\tif(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL)\n\t\t{\n\t\t\t// clear out window handle\n\t\t\tHWND hWndThis = pThis->m_hWnd;\n\t\t\tpThis->m_hWnd = NULL;\n\t\t\tpThis->m_dwState &= ~WINSTATE_DESTROYED;\n\t\t\t// clean up after window is destroyed\n\t\t\tpThis->OnFinalMessage(hWndThis);\n\t\t}\n#endif // (_ATL_VER >= 0x0700)\n\t\treturn lRes;\n\t}\n\n\t// Overriden to call DefWindowProc which uses DefFrameProc\n\tLRESULT DefWindowProc()\n\t{\n\t\tconst MSG* pMsg = m_pCurrentMsg;\n\t\tLRESULT lRes = 0;\n\t\tif (pMsg != NULL)\n\t\t\tlRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);\n\t\treturn lRes;\n\t}\n\n\tLRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\treturn ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam);\n\t}\n\n\tBOOL PreTranslateMessage(MSG* pMsg)\n\t{\n\t\tif(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))\n\t\t\treturn TRUE;\n\t\treturn ::TranslateMDISysAccel(m_hWndMDIClient, pMsg);\n\t}\n\n\tHWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)\n\t{\n\t\tDWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;\n\t\tDWORD dwExStyle = WS_EX_CLIENTEDGE;\n\n\t\tCLIENTCREATESTRUCT ccs = { 0 };\n\t\tccs.hWindowMenu = hWindowMenu;\n\t\tccs.idFirstChild = nFirstChildID;\n\n\t\tif((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)\n\t\t{\n\t\t\t// parent MDI frame's scroll styles move to the MDICLIENT\n\t\t\tdwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL));\n\n\t\t\t// fast way to turn off the scrollbar bits (without a resize)\n\t\t\tModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);\n\t\t}\n\n\t\t// Create MDICLIENT window\n\t\tm_hWndClient = ::CreateWindowEx(dwExStyle, _T(\"MDIClient\"), NULL,\n\t\t\tdwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID),\n\t\t\tModuleHelper::GetModuleInstance(), (LPVOID)&ccs);\n\t\tif (m_hWndClient == NULL)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"MDI Frame failed to create MDICLIENT.\\n\"));\n\t\t\treturn NULL;\n\t\t}\n\n\t\t// Move it to the top of z-order\n\t\t::BringWindowToTop(m_hWndClient);\n\n\t\t// set as MDI client window\n\t\tm_hWndMDIClient = m_hWndClient;\n\n\t\t// update to proper size\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout();\n\n\t\treturn m_hWndClient;\n\t}\n\n\ttypedef CFrameWindowImplBase<TBase, TWinTraits >   _baseClass;\n\n\tBEGIN_MSG_MAP(CMDIFrameWindowImpl)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tMESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\t\tNOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)\n#endif // (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0500)\n\t\tNOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_ATL_NO_REBAR_SUPPORT\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(wParam != SIZE_MINIMIZED)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\t\t// message must be handled, otherwise DefFrameProc would resize the client again\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\t// don't allow CFrameWindowImplBase to handle this one\n\t\treturn DefWindowProc(uMsg, wParam, lParam);\n\t}\n\n\tLRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tSetMDIFrameMenu();\n\t\treturn 0;\n\t}\n\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\tLRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout(FALSE);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500)\n\tLRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\t_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };\n\t\tif(!pT->PrepareChevronMenu(cmi))\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\t\t// display a popup menu with hidden items\n\t\tpT->DisplayChevronMenu(cmi);\n\t\t// cleanup\n\t\tpT->CleanupChevronMenu(cmi);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_ATL_NO_REBAR_SUPPORT\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMDIChildWindowImpl\n\n#ifndef _WIN32_WCE\n\ntemplate <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>\nclass ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >\n{\npublic:\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tUINT nMenuID = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);\n\n\t\tif(nMenuID != 0)\n\t\t\tm_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID));\n\n\t\tdwStyle = T::GetWndStyle(dwStyle);\n\t\tdwExStyle = T::GetWndExStyle(dwExStyle);\n\n\t\tdwExStyle |= WS_EX_MDICHILD;   // force this one\n\t\tm_pfnSuperWindowProc = ::DefMDIChildProc;\n\t\tm_hWndMDIClient = hWndParent;\n\t\tATLASSERT(::IsWindow(m_hWndMDIClient));\n\n\t\tif(rect.m_lpRect == NULL)\n\t\t\trect.m_lpRect = &TBase::rcDefault;\n\n\t\t// If the currently active MDI child is maximized, we want to create this one maximized too\n\t\tATL::CWindow wndParent = hWndParent;\n\t\tBOOL bMaximized = FALSE;\n\t\twndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);\n\t\tif(bMaximized)\n\t\t\twndParent.SetRedraw(FALSE);\n\n\t\tHWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);\n\n\t\tif(bMaximized)\n\t\t{\n\t\t\t// Maximize and redraw everything\n\t\t\tif(hWnd != NULL)\n\t\t\t\tMDIMaximize(hWnd);\n\t\t\twndParent.SetRedraw(TRUE);\n\t\t\twndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);\n\t\t\t::SetFocus(GetMDIFrame());   // focus will be set back to this window\n\t\t}\n\t\telse if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))\n\t\t{\n\t\t\t::SetFocus(hWnd);\n\t\t}\n\n\t\treturn hWnd;\n\t}\n\n\tHWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)\n\t{\n\t\tconst int cchName = 256;\n\t\tTCHAR szWindowName[cchName] = { 0 };\n\t\tif(lpcstrWindowName == NULL)\n\t\t{\n\t\t\t::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);\n\t\t\tlpcstrWindowName = szWindowName;\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);\n\n\t\tif(hWnd != NULL)\n\t\t\tm_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));\n\n\t\treturn hWnd;\n\t}\n\n\tBOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)\n\t{\n\t\tATLASSERT(!::IsWindow(m_hWndToolBar));\n\t\tif(nResourceID == 0)\n\t\t\tnResourceID = T::GetWndClassInfo().m_uCommonResourceID;\n\t\tm_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);\n\t\treturn (m_hWndToolBar != NULL);\n\t}\n\n\tBOOL UpdateClientEdge(LPRECT lpRect = NULL)\n\t{\n\t\t// only adjust for active MDI child window\n\t\tHWND hWndChild = MDIGetActive();\n\t\tif(hWndChild != NULL && hWndChild != m_hWnd)\n\t\t\treturn FALSE;\n\n\t\t// need to adjust the client edge style as max/restore happens\n\t\tDWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE);\n\t\tDWORD dwNewStyle = dwStyle;\n\t\tif(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0))\n\t\t\tdwNewStyle &= ~(WS_EX_CLIENTEDGE);\n\t\telse\n\t\t\tdwNewStyle |= WS_EX_CLIENTEDGE;\n\n\t\tif(dwStyle != dwNewStyle)\n\t\t{\n\t\t\t// SetWindowPos will not move invalid bits\n\t\t\t::RedrawWindow(m_hWndMDIClient, NULL, NULL,\n\t\t\t\tRDW_INVALIDATE | RDW_ALLCHILDREN);\n\t\t\t// remove/add WS_EX_CLIENTEDGE to MDI client area\n\t\t\t::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);\n\t\t\t::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0,\n\t\t\t\tSWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |\n\t\t\t\tSWP_NOZORDER | SWP_NOCOPYBITS);\n\n\t\t\t// return new client area\n\t\t\tif (lpRect != NULL)\n\t\t\t\t::GetClientRect(m_hWndMDIClient, lpRect);\n\n\t\t\treturn TRUE;\n\t\t}\n\n\t\treturn FALSE;\n\t}\n\n\ttypedef CFrameWindowImplBase<TBase, TWinTraits >   _baseClass;\n\tBEGIN_MSG_MAP(CMDIChildWindowImpl)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)\n\t\tMESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)\n\t\tMESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)\n\t\tMESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\t\tNOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)\n#endif // (_WIN32_IE >= 0x0400)\n#if (_WIN32_IE >= 0x0500)\n\t\tNOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_ATL_NO_REBAR_SUPPORT\n\t\tCHAIN_MSG_MAP(_baseClass)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tDefWindowProc(uMsg, wParam, lParam);   // needed for MDI children\n\t\tif(wParam != SIZE_MINIMIZED)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\t// update MDI client edge and adjust MDI child rect\n\t\tLPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;\n\n\t\tif(!(lpWndPos->flags & SWP_NOSIZE))\n\t\t{\n\t\t\tRECT rectClient = { 0 };\n\t\t\tif(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0))\n\t\t\t{\n\t\t\t\t::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle());\n\t\t\t\tlpWndPos->x = rectClient.left;\n\t\t\t\tlpWndPos->y = rectClient.top;\n\t\t\t\tlpWndPos->cx = rectClient.right - rectClient.left;\n\t\t\t\tlpWndPos->cy = rectClient.bottom - rectClient.top;\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tLRESULT lRes = DefWindowProc(uMsg, wParam, lParam);\n\n\t\t// Activate this MDI window if needed\n\t\tif(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT)\n\t\t{\n\t\t\tif(MDIGetActive() != m_hWnd)\n\t\t\t\tMDIActivate(m_hWnd);\n\t\t}\n\n\t\treturn lRes;\n\t}\n\n\tLRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\treturn ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam);\n\t}\n\n\tLRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif((HWND)lParam == m_hWnd && m_hMenu != NULL)\n\t\t\tSetMDIFrameMenu();\n\t\telse if((HWND)lParam == NULL)\n\t\t\t::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_hMenu != NULL)\n\t\t{\n\t\t\t::DestroyMenu(m_hMenu);\n\t\t\tm_hMenu = NULL;\n\t\t}\n\t\tUpdateClientEdge();\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n#ifndef _ATL_NO_REBAR_SUPPORT\n#if (_WIN32_IE >= 0x0400)\n\tLRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout(FALSE);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0400)\n\n#if (_WIN32_IE >= 0x0500)\n\tLRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\t_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };\n\t\tif(!pT->PrepareChevronMenu(cmi))\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t\treturn 1;\n\t\t}\n\t\t// display a popup menu with hidden items\n\t\tpT->DisplayChevronMenu(cmi);\n\t\t// cleanup\n\t\tpT->CleanupChevronMenu(cmi);\n\t\treturn 0;\n\t}\n#endif // (_WIN32_IE >= 0x0500)\n#endif // !_ATL_NO_REBAR_SUPPORT\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// COwnerDraw - MI class for owner-draw support\n\ntemplate <class T>\nclass COwnerDraw\n{\npublic:\n#if (_ATL_VER < 0x0700)\n\tBOOL m_bHandledOD;\n\n\tBOOL IsMsgHandled() const\n\t{\n\t\treturn m_bHandledOD;\n\t}\n\tvoid SetMsgHandled(BOOL bHandled)\n\t{\n\t\tm_bHandledOD = bHandled;\n\t}\n#endif // (_ATL_VER < 0x0700)\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(COwnerDraw< T >)\n\t\tMESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)\n\t\tMESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)\n\t\tMESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)\n\t\tMESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)\n\tALT_MSG_MAP(1)\n\t\tMESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)\n\t\tMESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)\n\t\tMESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)\n\t\tMESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)\n\tEND_MSG_MAP()\n\n\tLRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetMsgHandled(TRUE);\n\t\tpT->DrawItem((LPDRAWITEMSTRUCT)lParam);\n\t\tbHandled = pT->IsMsgHandled();\n\t\treturn (LRESULT)TRUE;\n\t}\n\n\tLRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetMsgHandled(TRUE);\n\t\tpT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);\n\t\tbHandled = pT->IsMsgHandled();\n\t\treturn (LRESULT)TRUE;\n\t}\n\n\tLRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetMsgHandled(TRUE);\n\t\tbHandled = pT->IsMsgHandled();\n\t\treturn (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);\n\t}\n\n\tLRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetMsgHandled(TRUE);\n\t\tpT->DeleteItem((LPDELETEITEMSTRUCT)lParam);\n\t\tbHandled = pT->IsMsgHandled();\n\t\treturn (LRESULT)TRUE;\n\t}\n\n// Overrideables\n\tvoid DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)\n\t{\n\t\t// must be implemented\n\t\tATLASSERT(FALSE);\n\t}\n\n\tvoid MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)\n\t{\n\t\tif(lpMeasureItemStruct->CtlType != ODT_MENU)\n\t\t{\n\t\t\t// return default height for a system font\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tHWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);\n\t\t\tCClientDC dc(hWnd);\n\t\t\tTEXTMETRIC tm = { 0 };\n\t\t\tdc.GetTextMetrics(&tm);\n\n\t\t\tlpMeasureItemStruct->itemHeight = tm.tmHeight;\n\t\t}\n\t\telse\n\t\t\tlpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);\n\t}\n\n\tint CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)\n\t{\n\t\t// all items are equal\n\t\treturn 0;\n\t}\n\n\tvoid DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)\n\t{\n\t\t// default - nothing\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Update UI macros\n\n// these build the Update UI map inside a class definition\n#define BEGIN_UPDATE_UI_MAP(thisClass) \\\n\tstatic const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \\\n\t{ \\\n\t\tstatic const _AtlUpdateUIMap theMap[] = \\\n\t\t{\n\n#define UPDATE_ELEMENT(nID, wType) \\\n\t\t\t{ nID,  wType },\n\n#define END_UPDATE_UI_MAP() \\\n\t\t\t{ (WORD)-1, 0 } \\\n\t\t}; \\\n\t\treturn theMap; \\\n\t}\n\n///////////////////////////////////////////////////////////////////////////////\n// CUpdateUI - manages UI elements updating\n\nclass CUpdateUIBase\n{\npublic:\n\t// constants\n\tenum\n\t{\n\t\t// UI element type\n\t\tUPDUI_MENUPOPUP\t\t= 0x0001,\n\t\tUPDUI_MENUBAR\t\t= 0x0002,\n\t\tUPDUI_CHILDWINDOW\t= 0x0004,\n\t\tUPDUI_TOOLBAR\t\t= 0x0008,\n\t\tUPDUI_STATUSBAR\t\t= 0x0010,\n\t\t// state\n\t\tUPDUI_ENABLED\t\t= 0x0000,\n\t\tUPDUI_DISABLED\t\t= 0x0100,\n\t\tUPDUI_CHECKED\t\t= 0x0200,\n\t\tUPDUI_CHECKED2\t\t= 0x0400,\n\t\tUPDUI_RADIO\t\t= 0x0800,\n\t\tUPDUI_DEFAULT\t\t= 0x1000,\n\t\tUPDUI_TEXT\t\t= 0x2000,\n\t\t// internal state\n\t\tUPDUI_CLEARDEFAULT\t= 0x4000,\n\t};\n\n\t// element data\n\tstruct _AtlUpdateUIElement\n\t{\n\t\tHWND m_hWnd;\n\t\tWORD m_wType;\n\n\t\tbool operator ==(const _AtlUpdateUIElement& e) const\n\t\t{ return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); }\n\t};\n\n\t// map data\n\tstruct _AtlUpdateUIMap\n\t{\n\t\tWORD m_nID;\n\t\tWORD m_wType;\n\n\t\tbool operator ==(const _AtlUpdateUIMap& e) const\n\t\t{ return (m_nID == e.m_nID && m_wType == e.m_wType); }\n\t};\n\n\t// instance data\n#pragma warning(push)\n#pragma warning(disable: 4201)   // nameless unions are part of C++\n\n\tstruct _AtlUpdateUIData\n\t{\n\t\tWORD m_wState;\n\t\tunion\n\t\t{\n\t\t\tvoid* m_lpData;\n\t\t\tLPTSTR m_lpstrText;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tWORD m_nIDFirst;\n\t\t\t\tWORD m_nIDLast;\n\t\t\t};\n\t\t};\n\n\t\tbool operator ==(const _AtlUpdateUIData& e) const\n\t\t{ return (m_wState == e.m_wState && m_lpData == e.m_lpData); }\n\t};\n\n#pragma warning(pop)\n\n\tATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements;   // elements data\n\tconst _AtlUpdateUIMap* m_pUIMap;                       // static UI data\n\t_AtlUpdateUIData* m_pUIData;                           // instance UI data\n\tWORD m_wDirtyType;                                     // global dirty flag\n\n\tbool m_bBlockAccelerators;\n\n\n// Constructor, destructor\n\tCUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)\n\t{ }\n\n\t~CUpdateUIBase()\n\t{\n\t\tif(m_pUIMap != NULL && m_pUIData != NULL)\n\t\t{\n\t\t\tconst _AtlUpdateUIMap* pUIMap = m_pUIMap;\n\t\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\t\twhile(pUIMap->m_nID != (WORD)-1)\n\t\t\t{\n\t\t\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t\t\tdelete [] pUIData->m_lpstrText;\n\t\t\t\tpUIMap++;\n\t\t\t\tpUIData++;\n\t\t\t}\n\t\t\tdelete [] m_pUIData;\n\t\t}\n\t}\n\n// Check for disabled commands\n\tbool UIGetBlockAccelerators() const\n\t{\n\t\treturn m_bBlockAccelerators;\n\t}\n\n\tbool UISetBlockAccelerators(bool bBlock)\n\t{\n\t\tbool bOld = m_bBlockAccelerators;\n\t\tm_bBlockAccelerators = bBlock;\n\t\treturn bOld;\n\t}\n\n// Add elements\n\tBOOL UIAddMenuBar(HWND hWnd)                // menu bar (main menu)\n\t{\n\t\tif(hWnd == NULL)\n\t\t\treturn FALSE;\n\t\t_AtlUpdateUIElement e;\n\t\te.m_hWnd = hWnd;\n\t\te.m_wType = UPDUI_MENUBAR;\n\t\treturn m_UIElements.Add(e);\n\t}\n\n\tBOOL UIAddToolBar(HWND hWnd)                // toolbar\n\t{\n\t\tif(hWnd == NULL)\n\t\t\treturn FALSE;\n\t\t_AtlUpdateUIElement e;\n\t\te.m_hWnd = hWnd;\n\t\te.m_wType = UPDUI_TOOLBAR;\n\t\treturn m_UIElements.Add(e);\n\t}\n\n\tBOOL UIAddStatusBar(HWND hWnd)              // status bar\n\t{\n\t\tif(hWnd == NULL)\n\t\t\treturn FALSE;\n\t\t_AtlUpdateUIElement e;\n\t\te.m_hWnd = hWnd;\n\t\te.m_wType = UPDUI_STATUSBAR;\n\t\treturn m_UIElements.Add(e);\n\t}\n\n\tBOOL UIAddChildWindowContainer(HWND hWnd)   // child window\n\t{\n\t\tif(hWnd == NULL)\n\t\t\treturn FALSE;\n\t\t_AtlUpdateUIElement e;\n\t\te.m_hWnd = hWnd;\n\t\te.m_wType = UPDUI_CHILDWINDOW;\n\t\treturn m_UIElements.Add(e);\n\t}\n\n// Message map for popup menu updates and accelerator blocking\n\tBEGIN_MSG_MAP(CUpdateUIBase)\n\t\tMESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)\n\t\tMESSAGE_HANDLER(WM_COMMAND, OnCommand)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n\t\tHMENU hMenu = (HMENU)wParam;\n\t\tif(hMenu == NULL)\n\t\t\treturn 1;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn 1;\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\twhile(pMap->m_nID != (WORD)-1)\n\t\t{\n\t\t\tif(pMap->m_wType & UPDUI_MENUPOPUP)\n\t\t\t{\n\t\t\t\tUIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);\n\n\t\t\t\tif((pUIData->m_wState & UPDUI_RADIO) != 0)\n\t\t\t\t\t::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND);\n\t\t\t}\n\t\t\tpMap++;\n\t\t\tpUIData++;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tbHandled = FALSE;\n\t\tif(m_bBlockAccelerators && HIWORD(wParam) == 1)   // accelerators only\n\t\t{\n\t\t\tint nID = LOWORD(wParam);\n\t\t\tif((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\\n\"), nID);\n\t\t\t\tbHandled = TRUE;   // eat the command, UI item is disabled\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n// methods for setting UI element state\n\tBOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tif(bEnable)\n\t\t\t\t{\n\t\t\t\t\tif(pUIData->m_wState & UPDUI_DISABLED)\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~UPDUI_DISABLED;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif(!(pUIData->m_wState & UPDUI_DISABLED))\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_DISABLED;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tswitch(nCheck)\n\t\t\t\t{\n\t\t\t\tcase 0:\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tif(!(pUIData->m_wState & UPDUI_CHECKED))\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~UPDUI_CHECKED2;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_CHECKED;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tif(!(pUIData->m_wState & UPDUI_CHECKED2))\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~UPDUI_CHECKED;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_CHECKED2;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\t// variant that supports bool (checked/not-checked, no intermediate state)\n\tBOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)\n\t{\n\t\treturn UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate);\n\t}\n\n\tBOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tif(bRadio)\n\t\t\t\t{\n\t\t\t\t\tif(!(pUIData->m_wState & UPDUI_RADIO))\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_RADIO;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif(pUIData->m_wState & UPDUI_RADIO)\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~UPDUI_RADIO;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\t// for menu items\n\tBOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tpUIData->m_wState |= UPDUI_RADIO;\n\t\t\t\tpUIData->m_nIDFirst = (WORD)nIDFirst;\n\t\t\t\tpUIData->m_nIDLast = (WORD)nIDLast;\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\t\t\t}\n\t\t\telse if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast)\n\t\t\t{\n\t\t\t\tif(pUIData->m_wState & UPDUI_RADIO)\n\t\t\t\t{\n\t\t\t\t\tpUIData->m_wState &= ~pMap->m_wType;\n\t\t\t\t\tpUIData->m_wState &= ~UPDUI_RADIO;\n\t\t\t\t\tpUIData->m_nIDFirst = 0;\n\t\t\t\t\tpUIData->m_nIDLast = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(pMap->m_nID == nIDLast)\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\t\tif(lpstrText == NULL)\n\t\t\tlpstrText = _T(\"\");\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tif(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText))\n\t\t\t\t{\n\t\t\t\t\tdelete [] pUIData->m_lpstrText;\n\t\t\t\t\tpUIData->m_lpstrText = NULL;\n\t\t\t\t\tint nStrLen = lstrlen(lpstrText);\n\t\t\t\t\tATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]);\n\t\t\t\t\tif(pUIData->m_lpstrText == NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"UISetText - memory allocation failed\\n\"));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tSecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText);\n\t\t\t\t\tpUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);\n\t\t\t\t}\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\n\t\t\t\tif(bDefault)\n\t\t\t\t{\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_DEFAULT) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_DEFAULT;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_DEFAULT) != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\t\t\tpUIData->m_wState &= ~UPDUI_DEFAULT;\n\t\t\t\t\t\tpUIData->m_wState |= UPDUI_CLEARDEFAULT;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif(bForceUpdate)\n\t\t\t\t\tpUIData->m_wState |= pMap->m_wType;\n\t\t\t\tif(pUIData->m_wState & pMap->m_wType)\n\t\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n// methods for complete state set/get\n\tBOOL UISetState(int nID, DWORD dwState)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t{\t\t\n\t\t\t\tpUIData->m_wState = (WORD)(dwState | pMap->m_wType);\n\t\t\t\tm_wDirtyType |= pMap->m_wType;\n\t\t\t\tbreak;   // found\n\t\t\t}\n\t\t}\n\t\treturn TRUE;\n\t}\n\n\tDWORD UIGetState(int nID)\n\t{\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn 0;\n\t\tfor( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)\n\t\t{\n\t\t\tif(nID == (int)pMap->m_nID)\n\t\t\t\treturn pUIData->m_wState;\n\t\t}\n\t\treturn 0;\n\t}\n\n// methods for updating UI\n#ifndef _WIN32_WCE\n\tBOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)\n\t{\n\t\tif(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)\n\t\t\treturn TRUE;\n\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\twhile(pMap->m_nID != (WORD)-1)\n\t\t{\n\t\t\tfor(int i = 0; i < m_UIElements.GetSize(); i++)\n\t\t\t{\n\t\t\t\tif(m_UIElements[i].m_wType == UPDUI_MENUBAR)\n\t\t\t\t{\n\t\t\t\t\tHMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);\n\t\t\t\t\tif(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))\n\t\t\t\t\t\tUIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);\n\t\t\t\t}\n\t\t\t\tif(bMainMenu)\n\t\t\t\t\t::DrawMenuBar(m_UIElements[i].m_hWnd);\n\t\t\t}\n\t\t\tpMap++;\n\t\t\tpUIData->m_wState &= ~UPDUI_MENUBAR;\n\t\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t{\n\t\t\t\tdelete [] pUIData->m_lpstrText;\n\t\t\t\tpUIData->m_lpstrText = NULL;\n\t\t\t\tpUIData->m_wState &= ~UPDUI_TEXT;\n\t\t\t}\n\t\t\tpUIData++;\n\t\t}\n\n\t\tm_wDirtyType &= ~UPDUI_MENUBAR;\n\t\treturn TRUE;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)\n\t{\n\t\tif(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)\n\t\t\treturn TRUE;\n\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\twhile(pMap->m_nID != (WORD)-1)\n\t\t{\n\t\t\tfor(int i = 0; i < m_UIElements.GetSize(); i++)\n\t\t\t{\n\t\t\t\tif(m_UIElements[i].m_wType == UPDUI_TOOLBAR)\n\t\t\t\t{\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))\n\t\t\t\t\t\tUIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);\n\t\t\t\t}\n\t\t\t}\n\t\t\tpMap++;\n\t\t\tpUIData->m_wState &= ~UPDUI_TOOLBAR;\n\t\t\tpUIData++;\n\t\t}\n\n\t\tm_wDirtyType &= ~UPDUI_TOOLBAR;\n\t\treturn TRUE;\n\t}\n\n\tBOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)\n\t{\n\t\tif(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)\n\t\t\treturn TRUE;\n\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\twhile(pMap->m_nID != (WORD)-1)\n\t\t{\n\t\t\tfor(int i = 0; i < m_UIElements.GetSize(); i++)\n\t\t\t{\n\t\t\t\tif(m_UIElements[i].m_wType == UPDUI_STATUSBAR)\n\t\t\t\t{\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))\n\t\t\t\t\t\tUIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);\n\t\t\t\t}\n\t\t\t}\n\t\t\tpMap++;\n\t\t\tpUIData->m_wState &= ~UPDUI_STATUSBAR;\n\t\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t{\n\t\t\t\tdelete [] pUIData->m_lpstrText;\n\t\t\t\tpUIData->m_lpstrText = NULL;\n\t\t\t\tpUIData->m_wState &= ~UPDUI_TEXT;\n\t\t\t}\n\t\t\tpUIData++;\n\t\t}\n\n\t\tm_wDirtyType &= ~UPDUI_STATUSBAR;\n\t\treturn TRUE;\n\t}\n\n\tBOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)\n\t{\n\t\tif(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)\n\t\t\treturn TRUE;\n\n\t\tconst _AtlUpdateUIMap* pMap = m_pUIMap;\n\t\t_AtlUpdateUIData* pUIData = m_pUIData;\n\t\tif(pUIData == NULL)\n\t\t\treturn FALSE;\n\n\t\twhile(pMap->m_nID != (WORD)-1)\n\t\t{\n\t\t\tfor(int i = 0; i < m_UIElements.GetSize(); i++)\n\t\t\t{\n\t\t\t\tif(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)\n\t\t\t\t{\n\t\t\t\t\tif((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))\n\t\t\t\t\t\tUIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);\n\t\t\t\t}\n\t\t\t}\n\t\t\tpMap++;\n\t\t\tpUIData->m_wState &= ~UPDUI_CHILDWINDOW;\n\t\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t{\n\t\t\t\tdelete [] pUIData->m_lpstrText;\n\t\t\t\tpUIData->m_lpstrText = NULL;\n\t\t\t\tpUIData->m_wState &= ~UPDUI_TEXT;\n\t\t\t}\n\t\t\tpUIData++;\n\t\t}\n\n\t\tm_wDirtyType &= ~UPDUI_CHILDWINDOW;\n\t\treturn TRUE;\n\t}\n\n// internal element specific methods\n\tstatic void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)\n\t{\n#ifndef _WIN32_WCE\n\t\tif((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0)\n\t\t{\n\t\t\t::SetMenuDefaultItem(hMenu, (UINT)-1, 0);\n\t\t\tpUIData->m_wState &= ~UPDUI_CLEARDEFAULT;\n\t\t}\n#endif // !_WIN32_WCE\n\n\t\tCMenuItemInfo mii;\n\t\tmii.fMask = MIIM_STATE;\n\t\tmii.wID = nID;\n\n#ifndef _WIN32_WCE\n\t\tif((pUIData->m_wState & UPDUI_DISABLED) != 0)\n\t\t\tmii.fState |= MFS_DISABLED | MFS_GRAYED;\n\t\telse\n\t\t\tmii.fState |= MFS_ENABLED;\n\n\t\tif((pUIData->m_wState & UPDUI_CHECKED) != 0)\n\t\t\tmii.fState |= MFS_CHECKED;\n\t\telse\n\t\t\tmii.fState |= MFS_UNCHECKED;\n\n\t\tif((pUIData->m_wState & UPDUI_DEFAULT) != 0)\n\t\t\tmii.fState |= MFS_DEFAULT;\n#else // CE specific\n\t\t// ::SetMenuItemInfo() can't disable or check menu items\n\t\t// on Windows CE, so we have to do that directly\n\t\tUINT uEnable = MF_BYCOMMAND;\n\t\tif((pUIData->m_wState & UPDUI_DISABLED) != 0)\n\t\t\tuEnable |= MF_GRAYED;\n\t\telse\n\t\t\tuEnable |= MF_ENABLED;\n\t\t::EnableMenuItem(hMenu, nID, uEnable);\n\n\t\tUINT uCheck = MF_BYCOMMAND;\n\t\tif((pUIData->m_wState & UPDUI_CHECKED) != 0)\n\t\t\tuCheck |= MF_CHECKED;\n\t\telse\n\t\t\tuCheck |= MF_UNCHECKED;\n\t\t::CheckMenuItem(hMenu, nID, uCheck);\n#endif // _WIN32_WCE\n\n\t\tif((pUIData->m_wState & UPDUI_TEXT) != 0)\n\t\t{\n\t\t\tCMenuItemInfo miiNow;\n\t\t\tmiiNow.fMask = MIIM_TYPE;\n\t\t\tmiiNow.wID = nID;\n\t\t\tif(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow))\n\t\t\t{\n\t\t\t\tmii.fMask |= MIIM_TYPE;\n\t\t\t\t// MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING\n#ifndef _WIN32_WCE\n\t\t\t\tmii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING;\n#else // CE specific\n\t\t\t\tmii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING;\n#endif // _WIN32_WCE\n\t\t\t\tmii.dwTypeData = pUIData->m_lpstrText;\n\t\t\t}\n\t\t}\n\n\t\t::SetMenuItemInfo(hMenu, nID, FALSE, &mii);\n\t}\n\n\tstatic void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)\n\t{\n\t\t// Note: only handles enabled/disabled, checked state, and radio (press)\n\t\t::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);\n\t\t::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);\n\t\t::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);\n\t\t::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);\n\t}\n\n\tstatic void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)\n\t{\n\t\t// Note: only handles text\n\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText);\n\t}\n\n\tstatic void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)\n\t{\n\t\tHWND hChild = ::GetDlgItem(hWnd, nID);\n\n\t\t::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);\n\t\t// for check and radio, assume that window is a button\n\t\tint nCheck = BST_UNCHECKED;\n\t\tif(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO)\n\t\t\tnCheck = BST_CHECKED;\n\t\telse if(pUIData->m_wState & UPDUI_CHECKED2)\n\t\t\tnCheck = BST_INDETERMINATE;\n\t\t::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);\n\t\tif(pUIData->m_wState & UPDUI_DEFAULT)\n\t\t{\n\t\t\tDWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);\n\t\t\tif(HIWORD(dwRet) == DC_HASDEFID)\n\t\t\t{\n\t\t\t\tHWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));\n\t\t\t\t// remove BS_DEFPUSHBUTTON\n\t\t\t\t::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));\n\t\t\t}\n\t\t\t::SendMessage(hWnd, DM_SETDEFID, nID, 0L);\n\t\t}\n\t\tif(pUIData->m_wState & UPDUI_TEXT)\n\t\t\t::SetWindowText(hChild, pUIData->m_lpstrText);\n\t}\n};\n\ntemplate <class T>\nclass CUpdateUI : public CUpdateUIBase\n{\npublic:\n\tCUpdateUI()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;\n\t\tconst _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();\n\t\tm_pUIMap = pMap;\n\t\tATLASSERT(m_pUIMap != NULL);\n\t\tint nCount = 1;\n\t\tfor( ; pMap->m_nID != (WORD)-1; nCount++)\n\t\t\tpMap++;\n\n\t\t// check for duplicates (debug only)\n#ifdef _DEBUG\n\t\tfor(int i = 0; i < nCount; i++)\n\t\t{\n\t\t\tfor(int j = 0; j < nCount; j++)\n\t\t\t{\n\t\t\t\t// shouldn't have duplicates in the update UI map\n\t\t\t\tif(i != j)\n\t\t\t\t\tATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);\n\t\t\t}\n\t\t}\n#endif // _DEBUG\n\n\t\tATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);\n\t\tATLASSERT(m_pUIData != NULL);\n\n\t\tif(m_pUIData != NULL)\n\t\t\tmemset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDynamicUpdateUI - allows update elements to dynamically added and removed\n//                    in addition to a static update UI map\n\ntemplate <class T>\nclass CDynamicUpdateUI : public CUpdateUIBase\n{\npublic:\n// Data members\n\tATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap;     // copy of the static UI data\n\tATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData;   // instance UI data\n\n// Constructor/destructor\n\tCDynamicUpdateUI()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;\n\t\tconst _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();\n\t\tATLASSERT(pMap != NULL);\n\n\t\tfor(;;)\n\t\t{\n\t\t\tBOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap);\n\t\t\tATLASSERT(bRet);\n\n\t\t\tif(bRet != FALSE)\n\t\t\t{\n\t\t\t\t_AtlUpdateUIData data = { 0, NULL };\n\t\t\t\tbRet = m_arrUIData.Add(data);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t}\n\n\t\t\tif(pMap->m_nID == (WORD)-1)\n\t\t\t\tbreak;\n\n\t\t\tpMap++;\n\t\t}\n\n\t\tATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize());\n\n#ifdef _DEBUG\n\t\t// check for duplicates (debug only)\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tfor(int j = 0; j < m_arrUIMap.GetSize(); j++)\n\t\t\t{\n\t\t\t\t// shouldn't have duplicates in the update UI map\n\t\t\t\tif(i != j)\n\t\t\t\t\tATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID);\n\t\t\t}\n\t\t}\n#endif // _DEBUG\n\n\t\t// Set internal data pointers to point to the new data arrays\n\t\tm_pUIMap = m_arrUIMap.m_aT;\n\t\tm_pUIData = m_arrUIData.m_aT;\n\t}\n\n\t~CDynamicUpdateUI()\n\t{\n\t\tfor(int i = 0; i < m_arrUIData.GetSize(); i++)\n\t\t{\n\t\t\tif((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)\n\t\t\t\tdelete [] m_arrUIData[i].m_lpstrText;\n\t\t}\n\n\t\t// Reset internal data pointers (memory will be released by CSimpleArray d-tor)\n\t\tm_pUIMap = NULL;\n\t\tm_pUIData = NULL;\n\t}\n\n// Methods for dynamically adding and removing update elements\n\tbool UIAddUpdateElement(WORD nID, WORD wType)\n\t{\n\t\t// check for duplicates\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\t// shouldn't have duplicates in the update UI map\n\t\t\tATLASSERT(m_arrUIMap[i].m_nID != nID);\n\t\t\tif(m_arrUIMap[i].m_nID == nID)\n\t\t\t\treturn false;\n\t\t}\n\n\t\tbool bRetVal = false;\n\n\t\t// Add new end element\n\t\t_AtlUpdateUIMap uumEnd = { (WORD)-1, 0 };\n\t\tBOOL bRet = m_arrUIMap.Add(uumEnd);\n\t\tATLASSERT(bRet);\n\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\t_AtlUpdateUIData uud = { 0, NULL };\n\t\t\tbRet = m_arrUIData.Add(uud);\n\t\t\tATLASSERT(bRet);\n\n\t\t\t// Set new data to the previous end element\n\t\t\tif(bRet != FALSE)\n\t\t\t{\n\t\t\t\tint nSize = m_arrUIMap.GetSize();\n\t\t\t\t_AtlUpdateUIMap uum = { nID, wType };\n\t\t\t\tm_arrUIMap.SetAtIndex(nSize - 2, uum);\n\t\t\t\tm_arrUIData.SetAtIndex(nSize - 2, uud);\n\n\t\t\t\t// Set internal data pointers again, just in case that memory moved\n\t\t\t\tm_pUIMap = m_arrUIMap.m_aT;\n\t\t\t\tm_pUIData = m_arrUIData.m_aT;\n\n\t\t\t\tbRetVal = true;\n\t\t\t}\n\t\t}\n\n\t\treturn bRetVal;\n\t}\n\n\tbool UIRemoveUpdateElement(WORD nID)\n\t{\n\t\tbool bRetVal = false;\n\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrUIMap[i].m_nID == nID)\n\t\t\t{\n\t\t\t\tif((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)\n\t\t\t\t\tdelete [] m_arrUIData[i].m_lpstrText;\n\n\t\t\t\tBOOL bRet = m_arrUIMap.RemoveAt(i);\n\t\t\t\tATLASSERT(bRet);\n\t\t\t\tbRet = m_arrUIData.RemoveAt(i);\n\t\t\t\tATLASSERT(bRet);\n\n\t\t\t\tbRetVal = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn bRetVal;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAutoUpdateUI : Automatic mapping of UI elements\n\ntemplate <class T>\nclass CAutoUpdateUI : public CDynamicUpdateUI<T>\n{\npublic:\n\tLPCTSTR UIGetText(int nID)\n\t{\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrUIMap[i].m_nID == nID)\n \t\t\t\treturn m_arrUIData[i].m_lpstrText;\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n// Element\n\ttemplate <WORD t_wType>\n\tbool UIAddElement(UINT nID)\n\t{\n\t\t// check for existing UI map element\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrUIMap[i].m_nID == nID)\n\t\t\t{\n\t\t\t\t// set requested type\n\t\t\t\tm_arrUIMap[i].m_wType |= t_wType;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Add element to UI map with requested type\n\t\treturn UIAddUpdateElement((WORD)nID, t_wType);\n\t}\n\n\ttemplate <WORD t_wType>\n\tbool UIRemoveElement(UINT nID)\n\t{\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrUIMap[i].m_nID == nID) // matching UI map element\n\t\t\t{\n\t\t\t\tWORD wType = m_arrUIMap[i].m_wType & ~t_wType;\n\t\t\t\tif (wType != 0)   // has other types \n\t\t\t\t{\n\t\t\t\t\tm_arrUIMap[i].m_wType = wType; // keep other types\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn UIRemoveUpdateElement((WORD)nID);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n// Menu\n\tbool UIAddMenu(HMENU hMenu, bool bSetText = false)\n\t{\n#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)\n\t\tusing ATL::GetMenuString;\n#endif\n\t\tATLASSERT(::IsMenu(hMenu));\n\t\tMENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU};\n\n\t\t// Complete the UI map\n\t\tfor (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++)\n\t\t{\n\t\t\tif(mii.hSubMenu)\n\t\t\t{\n\t\t\t\t// Add submenu to UI map\n\t\t\t\tUIAddMenu(mii.hSubMenu, bSetText);\n\t\t\t}\n\t\t\telse if (mii.wID != 0)\n\t\t\t{\n\t\t\t\t// Add element to UI map\n\t\t\t\tUIAddElement<UPDUI_MENUPOPUP>(mii.wID);\n#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\t\t\t\tif (bSetText)\n\t\t\t\t{\n\t\t\t\t\tTCHAR sText[64] = { 0 };\n\t\t\t\t\tif (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION))\n\t\t\t\t\t\tUISetText(mii.wID, sText);\n\t\t\t\t}\n#else\n\t\t\t\tbSetText;\n#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool UIAddMenu(UINT uID, bool bSetText = false)\n\t{\n\t\tCMenu menu;\n\t\tATLVERIFY(menu.LoadMenu(uID));\n\t\treturn UIAddMenu(menu, bSetText);\n\t}\n\n// ToolBar\n#if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))\n\tbool UIAddToolBar(HWND hWndToolBar)\n\t{\n\t\tATLASSERT(::IsWindow(hWndToolBar));\n\t\tTBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX };\n\n\t\t// Add toolbar buttons\n\t\tfor (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++)\n\t\t{\n\t\t\tif (tbbi.fsStyle ^ BTNS_SEP)\n\t\t\t\tUIAddElement<UPDUI_TOOLBAR>(tbbi.idCommand);\n\t\t}\n\n\t\t// Add embedded controls if any\n\t\tif (::GetWindow(hWndToolBar, GW_CHILD))\n\t\t\tUIAddChildWindowContainer(hWndToolBar);\n\n\t\treturn (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE);\n\t}\n#endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))\n\n// Container\n\tbool UIAddChildWindowContainer(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(hWnd));\n\n\t\t// Add children controls if any\n\t\tfor (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT))\n\t\t{\n\t\t\tint id = wCtl.GetDlgCtrlID();\n\t\t\tif(id != 0)\n\t\t\t\tUIAddElement<UPDUI_CHILDWINDOW>(id);\n\t\t}\n\n\t\treturn (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE);\n\t}\n\n// StatusBar\n\tBOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)\n\t{\n\t\tif(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)\n\t\t\treturn TRUE;\n\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tfor(int e = 0; e < m_UIElements.GetSize(); e++)\n\t\t\t{\n\t\t\t\tif((m_UIElements[e].m_wType == UPDUI_STATUSBAR) && \n\t\t\t\t   (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) && \n\t\t\t\t   (m_arrUIData[i].m_wState & UPDUI_STATUSBAR))\n\t\t\t\t{\n\t\t\t\t\tUIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd);\n\t\t\t\t\tm_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR;\n\t\t\t\t\tif(m_arrUIData[i].m_wState & UPDUI_TEXT)\n\t\t\t\t\t\tm_arrUIData[i].m_wState &= ~UPDUI_TEXT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tm_wDirtyType &= ~UPDUI_STATUSBAR;\n\t\treturn TRUE;\n\t}\n\n\tbool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1)\n\t{\n\t\tATLASSERT(::IsWindow(hWndStatusBar));\n\n\t\t// Add StatusBar panes\n\t\tfor (int iPane = 0; iPane < nPanes; iPane++)\n\t\t\tUIAddElement<UPDUI_STATUSBAR>(ID_DEFAULT_PANE + iPane);\n\n\t\treturn (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE);\n\t}\n\n// UI Map used if derived class has none\n\tBEGIN_UPDATE_UI_MAP(CAutoUpdateUI)\n\tEND_UPDATE_UI_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDialogResize - provides support for resizing dialog controls\n//                 (works for any window that has child controls)\n\n// Put CDialogResize in the list of base classes for a dialog (or even plain window),\n// then implement DLGRESIZE map by specifying controls and groups of control\n// and using DLSZ_* values to specify how are they supposed to be resized.\n//\n// Notes:\n// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template\n//   for top level dialogs (popup or overlapped), so that users can resize the dialog.\n// - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X,\n//   DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined.\n// - Order of controls is important - group controls are resized and moved based\n//   on the position of the previous control in a group.\n\n// dialog resize map macros\n#define BEGIN_DLGRESIZE_MAP(thisClass) \\\n\tstatic const _AtlDlgResizeMap* GetDlgResizeMap() \\\n\t{ \\\n\t\tstatic const _AtlDlgResizeMap theMap[] = \\\n\t\t{\n\n#define END_DLGRESIZE_MAP() \\\n\t\t\t{ -1, 0 }, \\\n\t\t}; \\\n\t\treturn theMap; \\\n\t}\n\n#define DLGRESIZE_CONTROL(id, flags) \\\n\t\t{ id, flags },\n\n#define BEGIN_DLGRESIZE_GROUP() \\\n\t\t{ -1, _DLSZ_BEGIN_GROUP },\n\n#define END_DLGRESIZE_GROUP() \\\n\t\t{ -1, _DLSZ_END_GROUP },\n\n\ntemplate <class T>\nclass CDialogResize\n{\npublic:\n// Data declarations and members\n\tenum\n\t{\n\t\tDLSZ_SIZE_X\t\t= 0x00000001,\n\t\tDLSZ_SIZE_Y\t\t= 0x00000002,\n\t\tDLSZ_MOVE_X\t\t= 0x00000004,\n\t\tDLSZ_MOVE_Y\t\t= 0x00000008,\n\t\tDLSZ_REPAINT\t\t= 0x00000010,\n\t\tDLSZ_CENTER_X\t\t= 0x00000020,\n\t\tDLSZ_CENTER_Y\t\t= 0x00000040,\n\n\t\t// internal use only\n\t\t_DLSZ_BEGIN_GROUP\t= 0x00001000,\n\t\t_DLSZ_END_GROUP\t\t= 0x00002000,\n\t\t_DLSZ_GRIPPER\t\t= 0x00004000\n\t};\n\n\tstruct _AtlDlgResizeMap\n\t{\n\t\tint m_nCtlID;\n\t\tDWORD m_dwResizeFlags;\n\t};\n\n\tstruct _AtlDlgResizeData\n\t{\n\t\tint m_nCtlID;\n\t\tDWORD m_dwResizeFlags;\n\t\tRECT m_rect;\n\n\t\tint GetGroupCount() const\n\t\t{\n\t\t\treturn (int)LOBYTE(HIWORD(m_dwResizeFlags));\n\t\t}\n\n\t\tvoid SetGroupCount(int nCount)\n\t\t{\n\t\t\tATLASSERT(nCount > 0 && nCount < 256);\n\t\t\tDWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));\n\t\t\tm_dwResizeFlags &= 0xFF00FFFF;\n\t\t\tm_dwResizeFlags |= dwCount;\n\t\t}\n\n\t\tbool operator ==(const _AtlDlgResizeData& r) const\n\t\t{ return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); }\n\t};\n\n\tATL::CSimpleArray<_AtlDlgResizeData> m_arrData;\n\tSIZE m_sizeDialog;\n\tPOINT m_ptMinTrackSize;\n\tbool m_bGripper;\n\n\n// Constructor\n\tCDialogResize() : m_bGripper(false)\n\t{\n\t\tm_sizeDialog.cx = 0;\n\t\tm_sizeDialog.cy = 0;\n\t\tm_ptMinTrackSize.x = -1;\n\t\tm_ptMinTrackSize.y = -1;\n\t}\n\n// Operations\n\tvoid DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tDWORD dwStyle = pT->GetStyle();\n\n#ifdef _DEBUG\n\t\t// Debug only: Check if top level dialogs have a resizeable border.\n\t\tif(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0))\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\\n\"));\n#endif // _DEBUG\n\n\t\t// Force specified styles (default WS_CLIPCHILDREN reduces flicker)\n\t\tif((dwStyle & dwForceStyle) != dwForceStyle)\n\t\t\tpT->ModifyStyle(0, dwForceStyle);\n\n#ifndef _WIN32_WCE\n\t\t// Adding this style removes an empty icon that dialogs with WS_THICKFRAME have.\n\t\t// Setting icon to NULL is required when XP themes are active.\n\t\t// Note: This will not prevent adding an icon for the dialog using SetIcon()\n\t\tif((dwStyle & WS_CHILD) == 0)\n\t\t{\n\t\t\tpT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME);\n\t\t\tif(pT->GetIcon(FALSE) == NULL)\n\t\t\t\tpT->SetIcon(NULL, FALSE);\n\t\t}\n#endif\n\n\t\t// Cleanup in case of multiple initialization\n\t\t// block: first check for the gripper control, destroy it if needed\n\t\t{\n\t\t\tATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);\n\t\t\tif(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)\n\t\t\t\twndGripper.DestroyWindow();\n\t\t}\n\t\t// clear out everything else\n\t\tm_arrData.RemoveAll();\n\t\tm_sizeDialog.cx = 0;\n\t\tm_sizeDialog.cy = 0;\n\t\tm_ptMinTrackSize.x = -1;\n\t\tm_ptMinTrackSize.y = -1;\n\n\t\t// Get initial dialog client size\n\t\tRECT rectDlg = { 0 };\n\t\tpT->GetClientRect(&rectDlg);\n\t\tm_sizeDialog.cx = rectDlg.right;\n\t\tm_sizeDialog.cy = rectDlg.bottom;\n\n#ifndef _WIN32_WCE\n\t\t// Create gripper if requested\n\t\tm_bGripper = false;\n\t\tif(bAddGripper)\n\t\t{\n\t\t\t// shouldn't exist already\n\t\t\tATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)));\n\t\t\tif(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)))\n\t\t\t{\n\t\t\t\tATL::CWindow wndGripper;\n\t\t\t\twndGripper.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);\n\t\t\t\tATLASSERT(wndGripper.IsWindow());\n\t\t\t\tif(wndGripper.IsWindow())\n\t\t\t\t{\n\t\t\t\t\tm_bGripper = true;\n\t\t\t\t\tRECT rectCtl = { 0 };\n\t\t\t\t\twndGripper.GetWindowRect(&rectCtl);\n\t\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);\n\t\t\t\t\t_AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };\n\t\t\t\t\tm_arrData.Add(data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#else // CE specific\n\t\tbAddGripper;   // avoid level 4 warning\n#endif // _WIN32_WCE\n\n\t\t// Get min track position if requested\n\t\tif(bUseMinTrackSize)\n\t\t{\n\t\t\tif((dwStyle & WS_CHILD) != 0)\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\tpT->GetClientRect(&rect);\n\t\t\t\tm_ptMinTrackSize.x = rect.right - rect.left;\n\t\t\t\tm_ptMinTrackSize.y = rect.bottom - rect.top;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\tpT->GetWindowRect(&rect);\n\t\t\t\tm_ptMinTrackSize.x = rect.right - rect.left;\n\t\t\t\tm_ptMinTrackSize.y = rect.bottom - rect.top;\n\t\t\t}\n\t\t}\n\n\t\t// Walk the map and initialize data\n\t\tconst _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();\n\t\tATLASSERT(pMap != NULL);\n\t\tint nGroupStart = -1;\n\t\tfor(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)\n\t\t{\n\t\t\tif(pMap->m_nCtlID == -1)\n\t\t\t{\n\t\t\t\tswitch(pMap->m_dwResizeFlags)\n\t\t\t\t{\n\t\t\t\tcase _DLSZ_BEGIN_GROUP:\n\t\t\t\t\tATLASSERT(nGroupStart == -1);\n\t\t\t\t\tnGroupStart = m_arrData.GetSize();\n\t\t\t\t\tbreak;\n\t\t\t\tcase _DLSZ_END_GROUP:\n\t\t\t\t\t{\n\t\t\t\t\t\tATLASSERT(nGroupStart != -1);\n\t\t\t\t\t\tint nGroupCount = m_arrData.GetSize() - nGroupStart;\n\t\t\t\t\t\tm_arrData[nGroupStart].SetGroupCount(nGroupCount);\n\t\t\t\t\t\tnGroupStart = -1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tATLASSERT(FALSE && _T(\"Invalid DLGRESIZE Map Entry\"));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// this ID conflicts with the default gripper one\n\t\t\t\tATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);\n\n\t\t\t\tATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);\n\t\t\t\tATLASSERT(ctl.IsWindow());\n\t\t\t\tRECT rectCtl = { 0 };\n\t\t\t\tctl.GetWindowRect(&rectCtl);\n\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);\n\n\t\t\t\tDWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;\n\t\t\t\t_AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };\n\t\t\t\tm_arrData.Add(data);\n\t\t\t}\n\t\t}\n\t\tATLASSERT((nGroupStart == -1) && _T(\"No End Group Entry in the DLGRESIZE Map\"));\n\t}\n\n\tvoid DlgResize_UpdateLayout(int cxWidth, int cyHeight)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\t// Restrict minimum size if requested\n\t\tif(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)\n\t\t{\n\t\t\tif(cxWidth < m_ptMinTrackSize.x)\n\t\t\t\tcxWidth = m_ptMinTrackSize.x;\n\t\t\tif(cyHeight < m_ptMinTrackSize.y)\n\t\t\t\tcyHeight = m_ptMinTrackSize.y;\n\t\t}\n\n\t\tBOOL bVisible = pT->IsWindowVisible();\n\t\tif(bVisible)\n\t\t\tpT->SetRedraw(FALSE);\n\n\t\tfor(int i = 0; i < m_arrData.GetSize(); i++)\n\t\t{\n\t\t\tif((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0)   // start of a group\n\t\t\t{\n\t\t\t\tint nGroupCount = m_arrData[i].GetGroupCount();\n\t\t\t\tATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());\n\t\t\t\tRECT rectGroup = m_arrData[i].m_rect;\n\n\t\t\t\tint j = 1;\n\t\t\t\tfor(j = 1; j < nGroupCount; j++)\n\t\t\t\t{\n\t\t\t\t\trectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left);\n\t\t\t\t\trectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top);\n\t\t\t\t\trectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right);\n\t\t\t\t\trectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);\n\t\t\t\t}\n\n\t\t\t\tfor(j = 0; j < nGroupCount; j++)\n\t\t\t\t{\n\t\t\t\t\t_AtlDlgResizeData* pDataPrev = NULL;\n\t\t\t\t\tif(j > 0)\n\t\t\t\t\t\tpDataPrev = &(m_arrData[i + j - 1]);\n\t\t\t\t\tpT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev);\n\t\t\t\t}\n\n\t\t\t\ti += nGroupCount - 1;   // increment to skip all group controls\n\t\t\t}\n\t\t\telse // one control entry\n\t\t\t{\n\t\t\t\tRECT rectGroup = { 0 };\n\t\t\t\tpT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);\n\t\t\t}\n\t\t}\n\n\t\tif(bVisible)\n\t\t\tpT->SetRedraw(TRUE);\n\n\t\tpT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CDialogResize)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)\n#endif // _WIN32_WCE\n\tEND_MSG_MAP()\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n#ifndef _WIN32_WCE\n\t\tif(m_bGripper)\n\t\t{\n\t\t\tATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);\n\t\t\tif(wParam == SIZE_MAXIMIZED)\n\t\t\t\twndGripper.ShowWindow(SW_HIDE);\n\t\t\telse if(wParam == SIZE_RESTORED)\n\t\t\t\twndGripper.ShowWindow(SW_SHOW);\n\t\t}\n#endif // _WIN32_WCE\n\t\tif(wParam != SIZE_MINIMIZED)\n\t\t{\n\t\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\t\tpT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n\t\t}\n\t\treturn 0;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)\n\t\t{\n\t\t\tLPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;\n\t\t\tlpMMI->ptMinTrackSize =  m_ptMinTrackSize;\n\t\t}\n\t\treturn 0;\n\t}\n#endif // _WIN32_WCE\n\n// Implementation\n\tbool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup, \n\t                               _AtlDlgResizeData* pDataPrev = NULL)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tATL::CWindow ctl;\n\t\tRECT rectCtl = { 0 };\n\n\t\tctl = pT->GetDlgItem(data.m_nCtlID);\n\t\tif(!ctl.GetWindowRect(&rectCtl))\n\t\t\treturn false;\n\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);\n\n\t\tif(bGroup)\n\t\t{\n\t\t\tif((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)\n\t\t\t{\n\t\t\t\tint cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx;\n\t\t\t\tint cxCtl = data.m_rect.right - data.m_rect.left;\n\t\t\t\trectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2;\n\t\t\t\trectCtl.right = rectCtl.left + cxCtl;\n\t\t\t}\n\t\t\telse if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)\n\t\t\t{\n\t\t\t\trectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);\n\n\t\t\t\tif((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)\n\t\t\t\t{\n\t\t\t\t\trectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);\n\n\t\t\t\t\tif(pDataPrev != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);\n\t\t\t\t\t\tRECT rcPrev = { 0 };\n\t\t\t\t\t\tctlPrev.GetWindowRect(&rcPrev);\n\t\t\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);\n\t\t\t\t\t\tint dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right);\n\t\t\t\t\t\trcPrev.right += dxAdjust;\n\t\t\t\t\t\tctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\trectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)\n\t\t\t{\n\t\t\t\tint cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy;\n\t\t\t\tint cyCtl = data.m_rect.bottom - data.m_rect.top;\n\t\t\t\trectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2;\n\t\t\t\trectCtl.bottom = rectCtl.top + cyCtl;\n\t\t\t}\n\t\t\telse if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)\n\t\t\t{\n\t\t\t\trectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);\n\n\t\t\t\tif((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)\n\t\t\t\t{\n\t\t\t\t\trectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);\n\n\t\t\t\t\tif(pDataPrev != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);\n\t\t\t\t\t\tRECT rcPrev = { 0 };\n\t\t\t\t\t\tctlPrev.GetWindowRect(&rcPrev);\n\t\t\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);\n\t\t\t\t\t\tint dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom);\n\t\t\t\t\t\trcPrev.bottom += dxAdjust;\n\t\t\t\t\t\tctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\trectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse // no group\n\t\t{\n\t\t\tif((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)\n\t\t\t{\n\t\t\t\tint cxCtl = data.m_rect.right - data.m_rect.left;\n\t\t\t\trectCtl.left = (cxWidth - cxCtl) / 2;\n\t\t\t\trectCtl.right = rectCtl.left + cxCtl;\n\t\t\t}\n\t\t\telse if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)\n\t\t\t{\n\t\t\t\trectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);\n\n\t\t\t\tif((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)\n\t\t\t\t\trectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);\n\t\t\t}\n\n\t\t\tif((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)\n\t\t\t{\n\t\t\t\tint cyCtl = data.m_rect.bottom - data.m_rect.top;\n\t\t\t\trectCtl.top = (cyHeight - cyCtl) / 2;\n\t\t\t\trectCtl.bottom = rectCtl.top + cyCtl;\n\t\t\t}\n\t\t\telse if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)\n\t\t\t{\n\t\t\t\trectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);\n\n\t\t\t\tif((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)\n\t\t\t\t\trectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);\n\t\t\t}\n\t\t}\n\n\t\tif((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)\n\t\t\tctl.Invalidate();\n\n\t\tif((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0)\n\t\t\tctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);\n\n\t\treturn true;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDoubleBufferImpl - Provides double-buffer painting support to any window\n\ntemplate <class T>\nclass CDoubleBufferImpl\n{\npublic:\n// Overrideables\n\tvoid DoPaint(CDCHandle /*dc*/)\n\t{\n\t\t// must be implemented in a derived class\n\t\tATLASSERT(FALSE);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CDoubleBufferImpl)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n#endif // !_WIN32_WCE\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background painting needed\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetClientRect(&rect);\n\t\t\tCMemoryDC dcMem((HDC)wParam, rect);\n\t\t\tpT->DoPaint(dcMem.m_hDC);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tCMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);\n\t\t\tpT->DoPaint(dcMem.m_hDC);\n\t\t}\n\n\t\treturn 0;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDoubleBufferWindowImpl - Implements a double-buffer painting window\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T >\n{\npublic:\n\tBEGIN_MSG_MAP(CDoubleBufferWindowImpl)\n\t\tCHAIN_MSG_MAP(CDoubleBufferImpl< T >)\n\tEND_MSG_MAP()\n};\n\n\n// command bar support\n#if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)\n  #undef CBRM_GETMENU\n  #undef CBRM_TRACKPOPUPMENU\n  #undef CBRM_GETCMDBAR\n  #undef CBRPOPUPMENU\n#endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)\n\n}; // namespace WTL\n\n#endif // __ATLFRAME_H__\n"
  },
  {
    "path": "WTL/atlgdi.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLGDI_H__\n#define __ATLGDI_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlgdi.h requires atlapp.h to be included first\n#endif\n\n\n// protect template members from windowsx.h macros\n#ifdef _INC_WINDOWSX\n  #undef CopyRgn\n  #undef CreateBrush\n  #undef CreatePen\n  #undef SelectBrush\n  #undef SelectPen\n  #undef SelectFont\n  #undef SelectBitmap\n#endif // _INC_WINDOWSX\n\n// required libraries\n#if !defined(_ATL_NO_MSIMG) && !defined(_WIN32_WCE)\n  #pragma comment(lib, \"msimg32.lib\")\n#endif\n#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)\n  #pragma comment(lib, \"opengl32.lib\")\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CPenT<t_bManaged>\n// CBrushT<t_bManaged>\n// CLogFont\n// CFontT<t_bManaged>\n// CBitmapT<t_bManaged>\n// CPaletteT<t_bManaged>\n// CRgnT<t_bManaged>\n// CDCT<t_bManaged>\n// CPaintDC\n// CClientDC\n// CWindowDC\n// CMemoryDC\n// CEnhMetaFileInfo\n// CEnhMetaFileT<t_bManaged>\n// CEnhMetaFileDC\n//\n// Global functions:\n//   AtlGetBitmapResourceInfo()\n//   AtlGetBitmapResourceBitsPerPixel()\n//   AtlIsAlphaBitmapResource()\n//   AtlIsDib16()\n//   AtlGetDibColorTableSize()\n//   AtlGetDibNumColors(),\n//   AtlGetDibBitmap()\n//   AtlCopyBitmap()\n//   AtlCreatePackedDib16()\n//   AtlSetClipboardDib16()\n//   AtlGetClipboardDib()\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// Bitmap resource helpers to extract bitmap information for a bitmap resource\n\ninline LPBITMAPINFOHEADER AtlGetBitmapResourceInfo(HMODULE hModule, ATL::_U_STRINGorID image)\n{\n\tHRSRC hResource = ::FindResource(hModule, image.m_lpstr, RT_BITMAP);\n\tATLASSERT(hResource != NULL);\n\tHGLOBAL hGlobal = ::LoadResource(hModule, hResource);\n\tATLASSERT(hGlobal != NULL);\n\tLPBITMAPINFOHEADER pBitmapInfoHeader = (LPBITMAPINFOHEADER)::LockResource(hGlobal);\n\tATLASSERT(pBitmapInfoHeader != NULL);\n\treturn pBitmapInfoHeader;\n}\n\ninline WORD AtlGetBitmapResourceBitsPerPixel(HMODULE hModule, ATL::_U_STRINGorID image)\n{\n\tLPBITMAPINFOHEADER pBitmapInfoHeader = AtlGetBitmapResourceInfo(hModule, image);\n\tATLASSERT(pBitmapInfoHeader != NULL);\n\treturn pBitmapInfoHeader->biBitCount;\n}\n\ninline WORD AtlGetBitmapResourceBitsPerPixel(ATL::_U_STRINGorID image)\n{\n\treturn AtlGetBitmapResourceBitsPerPixel(ModuleHelper::GetResourceInstance(), image);\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// 32-bit (alpha channel) bitmap resource helper\n\n// Note: 32-bit (alpha channel) images work only on Windows XP with Common Controls version 6.\n// If you want your app to work on older version of Windows, load non-alpha images if Common\n// Controls version is less than 6.\n\ninline bool AtlIsAlphaBitmapResource(ATL::_U_STRINGorID image)\n{\n\treturn (AtlGetBitmapResourceBitsPerPixel(image) == 32);\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPen\n\ntemplate <bool t_bManaged>\nclass CPenT\n{\npublic:\n// Data members\n\tHPEN m_hPen;\n\n// Constructor/destructor/operators\n\tCPenT(HPEN hPen = NULL) : m_hPen(hPen)\n\t{ }\n\n\t~CPenT()\n\t{\n\t\tif(t_bManaged && m_hPen != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCPenT<t_bManaged>& operator =(HPEN hPen)\n\t{\n\t\tAttach(hPen);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HPEN hPen)\n\t{\n\t\tif(t_bManaged && m_hPen != NULL && m_hPen != hPen)\n\t\t\t::DeleteObject(m_hPen);\n\t\tm_hPen = hPen;\n\t}\n\n\tHPEN Detach()\n\t{\n\t\tHPEN hPen = m_hPen;\n\t\tm_hPen = NULL;\n\t\treturn hPen;\n\t}\n\n\toperator HPEN() const { return m_hPen; }\n\n\tbool IsNull() const { return (m_hPen == NULL); }\n\n// Create methods\n\tHPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hPen == NULL);\n\t\tm_hPen = ::CreatePen(nPenStyle, nWidth, crColor);\n\t\treturn m_hPen;\n\t}\n\n#ifndef _WIN32_WCE\n\tHPEN CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL)\n\t{\n\t\tATLASSERT(m_hPen == NULL);\n\t\tm_hPen = ::ExtCreatePen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle);\n\t\treturn m_hPen;\n\t}\n#endif // !_WIN32_WCE\n\n\tHPEN CreatePenIndirect(LPLOGPEN lpLogPen)\n\t{\n\t\tATLASSERT(m_hPen == NULL);\n\t\tm_hPen = ::CreatePenIndirect(lpLogPen);\n\t\treturn m_hPen;\n\t}\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hPen != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hPen);\n\t\tif(bRet)\n\t\t\tm_hPen = NULL;\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetLogPen(LOGPEN* pLogPen) const\n\t{\n\t\tATLASSERT(m_hPen != NULL);\n\t\treturn ::GetObject(m_hPen, sizeof(LOGPEN), pLogPen);\n\t}\n\n\tbool GetLogPen(LOGPEN& LogPen) const\n\t{\n\t\tATLASSERT(m_hPen != NULL);\n\t\treturn (::GetObject(m_hPen, sizeof(LOGPEN), &LogPen) == sizeof(LOGPEN));\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetExtLogPen(EXTLOGPEN* pLogPen, int nSize = sizeof(EXTLOGPEN)) const\n\t{\n\t\tATLASSERT(m_hPen != NULL);\n\t\treturn ::GetObject(m_hPen, nSize, pLogPen);\n\t}\n\n\tbool GetExtLogPen(EXTLOGPEN& ExtLogPen, int nSize = sizeof(EXTLOGPEN)) const\n\t{\n\t\tATLASSERT(m_hPen != NULL);\n\t\tint nRet = ::GetObject(m_hPen, nSize, &ExtLogPen);\n\t\treturn ((nRet > 0) && (nRet <= nSize));\n\t}\n#endif // !_WIN32_WCE\n};\n\ntypedef CPenT<false>   CPenHandle;\ntypedef CPenT<true>    CPen;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBrush\n\ntemplate <bool t_bManaged>\nclass CBrushT\n{\npublic:\n// Data members\n\tHBRUSH m_hBrush;\n\n// Constructor/destructor/operators\n\tCBrushT(HBRUSH hBrush = NULL) : m_hBrush(hBrush)\n\t{ }\n\n\t~CBrushT()\n\t{\n\t\tif(t_bManaged && m_hBrush != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCBrushT<t_bManaged>& operator =(HBRUSH hBrush)\n\t{\n\t\tAttach(hBrush);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HBRUSH hBrush)\n\t{\n\t\tif(t_bManaged && m_hBrush != NULL && m_hBrush != hBrush)\n\t\t\t::DeleteObject(m_hBrush);\n\t\tm_hBrush = hBrush;\n\t}\n\n\tHBRUSH Detach()\n\t{\n\t\tHBRUSH hBrush = m_hBrush;\n\t\tm_hBrush = NULL;\n\t\treturn hBrush;\n\t}\n\n\toperator HBRUSH() const { return m_hBrush; }\n\n\tbool IsNull() const { return (m_hBrush == NULL); }\n\n// Create methods\n\tHBRUSH CreateSolidBrush(COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n\t\tm_hBrush = ::CreateSolidBrush(crColor);\n\t\treturn m_hBrush;\n\t}\n\n#ifndef _WIN32_WCE\n\tHBRUSH CreateHatchBrush(int nIndex, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n\t\tm_hBrush = ::CreateHatchBrush(nIndex, crColor);\n\t\treturn m_hBrush;\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\tHBRUSH CreateBrushIndirect(const LOGBRUSH* lpLogBrush)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n#ifndef _WIN32_WCE\n\t\tm_hBrush = ::CreateBrushIndirect(lpLogBrush);\n#else // CE specific\n\t\tm_hBrush = ATL::CreateBrushIndirect(lpLogBrush);\n#endif // _WIN32_WCE\n\t\treturn m_hBrush;\n\t}\n#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\n\tHBRUSH CreatePatternBrush(HBITMAP hBitmap)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n\t\tm_hBrush = ::CreatePatternBrush(hBitmap);\n\t\treturn m_hBrush;\n\t}\n\n\tHBRUSH CreateDIBPatternBrush(HGLOBAL hPackedDIB, UINT nUsage)\n\t{\n\t\tATLASSERT(hPackedDIB != NULL);\n\t\tconst void* lpPackedDIB = GlobalLock(hPackedDIB);\n\t\tATLASSERT(lpPackedDIB != NULL);\n\t\tm_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);\n\t\tGlobalUnlock(hPackedDIB);\n\t\treturn m_hBrush;\n\t}\n\n\tHBRUSH CreateDIBPatternBrush(const void* lpPackedDIB, UINT nUsage)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n\t\tm_hBrush = ::CreateDIBPatternBrushPt(lpPackedDIB, nUsage);\n\t\treturn m_hBrush;\n\t}\n\n\tHBRUSH CreateSysColorBrush(int nIndex)\n\t{\n\t\tATLASSERT(m_hBrush == NULL);\n\t\tm_hBrush = ::GetSysColorBrush(nIndex);\n\t\treturn m_hBrush;\n\t}\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hBrush != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hBrush);\n\t\tif(bRet)\n\t\t\tm_hBrush = NULL;\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetLogBrush(LOGBRUSH* pLogBrush) const\n\t{\n\t\tATLASSERT(m_hBrush != NULL);\n\t\treturn ::GetObject(m_hBrush, sizeof(LOGBRUSH), pLogBrush);\n\t}\n\n\tbool GetLogBrush(LOGBRUSH& LogBrush) const\n\t{\n\t\tATLASSERT(m_hBrush != NULL);\n\t\treturn (::GetObject(m_hBrush, sizeof(LOGBRUSH), &LogBrush) == sizeof(LOGBRUSH));\n\t}\n};\n\ntypedef CBrushT<false>   CBrushHandle;\ntypedef CBrushT<true>    CBrush;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFont\n\nclass CLogFont : public LOGFONT\n{\npublic:\n\tCLogFont()\n\t{\n\t\tmemset(this, 0, sizeof(LOGFONT));\n\t}\n\n\tCLogFont(const LOGFONT& lf)\n\t{\n\t\tCopy(&lf);\n\t}\n\n\tCLogFont(HFONT hFont)\n\t{\n\t\tATLASSERT(::GetObjectType(hFont) == OBJ_FONT);\n\t\t::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);\n\t}\n\n\tHFONT CreateFontIndirect()\n\t{\n\t\treturn ::CreateFontIndirect(this);\n\t}\n\n\tvoid SetBold()\n\t{\n\t\tlfWeight = FW_BOLD;\n\t}\n\n\tbool IsBold() const\n\t{\n\t\treturn (lfWeight >= FW_BOLD);\n\t}\n\n\tvoid MakeBolder(int iScale = 1)\n\t{\n\t\tlfWeight += FW_BOLD * iScale;\n\t}\n\n\tvoid MakeLarger(int iScale)\n\t{\n\t\tif(lfHeight > 0)\n\t\t\tlfHeight += iScale;\n\t\telse\n\t\t\tlfHeight -= iScale;\n\t}\n\n\tvoid SetHeight(LONG nPointSize, HDC hDC = NULL)\n\t{\n\t\tHDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);\n\t\t// For MM_TEXT mapping mode\n\t\tlfHeight = -::MulDiv(nPointSize, ::GetDeviceCaps(hDC1, LOGPIXELSY), 72);\n\t\tif(hDC == NULL)\n\t\t\t::ReleaseDC(NULL, hDC1);\n\t}\n\n\tLONG GetHeight(HDC hDC = NULL) const\n\t{\n\t\tHDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);\n\t\t// For MM_TEXT mapping mode\n\t\tLONG nPointSize = ::MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC1, LOGPIXELSY));\n\t\tif(hDC == NULL)\n\t\t\t::ReleaseDC(NULL, hDC1);\n\n\t\treturn nPointSize;\n\t}\n\n\tLONG GetDeciPointHeight(HDC hDC = NULL) const\n\t{\n\t\tHDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);\n#ifndef _WIN32_WCE\n\t\tPOINT ptOrg = { 0, 0 };\n\t\t::DPtoLP(hDC1, &ptOrg, 1);\n\t\tPOINT pt = { 0, 0 };\n\t\tpt.y = abs(lfHeight) + ptOrg.y;\n\t\t::LPtoDP(hDC1, &pt,1);\n\t\tLONG nDeciPoint = ::MulDiv(pt.y, 720, ::GetDeviceCaps(hDC1, LOGPIXELSY));   // 72 points/inch, 10 decipoints/point\n#else // CE specific\n\t\t// DP and LP are always the same on CE\n\t\tLONG nDeciPoint = ::MulDiv(abs(lfHeight), 720, ::GetDeviceCaps(hDC1, LOGPIXELSY));   // 72 points/inch, 10 decipoints/point\n#endif // _WIN32_WCE\n\t\tif(hDC == NULL)\n\t\t\t::ReleaseDC(NULL, hDC1);\n\n\t\treturn nDeciPoint;\n\t}\n\n\tvoid SetHeightFromDeciPoint(LONG nDeciPtHeight, HDC hDC = NULL)\n\t{\n\t\tHDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);\n#ifndef _WIN32_WCE\n\t\tPOINT pt = { 0, 0 };\n\t\tpt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720);   // 72 points/inch, 10 decipoints/point\n\t\t::DPtoLP(hDC1, &pt, 1);\n\t\tPOINT ptOrg = { 0, 0 };\n\t\t::DPtoLP(hDC1, &ptOrg, 1);\n\t\tlfHeight = -abs(pt.y - ptOrg.y);\n#else // CE specific\n\t\t// DP and LP are always the same on CE\n\t\tlfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), nDeciPtHeight, 720));   // 72 points/inch, 10 decipoints/point\n#endif // _WIN32_WCE\n\t\tif(hDC == NULL)\n\t\t\t::ReleaseDC(NULL, hDC1);\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid SetCaptionFont()\n\t{\n\t\tNONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));\n\t\tCopy(&ncm.lfCaptionFont);\n\t}\n\n\tvoid SetMenuFont()\n\t{\n\t\tNONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));\n\t\tCopy(&ncm.lfMenuFont);\n\t}\n\n\tvoid SetStatusFont()\n\t{\n\t\tNONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));\n\t\tCopy(&ncm.lfStatusFont);\n\t}\n\n\tvoid SetMessageBoxFont()\n\t{\n\t\tNONCLIENTMETRICS ncm = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };\n\t\tATLVERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));\n\t\tCopy(&ncm.lfMessageFont);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid Copy(const LOGFONT* pLogFont)\n\t{\n\t\tATLASSERT(pLogFont != NULL);\n\t\t*(LOGFONT*)this = *pLogFont;\n\t}\n\n\tCLogFont& operator =(const CLogFont& src)\n\t{\n\t\tCopy(&src);\n\t\treturn *this;\n\t}\n\n\tCLogFont& operator =(const LOGFONT& src)\n\t{\n\t\tCopy(&src);\n\t\treturn *this;\n\t}\n\n\tCLogFont& operator =(HFONT hFont)\n\t{\n\t\tATLASSERT(::GetObjectType(hFont) == OBJ_FONT);\n\t\t::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*)this);\n\t\treturn *this;\n\t}\n\n\tbool operator ==(const LOGFONT& logfont) const\n\t{\n\t\treturn(logfont.lfHeight == lfHeight &&\n\t\t       logfont.lfWidth == lfWidth &&\n\t\t       logfont.lfEscapement == lfEscapement &&\n\t\t       logfont.lfOrientation == lfOrientation &&\n\t\t       logfont.lfWeight == lfWeight &&\n\t\t       logfont.lfItalic == lfItalic &&\n\t\t       logfont.lfUnderline == lfUnderline &&\n\t\t       logfont.lfStrikeOut == lfStrikeOut &&\n\t\t       logfont.lfCharSet == lfCharSet &&\n\t\t       logfont.lfOutPrecision == lfOutPrecision &&\n\t\t       logfont.lfClipPrecision == lfClipPrecision &&\n\t\t       logfont.lfQuality == lfQuality &&\n\t\t       logfont.lfPitchAndFamily == lfPitchAndFamily &&\n\t\t       lstrcmp(logfont.lfFaceName, lfFaceName) == 0);\n\t}\n};\n\n\ntemplate <bool t_bManaged>\nclass CFontT\n{\npublic:\n// Data members\n\tHFONT m_hFont;\n\n// Constructor/destructor/operators\n\tCFontT(HFONT hFont = NULL) : m_hFont(hFont)\n\t{ }\n\n\t~CFontT()\n\t{\n\t\tif(t_bManaged && m_hFont != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCFontT<t_bManaged>& operator =(HFONT hFont)\n\t{\n\t\tAttach(hFont);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HFONT hFont)\n\t{\n\t\tif(t_bManaged && m_hFont != NULL && m_hFont != hFont)\n\t\t\t::DeleteObject(m_hFont);\n\t\tm_hFont = hFont;\n\t}\n\n\tHFONT Detach()\n\t{\n\t\tHFONT hFont = m_hFont;\n\t\tm_hFont = NULL;\n\t\treturn hFont;\n\t}\n\n\toperator HFONT() const { return m_hFont; }\n\n\tbool IsNull() const { return (m_hFont == NULL); }\n\n// Create methods\n\tHFONT CreateFontIndirect(const LOGFONT* lpLogFont)\n\t{\n\t\tATLASSERT(m_hFont == NULL);\n\t\tm_hFont = ::CreateFontIndirect(lpLogFont);\n\t\treturn m_hFont;\n\t}\n\n#if !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)\n\tHFONT CreateFontIndirectEx(CONST ENUMLOGFONTEXDV* penumlfex)\n\t{\n\t\tATLASSERT(m_hFont == NULL);\n\t\tm_hFont = ::CreateFontIndirectEx(penumlfex);\n\t\treturn m_hFont;\n\t}\n#endif // !defined(_WIN32_WCE) && (_WIN32_WINNT >= 0x0500)\n\n#if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\tHFONT CreateFont(int nHeight, int nWidth, int nEscapement,\n\t\t\tint nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline,\n\t\t\tBYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision,\n\t\t\tBYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily,\n\t\t\tLPCTSTR lpszFacename)\n\t{\n\t\tATLASSERT(m_hFont == NULL);\n#ifndef _WIN32_WCE\n\t\tm_hFont = ::CreateFont(nHeight, nWidth, nEscapement,\n\t\t\tnOrientation, nWeight, bItalic, bUnderline, cStrikeOut,\n\t\t\tnCharSet, nOutPrecision, nClipPrecision, nQuality,\n\t\t\tnPitchAndFamily, lpszFacename);\n#else // CE specific\n\t\tm_hFont = ATL::CreateFont(nHeight, nWidth, nEscapement,\n\t\t\tnOrientation, nWeight, bItalic, bUnderline, cStrikeOut,\n\t\t\tnCharSet, nOutPrecision, nClipPrecision, nQuality,\n\t\t\tnPitchAndFamily, lpszFacename);\n#endif // _WIN32_WCE\n\t\treturn m_hFont;\n\t}\n#endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)\n\n\tHFONT CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, HDC hDC = NULL, bool bBold = false, bool bItalic = false)\n\t{\n\t\tLOGFONT logFont = { 0 };\n\t\tlogFont.lfCharSet = DEFAULT_CHARSET;\n\t\tlogFont.lfHeight = nPointSize;\n\t\tSecureHelper::strncpy_x(logFont.lfFaceName, _countof(logFont.lfFaceName), lpszFaceName, _TRUNCATE);\n\n\t\tif(bBold)\n\t\t\tlogFont.lfWeight = FW_BOLD;\n\t\tif(bItalic)\n\t\t\tlogFont.lfItalic = (BYTE)TRUE;\n\n\t\treturn CreatePointFontIndirect(&logFont, hDC);\n\t}\n\n\tHFONT CreatePointFontIndirect(const LOGFONT* lpLogFont, HDC hDC = NULL)\n\t{\n\t\tHDC hDC1 = (hDC != NULL) ? hDC : ::GetDC(NULL);\n\n\t\t// convert nPointSize to logical units based on hDC\n\t\tLOGFONT logFont = *lpLogFont;\n#ifndef _WIN32_WCE\n\t\tPOINT pt = { 0, 0 };\n\t\tpt.y = ::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720);   // 72 points/inch, 10 decipoints/point\n\t\t::DPtoLP(hDC1, &pt, 1);\n\t\tPOINT ptOrg = { 0, 0 };\n\t\t::DPtoLP(hDC1, &ptOrg, 1);\n\t\tlogFont.lfHeight = -abs(pt.y - ptOrg.y);\n#else // CE specific\n\t\t// DP and LP are always the same on CE\n\t\tlogFont.lfHeight = -abs(::MulDiv(::GetDeviceCaps(hDC1, LOGPIXELSY), logFont.lfHeight, 720));   // 72 points/inch, 10 decipoints/point\n#endif // _WIN32_WCE\n\n\t\tif(hDC == NULL)\n\t\t\t::ReleaseDC(NULL, hDC1);\n\n\t\treturn CreateFontIndirect(&logFont);\n\t}\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hFont != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hFont);\n\t\tif(bRet)\n\t\t\tm_hFont = NULL;\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetLogFont(LOGFONT* pLogFont) const\n\t{\n\t\tATLASSERT(m_hFont != NULL);\n\t\treturn ::GetObject(m_hFont, sizeof(LOGFONT), pLogFont);\n\t}\n\n\tbool GetLogFont(LOGFONT& LogFont) const\n\t{\n\t\tATLASSERT(m_hFont != NULL);\n\t\treturn (::GetObject(m_hFont, sizeof(LOGFONT), &LogFont) == sizeof(LOGFONT));\n\t}\n};\n\ntypedef CFontT<false>   CFontHandle;\ntypedef CFontT<true>    CFont;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBitmap\n\ntemplate <bool t_bManaged>\nclass CBitmapT\n{\npublic:\n// Data members\n\tHBITMAP m_hBitmap;\n\n// Constructor/destructor/operators\n\tCBitmapT(HBITMAP hBitmap = NULL) : m_hBitmap(hBitmap)\n\t{ }\n\n\t~CBitmapT()\n\t{\n\t\tif(t_bManaged && m_hBitmap != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCBitmapT<t_bManaged>& operator =(HBITMAP hBitmap)\n\t{\n\t\tAttach(hBitmap);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HBITMAP hBitmap)\n\t{\n\t\tif(t_bManaged && m_hBitmap != NULL&& m_hBitmap != hBitmap)\n\t\t\t::DeleteObject(m_hBitmap);\n\t\tm_hBitmap = hBitmap;\n\t}\n\n\tHBITMAP Detach()\n\t{\n\t\tHBITMAP hBitmap = m_hBitmap;\n\t\tm_hBitmap = NULL;\n\t\treturn hBitmap;\n\t}\n\n\toperator HBITMAP() const { return m_hBitmap; }\n\n\tbool IsNull() const { return (m_hBitmap == NULL); }\n\n// Create and load methods\n\tHBITMAP LoadBitmap(ATL::_U_STRINGorID bitmap)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr);\n\t\treturn m_hBitmap;\n\t}\n\n\tHBITMAP LoadOEMBitmap(UINT nIDBitmap) // for OBM_/OCR_/OIC_\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::LoadBitmap(NULL, MAKEINTRESOURCE(nIDBitmap));\n\t\treturn m_hBitmap;\n\t}\n\n#ifndef _WIN32_WCE\n\tHBITMAP LoadMappedBitmap(UINT nIDBitmap, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateMappedBitmap(ModuleHelper::GetResourceInstance(), nIDBitmap, (WORD)nFlags, lpColorMap, nMapSize);\n\t\treturn m_hBitmap;\n\t}\n#endif // !_WIN32_WCE\n\n\tHBITMAP CreateBitmap(int nWidth, int nHeight, UINT nPlanes, UINT nBitsPerPixel, const void* lpBits)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateBitmap(nWidth, nHeight, nPlanes, nBitsPerPixel, lpBits);\n\t\treturn m_hBitmap;\n\t}\n\n#ifndef _WIN32_WCE\n\tHBITMAP CreateBitmapIndirect(LPBITMAP lpBitmap)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateBitmapIndirect(lpBitmap);\n\t\treturn m_hBitmap;\n\t}\n#endif // !_WIN32_WCE\n\n\tHBITMAP CreateCompatibleBitmap(HDC hDC, int nWidth, int nHeight)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateCompatibleBitmap(hDC, nWidth, nHeight);\n\t\treturn m_hBitmap;\n\t}\n\n#ifndef _WIN32_WCE\n\tHBITMAP CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateDiscardableBitmap(hDC, nWidth, nHeight);\n\t\treturn m_hBitmap;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hBitmap);\n\t\tif(bRet)\n\t\t\tm_hBitmap = NULL;\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetBitmap(BITMAP* pBitMap) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::GetObject(m_hBitmap, sizeof(BITMAP), pBitMap);\n\t}\n\n\tbool GetBitmap(BITMAP& bm) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn (::GetObject(m_hBitmap, sizeof(BITMAP), &bm) == sizeof(BITMAP));\n\t}\n\n\tbool GetSize(SIZE& size) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\tBITMAP bm = { 0 };\n\t\tif(!GetBitmap(&bm))\n\t\t\treturn false;\n\t\tsize.cx = bm.bmWidth;\n\t\tsize.cy = bm.bmHeight;\n\t\treturn true;\n\t}\n\n#ifndef _WIN32_WCE\n\tDWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::GetBitmapBits(m_hBitmap, dwCount, lpBits);\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)\n\tDWORD SetBitmapBits(DWORD dwCount, const void* lpBits)\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::SetBitmapBits(m_hBitmap, dwCount, lpBits);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)\n\n#ifndef _WIN32_WCE\n\tBOOL GetBitmapDimension(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::GetBitmapDimensionEx(m_hBitmap, lpSize);\n\t}\n\n\tBOOL SetBitmapDimension(int nWidth, int nHeight, LPSIZE lpSize = NULL)\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::SetBitmapDimensionEx(m_hBitmap, nWidth, nHeight, lpSize);\n\t}\n\n// DIB support\n\tHBITMAP CreateDIBitmap(HDC hDC, CONST BITMAPINFOHEADER* lpbmih, DWORD dwInit, CONST VOID* lpbInit, CONST BITMAPINFO* lpbmi, UINT uColorUse)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateDIBitmap(hDC, lpbmih, dwInit, lpbInit, lpbmi, uColorUse);\n\t\treturn m_hBitmap;\n\t}\n#endif // !_WIN32_WCE\n\n\tHBITMAP CreateDIBSection(HDC hDC, CONST BITMAPINFO* lpbmi, UINT uColorUse, VOID** ppvBits, HANDLE hSection, DWORD dwOffset)\n\t{\n\t\tATLASSERT(m_hBitmap == NULL);\n\t\tm_hBitmap = ::CreateDIBSection(hDC, lpbmi, uColorUse, ppvBits, hSection, dwOffset);\n\t\treturn m_hBitmap;\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines,  LPVOID lpvBits, LPBITMAPINFO lpbmi, UINT uColorUse) const\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::GetDIBits(hDC, m_hBitmap, uStartScan, cScanLines,  lpvBits, lpbmi, uColorUse);\n\t}\n\n\tint SetDIBits(HDC hDC, UINT uStartScan, UINT cScanLines, CONST VOID* lpvBits, CONST BITMAPINFO* lpbmi, UINT uColorUse)\n\t{\n\t\tATLASSERT(m_hBitmap != NULL);\n\t\treturn ::SetDIBits(hDC, m_hBitmap, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);\n\t}\n#endif // !_WIN32_WCE\n};\n\ntypedef CBitmapT<false>   CBitmapHandle;\ntypedef CBitmapT<true>    CBitmap;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPalette\n\ntemplate <bool t_bManaged>\nclass CPaletteT\n{\npublic:\n// Data members\n\tHPALETTE m_hPalette;\n\n// Constructor/destructor/operators\n\tCPaletteT(HPALETTE hPalette = NULL) : m_hPalette(hPalette)\n\t{ }\n\n\t~CPaletteT()\n\t{\n\t\tif(t_bManaged && m_hPalette != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCPaletteT<t_bManaged>& operator =(HPALETTE hPalette)\n\t{\n\t\tAttach(hPalette);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HPALETTE hPalette)\n\t{\n\t\tif(t_bManaged && m_hPalette != NULL && m_hPalette != hPalette)\n\t\t\t::DeleteObject(m_hPalette);\n\t\tm_hPalette = hPalette;\n\t}\n\n\tHPALETTE Detach()\n\t{\n\t\tHPALETTE hPalette = m_hPalette;\n\t\tm_hPalette = NULL;\n\t\treturn hPalette;\n\t}\n\n\toperator HPALETTE() const { return m_hPalette; }\n\n\tbool IsNull() const { return (m_hPalette == NULL); }\n\n// Create methods\n\tHPALETTE CreatePalette(LPLOGPALETTE lpLogPalette)\n\t{\n\t\tATLASSERT(m_hPalette == NULL);\n\t\tm_hPalette = ::CreatePalette(lpLogPalette);\n\t\treturn m_hPalette;\n\t}\n\n#ifndef _WIN32_WCE\n\tHPALETTE CreateHalftonePalette(HDC hDC)\n\t{\n\t\tATLASSERT(m_hPalette == NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\tm_hPalette = ::CreateHalftonePalette(hDC);\n\t\treturn m_hPalette;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hPalette);\n\t\tif(bRet)\n\t\t\tm_hPalette = NULL;\n\t\treturn bRet;\n\t}\n\n// Attributes\n\tint GetEntryCount() const\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\tWORD nEntries = 0;\n\t\t::GetObject(m_hPalette, sizeof(WORD), &nEntries);\n\t\treturn (int)nEntries;\n\t}\n\n\tUINT GetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors) const\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\treturn ::GetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);\n\t}\n\n\tUINT SetPaletteEntries(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\treturn ::SetPaletteEntries(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);\n\t}\n\n// Operations\n#ifndef _WIN32_WCE\n\tvoid AnimatePalette(UINT nStartIndex, UINT nNumEntries, LPPALETTEENTRY lpPaletteColors)\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\t::AnimatePalette(m_hPalette, nStartIndex, nNumEntries, lpPaletteColors);\n\t}\n\n\tBOOL ResizePalette(UINT nNumEntries)\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\treturn ::ResizePalette(m_hPalette, nNumEntries);\n\t}\n#endif // !_WIN32_WCE\n\n\tUINT GetNearestPaletteIndex(COLORREF crColor) const\n\t{\n\t\tATLASSERT(m_hPalette != NULL);\n\t\treturn ::GetNearestPaletteIndex(m_hPalette, crColor);\n\t}\n};\n\ntypedef CPaletteT<false>   CPaletteHandle;\ntypedef CPaletteT<true>    CPalette;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRgn\n\ntemplate <bool t_bManaged>\nclass CRgnT\n{\npublic:\n// Data members\n\tHRGN m_hRgn;\n\n// Constructor/destructor/operators\n\tCRgnT(HRGN hRgn = NULL) : m_hRgn(hRgn)\n\t{ }\n\n\t~CRgnT()\n\t{\n\t\tif(t_bManaged && m_hRgn != NULL)\n\t\t\tDeleteObject();\n\t}\n\n\tCRgnT<t_bManaged>& operator =(HRGN hRgn)\n\t{\n\t\tAttach(hRgn);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HRGN hRgn)\n\t{\n\t\tif(t_bManaged && m_hRgn != NULL && m_hRgn != hRgn)\n\t\t\t::DeleteObject(m_hRgn);\n\t\tm_hRgn = hRgn;\n\t}\n\n\tHRGN Detach()\n\t{\n\t\tHRGN hRgn = m_hRgn;\n\t\tm_hRgn = NULL;\n\t\treturn hRgn;\n\t}\n\n\toperator HRGN() const { return m_hRgn; }\n\n\tbool IsNull() const { return (m_hRgn == NULL); }\n\n// Create methods\n\tHRGN CreateRectRgn(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreateRectRgn(x1, y1, x2, y2);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreateRectRgnIndirect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreateRectRgnIndirect(lpRect);\n\t\treturn m_hRgn;\n\t}\n\n#ifndef _WIN32_WCE\n\tHRGN CreateEllipticRgn(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreateEllipticRgn(x1, y1, x2, y2);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreateEllipticRgnIndirect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreateEllipticRgnIndirect(lpRect);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreatePolygonRgn(LPPOINT lpPoints, int nCount, int nMode)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreatePolygonRgn(lpPoints, nCount, nMode);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreatePolyPolygonRgn(LPPOINT lpPoints, LPINT lpPolyCounts, int nCount, int nPolyFillMode)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreatePolyPolygonRgn(lpPoints, lpPolyCounts, nCount, nPolyFillMode);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreateRoundRectRgn(int x1, int y1, int x2, int y2, int x3, int y3)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::CreateRoundRectRgn(x1, y1, x2, y2, x3, y3);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreateFromPath(HDC hDC)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tATLASSERT(hDC != NULL);\n\t\tm_hRgn = ::PathToRegion(hDC);\n\t\treturn m_hRgn;\n\t}\n\n\tHRGN CreateFromData(const XFORM* lpXForm, int nCount, const RGNDATA* pRgnData)\n\t{\n\t\tATLASSERT(m_hRgn == NULL);\n\t\tm_hRgn = ::ExtCreateRegion(lpXForm, nCount, pRgnData);\n\t\treturn m_hRgn;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\tBOOL bRet = ::DeleteObject(m_hRgn);\n\t\tif(bRet)\n\t\t\tm_hRgn = NULL;\n\t\treturn bRet;\n\t}\n\n// Operations\n\tvoid SetRectRgn(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\t::SetRectRgn(m_hRgn, x1, y1, x2, y2);\n\t}\n\n\tvoid SetRectRgn(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\t::SetRectRgn(m_hRgn, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);\n\t}\n\n\tint CombineRgn(HRGN hRgnSrc1, HRGN hRgnSrc2, int nCombineMode)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::CombineRgn(m_hRgn, hRgnSrc1, hRgnSrc2, nCombineMode);\n\t}\n\n\tint CombineRgn(HRGN hRgnSrc, int nCombineMode)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::CombineRgn(m_hRgn, m_hRgn, hRgnSrc, nCombineMode);\n\t}\n\n\tint CopyRgn(HRGN hRgnSrc)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::CombineRgn(m_hRgn, hRgnSrc, NULL, RGN_COPY);\n\t}\n\n\tBOOL EqualRgn(HRGN hRgn) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::EqualRgn(m_hRgn, hRgn);\n\t}\n\n\tint OffsetRgn(int x, int y)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::OffsetRgn(m_hRgn, x, y);\n\t}\n\n\tint OffsetRgn(POINT point)\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::OffsetRgn(m_hRgn, point.x, point.y);\n\t}\n\n\tint GetRgnBox(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::GetRgnBox(m_hRgn, lpRect);\n\t}\n\n\tBOOL PtInRegion(int x, int y) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::PtInRegion(m_hRgn, x, y);\n\t}\n\n\tBOOL PtInRegion(POINT point) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::PtInRegion(m_hRgn, point.x, point.y);\n\t}\n\n\tBOOL RectInRegion(LPCRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn ::RectInRegion(m_hRgn, lpRect);\n\t}\n\n\tint GetRegionData(LPRGNDATA lpRgnData, int nDataSize) const\n\t{\n\t\tATLASSERT(m_hRgn != NULL);\n\t\treturn (int)::GetRegionData(m_hRgn, nDataSize, lpRgnData);\n\t}\n};\n\ntypedef CRgnT<false>   CRgnHandle;\ntypedef CRgnT<true>    CRgn;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDC - The device context class\n\ntemplate <bool t_bManaged>\nclass CDCT\n{\npublic:\n// Data members\n\tHDC m_hDC;\n\n// Constructor/destructor/operators\n\tCDCT(HDC hDC = NULL) : m_hDC(hDC)\n\t{\n\t}\n\n\t~CDCT()\n\t{\n\t\tif(t_bManaged && m_hDC != NULL)\n\t\t\t::DeleteDC(Detach());\n\t}\n\n\tCDCT<t_bManaged>& operator =(HDC hDC)\n\t{\n\t\tAttach(hDC);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HDC hDC)\n\t{\n\t\tif(t_bManaged && m_hDC != NULL && m_hDC != hDC)\n\t\t\t::DeleteDC(m_hDC);\n\t\tm_hDC = hDC;\n\t}\n\n\tHDC Detach()\n\t{\n\t\tHDC hDC = m_hDC;\n\t\tm_hDC = NULL;\n\t\treturn hDC;\n\t}\n\n\toperator HDC() const { return m_hDC; }\n\n\tbool IsNull() const { return (m_hDC == NULL); }\n\n// Operations\n#ifndef _WIN32_WCE\n\tHWND WindowFromDC() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::WindowFromDC(m_hDC);\n\t}\n#endif // !_WIN32_WCE\n\n\tCPenHandle GetCurrentPen() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn CPenHandle((HPEN)::GetCurrentObject(m_hDC, OBJ_PEN));\n\t}\n\n\tCBrushHandle GetCurrentBrush() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn CBrushHandle((HBRUSH)::GetCurrentObject(m_hDC, OBJ_BRUSH));\n\t}\n\n\tCPaletteHandle GetCurrentPalette() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn CPaletteHandle((HPALETTE)::GetCurrentObject(m_hDC, OBJ_PAL));\n\t}\n\n\tCFontHandle GetCurrentFont() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT));\n\t}\n\n\tCBitmapHandle GetCurrentBitmap() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn CBitmapHandle((HBITMAP)::GetCurrentObject(m_hDC, OBJ_BITMAP));\n\t}\n\n\tHDC CreateDC(LPCTSTR lpszDriverName, LPCTSTR lpszDeviceName, LPCTSTR lpszOutput, const DEVMODE* lpInitData)\n\t{\n\t\tATLASSERT(m_hDC == NULL);\n\t\tm_hDC = ::CreateDC(lpszDriverName, lpszDeviceName, lpszOutput, lpInitData);\n\t\treturn m_hDC;\n\t}\n\n\tHDC CreateCompatibleDC(HDC hDC = NULL)\n\t{\n\t\tATLASSERT(m_hDC == NULL);\n\t\tm_hDC = ::CreateCompatibleDC(hDC);\n\t\treturn m_hDC;\n\t}\n\n\tBOOL DeleteDC()\n\t{\n\t\tif(m_hDC == NULL)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = ::DeleteDC(m_hDC);\n\t\tif(bRet)\n\t\t\tm_hDC = NULL;\n\t\treturn bRet;\n\t}\n\n// Device-Context Functions\n\tint SaveDC()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SaveDC(m_hDC);\n\t}\n\n\tBOOL RestoreDC(int nSavedDC)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::RestoreDC(m_hDC, nSavedDC);\n\t}\n\n\tint GetDeviceCaps(int nIndex) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetDeviceCaps(m_hDC, nIndex);\n\t}\n\n#ifndef _WIN32_WCE\n\tUINT SetBoundsRect(LPCRECT lpRectBounds, UINT flags)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetBoundsRect(m_hDC, lpRectBounds, flags);\n\t}\n\n\tUINT GetBoundsRect(LPRECT lpRectBounds, UINT flags) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetBoundsRect(m_hDC, lpRectBounds, flags);\n\t}\n\n\tBOOL ResetDC(const DEVMODE* lpDevMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ResetDC(m_hDC, lpDevMode) != NULL;\n\t}\n\n// Drawing-Tool Functions\n\tBOOL GetBrushOrg(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetBrushOrgEx(m_hDC, lpPoint);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL SetBrushOrg(int x, int y, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetBrushOrgEx(m_hDC, x, y, lpPoint);\n\t}\n\n\tBOOL SetBrushOrg(POINT point, LPPOINT lpPointRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetBrushOrgEx(m_hDC, point.x, point.y, lpPointRet);\n\t}\n\n#ifndef _WIN32_WCE\n\tint EnumObjects(int nObjectType, int (CALLBACK* lpfn)(LPVOID, LPARAM), LPARAM lpData)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifdef STRICT\n\t\treturn ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, lpData);\n#else\n\t\treturn ::EnumObjects(m_hDC, nObjectType, (GOBJENUMPROC)lpfn, (LPVOID)lpData);\n#endif\n\t}\n#endif // !_WIN32_WCE\n\n// Type-safe selection helpers\n\tHPEN SelectPen(HPEN hPen)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifndef _WIN32_WCE\n\t\tATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN || ::GetObjectType(hPen) == OBJ_EXTPEN);\n#else // CE specific\n\t\tATLASSERT(hPen == NULL || ::GetObjectType(hPen) == OBJ_PEN);\n#endif // _WIN32_WCE\n\t\treturn (HPEN)::SelectObject(m_hDC, hPen);\n\t}\n\n\tHBRUSH SelectBrush(HBRUSH hBrush)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(hBrush == NULL || ::GetObjectType(hBrush) == OBJ_BRUSH);\n\t\treturn (HBRUSH)::SelectObject(m_hDC, hBrush);\n\t}\n\n\tHFONT SelectFont(HFONT hFont)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(hFont == NULL || ::GetObjectType(hFont) == OBJ_FONT);\n\t\treturn (HFONT)::SelectObject(m_hDC, hFont);\n\t}\n\n\tHBITMAP SelectBitmap(HBITMAP hBitmap)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(hBitmap == NULL || ::GetObjectType(hBitmap) == OBJ_BITMAP);\n\t\treturn (HBITMAP)::SelectObject(m_hDC, hBitmap);\n\t}\n\n\tint SelectRgn(HRGN hRgn)       // special return for regions\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(hRgn == NULL || ::GetObjectType(hRgn) == OBJ_REGION);\n\t\treturn PtrToInt(::SelectObject(m_hDC, hRgn));\n\t}\n\n// Type-safe selection helpers for stock objects\n\tHPEN SelectStockPen(int nPen)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#if (_WIN32_WINNT >= 0x0500)\n\t\tATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);\n#else\n\t\tATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);\n#endif // !(_WIN32_WINNT >= 0x0500)\n\t\treturn SelectPen((HPEN)::GetStockObject(nPen));\n\t}\n\n\tHBRUSH SelectStockBrush(int nBrush)\n\t{\n#if (_WIN32_WINNT >= 0x0500)\n\t\tATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);\n#else\n\t\tATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);\n#endif // !(_WIN32_WINNT >= 0x0500)\n\t\treturn SelectBrush((HBRUSH)::GetStockObject(nBrush));\n\t}\n\n\tHFONT SelectStockFont(int nFont)\n\t{\n#ifndef _WIN32_WCE\n\t\tATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);\n#else // CE specific\n\t\tATLASSERT(nFont == SYSTEM_FONT);\n#endif // _WIN32_WCE\n\t\treturn SelectFont((HFONT)::GetStockObject(nFont));\n\t}\n\n\tHPALETTE SelectStockPalette(int nPalette, BOOL bForceBackground)\n\t{\n\t\tATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported\n\t\treturn SelectPalette((HPALETTE)::GetStockObject(nPalette), bForceBackground);\n\t}\n\n// Color and Color Palette Functions\n\tCOLORREF GetNearestColor(COLORREF crColor) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetNearestColor(m_hDC, crColor);\n\t}\n\n\tHPALETTE SelectPalette(HPALETTE hPalette, BOOL bForceBackground)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\n\t\treturn ::SelectPalette(m_hDC, hPalette, bForceBackground);\n\t}\n\n\tUINT RealizePalette()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::RealizePalette(m_hDC);\n\t}\n\n#ifndef _WIN32_WCE\n\tvoid UpdateColors()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\t::UpdateColors(m_hDC);\n\t}\n#endif // !_WIN32_WCE\n\n// Drawing-Attribute Functions\n\tCOLORREF GetBkColor() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetBkColor(m_hDC);\n\t}\n\n\tint GetBkMode() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetBkMode(m_hDC);\n\t}\n\n#ifndef _WIN32_WCE\n\tint GetPolyFillMode() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetPolyFillMode(m_hDC);\n\t}\n\n\tint GetROP2() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetROP2(m_hDC);\n\t}\n\n\tint GetStretchBltMode() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetStretchBltMode(m_hDC);\n\t}\n#endif // !_WIN32_WCE\n\n\tCOLORREF GetTextColor() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextColor(m_hDC);\n\t}\n\n\tCOLORREF SetBkColor(COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetBkColor(m_hDC, crColor);\n\t}\n\n\tint SetBkMode(int nBkMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetBkMode(m_hDC, nBkMode);\n\t}\n\n#ifndef _WIN32_WCE\n\tint SetPolyFillMode(int nPolyFillMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPolyFillMode(m_hDC, nPolyFillMode);\n\t}\n#endif // !_WIN32_WCE\n\n\tint SetROP2(int nDrawMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetROP2(m_hDC, nDrawMode);\n\t}\n\n#ifndef _WIN32_WCE\n\tint SetStretchBltMode(int nStretchMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetStretchBltMode(m_hDC, nStretchMode);\n\t}\n#endif // !_WIN32_WCE\n\n\tCOLORREF SetTextColor(COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetTextColor(m_hDC, crColor);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetColorAdjustment(LPCOLORADJUSTMENT lpColorAdjust) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetColorAdjustment(m_hDC, lpColorAdjust);\n\t}\n\n\tBOOL SetColorAdjustment(const COLORADJUSTMENT* lpColorAdjust)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetColorAdjustment(m_hDC, lpColorAdjust);\n\t}\n\n// Mapping Functions\n\tint GetMapMode() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetMapMode(m_hDC);\n\t}\n\n\tBOOL GetViewportOrg(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetViewportOrgEx(m_hDC, lpPoint);\n\t}\n\n\tint SetMapMode(int nMapMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetMapMode(m_hDC, nMapMode);\n\t}\n#endif // !_WIN32_WCE\n\n\t// Viewport Origin\n\tBOOL SetViewportOrg(int x, int y, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetViewportOrgEx(m_hDC, x, y, lpPoint);\n\t}\n\n\tBOOL SetViewportOrg(POINT point, LPPOINT lpPointRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn SetViewportOrg(point.x, point.y, lpPointRet);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL OffsetViewportOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, lpPoint);\n\t}\n\n\t// Viewport Extent\n\tBOOL GetViewportExt(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetViewportExtEx(m_hDC, lpSize);\n\t}\n\n\tBOOL SetViewportExt(int x, int y, LPSIZE lpSize = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetViewportExtEx(m_hDC, x, y, lpSize);\n\t}\n\n\tBOOL SetViewportExt(SIZE size, LPSIZE lpSizeRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn SetViewportExt(size.cx, size.cy, lpSizeRet);\n\t}\n\n\tBOOL ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize);\n\t}\n#endif // !_WIN32_WCE\n\n\t// Window Origin\n#ifndef _WIN32_WCE\n\tBOOL GetWindowOrg(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetWindowOrgEx(m_hDC, lpPoint);\n\t}\n\n\tBOOL SetWindowOrg(int x, int y, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetWindowOrgEx(m_hDC, x, y, lpPoint);\n\t}\n\n\tBOOL SetWindowOrg(POINT point, LPPOINT lpPointRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn SetWindowOrg(point.x, point.y, lpPointRet);\n\t}\n\n\tBOOL OffsetWindowOrg(int nWidth, int nHeight, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::OffsetWindowOrgEx(m_hDC, nWidth, nHeight, lpPoint);\n\t}\n\n\t// Window extent\n\tBOOL GetWindowExt(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetWindowExtEx(m_hDC, lpSize);\n\t}\n\n\tBOOL SetWindowExt(int x, int y, LPSIZE lpSize = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetWindowExtEx(m_hDC, x, y, lpSize);\n\t}\n\n\tBOOL SetWindowExt(SIZE size, LPSIZE lpSizeRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn SetWindowExt(size.cx, size.cy, lpSizeRet);\n\t}\n\n\tBOOL ScaleWindowExt(int xNum, int xDenom, int yNum, int yDenom, LPSIZE lpSize = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ScaleWindowExtEx(m_hDC, xNum, xDenom, yNum, yDenom, lpSize);\n\t}\n\n// Coordinate Functions\n\tBOOL DPtoLP(LPPOINT lpPoints, int nCount = 1) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DPtoLP(m_hDC, lpPoints, nCount);\n\t}\n\n\tBOOL DPtoLP(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DPtoLP(m_hDC, (LPPOINT)lpRect, 2);\n\t}\n\n\tBOOL DPtoLP(LPSIZE lpSize) const\n\t{\n\t\tSIZE sizeWinExt = { 0, 0 };\n\t\tif(!GetWindowExt(&sizeWinExt))\n\t\t\treturn FALSE;\n\t\tSIZE sizeVpExt = { 0, 0 };\n\t\tif(!GetViewportExt(&sizeVpExt))\n\t\t\treturn FALSE;\n\t\tlpSize->cx = ::MulDiv(lpSize->cx, abs(sizeWinExt.cx), abs(sizeVpExt.cx));\n\t\tlpSize->cy = ::MulDiv(lpSize->cy, abs(sizeWinExt.cy), abs(sizeVpExt.cy));\n\t\treturn TRUE;\n\t}\n\n\tBOOL LPtoDP(LPPOINT lpPoints, int nCount = 1) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::LPtoDP(m_hDC, lpPoints, nCount);\n\t}\n\n\tBOOL LPtoDP(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::LPtoDP(m_hDC, (LPPOINT)lpRect, 2);\n\t}\n\n\tBOOL LPtoDP(LPSIZE lpSize) const\n\t{\n\t\tSIZE sizeWinExt = { 0, 0 };\n\t\tif(!GetWindowExt(&sizeWinExt))\n\t\t\treturn FALSE;\n\t\tSIZE sizeVpExt = { 0, 0 };\n\t\tif(!GetViewportExt(&sizeVpExt))\n\t\t\treturn FALSE;\n\t\tlpSize->cx = ::MulDiv(lpSize->cx, abs(sizeVpExt.cx), abs(sizeWinExt.cx));\n\t\tlpSize->cy = ::MulDiv(lpSize->cy, abs(sizeVpExt.cy), abs(sizeWinExt.cy));\n\t\treturn TRUE;\n\t}\n\n// Special Coordinate Functions (useful for dealing with metafiles and OLE)\n\t#define HIMETRIC_INCH   2540    // HIMETRIC units per inch\n\n\tvoid DPtoHIMETRIC(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tint nMapMode;\n\t\tif((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)\n\t\t{\n\t\t\t// when using a constrained map mode, map against physical inch\n\t\t\t((CDCHandle*)this)->SetMapMode(MM_HIMETRIC);\n\t\t\tDPtoLP(lpSize);\n\t\t\t((CDCHandle*)this)->SetMapMode(nMapMode);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// map against logical inch for non-constrained mapping modes\n\t\t\tint cxPerInch = GetDeviceCaps(LOGPIXELSX);\n\t\t\tint cyPerInch = GetDeviceCaps(LOGPIXELSY);\n\t\t\tATLASSERT(cxPerInch != 0 && cyPerInch != 0);\n\t\t\tlpSize->cx = ::MulDiv(lpSize->cx, HIMETRIC_INCH, cxPerInch);\n\t\t\tlpSize->cy = ::MulDiv(lpSize->cy, HIMETRIC_INCH, cyPerInch);\n\t\t}\n\t}\n\n\tvoid HIMETRICtoDP(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tint nMapMode;\n\t\tif((nMapMode = GetMapMode()) < MM_ISOTROPIC && nMapMode != MM_TEXT)\n\t\t{\n\t\t\t// when using a constrained map mode, map against physical inch\n\t\t\t((CDCHandle*)this)->SetMapMode(MM_HIMETRIC);\n\t\t\tLPtoDP(lpSize);\n\t\t\t((CDCHandle*)this)->SetMapMode(nMapMode);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// map against logical inch for non-constrained mapping modes\n\t\t\tint cxPerInch = GetDeviceCaps(LOGPIXELSX);\n\t\t\tint cyPerInch = GetDeviceCaps(LOGPIXELSY);\n\t\t\tATLASSERT(cxPerInch != 0 && cyPerInch != 0);\n\t\t\tlpSize->cx = ::MulDiv(lpSize->cx, cxPerInch, HIMETRIC_INCH);\n\t\t\tlpSize->cy = ::MulDiv(lpSize->cy, cyPerInch, HIMETRIC_INCH);\n\t\t}\n\t}\n\n\tvoid LPtoHIMETRIC(LPSIZE lpSize) const\n\t{\n\t\tLPtoDP(lpSize);\n\t\tDPtoHIMETRIC(lpSize);\n\t}\n\n\tvoid HIMETRICtoLP(LPSIZE lpSize) const\n\t{\n\t\tHIMETRICtoDP(lpSize);\n\t\tDPtoLP(lpSize);\n\t}\n#endif // !_WIN32_WCE\n\n// Region Functions\n\tBOOL FillRgn(HRGN hRgn, HBRUSH hBrush)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FillRgn(m_hDC, hRgn, hBrush);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL FrameRgn(HRGN hRgn, HBRUSH hBrush, int nWidth, int nHeight)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FrameRgn(m_hDC, hRgn, hBrush, nWidth, nHeight);\n\t}\n\n\tBOOL InvertRgn(HRGN hRgn)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::InvertRgn(m_hDC, hRgn);\n\t}\n\n\tBOOL PaintRgn(HRGN hRgn)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PaintRgn(m_hDC, hRgn);\n\t}\n#endif // !_WIN32_WCE\n\n// Clipping Functions\n\tint GetClipBox(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetClipBox(m_hDC, lpRect);\n\t}\n\n\tint GetClipRgn(CRgn& region) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(region.IsNull())\n\t\t\tregion.CreateRectRgn(0, 0, 0, 0);\n\n\t\tint nRet = ::GetClipRgn(m_hDC, region);\n\t\tif(nRet != 1)\n\t\t\tregion.DeleteObject();\n\n\t\treturn nRet;\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL PtVisible(int x, int y) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PtVisible(m_hDC, x, y);\n\t}\n\n\tBOOL PtVisible(POINT point) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PtVisible(m_hDC, point.x, point.y);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL RectVisible(LPCRECT lpRect) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::RectVisible(m_hDC, lpRect);\n\t}\n\n\tint SelectClipRgn(HRGN hRgn)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SelectClipRgn(m_hDC, (HRGN)hRgn);\n\t}\n\n\tint ExcludeClipRect(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExcludeClipRect(m_hDC, x1, y1, x2, y2);\n\t}\n\n\tint ExcludeClipRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExcludeClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);\n\t}\n\n#ifndef _WIN32_WCE\n\tint ExcludeUpdateRgn(HWND hWnd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExcludeUpdateRgn(m_hDC, hWnd);\n\t}\n#endif // !_WIN32_WCE\n\n\tint IntersectClipRect(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::IntersectClipRect(m_hDC, x1, y1, x2, y2);\n\t}\n\n\tint IntersectClipRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::IntersectClipRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);\n\t}\n\n#ifndef _WIN32_WCE\n\tint OffsetClipRgn(int x, int y)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::OffsetClipRgn(m_hDC, x, y);\n\t}\n\n\tint OffsetClipRgn(SIZE size)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::OffsetClipRgn(m_hDC, size.cx, size.cy);\n\t}\n\n\tint SelectClipRgn(HRGN hRgn, int nMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExtSelectClipRgn(m_hDC, hRgn, nMode);\n\t}\n#endif // !_WIN32_WCE\n\n// Line-Output Functions\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\tBOOL GetCurrentPosition(LPPOINT lpPoint) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCurrentPositionEx(m_hDC, lpPoint);\n\t}\n\n\tBOOL MoveTo(int x, int y, LPPOINT lpPoint = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::MoveToEx(m_hDC, x, y, lpPoint);\n\t}\n\n\tBOOL MoveTo(POINT point, LPPOINT lpPointRet = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn MoveTo(point.x, point.y, lpPointRet);\n\t}\n\n\tBOOL LineTo(int x, int y)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::LineTo(m_hDC, x, y);\n\t}\n\n\tBOOL LineTo(POINT point)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn LineTo(point.x, point.y);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\n#ifndef _WIN32_WCE\n\tBOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Arc(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);\n\t}\n\n\tBOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Arc(m_hDC, lpRect->left, lpRect->top,\n\t\t\tlpRect->right, lpRect->bottom, ptStart.x, ptStart.y,\n\t\t\tptEnd.x, ptEnd.y);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL Polyline(const POINT* lpPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Polyline(m_hDC, lpPoints, nCount);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::AngleArc(m_hDC, x, y, nRadius, fStartAngle, fSweepAngle);\n\t}\n\n\tBOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ArcTo(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);\n\t}\n\n\tBOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ArcTo(lpRect->left, lpRect->top, lpRect->right,\n\t\tlpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);\n\t}\n\n\tint GetArcDirection() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetArcDirection(m_hDC);\n\t}\n\n\tint SetArcDirection(int nArcDirection)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetArcDirection(m_hDC, nArcDirection);\n\t}\n\n\tBOOL PolyDraw(const POINT* lpPoints, const BYTE* lpTypes, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolyDraw(m_hDC, lpPoints, lpTypes, nCount);\n\t}\n\n\tBOOL PolylineTo(const POINT* lpPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolylineTo(m_hDC, lpPoints, nCount);\n\t}\n\n\tBOOL PolyPolyline(const POINT* lpPoints,\n\t\tconst DWORD* lpPolyPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolyPolyline(m_hDC, lpPoints, lpPolyPoints, nCount);\n\t}\n\n\tBOOL PolyBezier(const POINT* lpPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolyBezier(m_hDC, lpPoints, nCount);\n\t}\n\n\tBOOL PolyBezierTo(const POINT* lpPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolyBezierTo(m_hDC, lpPoints, nCount);\n\t}\n#endif // !_WIN32_WCE\n\n// Simple Drawing Functions\n\tBOOL FillRect(LPCRECT lpRect, HBRUSH hBrush)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FillRect(m_hDC, lpRect, hBrush);\n\t}\n\n\tBOOL FillRect(LPCRECT lpRect, int nColorIndex)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifndef _WIN32_WCE\n\t\treturn ::FillRect(m_hDC, lpRect, (HBRUSH)LongToPtr(nColorIndex + 1));\n#else // CE specific\n\t\treturn ::FillRect(m_hDC, lpRect, ::GetSysColorBrush(nColorIndex));\n#endif // _WIN32_WCE\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL FrameRect(LPCRECT lpRect, HBRUSH hBrush)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FrameRect(m_hDC, lpRect, hBrush);\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)\n\tBOOL InvertRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::InvertRect(m_hDC, lpRect);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)\n\n\tBOOL DrawIcon(int x, int y, HICON hIcon)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifndef _WIN32_WCE\n\t\treturn ::DrawIcon(m_hDC, x, y, hIcon);\n#else // CE specific\n\t\treturn ::DrawIconEx(m_hDC, x, y, hIcon, 0, 0, 0, NULL, DI_NORMAL);\n#endif // _WIN32_WCE\n\t}\n\n\tBOOL DrawIcon(POINT point, HICON hIcon)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifndef _WIN32_WCE\n\t\treturn ::DrawIcon(m_hDC, point.x, point.y, hIcon);\n#else // CE specific\n\t\treturn ::DrawIconEx(m_hDC, point.x, point.y, hIcon, 0, 0, 0, NULL, DI_NORMAL);\n#endif // _WIN32_WCE\n\t}\n\n\tBOOL DrawIconEx(int x, int y, HICON hIcon, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawIconEx(m_hDC, x, y, hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);\n\t}\n\n\tBOOL DrawIconEx(POINT point, HICON hIcon, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawIconEx(m_hDC, point.x, point.y, hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL DrawState(POINT pt, SIZE size, HBITMAP hBitmap, UINT nFlags, HBRUSH hBrush = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hBitmap, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_BITMAP);\n\t}\n\n\tBOOL DrawState(POINT pt, SIZE size, HICON hIcon, UINT nFlags, HBRUSH hBrush = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawState(m_hDC, hBrush, NULL, (LPARAM)hIcon, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_ICON);\n\t}\n\n\tBOOL DrawState(POINT pt, SIZE size, LPCTSTR lpszText, UINT nFlags, BOOL bPrefixText = TRUE, int nTextLen = 0, HBRUSH hBrush = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawState(m_hDC, hBrush, NULL, (LPARAM)lpszText, (WPARAM)nTextLen, pt.x, pt.y, size.cx, size.cy, nFlags | (bPrefixText ? DST_PREFIXTEXT : DST_TEXT));\n\t}\n\n\tBOOL DrawState(POINT pt, SIZE size, DRAWSTATEPROC lpDrawProc, LPARAM lData, UINT nFlags, HBRUSH hBrush = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawState(m_hDC, hBrush, lpDrawProc, lData, 0, pt.x, pt.y, size.cx, size.cy, nFlags | DST_COMPLEX);\n\t}\n#endif // !_WIN32_WCE\n\n// Ellipse and Polygon Functions\n#ifndef _WIN32_WCE\n\tBOOL Chord(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Chord(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);\n\t}\n\n\tBOOL Chord(LPCRECT lpRect, POINT ptStart, POINT ptEnd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Chord(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);\n\t}\n#endif // !_WIN32_WCE\n\n\tvoid DrawFocusRect(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\t::DrawFocusRect(m_hDC, lpRect);\n\t}\n\n\tBOOL Ellipse(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Ellipse(m_hDC, x1, y1, x2, y2);\n\t}\n\n\tBOOL Ellipse(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Ellipse(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Pie(m_hDC, x1, y1, x2, y2, x3, y3, x4, y4);\n\t}\n\n\tBOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Pie(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL Polygon(const POINT* lpPoints, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Polygon(m_hDC, lpPoints, nCount);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL PolyPolygon(const POINT* lpPoints, const INT* lpPolyCounts, int nCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PolyPolygon(m_hDC, lpPoints, lpPolyCounts, nCount);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL Rectangle(int x1, int y1, int x2, int y2)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Rectangle(m_hDC, x1, y1, x2, y2);\n\t}\n\n\tBOOL Rectangle(LPCRECT lpRect)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Rectangle(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);\n\t}\n\n\tBOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::RoundRect(m_hDC, x1, y1, x2, y2, x3, y3);\n\t}\n\n\tBOOL RoundRect(LPCRECT lpRect, POINT point)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::RoundRect(m_hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, point.x, point.y);\n\t}\n\n// Bitmap Functions\n\tBOOL PatBlt(int x, int y, int nWidth, int nHeight, DWORD dwRop)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PatBlt(m_hDC, x, y, nWidth, nHeight, dwRop);\n\t}\n\n\tBOOL BitBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC,\n\t\tint xSrc, int ySrc, DWORD dwRop)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::BitBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, dwRop);\n\t}\n\n\tBOOL StretchBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StretchBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop);\n\t}\n\n\tCOLORREF GetPixel(int x, int y) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetPixel(m_hDC, x, y);\n\t}\n\n\tCOLORREF GetPixel(POINT point) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetPixel(m_hDC, point.x, point.y);\n\t}\n\n\tCOLORREF SetPixel(int x, int y, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPixel(m_hDC, x, y, crColor);\n\t}\n\n\tCOLORREF SetPixel(POINT point, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPixel(m_hDC, point.x, point.y, crColor);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL FloodFill(int x, int y, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FloodFill(m_hDC, x, y, crColor);\n\t}\n\n\tBOOL ExtFloodFill(int x, int y, COLORREF crColor, UINT nFillType)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExtFloodFill(m_hDC, x, y, crColor, nFillType);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL MaskBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, HBITMAP hMaskBitmap, int xMask, int yMask, DWORD dwRop)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::MaskBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, hMaskBitmap, xMask, yMask, dwRop);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL PlgBlt(LPPOINT lpPoint, HDC hSrcDC, int xSrc, int ySrc, int nWidth, int nHeight, HBITMAP hMaskBitmap, int xMask, int yMask)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PlgBlt(m_hDC, lpPoint, hSrcDC, xSrc, ySrc, nWidth, nHeight, hMaskBitmap, xMask, yMask);\n\t}\n\n\tBOOL SetPixelV(int x, int y, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPixelV(m_hDC, x, y, crColor);\n\t}\n\n\tBOOL SetPixelV(POINT point, COLORREF crColor)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPixelV(m_hDC, point.x, point.y, crColor);\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)\n#ifndef _WIN32_WCE\n\tBOOL TransparentBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::TransparentBlt(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);\n\t}\n#else // CE specific\n\tBOOL TransparentImage(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::TransparentImage(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent);\n\t}\n#endif // _WIN32_WCE\n\n#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420))\n\tBOOL GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GradientFill(m_hDC, pVertices, nVertices, pMeshElements, nMeshElements, dwMode);\n\t}\n\n\tBOOL GradientFillRect(RECT& rect, COLORREF clr1, COLORREF clr2, bool bHorizontal)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\n\t\tTRIVERTEX arrTvx[2] = { { 0 }, { 0 } };\n\n\t\tarrTvx[0].x = rect.left;\n\t\tarrTvx[0].y = rect.top;\n\t\tarrTvx[0].Red = MAKEWORD(0, GetRValue(clr1));\n\t\tarrTvx[0].Green = MAKEWORD(0, GetGValue(clr1));\n\t\tarrTvx[0].Blue = MAKEWORD(0, GetBValue(clr1));\n\t\tarrTvx[0].Alpha = 0;\n\n\t\tarrTvx[1].x = rect.right;\n\t\tarrTvx[1].y = rect.bottom;\n\t\tarrTvx[1].Red = MAKEWORD(0, GetRValue(clr2));\n\t\tarrTvx[1].Green = MAKEWORD(0, GetGValue(clr2));\n\t\tarrTvx[1].Blue = MAKEWORD(0, GetBValue(clr2));\n\t\tarrTvx[1].Alpha = 0;\n\n\t\tGRADIENT_RECT gr = { 0, 1 };\n\n\t\treturn ::GradientFill(m_hDC, arrTvx, 2, &gr, 1, bHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 420)\n\n#if !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)\n\tBOOL AlphaBlend(int x, int y, int nWidth, int nHeight, HDC hSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BLENDFUNCTION bf)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::AlphaBlend(m_hDC, x, y, nWidth, nHeight, hSrcDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE > 0x500)\n#endif //  !defined(_ATL_NO_MSIMG) || defined(_WIN32_WCE)\n\n// Extra bitmap functions\n\t// Helper function for painting a disabled toolbar or menu bitmap\n\t// This function can take either an HBITMAP (for SS) or a DC with \n\t//           the bitmap already painted (for cmdbar)\n\tBOOL DitherBlt(int x, int y, int nWidth, int nHeight, HDC hSrcDC, HBITMAP hBitmap, int xSrc, int ySrc,\n\t\t\tHBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),\n\t\t\tHBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),\n\t\t\tHBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))\n\t{\n\t\tATLASSERT(m_hDC != NULL || hBitmap != NULL);\n\t\tATLASSERT(nWidth > 0 && nHeight > 0);\n\t\t\n\t\t// Create a generic DC for all BitBlts\n\t\tCDCHandle dc = (hSrcDC != NULL) ? hSrcDC : ::CreateCompatibleDC(m_hDC);\n\t\tATLASSERT(dc.m_hDC != NULL);\n\t\tif(dc.m_hDC == NULL)\n\t\t\treturn FALSE;\n\t\t\n\t\t// Create a DC for the monochrome DIB section\n\t\tCDC dcBW = ::CreateCompatibleDC(m_hDC);\n\t\tATLASSERT(dcBW.m_hDC != NULL);\n\t\tif(dcBW.m_hDC == NULL)\n\t\t{\n\t\t\tif(hSrcDC == NULL)\n\t\t\t\tdc.DeleteDC();\n\t\t\treturn FALSE;\n\t\t}\n\n\t\t// Create the monochrome DIB section with a black and white palette\n\t\tstruct RGBBWBITMAPINFO\n\t\t{\n\t\t\tBITMAPINFOHEADER bmiHeader; \n\t\t\tRGBQUAD bmiColors[2]; \n\t\t};\n\n\t\tRGBBWBITMAPINFO rgbBWBitmapInfo = \n\t\t{\n\t\t\t{ sizeof(BITMAPINFOHEADER), nWidth, nHeight, 1, 1, BI_RGB, 0, 0, 0, 0, 0 },\n\t\t\t{ { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } }\n\t\t};\n\n\t\tVOID* pbitsBW;\n\t\tCBitmap bmpBW = ::CreateDIBSection(dcBW, (LPBITMAPINFO)&rgbBWBitmapInfo, DIB_RGB_COLORS, &pbitsBW, NULL, 0);\n\t\tATLASSERT(bmpBW.m_hBitmap != NULL);\n\t\tif(bmpBW.m_hBitmap == NULL)\n\t\t{\n\t\t\tif(hSrcDC == NULL)\n\t\t\t\tdc.DeleteDC();\n\t\t\treturn FALSE;\n\t\t}\n\t\t\n\t\t// Attach the monochrome DIB section and the bitmap to the DCs\n\t\tHBITMAP hbmOldBW = dcBW.SelectBitmap(bmpBW);\n\t\tHBITMAP hbmOldDC = NULL;\n\t\tif(hBitmap != NULL)\n\t\t\thbmOldDC = dc.SelectBitmap(hBitmap);\n\n\t\t// Block: Dark gray removal: we want (128, 128, 128) pixels to become black and not white\n\t\t{\n\t\t\tCDC dcTemp1 = ::CreateCompatibleDC(m_hDC);\n\t\t\tCDC dcTemp2 = ::CreateCompatibleDC(m_hDC);\n\t\t\tCBitmap bmpTemp1;\n\t\t\tbmpTemp1.CreateCompatibleBitmap(dc, nWidth, nHeight);\n\t\t\tCBitmap bmpTemp2;\n\t\t\tbmpTemp2.CreateBitmap(nWidth, nHeight, 1, 1, NULL);\n\t\t\tHBITMAP hOldBmp1 = dcTemp1.SelectBitmap(bmpTemp1);\n\t\t\tHBITMAP hOldBmp2 = dcTemp2.SelectBitmap(bmpTemp2);\n\t\t\t// Let's copy our image, it will be altered\n\t\t\tdcTemp1.BitBlt(0, 0, nWidth, nHeight, dc, xSrc, ySrc, SRCCOPY);\n\n\t\t\t// All dark gray pixels will become white, the others black\n\t\t\tdcTemp1.SetBkColor(RGB(128, 128, 128));\n\t\t\tdcTemp2.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);\n\t\t\t// Do an XOR to set to black these white pixels\n\t\t\tdcTemp1.BitBlt(0, 0, nWidth, nHeight, dcTemp2, 0, 0, SRCINVERT);\n\n\t\t\t// BitBlt the bitmap into the monochrome DIB section\n\t\t\t// The DIB section will do a true monochrome conversion\n\t\t\t// The magenta background being closer to white will become white\n\t\t\tdcBW.BitBlt(0, 0, nWidth, nHeight, dcTemp1, 0, 0, SRCCOPY);\n\n\t\t\t// Cleanup\n\t\t\tdcTemp1.SelectBitmap(hOldBmp1);\n\t\t\tdcTemp2.SelectBitmap(hOldBmp2);\n\t\t}\n\t\t\n\t\t// Paint the destination rectangle using hBrushBackground\n\t\tif(hBrushBackground != NULL)\n\t\t{\n\t\t\tRECT rc = { x, y, x + nWidth, y + nHeight };\n\t\t\tFillRect(&rc, hBrushBackground);\n\t\t}\n\n\t\t// BitBlt the black bits in the monochrome bitmap into hBrush3DEffect color in the destination DC\n\t\t// The magic ROP comes from the Charles Petzold's book\n\t\tHBRUSH hOldBrush = SelectBrush(hBrush3DEffect);\n\t\tBitBlt(x + 1, y + 1, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);\n\n\t\t// BitBlt the black bits in the monochrome bitmap into hBrushDisabledImage color in the destination DC\n\t\tSelectBrush(hBrushDisabledImage);\n\t\tBitBlt(x, y, nWidth, nHeight, dcBW, 0, 0, 0xB8074A);\n\n\t\tSelectBrush(hOldBrush);\n\t\tdcBW.SelectBitmap(hbmOldBW);\n\t\tdc.SelectBitmap(hbmOldDC);\n\n\t\tif(hSrcDC == NULL)\n\t\t\tdc.DeleteDC();\n\n\t\treturn TRUE;\n\t}\n\n// Text Functions\n#ifndef _WIN32_WCE\n\tBOOL TextOut(int x, int y, LPCTSTR lpszString, int nCount = -1)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(nCount == -1)\n\t\t\tnCount = lstrlen(lpszString);\n\t\treturn ::TextOut(m_hDC, x, y, lpszString, nCount);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount = -1, LPINT lpDxWidths = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(nCount == -1)\n\t\t\tnCount = lstrlen(lpszString);\n\t\treturn ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths);\n\t}\n\n#ifndef _WIN32_WCE\n\tSIZE TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL, int nTabOrigin = 0)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(nCount == -1)\n\t\t\tnCount = lstrlen(lpszString);\n\t\tLONG lRes = ::TabbedTextOut(m_hDC, x, y, lpszString, nCount, nTabPositions, lpnTabStopPositions, nTabOrigin);\n\t\tSIZE size = { GET_X_LPARAM(lRes), GET_Y_LPARAM(lRes) };\n\t\treturn size;\n\t}\n#endif // !_WIN32_WCE\n\n\tint DrawText(LPCTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n#ifndef _WIN32_WCE\n\t\tATLASSERT((uFormat & DT_MODIFYSTRING) == 0);\n#endif // !_WIN32_WCE\n\t\treturn ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat);\n\t}\n\n\tint DrawText(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawText(m_hDC, lpstrText, cchText, lpRect, uFormat);\n\t}\n\n#ifndef _WIN32_WCE\n\tint DrawTextEx(LPTSTR lpstrText, int cchText, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpDTParams = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawTextEx(m_hDC, lpstrText, cchText, lpRect, uFormat, lpDTParams);\n\t}\n#endif // !_WIN32_WCE\n\n#if (_WIN32_WINNT >= 0x0501)\n\tint DrawShadowText(LPCWSTR lpstrText, int cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\t// This function is present only if comctl32.dll version 6 is loaded;\n\t\t// we use LoadLibrary/GetProcAddress to allow apps compiled with\n\t\t// _WIN32_WINNT >= 0x0501 to run on older Windows/CommCtrl\n\t\tint nRet = 0;\n\t\tHMODULE hCommCtrlDLL = ::LoadLibrary(_T(\"comctl32.dll\"));\n\t\tATLASSERT(hCommCtrlDLL != NULL);\n\t\tif(hCommCtrlDLL != NULL)\n\t\t{\n\t\t\ttypedef int (WINAPI *PFN_DrawShadowText)(HDC hDC, LPCWSTR lpstrText, UINT cchText, LPRECT lpRect, DWORD dwFlags, COLORREF clrText, COLORREF clrShadow, int xOffset, int yOffset);\n\t\t\tPFN_DrawShadowText pfnDrawShadowText = (PFN_DrawShadowText)::GetProcAddress(hCommCtrlDLL, \"DrawShadowText\");\n\t\t\tATLASSERT(pfnDrawShadowText != NULL);   // this function requires CommCtrl6\n\t\t\tif(pfnDrawShadowText != NULL)\n\t\t\t\tnRet = pfnDrawShadowText(m_hDC, lpstrText, cchText, lpRect, dwFlags, clrText, clrShadow, xOffset, yOffset);\n\t\t\t::FreeLibrary(hCommCtrlDLL);\n\t\t}\n\t\treturn nRet;\n\t}\n#endif // (_WIN32_WINNT >= 0x0501)\n\n\tBOOL GetTextExtent(LPCTSTR lpszString, int nCount, LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(nCount == -1)\n\t\t\tnCount = lstrlen(lpszString);\n\t\treturn ::GetTextExtentPoint32(m_hDC, lpszString, nCount, lpSize);\n\t}\n\n\tBOOL GetTextExtentExPoint(LPCTSTR lpszString, int cchString, LPSIZE lpSize, int nMaxExtent, LPINT lpnFit = NULL, LPINT alpDx = NULL)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextExtentExPoint(m_hDC, lpszString, cchString, nMaxExtent, lpnFit, alpDx, lpSize);\n\t}\n\n#ifndef _WIN32_WCE\n\tDWORD GetTabbedTextExtent(LPCTSTR lpszString, int nCount = -1, int nTabPositions = 0, LPINT lpnTabStopPositions = NULL) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(nCount == -1)\n\t\t\tnCount = lstrlen(lpszString);\n\t\treturn ::GetTabbedTextExtent(m_hDC, lpszString, nCount, nTabPositions, lpnTabStopPositions);\n\t}\n\n\tBOOL GrayString(HBRUSH hBrush, BOOL (CALLBACK* lpfnOutput)(HDC, LPARAM, int), LPARAM lpData, int nCount, int x, int y, int nWidth, int nHeight)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GrayString(m_hDC, hBrush, (GRAYSTRINGPROC)lpfnOutput, lpData, nCount, x, y, nWidth, nHeight);\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\tUINT GetTextAlign() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextAlign(m_hDC);\n\t}\n\n\tUINT SetTextAlign(UINT nFlags)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetTextAlign(m_hDC, nFlags);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\n\tint GetTextFace(LPTSTR lpszFacename, int nCount) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextFace(m_hDC, nCount, lpszFacename);\n\t}\n\n\tint GetTextFaceLen() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextFace(m_hDC, 0, NULL);\n\t}\n\n#ifndef _ATL_NO_COM\n#ifdef _OLEAUTO_H_\n\tBOOL GetTextFace(BSTR& bstrFace) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(bstrFace == NULL);\n\n\t\tint nLen = GetTextFaceLen();\n\t\tif(nLen == 0)\n\t\t\treturn FALSE;\n\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpszText = buff.Allocate(nLen);\n\t\tif(lpszText == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(!GetTextFace(lpszText, nLen))\n\t\t\treturn FALSE;\n\n\t\tbstrFace = ::SysAllocString(T2OLE(lpszText));\n\t\treturn (bstrFace != NULL) ? TRUE : FALSE;\n\t}\n#endif\n#endif // !_ATL_NO_COM\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetTextFace(_CSTRING_NS::CString& strFace) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\n\t\tint nLen = GetTextFaceLen();\n\t\tif(nLen == 0)\n\t\t\treturn 0;\n\n\t\tLPTSTR lpstr = strFace.GetBufferSetLength(nLen);\n\t\tif(lpstr == NULL)\n\t\t\treturn 0;\n\t\tint nRet = GetTextFace(lpstr, nLen);\n\t\tstrFace.ReleaseBuffer();\n\t\treturn nRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextMetrics(m_hDC, lpMetrics);\n\t}\n\n#ifndef _WIN32_WCE\n\tint SetTextJustification(int nBreakExtra, int nBreakCount)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetTextJustification(m_hDC, nBreakExtra, nBreakCount);\n\t}\n\n\tint GetTextCharacterExtra() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextCharacterExtra(m_hDC);\n\t}\n\n\tint SetTextCharacterExtra(int nCharExtra)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetTextCharacterExtra(m_hDC, nCharExtra);\n\t}\n#endif // !_WIN32_WCE\n\n// Advanced Drawing\n\tBOOL DrawEdge(LPRECT lpRect, UINT nEdge, UINT nFlags)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawEdge(m_hDC, lpRect, nEdge, nFlags);\n\t}\n\n\tBOOL DrawFrameControl(LPRECT lpRect, UINT nType, UINT nState)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawFrameControl(m_hDC, lpRect, nType, nState);\n\t}\n\n// Scrolling Functions\n\tBOOL ScrollDC(int dx, int dy, LPCRECT lpRectScroll, LPCRECT lpRectClip, HRGN hRgnUpdate, LPRECT lpRectUpdate)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ScrollDC(m_hDC, dx, dy, lpRectScroll, lpRectClip, hRgnUpdate, lpRectUpdate);\n\t}\n\n// Font Functions\n#ifndef _WIN32_WCE\n\tBOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharWidth(m_hDC, nFirstChar, nLastChar, lpBuffer);\n\t}\n\n\t// GetCharWidth32 is not supported under Win9x\n\tBOOL GetCharWidth32(UINT nFirstChar, UINT nLastChar, LPINT lpBuffer) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharWidth32(m_hDC, nFirstChar, nLastChar, lpBuffer);\n\t}\n\n\tDWORD SetMapperFlags(DWORD dwFlag)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetMapperFlags(m_hDC, dwFlag);\n\t}\n\n\tBOOL GetAspectRatioFilter(LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetAspectRatioFilterEx(m_hDC, lpSize);\n\t}\n\n\tBOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABC lpabc) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharABCWidths(m_hDC, nFirstChar, nLastChar, lpabc);\n\t}\n\n\tDWORD GetFontData(DWORD dwTable, DWORD dwOffset, LPVOID lpData, DWORD cbData) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetFontData(m_hDC, dwTable, dwOffset, lpData, cbData);\n\t}\n\n\tint GetKerningPairs(int nPairs, LPKERNINGPAIR lpkrnpair) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetKerningPairs(m_hDC, nPairs, lpkrnpair);\n\t}\n\n\tUINT GetOutlineTextMetrics(UINT cbData, LPOUTLINETEXTMETRIC lpotm) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetOutlineTextMetrics(m_hDC, cbData, lpotm);\n\t}\n\n\tDWORD GetGlyphOutline(UINT nChar, UINT nFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpBuffer, const MAT2* lpmat2) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetGlyphOutline(m_hDC, nChar, nFormat, lpgm, cbBuffer, lpBuffer, lpmat2);\n\t}\n\n\tBOOL GetCharABCWidths(UINT nFirstChar, UINT nLastChar, LPABCFLOAT lpABCF) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharABCWidthsFloat(m_hDC, nFirstChar, nLastChar, lpABCF);\n\t}\n\n\tBOOL GetCharWidth(UINT nFirstChar, UINT nLastChar, float* lpFloatBuffer) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharWidthFloat(m_hDC, nFirstChar, nLastChar, lpFloatBuffer);\n\t}\n#endif // !_WIN32_WCE\n\n// Printer/Device Escape Functions\n#ifndef _WIN32_WCE\n\tint Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData);\n\t}\n#endif // !_WIN32_WCE\n\n\tint Escape(int nEscape, int nInputSize, LPCSTR lpszInputData,\n\t\tint nOutputSize, LPSTR lpszOutputData)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ExtEscape(m_hDC, nEscape, nInputSize, lpszInputData, nOutputSize, lpszOutputData);\n\t}\n\n#ifndef _WIN32_WCE\n\tint DrawEscape(int nEscape, int nInputSize, LPCSTR lpszInputData)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DrawEscape(m_hDC, nEscape, nInputSize, lpszInputData);\n\t}\n#endif // !_WIN32_WCE\n\n\t// Escape helpers\n#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))\n\tint StartDoc(LPCTSTR lpszDocName)  // old Win3.0 version\n\t{\n\t\tDOCINFO di = { 0 };\n\t\tdi.cbSize = sizeof(DOCINFO);\n\t\tdi.lpszDocName = lpszDocName;\n\t\treturn StartDoc(&di);\n\t}\n\n\tint StartDoc(LPDOCINFO lpDocInfo)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StartDoc(m_hDC, lpDocInfo);\n\t}\n\n\tint StartPage()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StartPage(m_hDC);\n\t}\n\n\tint EndPage()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::EndPage(m_hDC);\n\t}\n\n\tint SetAbortProc(BOOL (CALLBACK* lpfn)(HDC, int))\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetAbortProc(m_hDC, (ABORTPROC)lpfn);\n\t}\n\n\tint AbortDoc()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::AbortDoc(m_hDC);\n\t}\n\n\tint EndDoc()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::EndDoc(m_hDC);\n\t}\n#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 200) && defined(StartDoc))\n\n// MetaFile Functions\n#ifndef _WIN32_WCE\n\tBOOL PlayMetaFile(HMETAFILE hMF)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tif(::GetDeviceCaps(m_hDC, TECHNOLOGY) == DT_METAFILE)\n\t\t{\n\t\t\t// playing metafile in metafile, just use core windows API\n\t\t\treturn ::PlayMetaFile(m_hDC, hMF);\n\t\t}\n\n\t\t// for special playback, lParam == pDC\n\t\treturn ::EnumMetaFile(m_hDC, hMF, EnumMetaFileProc, (LPARAM)this);\n\t}\n\n\tBOOL PlayMetaFile(HENHMETAFILE hEnhMetaFile, LPCRECT lpBounds)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::PlayEnhMetaFile(m_hDC, hEnhMetaFile, lpBounds);\n\t}\n\n\tBOOL AddMetaFileComment(UINT nDataSize, const BYTE* pCommentData) // can be used for enhanced metafiles only\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GdiComment(m_hDC, nDataSize, pCommentData);\n\t}\n\n\t// Special handling for metafile playback\n\tstatic int CALLBACK EnumMetaFileProc(HDC hDC, HANDLETABLE* pHandleTable, METARECORD* pMetaRec, int nHandles, LPARAM lParam)\n\t{\n\t\tCDCHandle* pDC = (CDCHandle*)lParam;\n\n\t\tswitch (pMetaRec->rdFunction)\n\t\t{\n\t\tcase META_SETMAPMODE:\n\t\t\tpDC->SetMapMode((int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETWINDOWEXT:\n\t\t\tpDC->SetWindowExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETWINDOWORG:\n\t\t\tpDC->SetWindowOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETVIEWPORTEXT:\n\t\t\tpDC->SetViewportExt((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETVIEWPORTORG:\n\t\t\tpDC->SetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SCALEWINDOWEXT:\n\t\t\tpDC->ScaleWindowExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2], \n\t\t\t\t(int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SCALEVIEWPORTEXT:\n\t\t\tpDC->ScaleViewportExt((int)(short)pMetaRec->rdParm[3], (int)(short)pMetaRec->rdParm[2],\n\t\t\t\t(int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_OFFSETVIEWPORTORG:\n\t\t\tpDC->OffsetViewportOrg((int)(short)pMetaRec->rdParm[1], (int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SAVEDC:\n\t\t\tpDC->SaveDC();\n\t\t\tbreak;\n\t\tcase META_RESTOREDC:\n\t\t\tpDC->RestoreDC((int)(short)pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETBKCOLOR:\n\t\t\tpDC->SetBkColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\t\tcase META_SETTEXTCOLOR:\n\t\t\tpDC->SetTextColor(*(UNALIGNED COLORREF*)&pMetaRec->rdParm[0]);\n\t\t\tbreak;\n\n\t\t// need to watch out for SelectObject(HFONT), for custom font mapping\n\t\tcase META_SELECTOBJECT:\n\t\t\t{\n\t\t\t\tHGDIOBJ hObject = pHandleTable->objectHandle[pMetaRec->rdParm[0]];\n\t\t\t\tUINT nObjType = ::GetObjectType(hObject);\n\t\t\t\tif(nObjType == 0)\n\t\t\t\t{\n\t\t\t\t\t// object type is unknown, determine if it is a font\n\t\t\t\t\tHFONT hStockFont = (HFONT)::GetStockObject(SYSTEM_FONT);\n\t\t\t\t\tHFONT hFontOld = (HFONT)::SelectObject(pDC->m_hDC, hStockFont);\n\t\t\t\t\tHGDIOBJ hObjOld = ::SelectObject(pDC->m_hDC, hObject);\n\t\t\t\t\tif(hObjOld == hStockFont)\n\t\t\t\t\t{\n\t\t\t\t\t\t// got the stock object back, so must be selecting a font\n\t\t\t\t\t\tpDC->SelectFont((HFONT)hObject);\n\t\t\t\t\t\tbreak;  // don't play the default record\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// didn't get the stock object back, so restore everything\n\t\t\t\t\t\t::SelectObject(pDC->m_hDC, hFontOld);\n\t\t\t\t\t\t::SelectObject(pDC->m_hDC, hObjOld);\n\t\t\t\t\t}\n\t\t\t\t\t// and fall through to PlayMetaFileRecord...\n\t\t\t\t}\n\t\t\t\telse if(nObjType == OBJ_FONT)\n\t\t\t\t{\n\t\t\t\t\t// play back as CDCHandle::SelectFont(HFONT)\n\t\t\t\t\tpDC->SelectFont((HFONT)hObject);\n\t\t\t\t\tbreak;  // don't play the default record\n\t\t\t\t}\n\t\t\t}\n\t\t\t// fall through...\n\n\t\tdefault:\n\t\t\t::PlayMetaFileRecord(hDC, pHandleTable, pMetaRec, nHandles);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn 1;\n\t}\n#endif // !_WIN32_WCE\n\n// Path Functions\n#ifndef _WIN32_WCE\n\tBOOL AbortPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::AbortPath(m_hDC);\n\t}\n\n\tBOOL BeginPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::BeginPath(m_hDC);\n\t}\n\n\tBOOL CloseFigure()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::CloseFigure(m_hDC);\n\t}\n\n\tBOOL EndPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::EndPath(m_hDC);\n\t}\n\n\tBOOL FillPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FillPath(m_hDC);\n\t}\n\n\tBOOL FlattenPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::FlattenPath(m_hDC);\n\t}\n\n\tBOOL StrokeAndFillPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StrokeAndFillPath(m_hDC);\n\t}\n\n\tBOOL StrokePath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StrokePath(m_hDC);\n\t}\n\n\tBOOL WidenPath()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::WidenPath(m_hDC);\n\t}\n\n\tBOOL GetMiterLimit(PFLOAT pfMiterLimit) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetMiterLimit(m_hDC, pfMiterLimit);\n\t}\n\n\tBOOL SetMiterLimit(float fMiterLimit)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetMiterLimit(m_hDC, fMiterLimit, NULL);\n\t}\n\n\tint GetPath(LPPOINT lpPoints, LPBYTE lpTypes, int nCount) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetPath(m_hDC, lpPoints, lpTypes, nCount);\n\t}\n\n\tBOOL SelectClipPath(int nMode)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SelectClipPath(m_hDC, nMode);\n\t}\n#endif // !_WIN32_WCE\n\n// Misc Helper Functions\n\tstatic CBrushHandle PASCAL GetHalftoneBrush()\n\t{\n\t\tHBRUSH halftoneBrush = NULL;\n\t\tWORD grayPattern[8] = { 0 };\n\t\tfor(int i = 0; i < 8; i++)\n\t\t\tgrayPattern[i] = (WORD)(0x5555 << (i & 1));\n\t\tHBITMAP grayBitmap = CreateBitmap(8, 8, 1, 1, &grayPattern);\n\t\tif(grayBitmap != NULL)\n\t\t{\n\t\t\thalftoneBrush = ::CreatePatternBrush(grayBitmap);\n\t\t\tDeleteObject(grayBitmap);\n\t\t}\n\t\treturn CBrushHandle(halftoneBrush);\n\t}\n\n\tvoid DrawDragRect(LPCRECT lpRect, SIZE size, LPCRECT lpRectLast, SIZE sizeLast, HBRUSH hBrush = NULL, HBRUSH hBrushLast = NULL)\n\t{\n\t\t// first, determine the update region and select it\n\t\tCRgn rgnOutside;\n\t\trgnOutside.CreateRectRgnIndirect(lpRect);\n\t\tRECT rect = *lpRect;\n\t\t::InflateRect(&rect, -size.cx, -size.cy);\n\t\t::IntersectRect(&rect, &rect, lpRect);\n\t\tCRgn rgnInside;\n\t\trgnInside.CreateRectRgnIndirect(&rect);\n\t\tCRgn rgnNew;\n\t\trgnNew.CreateRectRgn(0, 0, 0, 0);\n\t\trgnNew.CombineRgn(rgnOutside, rgnInside, RGN_XOR);\n\n\t\tHBRUSH hBrushOld = NULL;\n\t\tCBrush brushHalftone;\n\t\tif(hBrush == NULL)\n\t\t\tbrushHalftone = hBrush = CDCHandle::GetHalftoneBrush();\n\t\tif(hBrushLast == NULL)\n\t\t\thBrushLast = hBrush;\n\n\t\tCRgn rgnLast;\n\t\tCRgn rgnUpdate;\n\t\tif(lpRectLast != NULL)\n\t\t{\n\t\t\t// find difference between new region and old region\n\t\t\trgnLast.CreateRectRgn(0, 0, 0, 0);\n\t\t\trgnOutside.SetRectRgn(lpRectLast->left, lpRectLast->top, lpRectLast->right, lpRectLast->bottom);\n\t\t\trect = *lpRectLast;\n\t\t\t::InflateRect(&rect, -sizeLast.cx, -sizeLast.cy);\n\t\t\t::IntersectRect(&rect, &rect, lpRectLast);\n\t\t\trgnInside.SetRectRgn(rect.left, rect.top, rect.right, rect.bottom);\n\t\t\trgnLast.CombineRgn(rgnOutside, rgnInside, RGN_XOR);\n\n\t\t\t// only diff them if brushes are the same\n\t\t\tif(hBrush == hBrushLast)\n\t\t\t{\n\t\t\t\trgnUpdate.CreateRectRgn(0, 0, 0, 0);\n\t\t\t\trgnUpdate.CombineRgn(rgnLast, rgnNew, RGN_XOR);\n\t\t\t}\n\t\t}\n\t\tif(hBrush != hBrushLast && lpRectLast != NULL)\n\t\t{\n\t\t\t// brushes are different -- erase old region first\n\t\t\tSelectClipRgn(rgnLast);\n\t\t\tGetClipBox(&rect);\n\t\t\thBrushOld = SelectBrush(hBrushLast);\n\t\t\tPatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);\n\t\t\tSelectBrush(hBrushOld);\n\t\t\thBrushOld = NULL;\n\t\t}\n\n\t\t// draw into the update/new region\n\t\tSelectClipRgn(rgnUpdate.IsNull() ? rgnNew : rgnUpdate);\n\t\tGetClipBox(&rect);\n\t\thBrushOld = SelectBrush(hBrush);\n\t\tPatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);\n\n\t\t// cleanup DC\n\t\tif(hBrushOld != NULL)\n\t\t\tSelectBrush(hBrushOld);\n\t\tSelectClipRgn(NULL);\n\t}\n\n\tvoid FillSolidRect(LPCRECT lpRect, COLORREF clr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\n\t\tCOLORREF clrOld = ::SetBkColor(m_hDC, clr);\n\t\tATLASSERT(clrOld != CLR_INVALID);\n\t\tif(clrOld != CLR_INVALID)\n\t\t{\n\t\t\t::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);\n\t\t\t::SetBkColor(m_hDC, clrOld);\n\t\t}\n\t}\n\n\tvoid FillSolidRect(int x, int y, int cx, int cy, COLORREF clr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\n\t\tRECT rect = { x, y, x + cx, y + cy };\n\t\tFillSolidRect(&rect, clr);\n\t}\n\n\tvoid Draw3dRect(LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)\n\t{\n\t\tDraw3dRect(lpRect->left, lpRect->top, lpRect->right - lpRect->left,\n\t\t\tlpRect->bottom - lpRect->top, clrTopLeft, clrBottomRight);\n\t}\n\n\tvoid Draw3dRect(int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight)\n\t{\n\t\tFillSolidRect(x, y, cx - 1, 1, clrTopLeft);\n\t\tFillSolidRect(x, y, 1, cy - 1, clrTopLeft);\n\t\tFillSolidRect(x + cx, y, -1, cy, clrBottomRight);\n\t\tFillSolidRect(x, y + cy, cx, -1, clrBottomRight);\n\t}\n\n// DIB support\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)\n\tint 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)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetDIBitsToDevice(m_hDC, x, y, dwWidth, dwHeight, xSrc, ySrc, uStartScan, cScanLines, lpvBits, lpbmi, uColorUse);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 410)\n\n#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\tint 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)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::StretchDIBits(m_hDC, x, y, nWidth, nHeight, xSrc, ySrc, nSrcWidth, nSrcHeight, lpvBits, lpbmi, uColorUse, dwRop);\n\t}\n\n\tUINT GetDIBColorTable(UINT uStartIndex, UINT cEntries, RGBQUAD* pColors) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors);\n\t}\n\n\tUINT SetDIBColorTable(UINT uStartIndex, UINT cEntries, CONST RGBQUAD* pColors)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetDIBColorTable(m_hDC, uStartIndex, cEntries, pColors);\n\t}\n#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)\n\n// OpenGL support\n#if !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)\n\tint ChoosePixelFormat(CONST PIXELFORMATDESCRIPTOR* ppfd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ChoosePixelFormat(m_hDC, ppfd);\n\t}\n\n\tint DescribePixelFormat(int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::DescribePixelFormat(m_hDC, iPixelFormat, nBytes, ppfd);\n\t}\n\n\tint GetPixelFormat() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetPixelFormat(m_hDC);\n\t}\n\n\tBOOL SetPixelFormat(int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetPixelFormat(m_hDC, iPixelFormat, ppfd);\n\t}\n\n\tBOOL SwapBuffers()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SwapBuffers(m_hDC);\n\t}\n\n\tHGLRC wglCreateContext()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglCreateContext(m_hDC);\n\t}\n\n\tHGLRC wglCreateLayerContext(int iLayerPlane)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglCreateLayerContext(m_hDC, iLayerPlane);\n\t}\n\n\tBOOL wglMakeCurrent(HGLRC hglrc)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglMakeCurrent(m_hDC, hglrc);\n\t}\n\n\tBOOL wglUseFontBitmaps(DWORD dwFirst, DWORD dwCount, DWORD listBase)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglUseFontBitmaps(m_hDC, dwFirst, dwCount, listBase);\n\t}\n\n\tBOOL wglUseFontOutlines(DWORD dwFirst, DWORD dwCount, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglUseFontOutlines(m_hDC, dwFirst, dwCount, listBase, deviation, extrusion, format, lpgmf);\n\t}\n\n\tBOOL wglDescribeLayerPlane(int iPixelFormat, int iLayerPlane, UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglDescribeLayerPlane(m_hDC, iPixelFormat, iLayerPlane, nBytes, plpd);\n\t}\n\n\tint wglSetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, CONST COLORREF* pclr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglSetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr);\n\t}\n\n\tint wglGetLayerPaletteEntries(int iLayerPlane, int iStart, int cEntries, COLORREF* pclr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglGetLayerPaletteEntries(m_hDC, iLayerPlane, iStart, cEntries, pclr);\n\t}\n\n\tBOOL wglRealizeLayerPalette(int iLayerPlane, BOOL bRealize)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglRealizeLayerPalette(m_hDC, iLayerPlane, bRealize);\n\t}\n\n\tBOOL wglSwapLayerBuffers(UINT uPlanes)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::wglSwapLayerBuffers(m_hDC, uPlanes);\n\t}\n#endif // !defined(_ATL_NO_OPENGL) && !defined(_WIN32_WCE)\n\n// New for Windows 2000 only\n#if (_WIN32_WINNT >= 0x0500)\n\tCOLORREF GetDCPenColor() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetDCPenColor(m_hDC);\n\t}\n\n\tCOLORREF SetDCPenColor(COLORREF clr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetDCPenColor(m_hDC, clr);\n\t}\n\n\tCOLORREF GetDCBrushColor() const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetDCBrushColor(m_hDC);\n\t}\n\n\tCOLORREF SetDCBrushColor(COLORREF clr)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::SetDCBrushColor(m_hDC, clr);\n\t}\n\n#ifndef _WIN32_WCE\n\tDWORD GetFontUnicodeRanges(LPGLYPHSET lpgs) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetFontUnicodeRanges(m_hDC, lpgs);\n\t}\n#endif // !_WIN32_WCE\n\n\tDWORD GetGlyphIndices(LPCTSTR lpstr, int cch, LPWORD pgi, DWORD dwFlags) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetGlyphIndices(m_hDC, lpstr, cch, pgi, dwFlags);\n\t}\n\n\tBOOL GetTextExtentPointI(LPWORD pgiIn, int cgi, LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextExtentPointI(m_hDC, pgiIn, cgi, lpSize);\n\t}\n\n\tBOOL GetTextExtentExPointI(LPWORD pgiIn, int cgi, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetTextExtentExPointI(m_hDC, pgiIn, cgi, nMaxExtent, lpnFit, alpDx, lpSize);\n\t}\n\n\tBOOL GetCharWidthI(UINT giFirst, UINT cgi, LPWORD pgi, LPINT lpBuffer) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharWidthI(m_hDC, giFirst, cgi, pgi, lpBuffer);\n\t}\n\n\tBOOL GetCharABCWidthsI(UINT giFirst, UINT cgi, LPWORD pgi, LPABC lpabc) const\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::GetCharABCWidthsI(m_hDC, giFirst, cgi, pgi, lpabc);\n\t}\n#endif // (_WIN32_WINNT >= 0x0500)\n\n// New for Windows 2000 and Windows 98\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\tBOOL ColorCorrectPalette(HPALETTE hPalette, DWORD dwFirstEntry, DWORD dwNumOfEntries)\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\treturn ::ColorCorrectPalette(m_hDC, hPalette, dwFirstEntry, dwNumOfEntries);\n\t}\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n};\n\ntypedef CDCT<false>   CDCHandle;\ntypedef CDCT<true>    CDC;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDC Helpers\n\nclass CPaintDC : public CDC\n{\npublic:\n// Data members\n\tHWND m_hWnd;\n\tPAINTSTRUCT m_ps;\n\n// Constructor/destructor\n\tCPaintDC(HWND hWnd)\n\t{\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tm_hWnd = hWnd;\n\t\tm_hDC = ::BeginPaint(hWnd, &m_ps);\n\t}\n\n\t~CPaintDC()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::EndPaint(m_hWnd, &m_ps);\n\t\tDetach();\n\t}\n};\n\nclass CClientDC : public CDC\n{\npublic:\n// Data members\n\tHWND m_hWnd;\n\n// Constructor/destructor\n\tCClientDC(HWND hWnd)\n\t{\n\t\tATLASSERT(hWnd == NULL || ::IsWindow(hWnd));\n\t\tm_hWnd = hWnd;\n\t\tm_hDC = ::GetDC(hWnd);\n\t}\n\n\t~CClientDC()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\t::ReleaseDC(m_hWnd, Detach());\n\t}\n};\n\nclass CWindowDC : public CDC\n{\npublic:\n// Data members\n\tHWND m_hWnd;\n\n// Constructor/destructor\n\tCWindowDC(HWND hWnd)\n\t{\n\t\tATLASSERT(hWnd == NULL || ::IsWindow(hWnd));\n\t\tm_hWnd = hWnd;\n\t\tm_hDC = ::GetWindowDC(hWnd);\n\t}\n\n\t~CWindowDC()\n\t{\n\t\tATLASSERT(m_hDC != NULL);\n\t\t::ReleaseDC(m_hWnd, Detach());\n\t}\n};\n\nclass CMemoryDC : public CDC\n{\npublic:\n// Data members\n\tHDC m_hDCOriginal;\n\tRECT m_rcPaint;\n\tCBitmap m_bmp;\n\tHBITMAP m_hBmpOld;\n\n// Constructor/destructor\n\tCMemoryDC(HDC hDC, const RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL)\n\t{\n\t\tm_rcPaint = rcPaint;\n\t\tCreateCompatibleDC(m_hDCOriginal);\n\t\tATLASSERT(m_hDC != NULL);\n\t\tm_bmp.CreateCompatibleBitmap(m_hDCOriginal, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom - m_rcPaint.top);\n\t\tATLASSERT(m_bmp.m_hBitmap != NULL);\n\t\tm_hBmpOld = SelectBitmap(m_bmp);\n\t\tSetViewportOrg(-m_rcPaint.left, -m_rcPaint.top);\n\t}\n\n\t~CMemoryDC()\n\t{\n\t\t::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);\n\t\tSelectBitmap(m_hBmpOld);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Enhanced metafile support\n\n#ifndef _WIN32_WCE\n\nclass CEnhMetaFileInfo\n{\npublic:\n// Data members\n\tHENHMETAFILE m_hEMF;\n\tBYTE* m_pBits;\n\tTCHAR* m_pDesc;\n\tENHMETAHEADER m_header;\n\tPIXELFORMATDESCRIPTOR m_pfd;\n\n// Constructor/destructor\n\tCEnhMetaFileInfo(HENHMETAFILE hEMF) : m_pBits(NULL), m_pDesc(NULL), m_hEMF(hEMF)\n\t{ }\n\n\t~CEnhMetaFileInfo()\n\t{\n\t\tdelete [] m_pBits;\n\t\tdelete [] m_pDesc;\n\t}\n\n// Operations\n\tBYTE* GetEnhMetaFileBits()\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tUINT nBytes = ::GetEnhMetaFileBits(m_hEMF, 0, NULL);\n\t\tdelete [] m_pBits;\n\t\tm_pBits = NULL;\n\t\tATLTRY(m_pBits = new BYTE[nBytes]);\n\t\tif (m_pBits != NULL)\n\t\t\t::GetEnhMetaFileBits(m_hEMF, nBytes, m_pBits);\n\t\treturn m_pBits;\n\t}\n\n\tLPTSTR GetEnhMetaFileDescription()\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tUINT nLen = ::GetEnhMetaFileDescription(m_hEMF, 0, NULL);\n\t\tdelete [] m_pDesc;\n\t\tm_pDesc = NULL;\n\t\tATLTRY(m_pDesc = new TCHAR[nLen]);\n\t\tif (m_pDesc != NULL)\n\t\t\tnLen = ::GetEnhMetaFileDescription(m_hEMF, nLen, m_pDesc);\n\t\treturn m_pDesc;\n\t}\n\n\tENHMETAHEADER* GetEnhMetaFileHeader()\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tmemset(&m_header, 0, sizeof(m_header));\n\t\tm_header.iType = EMR_HEADER;\n\t\tm_header.nSize = sizeof(ENHMETAHEADER);\n\t\tUINT n = ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), &m_header);\n\t\treturn (n != 0) ? &m_header : NULL;\n\t}\n\n\tPIXELFORMATDESCRIPTOR* GetEnhMetaFilePixelFormat()\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tmemset(&m_pfd, 0, sizeof(m_pfd));\n\t\tUINT n = ::GetEnhMetaFilePixelFormat(m_hEMF, sizeof(m_pfd), &m_pfd);\n\t\treturn (n != 0) ? &m_pfd : NULL;\n\t}\n};\n\n\ntemplate <bool t_bManaged>\nclass CEnhMetaFileT\n{\npublic:\n// Data members\n\tHENHMETAFILE m_hEMF;\n\n// Constructor/destructor\n\tCEnhMetaFileT(HENHMETAFILE hEMF = NULL) : m_hEMF(hEMF)\n\t{\n\t}\n\n\t~CEnhMetaFileT()\n\t{\n\t\tif(t_bManaged && m_hEMF != NULL)\n\t\t\tDeleteObject();\n\t}\n\n// Operations\n\tCEnhMetaFileT<t_bManaged>& operator =(HENHMETAFILE hEMF)\n\t{\n\t\tAttach(hEMF);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HENHMETAFILE hEMF)\n\t{\n\t\tif(t_bManaged && m_hEMF != NULL && m_hEMF != hEMF)\n\t\t\tDeleteObject();\n\t\tm_hEMF = hEMF;\n\t}\n\n\tHENHMETAFILE Detach()\n\t{\n\t\tHENHMETAFILE hEMF = m_hEMF;\n\t\tm_hEMF = NULL;\n\t\treturn hEMF;\n\t}\n\n\toperator HENHMETAFILE() const { return m_hEMF; }\n\n\tbool IsNull() const { return (m_hEMF == NULL); }\n\n\tBOOL DeleteObject()\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tBOOL bRet = ::DeleteEnhMetaFile(m_hEMF);\n\t\tm_hEMF = NULL;\n\t\treturn bRet;\n\t}\n\n\tUINT GetEnhMetaFileBits(UINT cbBuffer, LPBYTE lpbBuffer) const\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\treturn ::GetEnhMetaFileBits(m_hEMF, cbBuffer, lpbBuffer);\n\t}\n\n\tUINT GetEnhMetaFileDescription(UINT cchBuffer, LPTSTR lpszDescription) const\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\treturn ::GetEnhMetaFileDescription(m_hEMF, cchBuffer, lpszDescription);\n\t}\n\n\tUINT GetEnhMetaFileHeader(LPENHMETAHEADER lpemh) const\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\tlpemh->iType = EMR_HEADER;\n\t\tlpemh->nSize = sizeof(ENHMETAHEADER);\n\t\treturn ::GetEnhMetaFileHeader(m_hEMF, sizeof(ENHMETAHEADER), lpemh);\n\t}\n\n\tUINT GetEnhMetaFilePaletteEntries(UINT cEntries, LPPALETTEENTRY lppe) const\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\treturn ::GetEnhMetaFilePaletteEntries(m_hEMF, cEntries, lppe);\n\t}\n\n\tUINT GetEnhMetaFilePixelFormat(DWORD cbBuffer, PIXELFORMATDESCRIPTOR* ppfd) const\n\t{\n\t\tATLASSERT(m_hEMF != NULL);\n\t\treturn ::GetEnhMetaFilePixelFormat(m_hEMF, cbBuffer, ppfd);\n\t}\n};\n\ntypedef CEnhMetaFileT<false>   CEnhMetaFileHandle;\ntypedef CEnhMetaFileT<true>    CEnhMetaFile;\n\n\nclass CEnhMetaFileDC : public CDC\n{\npublic:\n// Constructor/destructor\n\tCEnhMetaFileDC()\n\t{\n\t}\n\n\tCEnhMetaFileDC(HDC hdc, LPCRECT lpRect)\n\t{\n\t\tCreate(hdc, NULL, lpRect, NULL);\n\t\tATLASSERT(m_hDC != NULL);\n\t}\n\n\tCEnhMetaFileDC(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)\n\t{\n\t\tCreate(hdcRef, lpFilename, lpRect, lpDescription);\n\t\tATLASSERT(m_hDC != NULL);\n\t}\n\n\t~CEnhMetaFileDC()\n\t{\n\t\tHENHMETAFILE hEMF = Close();\n\t\tif (hEMF != NULL)\n\t\t\t::DeleteEnhMetaFile(hEMF);\n\t}\n\n// Operations\n\tvoid Create(HDC hdcRef, LPCTSTR lpFilename, LPCRECT lpRect, LPCTSTR lpDescription)\n\t{\n\t\tATLASSERT(m_hDC == NULL);\n\t\tm_hDC = ::CreateEnhMetaFile(hdcRef, lpFilename, lpRect, lpDescription);\n\t}\n\n\tHENHMETAFILE Close()\n\t{\n\t\tHENHMETAFILE hEMF = NULL;\n\t\tif (m_hDC != NULL)\n\t\t{\n\t\t\thEMF = ::CloseEnhMetaFile(m_hDC);\n\t\t\tm_hDC = NULL;\n\t\t}\n\t\treturn hEMF;\n\t}\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// WinCE compatible clipboard CF_DIB format support functions\n\n#ifndef _WTL_NO_DIB16\n\n#define DIBINFO16_BITFIELDS { 31744, 992, 31 }\n\n// DIBINFO16 - To avoid color table problems in WinCE we only create this type of Dib\nstruct DIBINFO16 // a BITMAPINFO with 2 additional color bitfields\n{\n\tBITMAPINFOHEADER bmiHeader;\n\tRGBQUAD bmiColors[3];\n\n\tDIBINFO16(SIZE size) \n\t{\n\t\tBITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), size.cx, size.cy, \n\t\t                          1, 16, BI_BITFIELDS, (DWORD)(2 * size.cx * size.cy), 0, 0, 3 };\n\t\tDWORD dw[3] = DIBINFO16_BITFIELDS ;\n\n\t\tbmiHeader = bmih;\n\t\tSecureHelper::memcpy_x(bmiColors, sizeof(bmiColors), dw, 3 * sizeof(DWORD));\n\t}\n};\n\n\n// AtlxxxDibxxx minimal packed DIB implementation and helpers to copy and paste CF_DIB\n \ninline bool AtlIsDib16(LPBITMAPINFOHEADER pbmih)\n{\n\treturn (pbmih->biBitCount == 16) && (pbmih->biCompression == BI_BITFIELDS);\n}\n\ninline int AtlGetDibColorTableSize(LPBITMAPINFOHEADER pbmih)\n{\n\tswitch (pbmih->biBitCount) \n\t{\n\t\tcase  2:\n\t\tcase  4:\n\t\tcase  8:\n\t\t\treturn pbmih->biClrUsed ? pbmih->biClrUsed : 1 << pbmih->biBitCount;\n\t\tcase 24:\n\t\t\tbreak;\n\t\tcase 16:\n\t\tcase 32:\n\t\t\treturn pbmih->biCompression == BI_BITFIELDS ? 3 : 0;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);   // should never come here\n\t}\n\n\treturn 0;\n}\n\ninline int AtlGetDibNumColors(LPBITMAPINFOHEADER pbmih)\n{\n\tswitch (pbmih->biBitCount) \n\t{\n\t\tcase  2:\n\t\tcase  4:\n\t\tcase  8: \n\t\t\tif (pbmih->biClrUsed)\n\t\t\t\treturn pbmih->biClrUsed;\n\t\t\telse\n\t\t\t\tbreak;\n\t\tcase 16: \n\t\t\tif (pbmih->biCompression == BI_BITFIELDS )\n\t\t\t\treturn 1 << 15;\n\t\t\telse\n\t\t\t\tbreak;\n\t\tcase 24:\n\t\t\tbreak;\n\t\tcase 32: \n\t\t\tif (pbmih->biCompression == BI_BITFIELDS )\n\t\t\t\treturn 1 << 24;\n\t\t\telse\n\t\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t}\n\n\treturn 1 << pbmih->biBitCount;\n}\n\ninline HBITMAP AtlGetDibBitmap(LPBITMAPINFO pbmi)\n{\n\tCDC dc(NULL);\n\tvoid* pBits = NULL;\n\n\tLPBYTE pDibBits = (LPBYTE)pbmi + sizeof(BITMAPINFOHEADER) + AtlGetDibColorTableSize(&pbmi->bmiHeader) * sizeof(RGBQUAD);\n\tHBITMAP hbm = CreateDIBSection(dc, pbmi, DIB_RGB_COLORS, &pBits, NULL, NULL);\n\tif (hbm != NULL)\n\t{\n\t\tint cbBits = pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biHeight * pbmi->bmiHeader.biBitCount / 8;\n\t\tSecureHelper::memcpy_x(pBits, cbBits, pDibBits, pbmi->bmiHeader.biSizeImage);\n\t}\n\n\treturn hbm;\n}\n\t\ninline HBITMAP AtlCopyBitmap(HBITMAP hbm, SIZE sizeDst, bool bAsBitmap = false)\n{\n\tCDC hdcSrc = CreateCompatibleDC(NULL);\n\tCDC hdcDst = CreateCompatibleDC(NULL);\n\n\tCBitmapHandle hbmOld = NULL, hbmOld2 = NULL, bmSrc = hbm;\n\n\tCBitmap bmNew = NULL;\n\n\tSIZE sizeSrc = { 0 };\n\tbmSrc.GetSize(sizeSrc);\n\n\thbmOld = hdcSrc.SelectBitmap(bmSrc);\n\n\tif (bAsBitmap)\n\t{\n\t\tbmNew.CreateCompatibleBitmap(hdcSrc, sizeDst.cx, sizeDst.cy);\n\t}\n\telse\n\t{\n\t\tDIBINFO16 dib16(sizeDst);\n\t\tLPVOID pBits = NULL;\n\t\tbmNew = CreateDIBSection(hdcDst, (const BITMAPINFO*)&dib16, DIB_RGB_COLORS, &pBits, NULL, NULL);\n\t}\n\t\n\tATLASSERT(!bmNew.IsNull());\n\n\thbmOld2 = hdcDst.SelectBitmap(bmNew);\n\tBOOL bOK = FALSE;\n\n\tif ((sizeDst.cx == sizeSrc.cx) && (sizeDst.cy == sizeSrc.cy))\n\t\tbOK = hdcDst.BitBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, SRCCOPY);\n\telse\n\t\tbOK = hdcDst.StretchBlt(0, 0, sizeDst.cx, sizeDst.cy, hdcSrc, 0, 0, sizeSrc.cx, sizeSrc.cy, SRCCOPY);\n\n\thdcSrc.SelectBitmap(hbmOld);\n\thdcDst.SelectBitmap(hbmOld2);\n\n\tif (bOK == FALSE)\n\t\tbmNew.DeleteObject();\n\n\treturn bmNew.Detach();\n}\n\ninline HLOCAL AtlCreatePackedDib16(HBITMAP hbm, SIZE size)\n{\n\tDIBSECTION ds = { 0 };\n\tLPBYTE pDib = NULL;\n\tbool bCopied = false;\n\n\tbool bOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds);\n\tif ((bOK == FALSE) || (ds.dsBm.bmBits == NULL) || (AtlIsDib16(&ds.dsBmih) == FALSE) || \n\t    (ds.dsBmih.biWidth != size.cx ) || (ds.dsBmih.biHeight != size.cy ))\n\t{\n\t\tif ((hbm = AtlCopyBitmap(hbm, size)) != NULL)\n\t\t{\n\t\t\tbCopied = true;\n\t\t\tbOK = GetObject(hbm, sizeof(ds), &ds) == sizeof(ds);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbOK = FALSE;\n\t\t}\n\t}\n\n\tif((bOK != FALSE) && (AtlIsDib16(&ds.dsBmih) != FALSE) && (ds.dsBm.bmBits != NULL))\n\t{\n\t\tpDib = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage);\n\t\tif (pDib != NULL)\n\t\t{\n\t\t\tSecureHelper::memcpy_x(pDib, sizeof(DIBINFO16) + ds.dsBmih.biSizeImage, &ds.dsBmih, sizeof(DIBINFO16));\n\t\t\tSecureHelper::memcpy_x(pDib + sizeof(DIBINFO16), ds.dsBmih.biSizeImage, ds.dsBm.bmBits, ds.dsBmih.biSizeImage);\n\t\t}\n\t}\n\n\tif (bCopied == true)\n\t\tDeleteObject(hbm);\n\n\treturn (HLOCAL)pDib;\n}\n\ninline bool AtlSetClipboardDib16(HBITMAP hbm, SIZE size, HWND hWnd)\n{\n\tATLASSERT(::IsWindow(hWnd));\n\tBOOL bOK = OpenClipboard(hWnd);\n\tif (bOK != FALSE)\n\t{\n\t\tbOK = EmptyClipboard();\n\t\tif (bOK != FALSE)\n\t\t{\n\t\t\tHLOCAL hDib = AtlCreatePackedDib16(hbm, size);\n\t\t\tif (hDib != NULL)\n\t\t\t{\n\t\t\t\tbOK = SetClipboardData(CF_DIB, hDib) != NULL;\n\t\t\t\tif (bOK == FALSE)  \n\t\t\t\t\tLocalFree(hDib);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbOK = FALSE;\n\t\t\t}\n\t\t}\n\t\tCloseClipboard();\n\t}\n\n\treturn (bOK != FALSE);\n}\n\ninline HBITMAP AtlGetClipboardDib(HWND hWnd)\n{\n\tATLASSERT(::IsWindow(hWnd) != FALSE);\n\tHBITMAP hbm = NULL;\n\tif  (OpenClipboard(hWnd) != FALSE)\n\t{\n\t\tLPBITMAPINFO pbmi = (LPBITMAPINFO)GetClipboardData(CF_DIB);\n\t\tif (pbmi != NULL)\n\t\t\thbm = AtlGetDibBitmap(pbmi);\n\t\tCloseClipboard();\n\t}\n\n\treturn hbm;\n}\n\n#endif // _WTL_NO_DIB16\n\n}; // namespace WTL\n\n#endif // __ATLGDI_H__\n"
  },
  {
    "path": "WTL/atlmisc.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLMISC_H__\n#define __ATLMISC_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlmisc.h requires atlapp.h to be included first\n#endif\n\n\n#ifdef _ATL_TMP_NO_CSTRING\n  #define _WTL_NO_CSTRING\n#endif\n\n#if defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)\n\t#error Conflicting options - both _WTL_USE_CSTRING and _WTL_NO_CSTRING are defined\n#endif // defined(_WTL_USE_CSTRING) && defined(_WTL_NO_CSTRING)\n\n#if !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)\n  #define _WTL_USE_CSTRING\n#endif // !defined(_WTL_USE_CSTRING) && !defined(_WTL_NO_CSTRING)\n\n#ifndef _WTL_NO_CSTRING\n  #if defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)\n\t#error Cannot use CString floating point formatting with _ATL_MIN_CRT defined\n  #endif // defined(_ATL_USE_CSTRING_FLOAT) && defined(_ATL_MIN_CRT)\n#endif // !_WTL_NO_CSTRING\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CSize\n// CPoint\n// CRect\n// CString\n//\n// CRecentDocumentListBase<T, t_cchItemLen, t_nFirstID, t_nLastID>\n// CRecentDocumentList\n// CFindFile\n//\n// Global functions:\n//   AtlGetStockPen()\n//   AtlGetStockBrush()\n//   AtlGetStockFont()\n//   AtlGetStockPalette()\n//\n//   AtlCompactPath()\n\n\nnamespace WTL\n{\n\n#ifndef _WTL_NO_WTYPES\n\n// forward declarations\nclass CSize;\nclass CPoint;\nclass CRect;\n\n///////////////////////////////////////////////////////////////////////////////\n// CSize - Wrapper for Windows SIZE structure.\n\nclass CSize : public SIZE\n{\npublic:\n// Constructors\n\tCSize()\n\t{\n\t\tcx = 0;\n\t\tcy = 0;\n\t}\n\n\tCSize(int initCX, int initCY)\n\t{\n\t\tcx = initCX;\n\t\tcy = initCY;\n\t}\n\n\tCSize(SIZE initSize)\n\t{\n\t\t*(SIZE*)this = initSize;\n\t}\n\n\tCSize(POINT initPt)\n\t{\n\t\t*(POINT*)this = initPt;\n\t}\n\n\tCSize(DWORD dwSize)\n\t{\n\t\tcx = (short)LOWORD(dwSize);\n\t\tcy = (short)HIWORD(dwSize);\n\t}\n\n// Operations\n\tBOOL operator ==(SIZE size) const\n\t{\n\t\treturn (cx == size.cx && cy == size.cy);\n\t}\n\n\tBOOL operator !=(SIZE size) const\n\t{\n\t\treturn (cx != size.cx || cy != size.cy);\n\t}\n\n\tvoid operator +=(SIZE size)\n\t{\n\t\tcx += size.cx;\n\t\tcy += size.cy;\n\t}\n\n\tvoid operator -=(SIZE size)\n\t{\n\t\tcx -= size.cx;\n\t\tcy -= size.cy;\n\t}\n\n\tvoid SetSize(int CX, int CY)\n\t{\n\t\tcx = CX;\n\t\tcy = CY;\n\t}\n\n// Operators returning CSize values\n\tCSize operator +(SIZE size) const\n\t{\n\t\treturn CSize(cx + size.cx, cy + size.cy);\n\t}\n\n\tCSize operator -(SIZE size) const\n\t{\n\t\treturn CSize(cx - size.cx, cy - size.cy);\n\t}\n\n\tCSize operator -() const\n\t{\n\t\treturn CSize(-cx, -cy);\n\t}\n\n// Operators returning CPoint values\n\tCPoint operator +(POINT point) const;\n\tCPoint operator -(POINT point) const;\n\n// Operators returning CRect values\n\tCRect operator +(const RECT* lpRect) const;\n\tCRect operator -(const RECT* lpRect) const;\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPoint - Wrapper for Windows POINT structure.\n\nclass CPoint : public POINT\n{\npublic:\n// Constructors\n\tCPoint()\n\t{\n\t\tx = 0;\n\t\ty = 0;\n\t}\n\n\tCPoint(int initX, int initY)\n\t{\n\t\tx = initX;\n\t\ty = initY;\n\t}\n\n\tCPoint(POINT initPt)\n\t{\n\t\t*(POINT*)this = initPt;\n\t}\n\n\tCPoint(SIZE initSize)\n\t{\n\t\t*(SIZE*)this = initSize;\n\t}\n\n\tCPoint(DWORD dwPoint)\n\t{\n\t\tx = (short)LOWORD(dwPoint);\n\t\ty = (short)HIWORD(dwPoint);\n\t}\n\n// Operations\n\tvoid Offset(int xOffset, int yOffset)\n\t{\n\t\tx += xOffset;\n\t\ty += yOffset;\n\t}\n\n\tvoid Offset(POINT point)\n\t{\n\t\tx += point.x;\n\t\ty += point.y;\n\t}\n\n\tvoid Offset(SIZE size)\n\t{\n\t\tx += size.cx;\n\t\ty += size.cy;\n\t}\n\n\tBOOL operator ==(POINT point) const\n\t{\n\t\treturn (x == point.x && y == point.y);\n\t}\n\n\tBOOL operator !=(POINT point) const\n\t{\n\t\treturn (x != point.x || y != point.y);\n\t}\n\n\tvoid operator +=(SIZE size)\n\t{\n\t\tx += size.cx;\n\t\ty += size.cy;\n\t}\n\n\tvoid operator -=(SIZE size)\n\t{\n\t\tx -= size.cx;\n\t\ty -= size.cy;\n\t}\n\n\tvoid operator +=(POINT point)\n\t{\n\t\tx += point.x;\n\t\ty += point.y;\n\t}\n\n\tvoid operator -=(POINT point)\n\t{\n\t\tx -= point.x;\n\t\ty -= point.y;\n\t}\n\n\tvoid SetPoint(int X, int Y)\n\t{\n\t\tx = X;\n\t\ty = Y;\n\t}\n\n// Operators returning CPoint values\n\tCPoint operator +(SIZE size) const\n\t{\n\t\treturn CPoint(x + size.cx, y + size.cy);\n\t}\n\n\tCPoint operator -(SIZE size) const\n\t{\n\t\treturn CPoint(x - size.cx, y - size.cy);\n\t}\n\n\tCPoint operator -() const\n\t{\n\t\treturn CPoint(-x, -y);\n\t}\n\n\tCPoint operator +(POINT point) const\n\t{\n\t\treturn CPoint(x + point.x, y + point.y);\n\t}\n\n// Operators returning CSize values\n\tCSize operator -(POINT point) const\n\t{\n\t\treturn CSize(x - point.x, y - point.y);\n\t}\n\n// Operators returning CRect values\n\tCRect operator +(const RECT* lpRect) const;\n\tCRect operator -(const RECT* lpRect) const;\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRect - Wrapper for Windows RECT structure.\n\nclass CRect : public RECT\n{\npublic:\n// Constructors\n\tCRect()\n\t{\n\t\tleft = 0;\n\t\ttop = 0;\n\t\tright = 0;\n\t\tbottom = 0;\n\t}\n\n\tCRect(int l, int t, int r, int b)\n\t{\n\t\tleft = l;\n\t\ttop = t;\n\t\tright = r;\n\t\tbottom = b;\n\t}\n\n\tCRect(const RECT& srcRect)\n\t{\n\t\t::CopyRect(this, &srcRect);\n\t}\n\n\tCRect(LPCRECT lpSrcRect)\n\t{\n\t\t::CopyRect(this, lpSrcRect);\n\t}\n\n\tCRect(POINT point, SIZE size)\n\t{\n\t\tright = (left = point.x) + size.cx;\n\t\tbottom = (top = point.y) + size.cy;\n\t}\n\n\tCRect(POINT topLeft, POINT bottomRight)\n\t{\n\t\tleft = topLeft.x;\n\t\ttop = topLeft.y;\n\t\tright = bottomRight.x;\n\t\tbottom = bottomRight.y;\n\t}\n\n// Attributes (in addition to RECT members)\n\tint Width() const\n\t{\n\t\treturn right - left;\n\t}\n\n\tint Height() const\n\t{\n\t\treturn bottom - top;\n\t}\n\n\tCSize Size() const\n\t{\n\t\treturn CSize(right - left, bottom - top);\n\t}\n\n\tCPoint& TopLeft()\n\t{\n\t\treturn *((CPoint*)this);\n\t}\n\n\tCPoint& BottomRight()\n\t{\n\t\treturn *((CPoint*)this + 1);\n\t}\n\n\tconst CPoint& TopLeft() const\n\t{\n\t\treturn *((CPoint*)this);\n\t}\n\n\tconst CPoint& BottomRight() const\n\t{\n\t\treturn *((CPoint*)this + 1);\n\t}\n\n\tCPoint CenterPoint() const\n\t{\n\t\treturn CPoint((left + right) / 2, (top + bottom) / 2);\n\t}\n\n\t// convert between CRect and LPRECT/LPCRECT (no need for &)\n\toperator LPRECT()\n\t{\n\t\treturn this;\n\t}\n\n\toperator LPCRECT() const\n\t{\n\t\treturn this;\n\t}\n\n\tBOOL IsRectEmpty() const\n\t{\n\t\treturn ::IsRectEmpty(this);\n\t}\n\n\tBOOL IsRectNull() const\n\t{\n\t\treturn (left == 0 && right == 0 && top == 0 && bottom == 0);\n\t}\n\n\tBOOL PtInRect(POINT point) const\n\t{\n\t\treturn ::PtInRect(this, point);\n\t}\n\n// Operations\n\tvoid SetRect(int x1, int y1, int x2, int y2)\n\t{\n\t\t::SetRect(this, x1, y1, x2, y2);\n\t}\n\n\tvoid SetRect(POINT topLeft, POINT bottomRight)\n\t{\n\t\t::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);\n\t}\n\n\tvoid SetRectEmpty()\n\t{\n\t\t::SetRectEmpty(this);\n\t}\n\n\tvoid CopyRect(LPCRECT lpSrcRect)\n\t{\n\t\t::CopyRect(this, lpSrcRect);\n\t}\n\n\tBOOL EqualRect(LPCRECT lpRect) const\n\t{\n\t\treturn ::EqualRect(this, lpRect);\n\t}\n\n\tvoid InflateRect(int x, int y)\n\t{\n\t\t::InflateRect(this, x, y);\n\t}\n\n\tvoid InflateRect(SIZE size)\n\t{\n\t\t::InflateRect(this, size.cx, size.cy);\n\t}\n\n\tvoid InflateRect(LPCRECT lpRect)\n\t{\n\t\tleft -= lpRect->left;\n\t\ttop -= lpRect->top;\n\t\tright += lpRect->right;\n\t\tbottom += lpRect->bottom;\n\t}\n\n\tvoid InflateRect(int l, int t, int r, int b)\n\t{\n\t\tleft -= l;\n\t\ttop -= t;\n\t\tright += r;\n\t\tbottom += b;\n\t}\n\n\tvoid DeflateRect(int x, int y)\n\t{\n\t\t::InflateRect(this, -x, -y);\n\t}\n\n\tvoid DeflateRect(SIZE size)\n\t{\n\t\t::InflateRect(this, -size.cx, -size.cy);\n\t}\n\n\tvoid DeflateRect(LPCRECT lpRect)\n\t{\n\t\tleft += lpRect->left;\n\t\ttop += lpRect->top;\n\t\tright -= lpRect->right;\n\t\tbottom -= lpRect->bottom;\n\t}\n\n\tvoid DeflateRect(int l, int t, int r, int b)\n\t{\n\t\tleft += l;\n\t\ttop += t;\n\t\tright -= r;\n\t\tbottom -= b;\n\t}\n\n\tvoid OffsetRect(int x, int y)\n\t{\n\t\t::OffsetRect(this, x, y);\n\t}\n\tvoid OffsetRect(SIZE size)\n\t{\n\t\t::OffsetRect(this, size.cx, size.cy);\n\t}\n\n\tvoid OffsetRect(POINT point)\n\t{\n\t\t::OffsetRect(this, point.x, point.y);\n\t}\n\n\tvoid NormalizeRect()\n\t{\n\t\tint nTemp;\n\t\tif (left > right)\n\t\t{\n\t\t\tnTemp = left;\n\t\t\tleft = right;\n\t\t\tright = nTemp;\n\t\t}\n\t\tif (top > bottom)\n\t\t{\n\t\t\tnTemp = top;\n\t\t\ttop = bottom;\n\t\t\tbottom = nTemp;\n\t\t}\n\t}\n\n\t// absolute position of rectangle\n\tvoid MoveToY(int y)\n\t{\n\t\tbottom = Height() + y;\n\t\ttop = y;\n\t}\n\n\tvoid MoveToX(int x)\n\t{\n\t\tright = Width() + x;\n\t\tleft = x;\n\t}\n\n\tvoid MoveToXY(int x, int y)\n\t{\n\t\tMoveToX(x);\n\t\tMoveToY(y);\n\t}\n\n\tvoid MoveToXY(POINT pt)\n\t{\n\t\tMoveToX(pt.x);\n\t\tMoveToY(pt.y);\n\t}\n\n\t// operations that fill '*this' with result\n\tBOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2)\n\t{\n\t\treturn ::IntersectRect(this, lpRect1, lpRect2);\n\t}\n\n\tBOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2)\n\t{\n\t\treturn ::UnionRect(this, lpRect1, lpRect2);\n\t}\n\n\tBOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2)\n\t{\n\t\treturn ::SubtractRect(this, lpRectSrc1, lpRectSrc2);\n\t}\n\n// Additional Operations\n\tvoid operator =(const RECT& srcRect)\n\t{\n\t\t::CopyRect(this, &srcRect);\n\t}\n\n\tBOOL operator ==(const RECT& rect) const\n\t{\n\t\treturn ::EqualRect(this, &rect);\n\t}\n\n\tBOOL operator !=(const RECT& rect) const\n\t{\n\t\treturn !::EqualRect(this, &rect);\n\t}\n\n\tvoid operator +=(POINT point)\n\t{\n\t\t::OffsetRect(this, point.x, point.y);\n\t}\n\n\tvoid operator +=(SIZE size)\n\t{\n\t\t::OffsetRect(this, size.cx, size.cy);\n\t}\n\n\tvoid operator +=(LPCRECT lpRect)\n\t{\n\t\tInflateRect(lpRect);\n\t}\n\n\tvoid operator -=(POINT point)\n\t{\n\t\t::OffsetRect(this, -point.x, -point.y);\n\t}\n\n\tvoid operator -=(SIZE size)\n\t{\n\t\t::OffsetRect(this, -size.cx, -size.cy);\n\t}\n\n\tvoid operator -=(LPCRECT lpRect)\n\t{\n\t\tDeflateRect(lpRect);\n\t}\n\n\tvoid operator &=(const RECT& rect)\n\t{\n\t\t::IntersectRect(this, this, &rect);\n\t}\n\n\tvoid operator |=(const RECT& rect)\n\t{\n\t\t::UnionRect(this, this, &rect);\n\t}\n\n// Operators returning CRect values\n\tCRect operator +(POINT pt) const\n\t{\n\t\tCRect rect(*this);\n\t\t::OffsetRect(&rect, pt.x, pt.y);\n\t\treturn rect;\n\t}\n\n\tCRect operator -(POINT pt) const\n\t{\n\t\tCRect rect(*this);\n\t\t::OffsetRect(&rect, -pt.x, -pt.y);\n\t\treturn rect;\n\t}\n\n\tCRect operator +(LPCRECT lpRect) const\n\t{\n\t\tCRect rect(this);\n\t\trect.InflateRect(lpRect);\n\t\treturn rect;\n\t}\n\n\tCRect operator +(SIZE size) const\n\t{\n\t\tCRect rect(*this);\n\t\t::OffsetRect(&rect, size.cx, size.cy);\n\t\treturn rect;\n\t}\n\n\tCRect operator -(SIZE size) const\n\t{\n\t\tCRect rect(*this);\n\t\t::OffsetRect(&rect, -size.cx, -size.cy);\n\t\treturn rect;\n\t}\n\n\tCRect operator -(LPCRECT lpRect) const\n\t{\n\t\tCRect rect(this);\n\t\trect.DeflateRect(lpRect);\n\t\treturn rect;\n\t}\n\n\tCRect operator &(const RECT& rect2) const\n\t{\n\t\tCRect rect;\n\t\t::IntersectRect(&rect, this, &rect2);\n\t\treturn rect;\n\t}\n\n\tCRect operator |(const RECT& rect2) const\n\t{\n\t\tCRect rect;\n\t\t::UnionRect(&rect, this, &rect2);\n\t\treturn rect;\n\t}\n\n\tCRect MulDiv(int nMultiplier, int nDivisor) const\n\t{\n\t\treturn CRect(\n\t\t\t::MulDiv(left, nMultiplier, nDivisor),\n\t\t\t::MulDiv(top, nMultiplier, nDivisor),\n\t\t\t::MulDiv(right, nMultiplier, nDivisor),\n\t\t\t::MulDiv(bottom, nMultiplier, nDivisor));\n\t}\n};\n\n\n// CSize implementation\n\ninline CPoint CSize::operator +(POINT point) const\n{ return CPoint(cx + point.x, cy + point.y); }\n\ninline CPoint CSize::operator -(POINT point) const\n{ return CPoint(cx - point.x, cy - point.y); }\n\ninline CRect CSize::operator +(const RECT* lpRect) const\n{ return CRect(lpRect) + *this; }\n\ninline CRect CSize::operator -(const RECT* lpRect) const\n{ return CRect(lpRect) - *this; }\n\n\n// CPoint implementation\n\ninline CRect CPoint::operator +(const RECT* lpRect) const\n{ return CRect(lpRect) + *this; }\n\ninline CRect CPoint::operator -(const RECT* lpRect) const\n{ return CRect(lpRect) - *this; }\n\n#endif // !_WTL_NO_WTYPES\n\n\n// WTL::CSize or ATL::CSize scalar operators \n\n#if !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))\n\ntemplate <class Num>\ninline CSize operator *(SIZE s, Num n) \n{\n\treturn CSize((int)(s.cx * n), (int)(s.cy * n));\n};\n\ntemplate <class Num>\ninline void operator *=(SIZE & s, Num n)\n{\n\ts = s * n;\n};\t\n\ntemplate <class Num>\ninline CSize operator /(SIZE s, Num n) \n{\n\treturn CSize((int)(s.cx / n), (int)(s.cy / n));\n};\n\ntemplate <class Num>\ninline void operator /=(SIZE & s, Num n)\n{\n\ts = s / n;\n};\t\n\n#endif // !defined(_WTL_NO_SIZE_SCALAR) && (!defined(_WTL_NO_WTYPES) || defined(__ATLTYPES_H__))\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CString - String class\n\n#ifndef _WTL_NO_CSTRING\n\nstruct CStringData\n{\n\tlong nRefs;     // reference count\n\tint nDataLength;\n\tint nAllocLength;\n\t// TCHAR data[nAllocLength]\n\n\tTCHAR* data()\n\t{ return (TCHAR*)(this + 1); }\n};\n\n// Globals\n\n// For an empty string, m_pchData will point here\n// (note: avoids special case of checking for NULL m_pchData)\n// empty string data (and locked)\n_declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 };\n_declspec(selectany) CStringData* _atltmpDataNil = (CStringData*)&rgInitData;\n_declspec(selectany) LPCTSTR _atltmpPchNil = (LPCTSTR)(((BYTE*)&rgInitData) + sizeof(CStringData));\n\n\nclass CString\n{\npublic:\n// Constructors\n\tCString()\n\t{\n\t\tInit();\n\t}\n\n\tCString(const CString& stringSrc)\n\t{\n\t\tATLASSERT(stringSrc.GetData()->nRefs != 0);\n\t\tif (stringSrc.GetData()->nRefs >= 0)\n\t\t{\n\t\t\tATLASSERT(stringSrc.GetData() != _atltmpDataNil);\n\t\t\tm_pchData = stringSrc.m_pchData;\n\t\t\tInterlockedIncrement(&GetData()->nRefs);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tInit();\n\t\t\t*this = stringSrc.m_pchData;\n\t\t}\n\t}\n\n\tCString(TCHAR ch, int nRepeat = 1)\n\t{\n\t\tATLASSERT(!_istlead(ch));   // can't create a lead byte string\n\t\tInit();\n\t\tif (nRepeat >= 1)\n\t\t{\n\t\t\tif(AllocBuffer(nRepeat))\n\t\t\t{\n#ifdef _UNICODE\n\t\t\t\tfor (int i = 0; i < nRepeat; i++)\n\t\t\t\t\tm_pchData[i] = ch;\n#else\n\t\t\t\tmemset(m_pchData, ch, nRepeat);\n#endif\n\t\t\t}\n\t\t}\n\t}\n\n\tCString(LPCTSTR lpsz)\n\t{\n\t\tInit();\n\t\tif (lpsz != NULL && HIWORD(lpsz) == NULL)\n\t\t{\n\t\t\tUINT nID = LOWORD((DWORD_PTR)lpsz);\n\t\t\tif (!LoadString(nID))\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Warning: implicit LoadString(%u) in CString failed\\n\"), nID);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint nLen = SafeStrlen(lpsz);\n\t\t\tif (nLen != 0)\n\t\t\t{\n\t\t\t\tif(AllocBuffer(nLen))\n\t\t\t\t\tSecureHelper::memcpy_x(m_pchData, (nLen + 1) * sizeof(TCHAR), lpsz, nLen * sizeof(TCHAR));\n\t\t\t}\n\t\t}\n\t}\n\n#ifdef _UNICODE\n\tCString(LPCSTR lpsz)\n\t{\n\t\tInit();\n#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)\n\t\tint nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;\n#else\n\t\tint nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;\n#endif\n\t\tif (nSrcLen != 0)\n\t\t{\n\t\t\tif(AllocBuffer(nSrcLen))\n\t\t\t{\n\t\t\t\t_mbstowcsz(m_pchData, lpsz, nSrcLen + 1);\n\t\t\t\tReleaseBuffer();\n\t\t\t}\n\t\t}\n\t}\n#else // !_UNICODE\n\tCString(LPCWSTR lpsz)\n\t{\n\t\tInit();\n\t\tint nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;\n\t\tif (nSrcLen != 0)\n\t\t{\n\t\t\tif(AllocBuffer(nSrcLen * 2))\n\t\t\t{\n\t\t\t\t_wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);\n\t\t\t\tReleaseBuffer();\n\t\t\t}\n\t\t}\n\t}\n#endif // !_UNICODE\n\n\tCString(LPCTSTR lpch, int nLength)\n\t{\n\t\tInit();\n\t\tif (nLength != 0)\n\t\t{\n\t\t\tif(AllocBuffer(nLength))\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (nLength + 1) * sizeof(TCHAR), lpch, nLength * sizeof(TCHAR));\n\t\t}\n\t}\n\n#ifdef _UNICODE\n\tCString(LPCSTR lpsz, int nLength)\n\t{\n\t\tInit();\n\t\tif (nLength != 0)\n\t\t{\n\t\t\tif(AllocBuffer(nLength))\n\t\t\t{\n\t\t\t\tint n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength + 1);\n\t\t\t\tReleaseBuffer((n >= 0) ? n : -1);\n\t\t\t}\n\t\t}\n\t}\n#else // !_UNICODE\n\tCString(LPCWSTR lpsz, int nLength)\n\t{\n\t\tInit();\n\t\tif (nLength != 0)\n\t\t{\n\t\t\tif(((nLength * 2) > nLength) && AllocBuffer(nLength * 2))\n\t\t\t{\n\t\t\t\tint n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData, (nLength * 2) + 1, NULL, NULL);\n\t\t\t\tReleaseBuffer((n >= 0) ? n : -1);\n\t\t\t}\n\t\t}\n\t}\n#endif // !_UNICODE\n\n\tCString(const unsigned char* lpsz)\n\t{\n\t\tInit();\n\t\t*this = (LPCSTR)lpsz;\n\t}\n\n// Attributes & Operations\n\tint GetLength() const   // as an array of characters\n\t{\n\t\treturn GetData()->nDataLength;\n\t}\n\n\tBOOL IsEmpty() const\n\t{\n\t\treturn GetData()->nDataLength == 0;\n\t}\n\n\tvoid Empty()   // free up the data\n\t{\n\t\tif (GetData()->nDataLength == 0)\n\t\t\treturn;\n\n\t\tif (GetData()->nRefs >= 0)\n\t\t\tRelease();\n\t\telse\n\t\t\t*this = _T(\"\");\n\n\t\tATLASSERT(GetData()->nDataLength == 0);\n\t\tATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);\n\t}\n\n\tTCHAR GetAt(int nIndex) const   // 0 based\n\t{\n\t\tATLASSERT(nIndex >= 0);\n\t\tATLASSERT(nIndex < GetData()->nDataLength);\n\t\treturn m_pchData[nIndex];\n\t}\n\n\tTCHAR operator [](int nIndex) const   // same as GetAt\n\t{\n\t\t// same as GetAt\n\t\tATLASSERT(nIndex >= 0);\n\t\tATLASSERT(nIndex < GetData()->nDataLength);\n\t\treturn m_pchData[nIndex];\n\t}\n\n\tvoid SetAt(int nIndex, TCHAR ch)\n\t{\n\t\tATLASSERT(nIndex >= 0);\n\t\tATLASSERT(nIndex < GetData()->nDataLength);\n\n\t\tCopyBeforeWrite();\n\t\tm_pchData[nIndex] = ch;\n\t}\n\n\toperator LPCTSTR() const   // as a C string\n\t{\n\t\treturn m_pchData;\n\t}\n\n\t// overloaded assignment\n\tCString& operator =(const CString& stringSrc)\n\t{\n\t\tif (m_pchData != stringSrc.m_pchData)\n\t\t{\n\t\t\tif ((GetData()->nRefs < 0 && GetData() != _atltmpDataNil) || stringSrc.GetData()->nRefs < 0)\n\t\t\t{\n\t\t\t\t// actual copy necessary since one of the strings is locked\n\t\t\t\tAssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// can just copy references around\n\t\t\t\tRelease();\n\t\t\t\tATLASSERT(stringSrc.GetData() != _atltmpDataNil);\n\t\t\t\tm_pchData = stringSrc.m_pchData;\n\t\t\t\tInterlockedIncrement(&GetData()->nRefs);\n\t\t\t}\n\t\t}\n\t\treturn *this;\n\t}\n\n\tCString& operator =(TCHAR ch)\n\t{\n\t\tATLASSERT(!_istlead(ch));   // can't set single lead byte\n\t\tAssignCopy(1, &ch);\n\t\treturn *this;\n\t}\n\n#ifdef _UNICODE\n\tCString& operator =(char ch)\n\t{\n\t\t*this = (TCHAR)ch;\n\t\treturn *this;\n\t}\n#endif\n\n\tCString& operator =(LPCTSTR lpsz)\n\t{\n\t\tATLASSERT(lpsz == NULL || _IsValidString(lpsz));\n\t\tAssignCopy(SafeStrlen(lpsz), lpsz);\n\t\treturn *this;\n\t}\n\n#ifdef _UNICODE\n\tCString& operator =(LPCSTR lpsz)\n\t{\n#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)\n\t\tint nSrcLen = (lpsz != NULL) ? ATL::lstrlenA(lpsz) : 0;\n#else\n\t\tint nSrcLen = (lpsz != NULL) ? lstrlenA(lpsz) : 0;\n#endif\n\t\tif(AllocBeforeWrite(nSrcLen))\n\t\t{\n\t\t\t_mbstowcsz(m_pchData, lpsz, nSrcLen + 1);\n\t\t\tReleaseBuffer();\n\t\t}\n\t\treturn *this;\n\t}\n#else // !_UNICODE\n\tCString& operator =(LPCWSTR lpsz)\n\t{\n\t\tint nSrcLen = (lpsz != NULL) ? (int)wcslen(lpsz) : 0;\n\t\tif(AllocBeforeWrite(nSrcLen * 2))\n\t\t{\n\t\t\t_wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1);\n\t\t\tReleaseBuffer();\n\t\t}\n\t\treturn *this;\n\t}\n#endif  // !_UNICODE\n\n\tCString& operator =(const unsigned char* lpsz)\n\t{\n\t\t*this = (LPCSTR)lpsz;\n\t\treturn *this;\n\t}\n\n\t// string concatenation\n\tCString& operator +=(const CString& string)\n\t{\n\t\tConcatInPlace(string.GetData()->nDataLength, string.m_pchData);\n\t\treturn *this;\n\t}\n\n\tCString& operator +=(TCHAR ch)\n\t{\n\t\tConcatInPlace(1, &ch);\n\t\treturn *this;\n\t}\n\n#ifdef _UNICODE\n\tCString& operator +=(char ch)\n\t{\n\t\t*this += (TCHAR)ch;\n\t\treturn *this;\n\t}\n#endif\n\n\tCString& operator +=(LPCTSTR lpsz)\n\t{\n\t\tATLASSERT(lpsz == NULL || _IsValidString(lpsz));\n\t\tConcatInPlace(SafeStrlen(lpsz), lpsz);\n\t\treturn *this;\n\t}\n\n\tfriend CString __stdcall operator +(const CString& string1, const CString& string2);\n\tfriend CString __stdcall operator +(const CString& string, TCHAR ch);\n\tfriend CString __stdcall operator +(TCHAR ch, const CString& string);\n#ifdef _UNICODE\n\tfriend CString __stdcall operator +(const CString& string, char ch);\n\tfriend CString __stdcall operator +(char ch, const CString& string);\n#endif\n\tfriend CString __stdcall operator +(const CString& string, LPCTSTR lpsz);\n\tfriend CString __stdcall operator +(LPCTSTR lpsz, const CString& string);\n\n\t// string comparison\n\tint Compare(LPCTSTR lpsz) const   // straight character (MBCS/Unicode aware)\n\t{\n\t\treturn _cstrcmp(m_pchData, lpsz);\n\t}\n\n\tint CompareNoCase(LPCTSTR lpsz) const   // ignore case (MBCS/Unicode aware)\n\t{\n\t\treturn _cstrcmpi(m_pchData, lpsz);\n\t}\n\n#ifndef _WIN32_WCE\n\t// CString::Collate is often slower than Compare but is MBSC/Unicode\n\t//  aware as well as locale-sensitive with respect to sort order.\n\tint Collate(LPCTSTR lpsz) const   // NLS aware\n\t{\n\t\treturn _cstrcoll(m_pchData, lpsz);\n\t}\n\n\tint CollateNoCase(LPCTSTR lpsz) const   // ignore case\n\t{\n\t\treturn _cstrcolli(m_pchData, lpsz);\n\t}\n#endif // !_WIN32_WCE\n\n\t// simple sub-string extraction\n\tCString Mid(int nFirst, int nCount) const\n\t{\n\t\t// out-of-bounds requests return sensible things\n\t\tif (nFirst < 0)\n\t\t\tnFirst = 0;\n\t\tif (nCount < 0)\n\t\t\tnCount = 0;\n\n\t\tif (nFirst + nCount > GetData()->nDataLength)\n\t\t\tnCount = GetData()->nDataLength - nFirst;\n\t\tif (nFirst > GetData()->nDataLength)\n\t\t\tnCount = 0;\n\n\t\tCString dest;\n\t\tAllocCopy(dest, nCount, nFirst, 0);\n\t\treturn dest;\n\t}\n\n\tCString Mid(int nFirst) const\n\t{\n\t\treturn Mid(nFirst, GetData()->nDataLength - nFirst);\n\t}\n\n\tCString Left(int nCount) const\n\t{\n\t\tif (nCount < 0)\n\t\t\tnCount = 0;\n\t\telse if (nCount > GetData()->nDataLength)\n\t\t\tnCount = GetData()->nDataLength;\n\n\t\tCString dest;\n\t\tAllocCopy(dest, nCount, 0, 0);\n\t\treturn dest;\n\t}\n\n\tCString Right(int nCount) const\n\t{\n\t\tif (nCount < 0)\n\t\t\tnCount = 0;\n\t\telse if (nCount > GetData()->nDataLength)\n\t\t\tnCount = GetData()->nDataLength;\n\n\t\tCString dest;\n\t\tAllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);\n\t\treturn dest;\n\t}\n\n\tCString SpanIncluding(LPCTSTR lpszCharSet) const   // strspn equivalent\n\t{\n\t\tATLASSERT(_IsValidString(lpszCharSet));\n\t\treturn Left(_cstrspn(m_pchData, lpszCharSet));\n\t}\n\n\tCString SpanExcluding(LPCTSTR lpszCharSet) const   // strcspn equivalent\n\t{\n\t\tATLASSERT(_IsValidString(lpszCharSet));\n\t\treturn Left(_cstrcspn(m_pchData, lpszCharSet));\n\t}\n\n\t// upper/lower/reverse conversion\n\tvoid MakeUpper()\n\t{\n\t\tCopyBeforeWrite();\n\t\tCharUpper(m_pchData);\n\t}\n\n\tvoid MakeLower()\n\t{\n\t\tCopyBeforeWrite();\n\t\tCharLower(m_pchData);\n\t}\n\n\tvoid MakeReverse()\n\t{\n\t\tCopyBeforeWrite();\n\t\t_cstrrev(m_pchData);\n\t}\n\n\t// trimming whitespace (either side)\n\tvoid TrimRight()\n\t{\n\t\tCopyBeforeWrite();\n\n\t\t// find beginning of trailing spaces by starting at beginning (DBCS aware)\n\t\tLPTSTR lpsz = m_pchData;\n\t\tLPTSTR lpszLast = NULL;\n\t\twhile (*lpsz != _T('\\0'))\n\t\t{\n\t\t\tif (_cstrisspace(*lpsz))\n\t\t\t{\n\t\t\t\tif (lpszLast == NULL)\n\t\t\t\t\tlpszLast = lpsz;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlpszLast = NULL;\n\t\t\t}\n\t\t\tlpsz = ::CharNext(lpsz);\n\t\t}\n\n\t\tif (lpszLast != NULL)\n\t\t{\n\t\t\t// truncate at trailing space start\n\t\t\t*lpszLast = _T('\\0');\n\t\t\tGetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);\n\t\t}\n\t}\n\n\tvoid TrimLeft()\n\t{\n\t\tCopyBeforeWrite();\n\n\t\t// find first non-space character\n\t\tLPCTSTR lpsz = m_pchData;\n\t\twhile (_cstrisspace(*lpsz))\n\t\t\tlpsz = ::CharNext(lpsz);\n\n\t\t// fix up data and length\n\t\tint nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);\n\t\tSecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));\n\t\tGetData()->nDataLength = nDataLength;\n\t}\n\n\t// remove continuous occurrences of chTarget starting from right\n\tvoid TrimRight(TCHAR chTarget)\n\t{\n\t\t// find beginning of trailing matches\n\t\t// by starting at beginning (DBCS aware)\n\n\t\tCopyBeforeWrite();\n\t\tLPTSTR lpsz = m_pchData;\n\t\tLPTSTR lpszLast = NULL;\n\n\t\twhile (*lpsz != _T('\\0'))\n\t\t{\n\t\t\tif (*lpsz == chTarget)\n\t\t\t{\n\t\t\t\tif (lpszLast == NULL)\n\t\t\t\t\tlpszLast = lpsz;\n\t\t\t}\n\t\t\telse\n\t\t\t\tlpszLast = NULL;\n\t\t\tlpsz = ::CharNext(lpsz);\n\t\t}\n\n\t\tif (lpszLast != NULL)\n\t\t{\n\t\t\t// truncate at left-most matching character\n\t\t\t*lpszLast = _T('\\0');\n\t\t\tGetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);\n\t\t}\n\t}\n\n\t// remove continuous occcurrences of characters in passed string, starting from right\n\tvoid TrimRight(LPCTSTR lpszTargetList)\n\t{\n\t\t// find beginning of trailing matches by starting at beginning (DBCS aware)\n\n\t\tCopyBeforeWrite();\n\t\tLPTSTR lpsz = m_pchData;\n\t\tLPTSTR lpszLast = NULL;\n\n\t\twhile (*lpsz != _T('\\0'))\n\t\t{\n\t\t\tTCHAR* pNext = ::CharNext(lpsz);\n\t\t\tif(pNext > lpsz + 1)\n\t\t\t{\n\t\t\t\tif (_cstrchr_db(lpszTargetList, *lpsz, *(lpsz + 1)) != NULL)\n\t\t\t\t{\n\t\t\t\t\tif (lpszLast == NULL)\n\t\t\t\t\t\tlpszLast = lpsz;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlpszLast = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (_cstrchr(lpszTargetList, *lpsz) != NULL)\n\t\t\t\t{\n\t\t\t\t\tif (lpszLast == NULL)\n\t\t\t\t\t\tlpszLast = lpsz;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlpszLast = NULL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlpsz = pNext;\n\t\t}\n\n\t\tif (lpszLast != NULL)\n\t\t{\n\t\t\t// truncate at left-most matching character\n\t\t\t*lpszLast = _T('\\0');\n\t\t\tGetData()->nDataLength = (int)(DWORD_PTR)(lpszLast - m_pchData);\n\t\t}\n\t}\n\n\t// remove continuous occurrences of chTarget starting from left\n\tvoid TrimLeft(TCHAR chTarget)\n\t{\n\t\t// find first non-matching character\n\n\t\tCopyBeforeWrite();\n\t\tLPCTSTR lpsz = m_pchData;\n\n\t\twhile (chTarget == *lpsz)\n\t\t\tlpsz = ::CharNext(lpsz);\n\n\t\tif (lpsz != m_pchData)\n\t\t{\n\t\t\t// fix up data and length\n\t\t\tint nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);\n\t\t\tSecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength = nDataLength;\n\t\t}\n\t}\n\n\t// remove continuous occcurrences of characters in passed string, starting from left\n\tvoid TrimLeft(LPCTSTR lpszTargets)\n\t{\n\t\t// if we're not trimming anything, we're not doing any work\n\t\tif (SafeStrlen(lpszTargets) == 0)\n\t\t\treturn;\n\n\t\tCopyBeforeWrite();\n\t\tLPCTSTR lpsz = m_pchData;\n\n\t\twhile (*lpsz != _T('\\0'))\n\t\t{\n\t\t\tTCHAR* pNext = ::CharNext(lpsz);\n\t\t\tif(pNext > lpsz + 1)\n\t\t\t{\n\t\t\t\tif (_cstrchr_db(lpszTargets, *lpsz, *(lpsz + 1)) == NULL)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (_cstrchr(lpszTargets, *lpsz) == NULL)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlpsz = pNext;\n\t\t}\n\n\t\tif (lpsz != m_pchData)\n\t\t{\n\t\t\t// fix up data and length\n\t\t\tint nDataLength = GetData()->nDataLength - (int)(DWORD_PTR)(lpsz - m_pchData);\n\t\t\tSecureHelper::memmove_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpsz, (nDataLength + 1) * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength = nDataLength;\n\t\t}\n\t}\n\n\t// advanced manipulation\n\t// replace occurrences of chOld with chNew\n\tint Replace(TCHAR chOld, TCHAR chNew)\n\t{\n\t\tint nCount = 0;\n\n\t\t// short-circuit the nop case\n\t\tif (chOld != chNew)\n\t\t{\n\t\t\t// otherwise modify each character that matches in the string\n\t\t\tCopyBeforeWrite();\n\t\t\tLPTSTR psz = m_pchData;\n\t\t\tLPTSTR pszEnd = psz + GetData()->nDataLength;\n\t\t\twhile (psz < pszEnd)\n\t\t\t{\n\t\t\t\t// replace instances of the specified character only\n\t\t\t\tif (*psz == chOld)\n\t\t\t\t{\n\t\t\t\t\t*psz = chNew;\n\t\t\t\t\tnCount++;\n\t\t\t\t}\n\t\t\t\tpsz = ::CharNext(psz);\n\t\t\t}\n\t\t}\n\t\treturn nCount;\n\t}\n\n\t// replace occurrences of substring lpszOld with lpszNew;\n\t// empty lpszNew removes instances of lpszOld\n\tint Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)\n\t{\n\t\t// can't have empty or NULL lpszOld\n\n\t\tint nSourceLen = SafeStrlen(lpszOld);\n\t\tif (nSourceLen == 0)\n\t\t\treturn 0;\n\t\tint nReplacementLen = SafeStrlen(lpszNew);\n\n\t\t// loop once to figure out the size of the result string\n\t\tint nCount = 0;\n\t\tLPTSTR lpszStart = m_pchData;\n\t\tLPTSTR lpszEnd = m_pchData + GetData()->nDataLength;\n\t\tLPTSTR lpszTarget = NULL;\n\t\twhile (lpszStart < lpszEnd)\n\t\t{\n\t\t\twhile ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)\n\t\t\t{\n\t\t\t\tnCount++;\n\t\t\t\tlpszStart = lpszTarget + nSourceLen;\n\t\t\t}\n\t\t\tlpszStart += lstrlen(lpszStart) + 1;\n\t\t}\n\n\t\t// if any changes were made, make them\n\t\tif (nCount > 0)\n\t\t{\n\t\t\tCopyBeforeWrite();\n\n\t\t\t// if the buffer is too small, just allocate a new buffer (slow but sure)\n\t\t\tint nOldLength = GetData()->nDataLength;\n\t\t\tint nNewLength =  nOldLength + (nReplacementLen - nSourceLen) * nCount;\n\t\t\tif (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)\n\t\t\t{\n\t\t\t\tCStringData* pOldData = GetData();\n\t\t\t\tLPTSTR pstr = m_pchData;\n\t\t\t\tif(!AllocBuffer(nNewLength))\n\t\t\t\t\treturn -1;\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, pOldData->nDataLength * sizeof(TCHAR));\n\t\t\t\tCString::Release(pOldData);\n\t\t\t}\n\t\t\t// else, we just do it in-place\n\t\t\tlpszStart = m_pchData;\n\t\t\tlpszEnd = m_pchData + GetData()->nDataLength;\n\n\t\t\t// loop again to actually do the work\n\t\t\twhile (lpszStart < lpszEnd)\n\t\t\t{\n\t\t\t\twhile ((lpszTarget = (TCHAR*)_cstrstr(lpszStart, lpszOld)) != NULL)\n\t\t\t\t{\n\t\t\t\t\tint nBalance = nOldLength - ((int)(DWORD_PTR)(lpszTarget - m_pchData) + nSourceLen);\n\t\t\t\t\tint cchBuffLen = GetData()->nAllocLength - (int)(DWORD_PTR)(lpszTarget - m_pchData);\n\t\t\t\t\tSecureHelper::memmove_x(lpszTarget + nReplacementLen, (cchBuffLen - nReplacementLen + 1) * sizeof(TCHAR), lpszTarget + nSourceLen, nBalance * sizeof(TCHAR));\n\t\t\t\t\tSecureHelper::memcpy_x(lpszTarget, (cchBuffLen + 1) * sizeof(TCHAR), lpszNew, nReplacementLen * sizeof(TCHAR));\n\t\t\t\t\tlpszStart = lpszTarget + nReplacementLen;\n\t\t\t\t\tlpszStart[nBalance] = _T('\\0');\n\t\t\t\t\tnOldLength += (nReplacementLen - nSourceLen);\n\t\t\t\t}\n\t\t\t\tlpszStart += lstrlen(lpszStart) + 1;\n\t\t\t}\n\t\t\tATLASSERT(m_pchData[nNewLength] == _T('\\0'));\n\t\t\tGetData()->nDataLength = nNewLength;\n\t\t}\n\n\t\treturn nCount;\n\t}\n\n\t// remove occurrences of chRemove\n\tint Remove(TCHAR chRemove)\n\t{\n\t\tCopyBeforeWrite();\n\n\t\tLPTSTR pstrSource = m_pchData;\n\t\tLPTSTR pstrDest = m_pchData;\n\t\tLPTSTR pstrEnd = m_pchData + GetData()->nDataLength;\n\n\t\twhile (pstrSource < pstrEnd)\n\t\t{\n\t\t\tif (*pstrSource != chRemove)\n\t\t\t{\n\t\t\t\t*pstrDest = *pstrSource;\n\t\t\t\tpstrDest = ::CharNext(pstrDest);\n\t\t\t}\n\t\t\tpstrSource = ::CharNext(pstrSource);\n\t\t}\n\t\t*pstrDest = _T('\\0');\n\t\tint nCount = (int)(DWORD_PTR)(pstrSource - pstrDest);\n\t\tGetData()->nDataLength -= nCount;\n\n\t\treturn nCount;\n\t}\n\n\t// insert character at zero-based index; concatenates if index is past end of string\n\tint Insert(int nIndex, TCHAR ch)\n\t{\n\t\tCopyBeforeWrite();\n\n\t\tif (nIndex < 0)\n\t\t\tnIndex = 0;\n\n\t\tint nNewLength = GetData()->nDataLength;\n\t\tif (nIndex > nNewLength)\n\t\t\tnIndex = nNewLength;\n\t\tnNewLength++;\n\n\t\tif (GetData()->nAllocLength < nNewLength)\n\t\t{\n\t\t\tCStringData* pOldData = GetData();\n\t\t\tLPTSTR pstr = m_pchData;\n\t\t\tif(!AllocBuffer(nNewLength))\n\t\t\t\treturn -1;\n\t\t\tSecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstr, (pOldData->nDataLength + 1) * sizeof(TCHAR));\n\t\t\tCString::Release(pOldData);\n\t\t}\n\n\t\t// move existing bytes down\n\t\tSecureHelper::memmove_x(m_pchData + nIndex + 1, (GetData()->nAllocLength - nIndex) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex) * sizeof(TCHAR));\n\t\tm_pchData[nIndex] = ch;\n\t\tGetData()->nDataLength = nNewLength;\n\n\t\treturn nNewLength;\n\t}\n\n\t// insert substring at zero-based index; concatenates if index is past end of string\n\tint Insert(int nIndex, LPCTSTR pstr)\n\t{\n\t\tif (nIndex < 0)\n\t\t\tnIndex = 0;\n\n\t\tint nInsertLength = SafeStrlen(pstr);\n\t\tint nNewLength = GetData()->nDataLength;\n\t\tif (nInsertLength > 0)\n\t\t{\n\t\t\tCopyBeforeWrite();\n\t\t\tif (nIndex > nNewLength)\n\t\t\t\tnIndex = nNewLength;\n\t\t\tnNewLength += nInsertLength;\n\n\t\t\tif (GetData()->nAllocLength < nNewLength)\n\t\t\t{\n\t\t\t\tCStringData* pOldData = GetData();\n\t\t\t\tLPTSTR pstrTmp = m_pchData;\n\t\t\t\tif(!AllocBuffer(nNewLength))\n\t\t\t\t\treturn -1;\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (nNewLength + 1) * sizeof(TCHAR), pstrTmp, (pOldData->nDataLength + 1) * sizeof(TCHAR));\n\t\t\t\tCString::Release(pOldData);\n\t\t\t}\n\n\t\t\t// move existing bytes down\n\t\t\tSecureHelper::memmove_x(m_pchData + nIndex + nInsertLength, (GetData()->nAllocLength + 1 - nIndex - nInsertLength) * sizeof(TCHAR), m_pchData + nIndex, (nNewLength - nIndex - nInsertLength + 1) * sizeof(TCHAR));\n\t\t\tSecureHelper::memcpy_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), pstr, nInsertLength * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength = nNewLength;\n\t\t}\n\n\t\treturn nNewLength;\n\t}\n\n\t// delete nCount characters starting at zero-based index\n\tint Delete(int nIndex, int nCount = 1)\n\t{\n\t\tif (nIndex < 0)\n\t\t\tnIndex = 0;\n\t\tint nLength = GetData()->nDataLength;\n\t\tif (nCount > 0 && nIndex < nLength)\n\t\t{\n\t\t\tif((nIndex + nCount) > nLength)\n\t\t\t\tnCount = nLength - nIndex;\n\t\t\tCopyBeforeWrite();\n\t\t\tint nBytesToCopy = nLength - (nIndex + nCount) + 1;\n\n\t\t\tSecureHelper::memmove_x(m_pchData + nIndex, (GetData()->nAllocLength + 1 - nIndex) * sizeof(TCHAR), m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));\n\t\t\tnLength -= nCount;\n\t\t\tGetData()->nDataLength = nLength;\n\t\t}\n\n\t\treturn nLength;\n\t}\n\n\t// searching (return starting index, or -1 if not found)\n\t// look for a single character match\n\tint Find(TCHAR ch) const   // like \"C\" strchr\n\t{\n\t\treturn Find(ch, 0);\n\t}\n\n\tint ReverseFind(TCHAR ch) const\n\t{\n\t\t// find last single character\n\t\tLPCTSTR lpsz = _cstrrchr(m_pchData, (_TUCHAR)ch);\n\n\t\t// return -1 if not found, distance from beginning otherwise\n\t\treturn (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);\n\t}\n\n\tint Find(TCHAR ch, int nStart) const   // starting at index\n\t{\n\t\tint nLength = GetData()->nDataLength;\n\t\tif (nStart < 0 || nStart >= nLength)\n\t\t\treturn -1;\n\n\t\t// find first single character\n\t\tLPCTSTR lpsz = _cstrchr(m_pchData + nStart, (_TUCHAR)ch);\n\n\t\t// return -1 if not found and index otherwise\n\t\treturn (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);\n\t}\n\n\tint FindOneOf(LPCTSTR lpszCharSet) const\n\t{\n\t\tATLASSERT(_IsValidString(lpszCharSet));\n\t\tLPCTSTR lpsz = _cstrpbrk(m_pchData, lpszCharSet);\n\t\treturn (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);\n\t}\n\n\t// look for a specific sub-string\n\t// find a sub-string (like strstr)\n\tint Find(LPCTSTR lpszSub) const   // like \"C\" strstr\n\t{\n\t\treturn Find(lpszSub, 0);\n\t}\n\n\tint Find(LPCTSTR lpszSub, int nStart) const   // starting at index\n\t{\n\t\tATLASSERT(_IsValidString(lpszSub));\n\n\t\tint nLength = GetData()->nDataLength;\n\t\tif (nStart < 0 || nStart > nLength)\n\t\t\treturn -1;\n\n\t\t// find first matching substring\n\t\tLPCTSTR lpsz = _cstrstr(m_pchData + nStart, lpszSub);\n\n\t\t// return -1 for not found, distance from beginning otherwise\n\t\treturn (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);\n\t}\n\n\t// Concatentation for non strings\n\tCString& Append(int n)\n\t{\n\t\tconst int cchBuff = 12;\n\t\tTCHAR szBuffer[cchBuff] = { 0 };\n\t\tSecureHelper::wsprintf_x(szBuffer, cchBuff, _T(\"%d\"), n);\n\t\tConcatInPlace(SafeStrlen(szBuffer), szBuffer);\n\t\treturn *this;\n\t}\n\n\t// simple formatting\n\t// formatting (using wsprintf style formatting)\n\tBOOL __cdecl Format(LPCTSTR lpszFormat, ...)\n\t{\n\t\tATLASSERT(_IsValidString(lpszFormat));\n\n\t\tva_list argList;\n\t\tva_start(argList, lpszFormat);\n\t\tBOOL bRet = FormatV(lpszFormat, argList);\n\t\tva_end(argList);\n\t\treturn bRet;\n\t}\n\n\tBOOL __cdecl Format(UINT nFormatID, ...)\n\t{\n\t\tCString strFormat;\n\t\tBOOL bRet = strFormat.LoadString(nFormatID);\n\t\tATLASSERT(bRet != 0);\n\n\t\tva_list argList;\n\t\tva_start(argList, nFormatID);\n\t\tbRet = FormatV(strFormat, argList);\n\t\tva_end(argList);\n\t\treturn bRet;\n\t}\n\n\tBOOL FormatV(LPCTSTR lpszFormat, va_list argList)\n\t{\n\t\tATLASSERT(_IsValidString(lpszFormat));\n\n\t\tenum _FormatModifiers\n\t\t{\n\t\t\tFORCE_ANSI =\t0x10000,\n\t\t\tFORCE_UNICODE =\t0x20000,\n\t\t\tFORCE_INT64 =\t0x40000\n\t\t};\n\n\t\tva_list argListSave = argList;\n\n\t\t// make a guess at the maximum length of the resulting string\n\t\tint nMaxLen = 0;\n\t\tfor (LPCTSTR lpsz = lpszFormat; *lpsz != _T('\\0'); lpsz = ::CharNext(lpsz))\n\t\t{\n\t\t\t// handle '%' character, but watch out for '%%'\n\t\t\tif (*lpsz != _T('%') || *(lpsz = ::CharNext(lpsz)) == _T('%'))\n\t\t\t{\n\t\t\t\tnMaxLen += (int)(::CharNext(lpsz) - lpsz);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tint nItemLen = 0;\n\n\t\t\t// handle '%' character with format\n\t\t\tint nWidth = 0;\n\t\t\tfor (; *lpsz != _T('\\0'); lpsz = ::CharNext(lpsz))\n\t\t\t{\n\t\t\t\t// check for valid flags\n\t\t\t\tif (*lpsz == _T('#'))\n\t\t\t\t\tnMaxLen += 2;   // for '0x'\n\t\t\t\telse if (*lpsz == _T('*'))\n\t\t\t\t\tnWidth = va_arg(argList, int);\n\t\t\t\telse if (*lpsz == _T('-') || *lpsz == _T('+') || *lpsz == _T('0') || *lpsz == _T(' '))\n\t\t\t\t\t;\n\t\t\t\telse // hit non-flag character\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// get width and skip it\n\t\t\tif (nWidth == 0)\n\t\t\t{\n\t\t\t\t// width indicated by\n\t\t\t\tnWidth = _cstrtoi(lpsz);\n\t\t\t\tfor (; *lpsz != _T('\\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))\n\t\t\t\t\t;\n\t\t\t}\n\t\t\tATLASSERT(nWidth >= 0);\n\n\t\t\tint nPrecision = 0;\n\t\t\tif (*lpsz == _T('.'))\n\t\t\t{\n\t\t\t\t// skip past '.' separator (width.precision)\n\t\t\t\tlpsz = ::CharNext(lpsz);\n\n\t\t\t\t// get precision and skip it\n\t\t\t\tif (*lpsz == _T('*'))\n\t\t\t\t{\n\t\t\t\t\tnPrecision = va_arg(argList, int);\n\t\t\t\t\tlpsz = ::CharNext(lpsz);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnPrecision = _cstrtoi(lpsz);\n\t\t\t\t\tfor (; *lpsz != _T('\\0') && _cstrisdigit(*lpsz); lpsz = ::CharNext(lpsz))\n\t\t\t\t\t\t;\n\t\t\t\t}\n\t\t\t\tATLASSERT(nPrecision >= 0);\n\t\t\t}\n\n\t\t\t// should be on type modifier or specifier\n\t\t\tint nModifier = 0;\n\t\t\tif(lpsz[0] == _T('I'))\n\t\t\t{\n\t\t\t\tif((lpsz[1] == _T('6')) && (lpsz[2] == _T('4')))\n\t\t\t\t{\n\t\t\t\t\tlpsz += 3;\n\t\t\t\t\tnModifier = FORCE_INT64;\n\t\t\t\t}\n\t\t\t\telse if((lpsz[1] == _T('3')) && (lpsz[2] == _T('2')))\n\t\t\t\t{\n\t\t\t\t\tlpsz += 3;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlpsz++;\n\t\t\t\t\tif(sizeof(size_t) == 8)\n\t\t\t\t\t\tnModifier = FORCE_INT64;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (*lpsz)\n\t\t\t\t{\n\t\t\t\t// modifiers that affect size\n\t\t\t\tcase _T('h'):\n\t\t\t\t\tnModifier = FORCE_ANSI;\n\t\t\t\t\tlpsz = ::CharNext(lpsz);\n\t\t\t\t\tbreak;\n\t\t\t\tcase _T('l'):\n\t\t\t\t\tnModifier = FORCE_UNICODE;\n\t\t\t\t\tlpsz = ::CharNext(lpsz);\n\t\t\t\t\tbreak;\n\n\t\t\t\t// modifiers that do not affect size\n\t\t\t\tcase _T('F'):\n\t\t\t\tcase _T('N'):\n\t\t\t\tcase _T('L'):\n\t\t\t\t\tlpsz = ::CharNext(lpsz);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// now should be on specifier\n\t\t\tswitch (*lpsz | nModifier)\n\t\t\t{\n\t\t\t// single characters\n\t\t\tcase _T('c'):\n\t\t\tcase _T('C'):\n\t\t\t\tnItemLen = 2;\n\t\t\t\tva_arg(argList, TCHAR);\n\t\t\t\tbreak;\n\t\t\tcase _T('c') | FORCE_ANSI:\n\t\t\tcase _T('C') | FORCE_ANSI:\n\t\t\t\tnItemLen = 2;\n\t\t\t\tva_arg(argList, char);\n\t\t\t\tbreak;\n\t\t\tcase _T('c') | FORCE_UNICODE:\n\t\t\tcase _T('C') | FORCE_UNICODE:\n\t\t\t\tnItemLen = 2;\n\t\t\t\tva_arg(argList, WCHAR);\n\t\t\t\tbreak;\n\n\t\t\t// strings\n\t\t\tcase _T('s'):\n\t\t\t{\n\t\t\t\tLPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);\n\t\t\t\tif (pstrNextArg == NULL)\n\t\t\t\t{\n\t\t\t\t\tnItemLen = 6;  // \"(null)\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnItemLen = lstrlen(pstrNextArg);\n\t\t\t\t\tnItemLen = __max(1, nItemLen);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase _T('S'):\n\t\t\t{\n#ifndef _UNICODE\n\t\t\t\tLPWSTR pstrNextArg = va_arg(argList, LPWSTR);\n\t\t\t\tif (pstrNextArg == NULL)\n\t\t\t\t{\n\t\t\t\t\tnItemLen = 6;  // \"(null)\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnItemLen = (int)wcslen(pstrNextArg);\n\t\t\t\t\tnItemLen = __max(1, nItemLen);\n\t\t\t\t}\n#else // _UNICODE\n\t\t\t\tLPCSTR pstrNextArg = va_arg(argList, LPCSTR);\n\t\t\t\tif (pstrNextArg == NULL)\n\t\t\t\t{\n\t\t\t\t\tnItemLen = 6; // \"(null)\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)\n\t\t\t\t\tnItemLen = ATL::lstrlenA(pstrNextArg);\n#else\n\t\t\t\t\tnItemLen = lstrlenA(pstrNextArg);\n#endif\n\t\t\t\t\tnItemLen = __max(1, nItemLen);\n\t\t\t\t}\n#endif // _UNICODE\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase _T('s') | FORCE_ANSI:\n\t\t\tcase _T('S') | FORCE_ANSI:\n\t\t\t{\n\t\t\t\tLPCSTR pstrNextArg = va_arg(argList, LPCSTR);\n\t\t\t\tif (pstrNextArg == NULL)\n\t\t\t\t{\n\t\t\t\t\tnItemLen = 6; // \"(null)\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n#if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)\n\t\t\t\t\tnItemLen = ATL::lstrlenA(pstrNextArg);\n#else\n\t\t\t\t\tnItemLen = lstrlenA(pstrNextArg);\n#endif\n\t\t\t\t\tnItemLen = __max(1, nItemLen);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase _T('s') | FORCE_UNICODE:\n\t\t\tcase _T('S') | FORCE_UNICODE:\n\t\t\t{\n\t\t\t\tLPWSTR pstrNextArg = va_arg(argList, LPWSTR);\n\t\t\t\tif (pstrNextArg == NULL)\n\t\t\t\t{\n\t\t\t\t\tnItemLen = 6; // \"(null)\"\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnItemLen = (int)wcslen(pstrNextArg);\n\t\t\t\t\tnItemLen = __max(1, nItemLen);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\n\t\t\t// adjust nItemLen for strings\n\t\t\tif (nItemLen != 0)\n\t\t\t{\n\t\t\t\tnItemLen = __max(nItemLen, nWidth);\n\t\t\t\tif (nPrecision != 0)\n\t\t\t\t\tnItemLen = __min(nItemLen, nPrecision);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (*lpsz)\n\t\t\t\t{\n\t\t\t\t// integers\n\t\t\t\tcase _T('d'):\n\t\t\t\tcase _T('i'):\n\t\t\t\tcase _T('u'):\n\t\t\t\tcase _T('x'):\n\t\t\t\tcase _T('X'):\n\t\t\t\tcase _T('o'):\n\t\t\t\t\tif (nModifier & FORCE_INT64)\n\t\t\t\t\t\tva_arg(argList, __int64);\n\t\t\t\t\telse\n\t\t\t\t\t\tva_arg(argList, int);\n\t\t\t\t\tnItemLen = 32;\n\t\t\t\t\tnItemLen = __max(nItemLen, nWidth + nPrecision);\n\t\t\t\t\tbreak;\n\n#ifndef _ATL_USE_CSTRING_FLOAT\n\t\t\t\tcase _T('e'):\n\t\t\t\tcase _T('E'):\n\t\t\t\tcase _T('f'):\n\t\t\t\tcase _T('g'):\n\t\t\t\tcase _T('G'):\n\t\t\t\t\tATLASSERT(!\"Floating point (%%e, %%E, %%f, %%g, and %%G) is not supported by the WTL::CString class.\");\n#ifndef _DEBUG\n\t\t\t\t\t::OutputDebugString(_T(\"Floating point (%%e, %%f, %%g, and %%G) is not supported by the WTL::CString class.\"));\n#ifndef _WIN32_WCE\n\t\t\t\t\t::DebugBreak();\n#else // CE specific\n\t\t\t\t\tDebugBreak();\n#endif // _WIN32_WCE\n#endif // !_DEBUG\n\t\t\t\t\tbreak;\n#else // _ATL_USE_CSTRING_FLOAT\n\t\t\t\tcase _T('e'):\n\t\t\t\tcase _T('E'):\n\t\t\t\tcase _T('g'):\n\t\t\t\tcase _T('G'):\n\t\t\t\t\tva_arg(argList, double);\n\t\t\t\t\tnItemLen = 128;\n\t\t\t\t\tnItemLen = __max(nItemLen, nWidth + nPrecision);\n\t\t\t\t\tbreak;\n\t\t\t\tcase _T('f'):\n\t\t\t\t\t{\n\t\t\t\t\t\tdouble f = va_arg(argList, double);\n\t\t\t\t\t\t// 312 == strlen(\"-1+(309 zeroes).\")\n\t\t\t\t\t\t// 309 zeroes == max precision of a double\n\t\t\t\t\t\t// 6 == adjustment in case precision is not specified,\n\t\t\t\t\t\t//   which means that the precision defaults to 6\n\t\t\t\t\t\tint cchLen = __max(nWidth, 312 + nPrecision + 6);\n\t\t\t\t\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\t\t\t\t\tLPTSTR pszTemp = buff.Allocate(cchLen);\n\t\t\t\t\t\tif(pszTemp != NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSecureHelper::sprintf_x(pszTemp, cchLen, _T(\"%*.*f\"), nWidth, nPrecision + 6, f);\n\t\t\t\t\t\t\tnItemLen = (int)_tcslen(pszTemp);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnItemLen = cchLen;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n#endif // _ATL_USE_CSTRING_FLOAT\n\n\t\t\t\tcase _T('p'):\n\t\t\t\t\tva_arg(argList, void*);\n\t\t\t\t\tnItemLen = 32;\n\t\t\t\t\tnItemLen = __max(nItemLen, nWidth + nPrecision);\n\t\t\t\t\tbreak;\n\n\t\t\t\t// no output\n\t\t\t\tcase _T('n'):\n\t\t\t\t\tva_arg(argList, int*);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tATLASSERT(FALSE);  // unknown formatting option\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// adjust nMaxLen for output nItemLen\n\t\t\tnMaxLen += nItemLen;\n\t\t}\n\n\t\tif(GetBuffer(nMaxLen) == NULL)\n\t\t\treturn FALSE;\n#ifndef _ATL_USE_CSTRING_FLOAT\n\t\tint nRet = SecureHelper::wvsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);\n#else // _ATL_USE_CSTRING_FLOAT\n\t\tint nRet = SecureHelper::vsprintf_x(m_pchData, GetAllocLength() + 1, lpszFormat, argListSave);\n#endif // _ATL_USE_CSTRING_FLOAT\n\t\tnRet;   // ref\n\t\tATLASSERT(nRet <= GetAllocLength());\n\t\tReleaseBuffer();\n\n\t\tva_end(argListSave);\n\t\treturn TRUE;\n\t}\n\n\t// formatting for localization (uses FormatMessage API)\n\t// formatting (using FormatMessage style formatting)\n\tBOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...)\n\t{\n\t\t// format message into temporary buffer lpszTemp\n\t\tva_list argList;\n\t\tva_start(argList, lpszFormat);\n\t\tLPTSTR lpszTemp = NULL;\n\t\tBOOL bRet = TRUE;\n\n\t\tif ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n\t\t\t\tlpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL))\n\t\t\tbRet = FALSE;\n\n\t\t// assign lpszTemp into the resulting string and free the temporary\n\t\t*this = lpszTemp;\n\t\tLocalFree(lpszTemp);\n\t\tva_end(argList);\n\t\treturn bRet;\n\t}\n\n\tBOOL __cdecl FormatMessage(UINT nFormatID, ...)\n\t{\n\t\t// get format string from string table\n\t\tCString strFormat;\n\t\tBOOL bRetTmp = strFormat.LoadString(nFormatID);\n\t\tbRetTmp;   // ref\n\t\tATLASSERT(bRetTmp != 0);\n\n\t\t// format message into temporary buffer lpszTemp\n\t\tva_list argList;\n\t\tva_start(argList, nFormatID);\n\t\tLPTSTR lpszTemp = NULL;\n\t\tBOOL bRet = TRUE;\n\n\t\tif ((::FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n\t\t\t\tstrFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0) || (lpszTemp == NULL))\n\t\t\tbRet = FALSE;\n\n\t\t// assign lpszTemp into the resulting string and free lpszTemp\n\t\t*this = lpszTemp;\n\t\tLocalFree(lpszTemp);\n\t\tva_end(argList);\n\t\treturn bRet;\n\t}\n\n\t// Windows support\n\tBOOL LoadString(UINT nID)   // load from string resource (255 chars max.)\n\t{\n#ifdef _UNICODE\n\t\tconst int CHAR_FUDGE = 1;   // one TCHAR unused is good enough\n#else\n\t\tconst int CHAR_FUDGE = 2;   // two BYTES unused for case of DBC last char\n#endif\n\n\t\t// try fixed buffer first (to avoid wasting space in the heap)\n\t\tTCHAR szTemp[256] = { 0 };\n\t\tint nCount =  sizeof(szTemp) / sizeof(szTemp[0]);\n\t\tint nLen = _LoadString(nID, szTemp, nCount);\n\t\tif (nCount - nLen > CHAR_FUDGE)\n\t\t{\n\t\t\t*this = szTemp;\n\t\t\treturn (nLen > 0);\n\t\t}\n\n\t\t// try buffer size of 512, then larger size until entire string is retrieved\n\t\tint nSize = 256;\n\t\tdo\n\t\t{\n\t\t\tnSize += 256;\n\t\t\tLPTSTR lpstr = GetBuffer(nSize - 1);\n\t\t\tif(lpstr == NULL)\n\t\t\t{\n\t\t\t\tnLen = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tnLen = _LoadString(nID, lpstr, nSize);\n\t\t} while (nSize - nLen <= CHAR_FUDGE);\n\t\tReleaseBuffer();\n\n\t\treturn (nLen > 0);\n\t}\n\n#ifndef _UNICODE\n\t// ANSI <-> OEM support (convert string in place)\n\tvoid AnsiToOem()\n\t{\n\t\tCopyBeforeWrite();\n\t\t::AnsiToOem(m_pchData, m_pchData);\n\t}\n\n\tvoid OemToAnsi()\n\t{\n\t\tCopyBeforeWrite();\n\t\t::OemToAnsi(m_pchData, m_pchData);\n\t}\n#endif\n\n#ifndef _ATL_NO_COM\n\t// OLE BSTR support (use for OLE automation)\n\tBSTR AllocSysString() const\n\t{\n#if defined(_UNICODE) || defined(OLE2ANSI)\n\t\tBSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);\n#else\n\t\tint nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,\n\t\t\tGetData()->nDataLength, NULL, NULL);\n\t\tBSTR bstr = ::SysAllocStringLen(NULL, nLen);\n\t\tif(bstr != NULL)\n\t\t\tMultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen);\n#endif\n\t\treturn bstr;\n\t}\n\n\tBSTR SetSysString(BSTR* pbstr) const\n\t{\n#if defined(_UNICODE) || defined(OLE2ANSI)\n\t\t::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);\n#else\n\t\tint nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,\n\t\t\tGetData()->nDataLength, NULL, NULL);\n\t\tif(::SysReAllocStringLen(pbstr, NULL, nLen))\n\t\t\tMultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen);\n#endif\n\t\tATLASSERT(*pbstr != NULL);\n\t\treturn *pbstr;\n\t}\n#endif // !_ATL_NO_COM\n\n\t// Access to string implementation buffer as \"C\" character array\n\tLPTSTR GetBuffer(int nMinBufLength)\n\t{\n\t\tATLASSERT(nMinBufLength >= 0);\n\n\t\tif (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)\n\t\t{\n\t\t\t// we have to grow the buffer\n\t\t\tCStringData* pOldData = GetData();\n\t\t\tint nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it\n\t\t\tif (nMinBufLength < nOldLen)\n\t\t\t\tnMinBufLength = nOldLen;\n\n\t\t\tif(!AllocBuffer(nMinBufLength))\n\t\t\t\treturn NULL;\n\n\t\t\tSecureHelper::memcpy_x(m_pchData, (nMinBufLength + 1) * sizeof(TCHAR), pOldData->data(), (nOldLen + 1) * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength = nOldLen;\n\t\t\tCString::Release(pOldData);\n\t\t}\n\t\tATLASSERT(GetData()->nRefs <= 1);\n\n\t\t// return a pointer to the character storage for this string\n\t\tATLASSERT(m_pchData != NULL);\n\t\treturn m_pchData;\n\t}\n\n\tvoid ReleaseBuffer(int nNewLength = -1)\n\t{\n\t\tCopyBeforeWrite();   // just in case GetBuffer was not called\n\n\t\tif (nNewLength == -1)\n\t\t\tnNewLength = lstrlen(m_pchData);   // zero terminated\n\n\t\tATLASSERT(nNewLength <= GetData()->nAllocLength);\n\t\tGetData()->nDataLength = nNewLength;\n\t\tm_pchData[nNewLength] = _T('\\0');\n\t}\n\n\tLPTSTR GetBufferSetLength(int nNewLength)\n\t{\n\t\tATLASSERT(nNewLength >= 0);\n\n\t\tif(GetBuffer(nNewLength) == NULL)\n\t\t\treturn NULL;\n\n\t\tGetData()->nDataLength = nNewLength;\n\t\tm_pchData[nNewLength] = _T('\\0');\n\t\treturn m_pchData;\n\t}\n\n\tvoid FreeExtra()\n\t{\n\t\tATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);\n\t\tif (GetData()->nDataLength != GetData()->nAllocLength)\n\t\t{\n\t\t\tCStringData* pOldData = GetData();\n\t\t\tif(AllocBuffer(GetData()->nDataLength))\n\t\t\t{\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pOldData->data(), pOldData->nDataLength * sizeof(TCHAR));\n\t\t\t\tATLASSERT(m_pchData[GetData()->nDataLength] == _T('\\0'));\n\t\t\t\tCString::Release(pOldData);\n\t\t\t}\n\t\t}\n\t\tATLASSERT(GetData() != NULL);\n\t}\n\n\t// Use LockBuffer/UnlockBuffer to turn refcounting off\n\tLPTSTR LockBuffer()\n\t{\n\t\tLPTSTR lpsz = GetBuffer(0);\n\t\tif(lpsz != NULL)\n\t\t\tGetData()->nRefs = -1;\n\t\treturn lpsz;\n\t}\n\n\tvoid UnlockBuffer()\n\t{\n\t\tATLASSERT(GetData()->nRefs == -1);\n\t\tif (GetData() != _atltmpDataNil)\n\t\t\tGetData()->nRefs = 1;\n\t}\n\n// Implementation\npublic:\n\t~CString()   //  free any attached data\n\t{\n\t\tif (GetData() != _atltmpDataNil)\n\t\t{\n\t\t\tif (InterlockedDecrement(&GetData()->nRefs) <= 0)\n\t\t\t\tdelete[] (BYTE*)GetData();\n\t\t}\n\t}\n\n\tint GetAllocLength() const\n\t{\n\t\treturn GetData()->nAllocLength;\n\t}\n\n\tstatic BOOL __stdcall _IsValidString(LPCTSTR lpsz, int /*nLength*/ = -1)\n\t{\n\t\treturn (lpsz != NULL) ? TRUE : FALSE;\n\t}\n\nprotected:\n\tLPTSTR m_pchData;   // pointer to ref counted string data\n\n\t// implementation helpers\n\tCStringData* GetData() const\n\t{\n\t\tATLASSERT(m_pchData != NULL);\n\t\treturn ((CStringData*)m_pchData) - 1;\n\t}\n\n\tvoid Init()\n\t{\n\t\tm_pchData = _GetEmptyString().m_pchData;\n\t}\n\n\tBOOL AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const\n\t{\n\t\t// will clone the data attached to this string\n\t\t// allocating 'nExtraLen' characters\n\t\t// Places results in uninitialized string 'dest'\n\t\t// Will copy the part or all of original data to start of new string\n\n\t\tBOOL bRet = FALSE;\n\t\tint nNewLen = nCopyLen + nExtraLen;\n\t\tif (nNewLen == 0)\n\t\t{\n\t\t\tdest.Init();\n\t\t\tbRet = TRUE;\n\t\t}\n\t\telse if(nNewLen >= nCopyLen)\n\t\t{\n\t\t\tif(dest.AllocBuffer(nNewLen))\n\t\t\t{\n\t\t\t\tSecureHelper::memcpy_x(dest.m_pchData, (nNewLen + 1) * sizeof(TCHAR), m_pchData + nCopyIndex, nCopyLen * sizeof(TCHAR));\n\t\t\t\tbRet = TRUE;\n\t\t\t}\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\t// always allocate one extra character for '\\0' termination\n\t// assumes [optimistically] that data length will equal allocation length\n\tBOOL AllocBuffer(int nLen)\n\t{\n\t\tATLASSERT(nLen >= 0);\n\t\tATLASSERT(nLen <= INT_MAX - 1);   // max size (enough room for 1 extra)\n\n\t\tif (nLen == 0)\n\t\t{\n\t\t\tInit();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCStringData* pData = NULL;\n\t\t\tATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen + 1) * sizeof(TCHAR)]);\n\t\t\tif(pData == NULL)\n\t\t\t\treturn FALSE;\n\n\t\t\tpData->nRefs = 1;\n\t\t\tpData->data()[nLen] = _T('\\0');\n\t\t\tpData->nDataLength = nLen;\n\t\t\tpData->nAllocLength = nLen;\n\t\t\tm_pchData = pData->data();\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\t// Assignment operators\n\t//  All assign a new value to the string\n\t//      (a) first see if the buffer is big enough\n\t//      (b) if enough room, copy on top of old buffer, set size and type\n\t//      (c) otherwise free old string data, and create a new one\n\t//\n\t//  All routines return the new string (but as a 'const CString&' so that\n\t//      assigning it again will cause a copy, eg: s1 = s2 = \"hi there\".\n\t//\n\tvoid AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)\n\t{\n\t\tif(AllocBeforeWrite(nSrcLen))\n\t\t{\n\t\t\tSecureHelper::memcpy_x(m_pchData, (nSrcLen + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength = nSrcLen;\n\t\t\tm_pchData[nSrcLen] = _T('\\0');\n\t\t}\n\t}\n\n\t// Concatenation\n\t// NOTE: \"operator +\" is done as friend functions for simplicity\n\t//      There are three variants:\n\t//          CString + CString\n\t// and for ? = TCHAR, LPCTSTR\n\t//          CString + ?\n\t//          ? + CString\n\tBOOL ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data)\n\t{\n\t\t// -- master concatenation routine\n\t\t// Concatenate two sources\n\t\t// -- assume that 'this' is a new CString object\n\n\t\tBOOL bRet = TRUE;\n\t\tint nNewLen = nSrc1Len + nSrc2Len;\n\t\tif(nNewLen < nSrc1Len || nNewLen < nSrc2Len)\n\t\t{\n\t\t\tbRet = FALSE;\n\t\t}\n\t\telse if(nNewLen != 0)\n\t\t{\n\t\t\tbRet = AllocBuffer(nNewLen);\n\t\t\tif (bRet)\n\t\t\t{\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (nNewLen + 1) * sizeof(TCHAR), lpszSrc1Data, nSrc1Len * sizeof(TCHAR));\n\t\t\t\tSecureHelper::memcpy_x(m_pchData + nSrc1Len, (nNewLen + 1 - nSrc1Len) * sizeof(TCHAR), lpszSrc2Data, nSrc2Len * sizeof(TCHAR));\n\t\t\t}\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tvoid ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)\n\t{\n\t\t//  -- the main routine for += operators\n\n\t\t// concatenating an empty string is a no-op!\n\t\tif (nSrcLen == 0)\n\t\t\treturn;\n\n\t\t// if the buffer is too small, or we have a width mis-match, just\n\t\t//   allocate a new buffer (slow but sure)\n\t\tif (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)\n\t\t{\n\t\t\t// we have to grow the buffer, use the ConcatCopy routine\n\t\t\tCStringData* pOldData = GetData();\n\t\t\tif (ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData))\n\t\t\t{\n\t\t\t\tATLASSERT(pOldData != NULL);\n\t\t\t\tCString::Release(pOldData);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// fast concatenation when buffer big enough\n\t\t\tSecureHelper::memcpy_x(m_pchData + GetData()->nDataLength, (GetData()->nAllocLength + 1) * sizeof(TCHAR), lpszSrcData, nSrcLen * sizeof(TCHAR));\n\t\t\tGetData()->nDataLength += nSrcLen;\n\t\t\tATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);\n\t\t\tm_pchData[GetData()->nDataLength] = _T('\\0');\n\t\t}\n\t}\n\n\tvoid CopyBeforeWrite()\n\t{\n\t\tif (GetData()->nRefs > 1)\n\t\t{\n\t\t\tCStringData* pData = GetData();\n\t\t\tRelease();\n\t\t\tif(AllocBuffer(pData->nDataLength))\n\t\t\t\tSecureHelper::memcpy_x(m_pchData, (GetData()->nAllocLength + 1) * sizeof(TCHAR), pData->data(), (pData->nDataLength + 1) * sizeof(TCHAR));\n\t\t}\n\t\tATLASSERT(GetData()->nRefs <= 1);\n\t}\n\n\tBOOL AllocBeforeWrite(int nLen)\n\t{\n\t\tBOOL bRet = TRUE;\n\t\tif (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)\n\t\t{\n\t\t\tRelease();\n\t\t\tbRet = AllocBuffer(nLen);\n\t\t}\n\t\tATLASSERT(GetData()->nRefs <= 1);\n\t\treturn bRet;\n\t}\n\n\tvoid Release()\n\t{\n\t\tif (GetData() != _atltmpDataNil)\n\t\t{\n\t\t\tATLASSERT(GetData()->nRefs != 0);\n\t\t\tif (InterlockedDecrement(&GetData()->nRefs) <= 0)\n\t\t\t\tdelete[] (BYTE*)GetData();\n\t\t\tInit();\n\t\t}\n\t}\n\n\tstatic void PASCAL Release(CStringData* pData)\n\t{\n\t\tif (pData != _atltmpDataNil)\n\t\t{\n\t\t\tATLASSERT(pData->nRefs != 0);\n\t\t\tif (InterlockedDecrement(&pData->nRefs) <= 0)\n\t\t\t\tdelete[] (BYTE*)pData;\n\t\t}\n\t}\n\n\tstatic int PASCAL SafeStrlen(LPCTSTR lpsz)\n\t{\n\t\treturn (lpsz == NULL) ? 0 : lstrlen(lpsz);\n\t}\n\n\tstatic int __stdcall _LoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)\n\t{\n#ifdef _DEBUG\n\t\t// LoadString without annoying warning from the Debug kernel if the\n\t\t//  segment containing the string is not present\n\t\tif (::FindResource(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE((nID >> 4) + 1), RT_STRING) == NULL)\n\t\t{\n\t\t\tlpszBuf[0] = _T('\\0');\n\t\t\treturn 0;   // not found\n\t\t}\n#endif // _DEBUG\n\n\t\tint nLen = ::LoadString(ModuleHelper::GetResourceInstance(), nID, lpszBuf, nMaxBuf);\n\t\tif (nLen == 0)\n\t\t\tlpszBuf[0] = _T('\\0');\n\n\t\treturn nLen;\n\t}\n\n\tstatic const CString& __stdcall _GetEmptyString()\n\t{\n\t\treturn *(CString*)&_atltmpPchNil;\n\t}\n\n// CString conversion helpers\n\tstatic int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)\n\t{\n\t\tif (count == 0 && mbstr != NULL)\n\t\t\treturn 0;\n\n\t\tint result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, (int)count, NULL, NULL);\n\t\tATLASSERT(mbstr == NULL || result <= (int)count);\n\t\tif ((mbstr != NULL) && (result > 0))\n\t\t\tmbstr[result - 1] = 0;\n\t\treturn result;\n\t}\n\n\tstatic int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)\n\t{\n\t\tif (count == 0 && wcstr != NULL)\n\t\t\treturn 0;\n\n\t\tint result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1, wcstr, (int)count);\n\t\tATLASSERT(wcstr == NULL || result <= (int)count);\n\t\tif ((wcstr != NULL) && (result > 0))\n\t\t\twcstr[result - 1] = 0;\n\t\treturn result;\n\t}\n\n// Helpers to avoid CRT startup code\n#ifdef _ATL_MIN_CRT\n\tstatic const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)\n\t{\n\t\t// strchr for '\\0' should succeed\n\t\twhile (*p != 0)\n\t\t{\n\t\t\tif (*p == ch)\n\t\t\t\tbreak;\n\t\t\tp = ::CharNext(p);\n\t\t}\n\t\treturn (*p == ch) ? p : NULL;\n\t}\n\n\tstatic TCHAR* _cstrrev(TCHAR* pStr)\n\t{\n\t\t// optimize NULL, zero-length, and single-char case\n\t\tif ((pStr == NULL) || (pStr[0] == _T('\\0')) || (pStr[1] == _T('\\0')))\n\t\t\treturn pStr;\n\n\t\tTCHAR* p = pStr;\n\n\t\twhile (*p != 0) \n\t\t{\n\t\t\tTCHAR* pNext = ::CharNext(p);\n\t\t\tif(pNext > p + 1)\n\t\t\t{\n\t\t\t\tchar p1 = *(char*)p;\n\t\t\t\t*(char*)p = *(char*)(p + 1);\n\t\t\t\t*(char*)(p + 1) = p1;\n\t\t\t}\n\t\t\tp = pNext;\n\t\t}\n\n\t\tp--;\n\t\tTCHAR* q = pStr;\n\n\t\twhile (q < p)\n\t\t{\n\t\t\tTCHAR t = *q;\n\t\t\t*q = *p;\n\t\t\t*p = t;\n\t\t\tq++;\n\t\t\tp--;\n\t\t}\n\t\treturn pStr;\n\t}\n\n\tstatic const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\tint nLen = lstrlen(pCharSet);\n\t\tif (nLen == 0)\n\t\t\treturn (TCHAR*)pStr;\n\n\t\tconst TCHAR* pRet = NULL;\n\t\tconst TCHAR* pCur = pStr;\n\t\twhile((pCur = _cstrchr(pCur, *pCharSet)) != NULL)\n\t\t{\n\t\t\tif(memcmp(pCur, pCharSet, nLen * sizeof(TCHAR)) == 0)\n\t\t\t{\n\t\t\t\tpRet = pCur;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpCur = ::CharNext(pCur);\n\t\t}\n\t\treturn pRet;\n\t}\n\n\tstatic int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\tint nRet = 0;\n\t\tconst TCHAR* p = pStr;\n\t\twhile (*p != 0)\n\t\t{\n\t\t\tconst TCHAR* pNext = ::CharNext(p);\n\t\t\tif(pNext > p + 1)\n\t\t\t{\n\t\t\t\tif(_cstrchr_db(pCharSet, *p, *(p + 1)) == NULL)\n\t\t\t\t\tbreak;\n\t\t\t\tnRet += 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(_cstrchr(pCharSet, *p) == NULL)\n\t\t\t\t\tbreak;\n\t\t\t\tnRet++;\n\t\t\t}\n\t\t\tp = pNext;\n\t\t}\n\t\treturn nRet;\n\t}\n\n\tstatic int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\tint nRet = 0;\n\t\tTCHAR* p = (TCHAR*)pStr;\n\t\twhile (*p != 0)\n\t\t{\n\t\t\tTCHAR* pNext = ::CharNext(p);\n\t\t\tif(pNext > p + 1)\n\t\t\t{\n\t\t\t\tif(_cstrchr_db(pCharSet, *p, *(p + 1)) != NULL)\n\t\t\t\t\tbreak;\n\t\t\t\tnRet += 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(_cstrchr(pCharSet, *p) != NULL)\n\t\t\t\t\tbreak;\n\t\t\t\tnRet++;\n\t\t\t}\n\t\t\tp = pNext;\n\t\t}\n\t\treturn nRet;\n\t}\n\n\tstatic const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)\n\t{\n\t\tint n = _cstrcspn(p, lpszCharSet);\n\t\treturn (p[n] != 0) ? &p[n] : NULL;\n\t}\n\n\tstatic int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn lstrcmp(pstrOne, pstrOther);\n\t}\n\n\tstatic int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn lstrcmpi(pstrOne, pstrOther);\n\t}\n\n\tstatic int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\tint nRet = CompareString(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);\n\t\tATLASSERT(nRet != 0);\n\t\treturn nRet - 2;   // convert to strcmp convention\n\t}\n\n\tstatic int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\tint nRet = CompareString(GetThreadLocale(), NORM_IGNORECASE, pstrOne, -1, pstrOther, -1);\n\t\tATLASSERT(nRet != 0);\n\t\treturn nRet - 2;   // convert to strcmp convention\n\t}\n#else // !_ATL_MIN_CRT\n\tstatic const TCHAR* _cstrchr(const TCHAR* p, TCHAR ch)\n\t{\n\t\treturn _tcschr(p, ch);\n\t}\n\n\tstatic TCHAR* _cstrrev(TCHAR* pStr)\n\t{\n\t\treturn _tcsrev(pStr);\n\t}\n\n\tstatic const TCHAR* _cstrstr(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\treturn _tcsstr(pStr, pCharSet);\n\t}\n\n\tstatic int _cstrspn(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\treturn (int)_tcsspn(pStr, pCharSet);\n\t}\n\n\tstatic int _cstrcspn(const TCHAR* pStr, const TCHAR* pCharSet)\n\t{\n\t\treturn (int)_tcscspn(pStr, pCharSet);\n\t}\n\n\tstatic const TCHAR* _cstrpbrk(const TCHAR* p, const TCHAR* lpszCharSet)\n\t{\n\t\treturn _tcspbrk(p, lpszCharSet);\n\t}\n\n\tstatic int _cstrcmp(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn _tcscmp(pstrOne, pstrOther);\n\t}\n\n\tstatic int _cstrcmpi(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn _tcsicmp(pstrOne, pstrOther);\n\t}\n\n#ifndef _WIN32_WCE\n\tstatic int _cstrcoll(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn _tcscoll(pstrOne, pstrOther);\n\t}\n\n\tstatic int _cstrcolli(const TCHAR* pstrOne, const TCHAR* pstrOther)\n\t{\n\t\treturn _tcsicoll(pstrOne, pstrOther);\n\t}\n#endif // !_WIN32_WCE\n#endif // !_ATL_MIN_CRT\n\n\tstatic const TCHAR* _cstrrchr(const TCHAR* p, TCHAR ch)\n\t{\n\t\treturn MinCrtHelper::_strrchr(p, ch);\n\t}\n\n\tstatic int _cstrisdigit(TCHAR ch)\n\t{\n\t\treturn MinCrtHelper::_isdigit(ch);\n\t}\n\n\tstatic int _cstrisspace(TCHAR ch)\n\t{\n\t\treturn MinCrtHelper::_isspace(ch);\n\t}\n\n\tstatic int _cstrtoi(const TCHAR* nptr)\n\t{\n\t\treturn MinCrtHelper::_atoi(nptr);\n\t}\n\n\tstatic const TCHAR* _cstrchr_db(const TCHAR* p, TCHAR ch1, TCHAR ch2)\n\t{\n\t\tconst TCHAR* lpsz = NULL;\n\t\twhile (*p != 0)\n\t\t{\n\t\t\tif (*p == ch1 && *(p + 1) == ch2)\n\t\t\t{\n\t\t\t\tlpsz = p;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tp = ::CharNext(p);\n\t\t}\n\t\treturn lpsz;\n\t}\n};\n\n\n// Compare helpers\n\ninline bool __stdcall operator ==(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) == 0; }\n\ninline bool __stdcall operator ==(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) == 0; }\n\ninline bool __stdcall operator ==(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) == 0; }\n\ninline bool __stdcall operator !=(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) != 0; }\n\ninline bool __stdcall operator !=(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) != 0; }\n\ninline bool __stdcall operator !=(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) != 0; }\n\ninline bool __stdcall operator <(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) < 0; }\n\ninline bool __stdcall operator <(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) < 0; }\n\ninline bool __stdcall operator <(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) > 0; }\n\ninline bool __stdcall operator >(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) > 0; }\n\ninline bool __stdcall operator >(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) > 0; }\n\ninline bool __stdcall operator >(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) < 0; }\n\ninline bool __stdcall operator <=(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) <= 0; }\n\ninline bool __stdcall operator <=(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) <= 0; }\n\ninline bool __stdcall operator <=(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) >= 0; }\n\ninline bool __stdcall operator >=(const CString& s1, const CString& s2)\n{ return s1.Compare(s2) >= 0; }\n\ninline bool __stdcall operator >=(const CString& s1, LPCTSTR s2)\n{ return s1.Compare(s2) >= 0; }\n\ninline bool __stdcall operator >=(LPCTSTR s1, const CString& s2)\n{ return s2.Compare(s1) <= 0; }\n\n\n// CString \"operator +\" functions\n\ninline CString __stdcall operator +(const CString& string1, const CString& string2)\n{\n\tCString s;\n\ts.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, string2.GetData()->nDataLength, string2.m_pchData);\n\treturn s;\n}\n\ninline CString __stdcall operator +(const CString& string, TCHAR ch)\n{\n\tCString s;\n\ts.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch);\n\treturn s;\n}\n\ninline CString __stdcall operator +(TCHAR ch, const CString& string)\n{\n\tCString s;\n\ts.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);\n\treturn s;\n}\n\n#ifdef _UNICODE\ninline CString __stdcall operator +(const CString& string, char ch)\n{\n\treturn string + (TCHAR)ch;\n}\n\ninline CString __stdcall operator +(char ch, const CString& string)\n{\n\treturn (TCHAR)ch + string;\n}\n#endif // _UNICODE\n\ninline CString __stdcall operator +(const CString& string, LPCTSTR lpsz)\n{\n\tATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));\n\tCString s;\n\ts.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, CString::SafeStrlen(lpsz), lpsz);\n\treturn s;\n}\n\ninline CString __stdcall operator +(LPCTSTR lpsz, const CString& string)\n{\n\tATLASSERT(lpsz == NULL || CString::_IsValidString(lpsz));\n\tCString s;\n\ts.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength, string.m_pchData);\n\treturn s;\n}\n\n#endif // !_WTL_NO_CSTRING\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRecentDocumentList - MRU List Support\n\n#ifndef _WIN32_WCE\n\n#ifndef _WTL_MRUEMPTY_TEXT\n  #define _WTL_MRUEMPTY_TEXT\t_T(\"(empty)\")\n#endif\n\n// forward declaration\ninline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen);\n\ntemplate <class T, int t_cchItemLen = MAX_PATH, int t_nFirstID = ID_FILE_MRU_FIRST, int t_nLastID = ID_FILE_MRU_LAST>\nclass CRecentDocumentListBase\n{\npublic:\n// Declarations\n\tstruct _DocEntry\n\t{\n\t\tTCHAR szDocName[t_cchItemLen];\n\t\tbool operator ==(const _DocEntry& de) const\n\t\t{ return (lstrcmpi(szDocName, de.szDocName) == 0); }\n\t};\n\n\tenum\n\t{\n\t\tm_nMaxEntries_Min = 2,\n\t\tm_nMaxEntries_Max = t_nLastID - t_nFirstID + 1,\n\t\tm_cchMaxItemLen_Min = 6,\n\t\tm_cchMaxItemLen_Max = t_cchItemLen,\n\t\tm_cchItemNameLen = 11\n\t};\n\n// Data members\n\tATL::CSimpleArray<_DocEntry> m_arrDocs;\n\tint m_nMaxEntries;   // default is 4\n\tHMENU m_hMenu;\n\n\tTCHAR m_szNoEntries[t_cchItemLen];\n\n\tint m_cchMaxItemLen;\n\n// Constructor\n\tCRecentDocumentListBase() : m_hMenu(NULL), m_nMaxEntries(4), m_cchMaxItemLen(-1)\n\t{\n\t\t// These ASSERTs verify values of the template arguments\n\t\tATLASSERT(t_cchItemLen > m_cchMaxItemLen_Min);\n\t\tATLASSERT(m_nMaxEntries_Max > m_nMaxEntries_Min);\n\t}\n\n// Attributes\n\tHMENU GetMenuHandle() const\n\t{\n\t\treturn m_hMenu;\n\t}\n\n\tvoid SetMenuHandle(HMENU hMenu)\n\t{\n\t\tATLASSERT(hMenu == NULL || ::IsMenu(hMenu));\n\t\tm_hMenu = hMenu;\n\t\tif(m_hMenu == NULL || (::GetMenuString(m_hMenu, t_nFirstID, m_szNoEntries, t_cchItemLen, MF_BYCOMMAND) == 0))\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT;   // avoid level 4 warning\n\t\t\tSecureHelper::strncpy_x(m_szNoEntries, _countof(m_szNoEntries), pT->GetMRUEmptyText(), _TRUNCATE);\n\t\t}\n\t}\n\n\tint GetMaxEntries() const\n\t{\n\t\treturn m_nMaxEntries;\n\t}\n\n\tvoid SetMaxEntries(int nMaxEntries)\n\t{\n\t\tATLASSERT(nMaxEntries >= m_nMaxEntries_Min && nMaxEntries <= m_nMaxEntries_Max);\n\t\tif(nMaxEntries < m_nMaxEntries_Min)\n\t\t\tnMaxEntries = m_nMaxEntries_Min;\n\t\telse if(nMaxEntries > m_nMaxEntries_Max)\n\t\t\tnMaxEntries = m_nMaxEntries_Max;\n\t\tm_nMaxEntries = nMaxEntries;\n\t}\n\n\tint GetMaxItemLength() const\n\t{\n\t\treturn m_cchMaxItemLen;\n\t}\n\n\tvoid SetMaxItemLength(int cchMaxLen)\n\t{\n\t\tATLASSERT((cchMaxLen >= m_cchMaxItemLen_Min && cchMaxLen <= m_cchMaxItemLen_Max) || cchMaxLen == -1);\n\t\tif(cchMaxLen != -1)\n\t\t{\n\t\t\tif(cchMaxLen < m_cchMaxItemLen_Min)\n\t\t\t\tcchMaxLen = m_cchMaxItemLen_Min;\n\t\t\telse if(cchMaxLen > m_cchMaxItemLen_Max)\n\t\t\t\tcchMaxLen = m_cchMaxItemLen_Max;\n\t\t}\n\t\tm_cchMaxItemLen = cchMaxLen;\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateMenu();\n\t}\n\n// Operations\n\tBOOL AddToList(LPCTSTR lpstrDocName)\n\t{\n\t\t_DocEntry de;\n\t\terrno_t nRet = SecureHelper::strncpy_x(de.szDocName, _countof(de.szDocName), lpstrDocName, _TRUNCATE);\n\t\tif(nRet != 0 && nRet != STRUNCATE)\n\t\t\treturn FALSE;\n\n\t\tfor(int i = 0; i < m_arrDocs.GetSize(); i++)\n\t\t{\n\t\t\tif(lstrcmpi(m_arrDocs[i].szDocName, lpstrDocName) == 0)\n\t\t\t{\n\t\t\t\tm_arrDocs.RemoveAt(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif(m_arrDocs.GetSize() == m_nMaxEntries)\n\t\t\tm_arrDocs.RemoveAt(0);\n\n\t\tBOOL bRet = m_arrDocs.Add(de);\n\t\tif(bRet)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tbRet = pT->UpdateMenu();\n\t\t}\n\t\treturn bRet;\n\t}\n\n\t// This function is deprecated because it is not safe. \n\t// Use the version below that accepts the buffer length.\n#if (_MSC_VER >= 1300)\n\t__declspec(deprecated)\n#endif\n\tBOOL GetFromList(int /*nItemID*/, LPTSTR /*lpstrDocName*/)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn FALSE;\n\t}\n\n\tBOOL GetFromList(int nItemID, LPTSTR lpstrDocName, int cchLength)\n\t{\n\t\tint nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;\n\t\tif(nIndex < 0 || nIndex >= m_arrDocs.GetSize())\n\t\t\treturn FALSE;\n\t\tif(lstrlen(m_arrDocs[nIndex].szDocName) >= cchLength)\n\t\t\treturn FALSE;\n\t\tSecureHelper::strcpy_x(lpstrDocName, cchLength, m_arrDocs[nIndex].szDocName);\n\n\t\treturn TRUE;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tBOOL GetFromList(int nItemID, _CSTRING_NS::CString& strDocName)\n\t{\n\t\tint nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;\n\t\tif(nIndex < 0 || nIndex >= m_arrDocs.GetSize())\n\t\t\treturn FALSE;\n\t\tstrDocName = m_arrDocs[nIndex].szDocName;\n\t\treturn TRUE;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL RemoveFromList(int nItemID)\n\t{\n\t\tint nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;\n\t\tBOOL bRet = m_arrDocs.RemoveAt(nIndex);\n\t\tif(bRet)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tbRet = pT->UpdateMenu();\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL MoveToTop(int nItemID)\n\t{\n\t\tint nIndex = m_arrDocs.GetSize() - (nItemID - t_nFirstID) - 1;\n\t\tif(nIndex < 0 || nIndex >= m_arrDocs.GetSize())\n\t\t\treturn FALSE;\n\t\t_DocEntry de;\n\t\tde = m_arrDocs[nIndex];\n\t\tm_arrDocs.RemoveAt(nIndex);\n\t\tBOOL bRet = m_arrDocs.Add(de);\n\t\tif(bRet)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tbRet = pT->UpdateMenu();\n\t\t}\n\t\treturn bRet;\n\t}\n\n\tBOOL ReadFromRegistry(LPCTSTR lpstrRegKey)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tCRegKeyEx rkParent;\n\t\tCRegKeyEx rk;\n\n\t\tLONG lRet = rkParent.Open(HKEY_CURRENT_USER, lpstrRegKey);\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn FALSE;\n\t\tlRet = rk.Open(rkParent, pT->GetRegKeyName());\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn FALSE;\n\n\t\tDWORD dwRet = 0;\n\t\tlRet = rk.QueryDWORDValue(pT->GetRegCountName(), dwRet);\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn FALSE;\n\t\tSetMaxEntries(dwRet);\n\n\t\tm_arrDocs.RemoveAll();\n\n\t\tTCHAR szRetString[t_cchItemLen] = { 0 };\n\t\t_DocEntry de;\n\n\t\tfor(int nItem = m_nMaxEntries; nItem > 0; nItem--)\n\t\t{\n\t\t\tTCHAR szBuff[m_cchItemNameLen] = { 0 };\n\t\t\tSecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);\n\t\t\tULONG ulCount = t_cchItemLen;\n\t\t\tlRet = rk.QueryStringValue(szBuff, szRetString, &ulCount);\n\t\t\tif(lRet == ERROR_SUCCESS)\n\t\t\t{\n\t\t\t\tSecureHelper::strcpy_x(de.szDocName, _countof(de.szDocName), szRetString);\n\t\t\t\tm_arrDocs.Add(de);\n\t\t\t}\n\t\t}\n\n\t\trk.Close();\n\t\trkParent.Close();\n\n\t\treturn pT->UpdateMenu();\n\t}\n\n\tBOOL WriteToRegistry(LPCTSTR lpstrRegKey)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tCRegKeyEx rkParent;\n\t\tCRegKeyEx rk;\n\n\t\tLONG lRet = rkParent.Create(HKEY_CURRENT_USER, lpstrRegKey);\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn FALSE;\n\t\tlRet = rk.Create(rkParent, pT->GetRegKeyName());\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn FALSE;\n\n\t\tlRet = rk.SetDWORDValue(pT->GetRegCountName(), m_nMaxEntries);\n\t\tATLASSERT(lRet == ERROR_SUCCESS);\n\n\t\t// set new values\n\t\tint nItem;\n\t\tfor(nItem = m_arrDocs.GetSize(); nItem > 0; nItem--)\n\t\t{\n\t\t\tTCHAR szBuff[m_cchItemNameLen] = { 0 };\n\t\t\tSecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);\n\t\t\tTCHAR szDocName[t_cchItemLen] = { 0 };\n\t\t\tGetFromList(t_nFirstID + nItem - 1, szDocName, t_cchItemLen);\n\t\t\tlRet = rk.SetStringValue(szBuff, szDocName);\n\t\t\tATLASSERT(lRet == ERROR_SUCCESS);\n\t\t}\n\n\t\t// delete unused keys\n\t\tfor(nItem = m_arrDocs.GetSize() + 1; nItem <= m_nMaxEntries_Max; nItem++)\n\t\t{\n\t\t\tTCHAR szBuff[m_cchItemNameLen] = { 0 };\n\t\t\tSecureHelper::wsprintf_x(szBuff, m_cchItemNameLen, pT->GetRegItemName(), nItem);\n\t\t\trk.DeleteValue(szBuff);\n\t\t}\n\n\t\trk.Close();\n\t\trkParent.Close();\n\n\t\treturn TRUE;\n\t}\n\n// Implementation\n\tBOOL UpdateMenu()\n\t{\n\t\tif(m_hMenu == NULL)\n\t\t\treturn FALSE;\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\n\t\tint nItems = ::GetMenuItemCount(m_hMenu);\n\t\tint nInsertPoint = 0;\n\t\tfor(int i = 0; i < nItems; i++)\n\t\t{\n\t\t\tCMenuItemInfo mi;\n\t\t\tmi.fMask = MIIM_ID;\n\t\t\t::GetMenuItemInfo(m_hMenu, i, TRUE, &mi);\n\t\t\tif (mi.wID == t_nFirstID)\n\t\t\t{\n\t\t\t\tnInsertPoint = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tATLASSERT(nInsertPoint < nItems && \"You need a menu item with an ID = t_nFirstID\");\n\n\t\tfor(int j = t_nFirstID; j < (t_nFirstID + m_nMaxEntries); j++)\n\t\t{\n\t\t\t// keep the first one as an insertion point\n\t\t\tif (j != t_nFirstID)\n\t\t\t\t::DeleteMenu(m_hMenu, j, MF_BYCOMMAND);\n\t\t}\n\n\t\tTCHAR szItemText[t_cchItemLen + 6] = { 0 };   // add space for &, 2 digits, and a space\n\t\tint nSize = m_arrDocs.GetSize();\n\t\tint nItem = 0;\n\t\tif(nSize > 0)\n\t\t{\n\t\t\tfor(nItem = 0; nItem < nSize; nItem++)\n\t\t\t{\n\t\t\t\tif(m_cchMaxItemLen == -1)\n\t\t\t\t{\n\t\t\t\t\tSecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T(\"&%i %s\"), nItem + 1, m_arrDocs[nSize - 1 - nItem].szDocName);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tTCHAR szBuff[t_cchItemLen] = { 0 };\n\t\t\t\t\tT* pT = static_cast<T*>(this);\n\t\t\t\t\tpT;   // avoid level 4 warning\n\t\t\t\t\tbool bRet = pT->CompactDocumentName(szBuff, m_arrDocs[nSize - 1 - nItem].szDocName, m_cchMaxItemLen);\n\t\t\t\t\tbRet;   // avoid level 4 warning\n\t\t\t\t\tATLASSERT(bRet);\n\t\t\t\t\tSecureHelper::wsprintf_x(szItemText, t_cchItemLen + 6, _T(\"&%i %s\"), nItem + 1, szBuff);\n\t\t\t\t}\n\n\t\t\t\t::InsertMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION | MF_STRING, t_nFirstID + nItem, szItemText);\n\t\t\t}\n\t\t}\n\t\telse\t// empty\n\t\t{\n\t\t\t::InsertMenu(m_hMenu, nInsertPoint, MF_BYPOSITION | MF_STRING, t_nFirstID, m_szNoEntries);\n\t\t\t::EnableMenuItem(m_hMenu, t_nFirstID, MF_GRAYED);\n\t\t\tnItem++;\n\t\t}\n\t\t::DeleteMenu(m_hMenu, nInsertPoint + nItem, MF_BYPOSITION);\n\n\t\treturn TRUE;\n\t}\n\n// Overrideables\n\t// override to provide a different method of compacting document names\n\tstatic bool CompactDocumentName(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)\n\t{\n\t\treturn AtlCompactPath(lpstrOut, lpstrIn, cchLen);\n\t}\n\n\tstatic LPCTSTR GetRegKeyName()\n\t{\n\t\treturn _T(\"Recent Document List\");\n\t}\n\n\tstatic LPCTSTR GetRegCountName()\n\t{\n\t\treturn _T(\"DocumentCount\");\n\t}\n\n\tstatic LPCTSTR GetRegItemName()\n\t{\n\t\t// Note: This string is a format string used with wsprintf().\n\t\t// Resulting formatted string must be m_cchItemNameLen or less \n\t\t// characters long, including the terminating null character.\n\t\treturn _T(\"Document%i\");\n\t}\n\n\tstatic LPCTSTR GetMRUEmptyText()\n\t{\n\t\treturn _WTL_MRUEMPTY_TEXT;\n\t}\n};\n\nclass CRecentDocumentList : public CRecentDocumentListBase<CRecentDocumentList>\n{\npublic:\n// nothing here\n};\n\n#endif // _WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFindFile - file search helper class\n\nclass CFindFile\n{\npublic:\n// Data members\n\tWIN32_FIND_DATA m_fd;\n\tTCHAR m_lpszRoot[MAX_PATH];\n\tTCHAR m_chDirSeparator;\n\tHANDLE m_hFind;\n\tBOOL m_bFound;\n\n// Constructor/destructor\n\tCFindFile() : m_hFind(NULL), m_chDirSeparator(_T('\\\\')), m_bFound(FALSE)\n\t{ }\n\n\t~CFindFile()\n\t{\n\t\tClose();\n\t}\n\n// Attributes\n\tULONGLONG GetFileSize() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tULARGE_INTEGER nFileSize = { 0 };\n\n\t\tif(m_bFound)\n\t\t{\n\t\t\tnFileSize.LowPart = m_fd.nFileSizeLow;\n\t\t\tnFileSize.HighPart = m_fd.nFileSizeHigh;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnFileSize.QuadPart = 0;\n\t\t}\n\n\t\treturn nFileSize.QuadPart;\n\t}\n\n\tBOOL GetFileName(LPTSTR lpstrFileName, int cchLength) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\t\tif(lstrlen(m_fd.cFileName) >= cchLength)\n\t\t\treturn FALSE;\n\n\t\tif(m_bFound)\n\t\t\tSecureHelper::strcpy_x(lpstrFileName, cchLength, m_fd.cFileName);\n\n\t\treturn m_bFound;\n\t}\n\n\tBOOL GetFilePath(LPTSTR lpstrFilePath, int cchLength) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tint nLen = lstrlen(m_lpszRoot);\n#ifndef _WIN32_WCE\n\t\tATLASSERT(nLen > 0);\n\t\tif(nLen == 0)\n\t\t\treturn FALSE;\n\n\t\tbool bAddSep = (m_lpszRoot[nLen - 1] != _T('\\\\') && m_lpszRoot[nLen - 1] !=_T('/'));\n#else // CE specific\n\t\t// allow diskless devices (nLen == 0)\n\t\tbool bAddSep = ((nLen == 0) || (m_lpszRoot[nLen - 1] != _T('\\\\') && m_lpszRoot[nLen - 1] !=_T('/')));\n#endif // _WIN32_WCE\n\n\t\tif((lstrlen(m_lpszRoot) + (bAddSep ?  1 : 0)) >= cchLength)\n\t\t\treturn FALSE;\n\n\t\tSecureHelper::strcpy_x(lpstrFilePath, cchLength, m_lpszRoot);\n\n\t\tif(bAddSep)\n\t\t{\n\t\t\tTCHAR szSeparator[2] = { m_chDirSeparator, 0 };\n\t\t\tSecureHelper::strcat_x(lpstrFilePath, cchLength, szSeparator);\n\t\t}\n\n\t\tSecureHelper::strcat_x(lpstrFilePath, cchLength, m_fd.cFileName);\n\n\t\treturn TRUE;\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetFileTitle(LPTSTR lpstrFileTitle, int cchLength) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tTCHAR szBuff[MAX_PATH] = { 0 };\n\t\tif(!GetFileName(szBuff, MAX_PATH))\n\t\t\treturn FALSE;\n\n\t\tif(lstrlen(szBuff) >= cchLength || cchLength < 1)\n\t\t\treturn FALSE;\n\n\t\t// find the last dot\n\t\tLPTSTR pstrDot  = MinCrtHelper::_strrchr(szBuff, _T('.'));\n\t\tif(pstrDot != NULL)\n\t\t\t*pstrDot = 0;\n\n\t\tSecureHelper::strcpy_x(lpstrFileTitle, cchLength, szBuff);\n\n\t\treturn TRUE;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL GetFileURL(LPTSTR lpstrFileURL, int cchLength) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tTCHAR szBuff[MAX_PATH] = { 0 };\n\t\tif(!GetFilePath(szBuff, MAX_PATH))\n\t\t\treturn FALSE;\n\t\tLPCTSTR lpstrFileURLPrefix = _T(\"file://\");\n\t\tif(lstrlen(szBuff) + lstrlen(lpstrFileURLPrefix) >= cchLength)\n\t\t\treturn FALSE;\n\t\tSecureHelper::strcpy_x(lpstrFileURL, cchLength, lpstrFileURLPrefix);\n\t\tSecureHelper::strcat_x(lpstrFileURL, cchLength, szBuff);\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL GetRoot(LPTSTR lpstrRoot, int cchLength) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\t\tif(lstrlen(m_lpszRoot) >= cchLength)\n\t\t\treturn FALSE;\n\n\t\tSecureHelper::strcpy_x(lpstrRoot, cchLength, m_lpszRoot);\n\n\t\treturn TRUE;\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\t_CSTRING_NS::CString GetFileName() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t_CSTRING_NS::CString ret;\n\n\t\tif(m_bFound)\n\t\t\tret = m_fd.cFileName;\n\t\treturn ret;\n\t}\n\n\t_CSTRING_NS::CString GetFilePath() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t_CSTRING_NS::CString strResult = m_lpszRoot;\n\t\tint nLen = strResult.GetLength();\n#ifndef _WIN32_WCE\n\t\tATLASSERT(nLen > 0);\n\t\tif(nLen == 0)\n\t\t\treturn strResult;\n\n\t\tif((strResult[nLen - 1] != _T('\\\\')) && (strResult[nLen - 1] != _T('/')))\n#else // CE specific\n\t\t// allow diskless devices (nLen == 0)\n\t\tif((nLen == 0) || ((strResult[nLen - 1] != _T('\\\\')) && (strResult[nLen - 1] != _T('/'))))\n#endif // _WIN32_WCE\n\t\t\tstrResult += m_chDirSeparator;\n\t\tstrResult += GetFileName();\n\t\treturn strResult;\n\t}\n\n#ifndef _WIN32_WCE\n\t_CSTRING_NS::CString GetFileTitle() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t_CSTRING_NS::CString strResult;\n\t\tGetFileTitle(strResult.GetBuffer(MAX_PATH), MAX_PATH);\n\t\tstrResult.ReleaseBuffer();\n\n\t\treturn strResult;\n\t}\n#endif // !_WIN32_WCE\n\n\t_CSTRING_NS::CString GetFileURL() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t_CSTRING_NS::CString strResult(\"file://\");\n\t\tstrResult += GetFilePath();\n\t\treturn strResult;\n\t}\n\n\t_CSTRING_NS::CString GetRoot() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t_CSTRING_NS::CString str = m_lpszRoot;\n\t\treturn str;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tBOOL GetLastWriteTime(FILETIME* pTimeStamp) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\t\tATLASSERT(pTimeStamp != NULL);\n\n\t\tif(m_bFound && pTimeStamp != NULL)\n\t\t{\n\t\t\t*pTimeStamp = m_fd.ftLastWriteTime;\n\t\t\treturn TRUE;\n\t\t}\n\n\t\treturn FALSE;\n\t}\n\n\tBOOL GetLastAccessTime(FILETIME* pTimeStamp) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\t\tATLASSERT(pTimeStamp != NULL);\n\n\t\tif(m_bFound && pTimeStamp != NULL)\n\t\t{\n\t\t\t*pTimeStamp = m_fd.ftLastAccessTime;\n\t\t\treturn TRUE;\n\t\t}\n\n\t\treturn FALSE;\n\t}\n\n\tBOOL GetCreationTime(FILETIME* pTimeStamp) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tif(m_bFound && pTimeStamp != NULL)\n\t\t{\n\t\t\t*pTimeStamp = m_fd.ftCreationTime;\n\t\t\treturn TRUE;\n\t\t}\n\n\t\treturn FALSE;\n\t}\n\n\tBOOL MatchesMask(DWORD dwMask) const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tif(m_bFound)\n\t\t\treturn ((m_fd.dwFileAttributes & dwMask) != 0);\n\n\t\treturn FALSE;\n\t}\n\n\tBOOL IsDots() const\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\t// return TRUE if the file name is \".\" or \"..\" and\n\t\t// the file is a directory\n\n\t\tBOOL bResult = FALSE;\n\t\tif(m_bFound && IsDirectory())\n\t\t{\n\t\t\tif(m_fd.cFileName[0] == _T('.') && (m_fd.cFileName[1] == _T('\\0') || (m_fd.cFileName[1] == _T('.') && m_fd.cFileName[2] == _T('\\0'))))\n\t\t\t\tbResult = TRUE;\n\t\t}\n\n\t\treturn bResult;\n\t}\n\n\tBOOL IsReadOnly() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_READONLY);\n\t}\n\n\tBOOL IsDirectory() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_DIRECTORY);\n\t}\n\n\tBOOL IsCompressed() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_COMPRESSED);\n\t}\n\n\tBOOL IsSystem() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_SYSTEM);\n\t}\n\n\tBOOL IsHidden() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_HIDDEN);\n\t}\n\n\tBOOL IsTemporary() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_TEMPORARY);\n\t}\n\n\tBOOL IsNormal() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_NORMAL);\n\t}\n\n\tBOOL IsArchived() const\n\t{\n\t\treturn MatchesMask(FILE_ATTRIBUTE_ARCHIVE);\n\t}\n\n// Operations\n\tBOOL FindFile(LPCTSTR pstrName = NULL)\n\t{\n\t\tClose();\n\n\t\tif(pstrName == NULL)\n\t\t{\n\t\t\tpstrName = _T(\"*.*\");\n\t\t}\n\t\telse if(lstrlen(pstrName) >= MAX_PATH)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tSecureHelper::strcpy_x(m_fd.cFileName, _countof(m_fd.cFileName), pstrName);\n\n\t\tm_hFind = ::FindFirstFile(pstrName, &m_fd);\n\n\t\tif(m_hFind == INVALID_HANDLE_VALUE)\n\t\t\treturn FALSE;\n\n#ifndef _WIN32_WCE\n\t\tbool bFullPath = (::GetFullPathName(pstrName, MAX_PATH, m_lpszRoot, NULL) != 0);\n#else // CE specific\n\t\terrno_t nRet = SecureHelper::strncpy_x(m_lpszRoot, _countof(m_lpszRoot), pstrName, _TRUNCATE);\n\t\tbool bFullPath = (nRet == 0 || nRet == STRUNCATE);\n#endif // _WIN32_WCE\n\n\t\t// passed name isn't a valid path but was found by the API\n\t\tATLASSERT(bFullPath);\n\t\tif(!bFullPath)\n\t\t{\n\t\t\tClose();\n\t\t\t::SetLastError(ERROR_INVALID_NAME);\n\t\t\treturn FALSE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// find the last forward or backward whack\n\t\t\tLPTSTR pstrBack  = MinCrtHelper::_strrchr(m_lpszRoot, _T('\\\\'));\n\t\t\tLPTSTR pstrFront = MinCrtHelper::_strrchr(m_lpszRoot, _T('/'));\n\n\t\t\tif(pstrFront != NULL || pstrBack != NULL)\n\t\t\t{\n\t\t\t\tif(pstrFront == NULL)\n\t\t\t\t\tpstrFront = m_lpszRoot;\n\t\t\t\tif(pstrBack == NULL)\n\t\t\t\t\tpstrBack = m_lpszRoot;\n\n\t\t\t\t// from the start to the last whack is the root\n\n\t\t\t\tif(pstrFront >= pstrBack)\n\t\t\t\t\t*pstrFront = _T('\\0');\n\t\t\t\telse\n\t\t\t\t\t*pstrBack = _T('\\0');\n\t\t\t}\n\t\t}\n\n\t\tm_bFound = TRUE;\n\n\t\treturn TRUE;\n\t}\n\n\tBOOL FindNextFile()\n\t{\n\t\tATLASSERT(m_hFind != NULL);\n\n\t\tif(m_hFind == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(!m_bFound)\n\t\t\treturn FALSE;\n\n\t\tm_bFound = ::FindNextFile(m_hFind, &m_fd);\n\n\t\treturn m_bFound;\n\t}\n\n\tvoid Close()\n\t{\n\t\tm_bFound = FALSE;\n\n\t\tif(m_hFind != NULL && m_hFind != INVALID_HANDLE_VALUE)\n\t\t{\n\t\t\t::FindClose(m_hFind);\n\t\t\tm_hFind = NULL;\n\t\t}\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global functions for stock GDI objects\n\ninline HPEN AtlGetStockPen(int nPen)\n{\n#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)\n\tATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN || nPen == DC_PEN);\n#else\n\tATLASSERT(nPen == WHITE_PEN || nPen == BLACK_PEN || nPen == NULL_PEN);\n#endif\n\treturn (HPEN)::GetStockObject(nPen);\n}\n\ninline HBRUSH AtlGetStockBrush(int nBrush)\n{\n#if (_WIN32_WINNT >= 0x0500) && !defined(_WIN32_WCE)\n\tATLASSERT((nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH) || nBrush == DC_BRUSH);\n#else\n\tATLASSERT(nBrush >= WHITE_BRUSH && nBrush <= HOLLOW_BRUSH);\n#endif\n\treturn (HBRUSH)::GetStockObject(nBrush);\n}\n\ninline HFONT AtlGetStockFont(int nFont)\n{\n#ifndef _WIN32_WCE\n\tATLASSERT((nFont >= OEM_FIXED_FONT && nFont <= SYSTEM_FIXED_FONT) || nFont == DEFAULT_GUI_FONT);\n#else // CE specific\n\tATLASSERT(nFont == SYSTEM_FONT);\n#endif // _WIN32_WCE\n\treturn (HFONT)::GetStockObject(nFont);\n}\n\ninline HPALETTE AtlGetStockPalette(int nPalette)\n{\n\tATLASSERT(nPalette == DEFAULT_PALETTE); // the only one supported\n\treturn (HPALETTE)::GetStockObject(nPalette);\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global function for compacting a path by replacing parts with ellipsis\n\n// helper for multi-byte character sets\ninline bool _IsDBCSTrailByte(LPCTSTR lpstr, int nChar)\n{\n#ifndef _UNICODE\n\tint i = nChar;\n\tfor( ; i > 0; i--)\n\t{\n\t\tif(!::IsDBCSLeadByte(lpstr[i - 1]))\n\t\t\tbreak;\n\t}\n\treturn ((nChar > 0) && (((nChar - i) & 1) != 0));\n#else // _UNICODE\n\tlpstr; nChar;\n\treturn false;\n#endif // _UNICODE\n}\n\ninline bool AtlCompactPath(LPTSTR lpstrOut, LPCTSTR lpstrIn, int cchLen)\n{\n\tATLASSERT(lpstrOut != NULL);\n\tATLASSERT(lpstrIn != NULL);\n\tATLASSERT(cchLen > 0);\n\n\tLPCTSTR szEllipsis = _T(\"...\");\n\tconst int cchEndEllipsis = 3;\n\tconst int cchMidEllipsis = 4;\n\n\tif(lstrlen(lpstrIn) < cchLen)\n\t{\n\t\tSecureHelper::strcpy_x(lpstrOut, cchLen, lpstrIn);\n\t\treturn true;\n\t}\n\n\tlpstrOut[0] = 0;\n\n\t// check if the separator is a slash or a backslash\n\tTCHAR chSlash = _T('\\\\');\n\tfor(LPTSTR lpstr = (LPTSTR)lpstrIn; *lpstr != 0; lpstr = ::CharNext(lpstr))\n\t{\n\t\tif((*lpstr == _T('/')) || (*lpstr == _T('\\\\')))\n\t\t\tchSlash = *lpstr;\n\t}\n\n\t// find the filename portion of the path\n\tLPCTSTR lpstrFileName = lpstrIn;\n\tfor(LPCTSTR pPath = lpstrIn; *pPath; pPath = ::CharNext(pPath))\n\t{\n\t\tif((pPath[0] == _T('\\\\') || pPath[0] == _T(':') || pPath[0] == _T('/'))\n\t\t\t\t&& pPath[1] && pPath[1] != _T('\\\\') && pPath[1] != _T('/'))\n\t\t\tlpstrFileName = pPath + 1;\n\t}\n\tint cchFileName = lstrlen(lpstrFileName);\n\n\t// handle just the filename without a path\n\tif(lpstrFileName == lpstrIn && cchLen > cchEndEllipsis)\n\t{\n\t\tbool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchLen - cchEndEllipsis - 1) == 0);\n\t\tif(bRet)\n\t\t{\n#ifndef _UNICODE\n\t\t\tif(_IsDBCSTrailByte(lpstrIn, cchLen - cchEndEllipsis))\n\t\t\t\tlpstrOut[cchLen - cchEndEllipsis - 1] = 0;\n#endif // _UNICODE\n\t\t\tSecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);\n\t\t}\n\t\treturn bRet;\n\t}\n\n\t// handle just ellipsis\n\tif((cchLen < (cchMidEllipsis + cchEndEllipsis)))\n\t{\n\t\tfor(int i = 0; i < cchLen - 1; i++)\n\t\t\tlpstrOut[i] = ((i + 1) == cchMidEllipsis) ? chSlash : _T('.');\n\t\tlpstrOut[cchLen - 1] = 0;\n\t\treturn true;\n\t}\n\n\t// calc how much we have to copy\n\tint cchToCopy = cchLen - (cchMidEllipsis + cchFileName) - 1;\n\n\tif(cchToCopy < 0)\n\t\tcchToCopy = 0;\n\n#ifndef _UNICODE\n\tif(cchToCopy > 0 && _IsDBCSTrailByte(lpstrIn, cchToCopy))\n\t\tcchToCopy--;\n#endif // _UNICODE\n\n\tbool bRet = (SecureHelper::strncpy_x(lpstrOut, cchLen, lpstrIn, cchToCopy) == 0);\n\tif(!bRet)\n\t\treturn false;\n\n\t// add ellipsis\n\tSecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);\n\tTCHAR szSlash[2] = { chSlash, 0 };\n\tSecureHelper::strcat_x(lpstrOut, cchLen, szSlash);\n\n\t// add filename (and ellipsis, if needed)\n\tif(cchLen > (cchMidEllipsis + cchFileName))\n\t{\n\t\tSecureHelper::strcat_x(lpstrOut, cchLen, lpstrFileName);\n\t}\n\telse\n\t{\n\t\tcchToCopy = cchLen - cchMidEllipsis - cchEndEllipsis - 1;\n#ifndef _UNICODE\n\t\tif(cchToCopy > 0 && _IsDBCSTrailByte(lpstrFileName, cchToCopy))\n\t\t\tcchToCopy--;\n#endif // _UNICODE\n\t\tbRet = (SecureHelper::strncpy_x(&lpstrOut[cchMidEllipsis], cchLen - cchMidEllipsis, lpstrFileName, cchToCopy) == 0);\n\t\tif(bRet)\n\t\t\tSecureHelper::strcat_x(lpstrOut, cchLen, szEllipsis);\n\t}\n\n\treturn bRet;\n}\n\n}; // namespace WTL\n\n#endif // __ATLMISC_H__\n"
  },
  {
    "path": "WTL/atlprint.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLPRINT_H__\n#define __ATLPRINT_H__\n\n#pragma once\n\n#ifdef _WIN32_WCE\n\t#error atlprint.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLAPP_H__\n\t#error atlprint.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlprint.h requires atlwin.h to be included first\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CPrinterInfo<t_nInfo>\n// CPrinterT<t_bManaged>\n// CDevModeT<t_bManaged>\n// CPrinterDC\n// CPrintJobInfo\n// CPrintJob\n// CPrintPreview\n// CPrintPreviewWindowImpl<T, TBase, TWinTraits>\n// CPrintPreviewWindow\n// CZoomPrintPreviewWindowImpl<T, TBase, TWinTraits>\n// CZoomPrintPreviewWindow\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures\n//                and provided by ::GetPrinter.\n\ntemplate <unsigned int t_nInfo>\nclass _printer_info\n{\npublic:\n\ttypedef void infotype;\n};\n\ntemplate <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; };\ntemplate <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; };\ntemplate <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; };\ntemplate <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; };\ntemplate <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; };\ntemplate <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; };\ntemplate <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; };\n// these are not in the old (vc6.0) headers\n#ifdef _ATL_USE_NEW_PRINTER_INFO\ntemplate <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; };\ntemplate <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; };\n#endif // _ATL_USE_NEW_PRINTER_INFO\n\n\ntemplate <unsigned int t_nInfo>\nclass CPrinterInfo\n{\npublic:\n// Data members\n\ttypename _printer_info<t_nInfo>::infotype* m_pi;\n\n// Constructor/destructor\n\tCPrinterInfo() : m_pi(NULL)\n\t{ }\n\n\tCPrinterInfo(HANDLE hPrinter) : m_pi(NULL)\n\t{\n\t\tGetPrinterInfo(hPrinter);\n\t}\n\n\t~CPrinterInfo()\n\t{\n\t\tCleanup();\n\t}\n\n// Operations\n\tbool GetPrinterInfo(HANDLE hPrinter)\n\t{\n\t\tCleanup();\n\t\treturn GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);\n\t}\n\n// Implementation\n\tvoid Cleanup()\n\t{\n\t\tdelete [] (BYTE*)m_pi;\n\t\tm_pi = NULL;\n\t}\n\n\tstatic bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex)\n\t{\n\t\tATLASSERT(pi != NULL);\n\t\tDWORD dw = 0;\n\t\tBYTE* pb = NULL;\n\t\t::GetPrinter(hPrinter, nIndex, NULL, 0, &dw);\n\t\tif (dw > 0)\n\t\t{\n\t\t\tATLTRY(pb = new BYTE[dw]);\n\t\t\tif (pb != NULL)\n\t\t\t{\n\t\t\t\tmemset(pb, 0, dw);\n\t\t\t\tDWORD dwNew;\n\t\t\t\tif (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew))\n\t\t\t\t{\n\t\t\t\t\tdelete [] pb;\n\t\t\t\t\tpb = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t*pi = pb;\n\t\treturn (pb != NULL);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrinter - Wrapper class for a HANDLE to a printer\n\ntemplate <bool t_bManaged>\nclass CPrinterT\n{\npublic:\n// Data members\n\tHANDLE m_hPrinter;\n\n// Constructor/destructor\n\tCPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)\n\t{ }\n\n\t~CPrinterT()\n\t{\n\t\tClosePrinter();\n\t}\n\n// Operations\n\tCPrinterT& operator =(HANDLE hPrinter)\n\t{\n\t\tif (hPrinter != m_hPrinter)\n\t\t{\n\t\t\tClosePrinter();\n\t\t\tm_hPrinter = hPrinter;\n\t\t}\n\t\treturn *this;\n\t}\n\n\tbool IsNull() const { return (m_hPrinter == NULL); }\n\n\tbool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL)\n\t{\n\t\tbool b = false;\n\t\tDEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames);\n\t\tif (pdn != NULL)\n\t\t{\n\t\t\tLPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset;\n\t\t\tb = OpenPrinter(lpszPrinterName, pDevMode);\n\t\t\t::GlobalUnlock(hDevNames);\n\t\t}\n\t\treturn b;\n\t}\n\n\tbool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL)\n\t{\n\t\tClosePrinter();\n\t\tPRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };\n\t\t::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);\n\n\t\treturn (m_hPrinter != NULL);\n\t}\n\n\tbool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs)\n\t{\n\t\tClosePrinter();\n\t\t::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs);\n\t\treturn (m_hPrinter != NULL);\n\t}\n\n\tbool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL)\n\t{\n\t\tClosePrinter();\n\t\tconst int cchBuff = 512;\n\t\tTCHAR buffer[cchBuff] = { 0 };\n\t\t::GetProfileString(_T(\"windows\"), _T(\"device\"), _T(\",,,\"), buffer, cchBuff);\n\t\tint nLen = lstrlen(buffer);\n\t\tif (nLen != 0)\n\t\t{\n\t\t\tLPTSTR lpsz = buffer;\n\t\t\twhile (*lpsz)\n\t\t\t{\n\t\t\t\tif (*lpsz == _T(','))\n\t\t\t\t{\n\t\t\t\t\t*lpsz = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlpsz = CharNext(lpsz);\n\t\t\t}\n\t\t\tPRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };\n\t\t\t::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);\n\t\t}\n\t\treturn m_hPrinter != NULL;\n\t}\n\n\tvoid ClosePrinter()\n\t{\n\t\tif (m_hPrinter != NULL)\n\t\t{\n\t\t\tif (t_bManaged)\n\t\t\t\t::ClosePrinter(m_hPrinter);\n\t\t\tm_hPrinter = NULL;\n\t\t}\n\t}\n\n\tbool PrinterProperties(HWND hWnd = NULL)\n\t{\n\t\tif (hWnd == NULL)\n\t\t\thWnd = ::GetActiveWindow();\n\t\treturn !!::PrinterProperties(hWnd, m_hPrinter);\n\t}\n\n\tHANDLE CopyToHDEVNAMES() const\n\t{\n\t\tHANDLE h = NULL;\n\t\tCPrinterInfo<5> pinfon5;\n\t\tCPrinterInfo<2> pinfon2;\n\t\tLPTSTR lpszPrinterName = NULL;\n\t\t// Some printers fail for PRINTER_INFO_5 in some situations\n\t\tif (pinfon5.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfon5.m_pi->pPrinterName;\n\t\telse if (pinfon2.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfon2.m_pi->pPrinterName;\n\t\tif (lpszPrinterName != NULL)\n\t\t{\n\t\t\tint nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR);\n\t\t\th = ::GlobalAlloc(GMEM_MOVEABLE, nLen);\n\t\t\tBYTE* pv = (BYTE*)::GlobalLock(h);\n\t\t\tDEVNAMES* pdev = (DEVNAMES*)pv;\n\t\t\tif (pv != NULL)\n\t\t\t{\n\t\t\t\tmemset(pv, 0, nLen);\n\t\t\t\tpdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR);\n\t\t\t\tpv = pv + sizeof(DEVNAMES); // now points to end\n\t\t\t\tSecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName);\n\t\t\t\t::GlobalUnlock(h);\n\t\t\t}\n\t\t}\n\t\treturn h;\n\t}\n\n\tHDC CreatePrinterDC(const DEVMODE* pdm = NULL) const\n\t{\n\t\tCPrinterInfo<5> pinfo5;\n\t\tCPrinterInfo<2> pinfo2;\n\t\tHDC hDC = NULL;\n\t\tLPTSTR lpszPrinterName = NULL;\n\t\t// Some printers fail for PRINTER_INFO_5 in some situations\n\t\tif (pinfo5.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfo5.m_pi->pPrinterName;\n\t\telse if (pinfo2.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfo2.m_pi->pPrinterName;\n\t\tif (lpszPrinterName != NULL)\n\t\t\thDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm);\n\t\treturn hDC;\n\t}\n\n\tHDC CreatePrinterIC(const DEVMODE* pdm = NULL) const\n\t{\n\t\tCPrinterInfo<5> pinfo5;\n\t\tCPrinterInfo<2> pinfo2;\n\t\tHDC hDC = NULL;\n\t\tLPTSTR lpszPrinterName = NULL;\n\t\t// Some printers fail for PRINTER_INFO_5 in some situations\n\t\tif (pinfo5.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfo5.m_pi->pPrinterName;\n\t\telse if (pinfo2.GetPrinterInfo(m_hPrinter))\n\t\t\tlpszPrinterName = pinfo2.m_pi->pPrinterName;\n\t\tif (lpszPrinterName != NULL)\n\t\t\thDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm);\n\t\treturn hDC;\n\t}\n\n\tvoid Attach(HANDLE hPrinter)\n\t{\n\t\tClosePrinter();\n\t\tm_hPrinter = hPrinter;\n\t}\n\n\tHANDLE Detach()\n\t{\n\t\tHANDLE hPrinter = m_hPrinter;\n\t\tm_hPrinter = NULL;\n\t\treturn hPrinter;\n\t}\n\n\toperator HANDLE() const { return m_hPrinter; }\n};\n\ntypedef CPrinterT<false>   CPrinterHandle;\ntypedef CPrinterT<true>    CPrinter;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CDevMode - Wrapper class for DEVMODE\n\ntemplate <bool t_bManaged>\nclass CDevModeT\n{\npublic:\n// Data members\n\tHANDLE m_hDevMode;\n\tDEVMODE* m_pDevMode;\n\n// Constructor/destructor\n\tCDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode)\n\t{\n\t\tm_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;\n\t}\n\n\t~CDevModeT()\n\t{\n\t\tCleanup();\n\t}\n\n// Operations\n\tCDevModeT<t_bManaged>& operator =(HANDLE hDevMode)\n\t{\n\t\tAttach(hDevMode);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HANDLE hDevModeNew)\n\t{\n\t\tCleanup();\n\t\tm_hDevMode = hDevModeNew;\n\t\tm_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;\n\t}\n\n\tHANDLE Detach()\n\t{\n\t\tif (m_hDevMode != NULL)\n\t\t\t::GlobalUnlock(m_hDevMode);\n\t\tHANDLE hDevMode = m_hDevMode;\n\t\tm_hDevMode = NULL;\n\t\treturn hDevMode;\n\t}\n\n\tbool IsNull() const { return (m_hDevMode == NULL); }\n\n\tbool CopyFromPrinter(HANDLE hPrinter)\n\t{\n\t\tCPrinterInfo<2> pinfo;\n\t\tbool b = pinfo.GetPrinterInfo(hPrinter);\n\t\tif (b)\n\t\t b = CopyFromDEVMODE(pinfo.m_pi->pDevMode);\n\t\treturn b;\n\t}\n\n\tbool CopyFromDEVMODE(const DEVMODE* pdm)\n\t{\n\t\tif (pdm == NULL)\n\t\t\treturn false;\n\t\tint nSize = pdm->dmSize + pdm->dmDriverExtra;\n\t\tHANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);\n\t\tif (h != NULL)\n\t\t{\n\t\t\tvoid* p = ::GlobalLock(h);\n\t\t\tSecureHelper::memcpy_x(p, nSize, pdm, nSize);\n\t\t\t::GlobalUnlock(h);\n\t\t}\n\t\tAttach(h);\n\t\treturn (h != NULL);\n\t}\n\n\tbool CopyFromHDEVMODE(HANDLE hdm)\n\t{\n\t\tbool b = false;\n\t\tif (hdm != NULL)\n\t\t{\n\t\t\tDEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm);\n\t\t\tb = CopyFromDEVMODE(pdm);\n\t\t\t::GlobalUnlock(hdm);\n\t\t}\n\t\treturn b;\n\t}\n\n\tHANDLE CopyToHDEVMODE()\n\t{\n\t\tif ((m_hDevMode == NULL) || (m_pDevMode == NULL))\n\t\t\treturn NULL;\n\t\tint nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra;\n\t\tHANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);\n\t\tif (h != NULL)\n\t\t{\n\t\t\tvoid* p = ::GlobalLock(h);\n\t\t\tSecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize);\n\t\t\t::GlobalUnlock(h);\n\t\t}\n\t\treturn h;\n\t}\n\n\t// If this devmode was for another printer, this will create a new devmode\n\t// based on the existing devmode, but retargeted at the new printer\n\tbool UpdateForNewPrinter(HANDLE hPrinter)\n\t{\n\t\tbool bRet = false;\n\t\tLONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0);\n\t\tCTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tDEVMODE* pdm = buff.AllocateBytes(nLen);\n\t\tif(pdm != NULL)\n\t\t{\n\t\t\tmemset(pdm, 0, nLen);\n\t\t\tLONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);\n\t\t\tif (l == IDOK)\n\t\t\t\tbRet = CopyFromDEVMODE(pdm);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tbool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL)\n\t{\n\t\tCPrinterInfo<1> pi;\n\t\tpi.GetPrinterInfo(hPrinter);\n\t\tif (hWnd == NULL)\n\t\t\thWnd = ::GetActiveWindow();\n\n\t\tbool bRet = false;\n\t\tLONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0);\n\t\tCTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tDEVMODE* pdm = buff.AllocateBytes(nLen);\n\t\tif(pdm != NULL)\n\t\t{\n\t\t\tmemset(pdm, 0, nLen);\n\t\t\tLONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT);\n\t\t\tif (l == IDOK)\n\t\t\t\tbRet = CopyFromDEVMODE(pdm);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\toperator HANDLE() const { return m_hDevMode; }\n\n\toperator DEVMODE*() const { return m_pDevMode; }\n\n// Implementation\n\tvoid Cleanup()\n\t{\n\t\tif (m_hDevMode != NULL)\n\t\t{\n\t\t\t::GlobalUnlock(m_hDevMode);\n\t\t\tif(t_bManaged)\n\t\t\t\t::GlobalFree(m_hDevMode);\n\t\t\tm_hDevMode = NULL;\n\t\t}\n\t}\n};\n\ntypedef CDevModeT<false>   CDevModeHandle;\ntypedef CDevModeT<true>    CDevMode;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrinterDC\n\nclass CPrinterDC : public CDC\n{\npublic:\n// Constructors/destructor\n\tCPrinterDC()\n\t{\n\t\tCPrinter printer;\n\t\tprinter.OpenDefaultPrinter();\n\t\tAttach(printer.CreatePrinterDC());\n\t\tATLASSERT(m_hDC != NULL);\n\t}\n\n\tCPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL)\n\t{\n\t\tCPrinterHandle p;\n\t\tp.Attach(hPrinter);\n\t\tAttach(p.CreatePrinterDC(pdm));\n\t\tATLASSERT(m_hDC != NULL);\n\t}\n\n\t~CPrinterDC()\n\t{\n\t\tDeleteDC();\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc)\n//             Handles aborting, background printing\n\n// Defines callbacks used by CPrintJob (not a COM interface)\nclass ATL_NO_VTABLE IPrintJobInfo\n{\npublic:\n\tvirtual void BeginPrintJob(HDC hDC) = 0;                // allocate handles needed, etc.\n\tvirtual void EndPrintJob(HDC hDC, bool bAborted) = 0;   // free handles, etc.\n\tvirtual void PrePrintPage(UINT nPage, HDC hDC) = 0;\n\tvirtual bool PrintPage(UINT nPage, HDC hDC) = 0;\n\tvirtual void PostPrintPage(UINT nPage, HDC hDC) = 0;\n\t// If you want per page devmodes, return the DEVMODE* to use for nPage.\n\t// You can optimize by only returning a new DEVMODE* when it is different\n\t// from the one for nLastPage, otherwise return NULL.\n\t// When nLastPage==0, the current DEVMODE* will be the default passed to\n\t// StartPrintJob.\n\t// Note: During print preview, nLastPage will always be \"0\".\n\tvirtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0;\n\tvirtual bool IsValidPage(UINT nPage) = 0;\n};\n\n// Provides a default implementatin for IPrintJobInfo\n// Typically, MI'd into a document or view class\nclass ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo\n{\npublic:\n\tvirtual void BeginPrintJob(HDC /*hDC*/)   // allocate handles needed, etc\n\t{\n\t}\n\n\tvirtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/)   // free handles, etc\n\t{\n\t}\n\n\tvirtual void PrePrintPage(UINT /*nPage*/, HDC hDC)\n\t{\n\t\tm_nPJState = ::SaveDC(hDC);\n\t}\n\n\tvirtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0;\n\n\tvirtual void PostPrintPage(UINT /*nPage*/, HDC hDC)\n\t{\n\t\tRestoreDC(hDC, m_nPJState);\n\t}\n\n\tvirtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)\n\t{\n\t\treturn NULL;\n\t}\n\n\tvirtual bool IsValidPage(UINT /*nPage*/)\n\t{\n\t\treturn true;\n\t}\n\n// Implementation - data\n\tint m_nPJState;\n};\n\n\nclass CPrintJob\n{\npublic:\n// Data members\n\tCPrinterHandle m_printer;\n\tIPrintJobInfo* m_pInfo;\n\tDEVMODE* m_pDefDevMode;\n\tDOCINFO m_docinfo;\n\tint m_nJobID;\n\tbool m_bCancel;\n\tbool m_bComplete;\n\tunsigned long m_nStartPage;\n\tunsigned long m_nEndPage;\n\n// Constructor/destructor\n\tCPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true)\n\t{ }\n\n\t~CPrintJob()\n\t{\n\t\tATLASSERT(IsJobComplete()); // premature destruction?\n\t}\n\n// Operations\n\tbool IsJobComplete() const\n\t{\n\t\treturn m_bComplete;\n\t}\n\n\tbool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode,\n\t\t\tIPrintJobInfo* pInfo, LPCTSTR lpszDocName, \n\t\t\tunsigned long nStartPage, unsigned long nEndPage,\n\t\t\tbool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL)\n\t{\n\t\tATLASSERT(m_bComplete); // previous job not done yet?\n\t\tif (pInfo == NULL)\n\t\t\treturn false;\n\n\t\tmemset(&m_docinfo, 0, sizeof(m_docinfo));\n\t\tm_docinfo.cbSize = sizeof(m_docinfo);\n\t\tm_docinfo.lpszDocName = lpszDocName;\n\t\tm_pInfo = pInfo;\n\t\tm_nStartPage = nStartPage;\n\t\tm_nEndPage = nEndPage;\n\t\tm_printer.Attach(hPrinter);\n\t\tm_pDefDevMode = pDefaultDevMode;\n\t\tm_bComplete = false;\n\n\t\tif(bPrintToFile)\n\t\t\tm_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T(\"FILE:\");\n\n\t\tif (!bBackground)\n\t\t{\n\t\t\tm_bComplete = true;\n\t\t\treturn StartHelper();\n\t\t}\n\n\t\t// Create a thread and return\n\t\tDWORD dwThreadID = 0;\n#if !defined(_ATL_MIN_CRT) && defined(_MT)\n\t\tHANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID);\n#else\n\t\tHANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID);\n#endif\n\t\tif (hThread == NULL)\n\t\t\treturn false;\n\n\t\t::CloseHandle(hThread);\n\n\t\treturn true;\n\t}\n\n// Implementation\n\tstatic DWORD WINAPI StartProc(void* p)\n\t{\n\t\tCPrintJob* pThis = (CPrintJob*)p;\n\t\tpThis->StartHelper();\n\t\tpThis->m_bComplete = true;\n\t\treturn 0;\n\t}\n\n\tbool StartHelper()\n\t{\n\t\tCDC dcPrinter;\n\t\tdcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode));\n\t\tif (dcPrinter.IsNull())\n\t\t\treturn false;\n\t\t\t\n\t\tm_nJobID = ::StartDoc(dcPrinter, &m_docinfo);\n\t\tif (m_nJobID <= 0)\n\t\t\treturn false;\n\n\t\tm_pInfo->BeginPrintJob(dcPrinter);\n\n\t\t// print all the pages now\n\t\tunsigned long nLastPage = 0;\n\t\tfor (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++)\n\t\t{\n\t\t\tif (!m_pInfo->IsValidPage(nPage))\n\t\t\t\tbreak;\n\t\t\tDEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage);\n\t\t\tif (pdm != NULL)\n\t\t\t\tdcPrinter.ResetDC(pdm);\n\t\t\tdcPrinter.StartPage();\n\t\t\tm_pInfo->PrePrintPage(nPage, dcPrinter);\n\t\t\tif (!m_pInfo->PrintPage(nPage, dcPrinter))\n\t\t\t\tm_bCancel = true;\n\t\t\tm_pInfo->PostPrintPage(nPage, dcPrinter);\n\t\t\tdcPrinter.EndPage();\n\t\t\tif (m_bCancel)\n\t\t\t\tbreak;\n\t\t\tnLastPage = nPage;\n\t\t}\n\n\t\tm_pInfo->EndPrintJob(dcPrinter, m_bCancel);\n\t\tif (m_bCancel)\n\t\t\t::AbortDoc(dcPrinter);\n\t\telse\n\t\t\t::EndDoc(dcPrinter);\n\t\tm_nJobID = 0;\n\t\treturn true;\n\t}\n\n\t// Cancels a print job. Can be called asynchronously.\n\tvoid CancelPrintJob()\n\t{\n\t\tm_bCancel = true;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrintPreview - Adds print preview support to an existing window\n\nclass CPrintPreview\n{\npublic:\n// Data members\n\tIPrintJobInfo* m_pInfo;\n\tCPrinterHandle m_printer;\n\tCEnhMetaFile m_meta;\n\tDEVMODE* m_pDefDevMode;\n\tDEVMODE* m_pCurDevMode;\n\tSIZE m_sizeCurPhysOffset;\n\n// Constructor\n\tCPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL)\n\t{\n\t\tm_sizeCurPhysOffset.cx = 0;\n\t\tm_sizeCurPhysOffset.cy = 0;\n\t}\n\n// Operations\n\tvoid SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji)\n\t{\n\t\tm_printer.Attach(hPrinter);\n\t\tm_pDefDevMode = pDefaultDevMode;\n\t\tm_pInfo = pji;\n\t\tm_nCurPage = 0;\n\t\tm_pCurDevMode = NULL;\n\t}\n\n\tvoid SetEnhMetaFile(HENHMETAFILE hEMF)\n\t{\n\t\tm_meta = hEMF;\n\t}\n\n\tvoid SetPage(int nPage)\n\t{\n\t\tif (!m_pInfo->IsValidPage(nPage))\n\t\t\treturn;\n\t\tm_nCurPage = nPage;\n\t\tm_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage);\n\t\tif (m_pCurDevMode == NULL)\n\t\t\tm_pCurDevMode = m_pDefDevMode;\n\t\tCDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode);\n\n\t\tint iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); \n\t\tint iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); \n\t\tint nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX);\n\t\tint nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY);\n\n\t\tRECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) };\n\n\t\tm_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX);\n\t\tm_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY);\n\t\t\n\t\tCEnhMetaFileDC dcMeta(dcPrinter, &rcMM);\n\t\tm_pInfo->PrePrintPage(nPage, dcMeta);\n\t\tm_pInfo->PrintPage(nPage, dcMeta);\n\t\tm_pInfo->PostPrintPage(nPage, dcMeta);\n\t\tm_meta.Attach(dcMeta.Close());\n\t}\n\n\tvoid GetPageRect(RECT& rc, LPRECT prc)\n\t{\n\t\tint x1 = rc.right-rc.left;\n\t\tint y1 = rc.bottom - rc.top;\n\t\tif ((x1 < 0) || (y1 < 0))\n\t\t\treturn;\n\n\t\tCEnhMetaFileInfo emfinfo(m_meta);\n\t\tENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();\n\n\t\t// Compute whether we are OK vertically or horizontally\n\t\tint x2 = pmh->szlDevice.cx;\n\t\tint y2 = pmh->szlDevice.cy;\n\t\tint y1p = MulDiv(x1, y2, x2);\n\t\tint x1p = MulDiv(y1, x2, y2);\n\t\tATLASSERT((x1p <= x1) || (y1p <= y1));\n\t\tif (x1p <= x1)\n\t\t{\n\t\t\tprc->left = rc.left + (x1 - x1p) / 2;\n\t\t\tprc->right = prc->left + x1p;\n\t\t\tprc->top = rc.top;\n\t\t\tprc->bottom = rc.bottom;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprc->left = rc.left;\n\t\t\tprc->right = rc.right;\n\t\t\tprc->top = rc.top + (y1 - y1p) / 2;\n\t\t\tprc->bottom = prc->top + y1p;\n\t\t}\n\t}\n\n// Painting helpers\n\tvoid DoPaint(CDCHandle dc)\n\t{\n\t\t// this one is not used\n\t}\n\n\tvoid DoPaint(CDCHandle dc, RECT& rc)\n\t{\n\t\tCEnhMetaFileInfo emfinfo(m_meta);\n\t\tENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();\n\t\tint nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);\n\t\tint nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);\n\n\t\tdc.OffsetWindowOrg(-nOffsetX, -nOffsetY);\n\t\tdc.PlayMetaFile(m_meta, &rc);\n\t}\n\n// Implementation - data\n\tint m_nCurPage;\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CPrintPreviewWindow - Implements a print preview window\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CPrintPreview\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1)\n\n\tenum { m_cxOffset = 10, m_cyOffset = 10 };\n\n// Constructor\n\tCPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0)\n\t{ }\n\n// Operations\n\tvoid SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, \n\t\tIPrintJobInfo* pji, int nMinPage, int nMaxPage)\n\t{\n\t\tCPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji);\n\t\tm_nMinPage = nMinPage;\n\t\tm_nMaxPage = nMaxPage;\n\t}\n\n\tbool NextPage()\n\t{\n\t\tif (m_nCurPage == m_nMaxPage)\n\t\t\treturn false;\n\t\tSetPage(m_nCurPage + 1);\n\t\tInvalidate();\n\t\treturn true;\n\t}\n\n\tbool PrevPage()\n\t{\n\t\tif (m_nCurPage == m_nMinPage)\n\t\t\treturn false;\n\t\tif (m_nCurPage == 0)\n\t\t\treturn false;\n\t\tSetPage(m_nCurPage - 1);\n\t\tInvalidate();\n\t\treturn true;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CPrintPreviewWindowImpl)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no need for the background\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rc = { 0 };\n\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tpT->DoPrePaint((HDC)wParam, rc);\n\t\t\tpT->DoPaint((HDC)wParam, rc);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(m_hWnd);\n\t\t\tpT->DoPrePaint(dc.m_hDC, rc);\n\t\t\tpT->DoPaint(dc.m_hDC, rc);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n// Painting helper\n\tvoid DoPrePaint(CDCHandle dc, RECT& rc)\n\t{\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tRECT rcArea = rcClient;\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\t::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);\n\t\tif (rcArea.left > rcArea.right)\n\t\t\trcArea.right = rcArea.left;\n\t\tif (rcArea.top > rcArea.bottom)\n\t\t\trcArea.bottom = rcArea.top;\n\t\tGetPageRect(rcArea, &rc);\n\t\tCRgn rgn1, rgn2;\n\t\trgn1.CreateRectRgnIndirect(&rc);\n\t\trgn2.CreateRectRgnIndirect(&rcClient);\n\t\trgn2.CombineRgn(rgn1, RGN_DIFF);\n\t\tdc.SelectClipRgn(rgn2);\n\t\tdc.FillRect(&rcClient, COLOR_BTNSHADOW);\n\t\tdc.SelectClipRgn(NULL);\n\t\tdc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH));\n\t}\n\n// Implementation - data\n\tint m_nMinPage;\n\tint m_nMaxPage;\n};\n\n\nclass CPrintPreviewWindow : public CPrintPreviewWindowImpl<CPrintPreviewWindow>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_PrintPreview\"), CS_VREDRAW | CS_HREDRAW, -1)\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CZoomPrintPreviewWindowImpl - Implements print preview window with zooming\n\n#ifdef __ATLSCRL_H__\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >\n{\npublic:\n\tbool m_bSized;\n\n\tCZoomPrintPreviewWindowImpl()  \n\t{\n\t\tSetScrollExtendedStyle(SCRL_DISABLENOSCROLL);\n\t\tInitZoom();\n\t}\n\n\t// should be called to reset data members before recreating window \n\tvoid InitZoom()\n\t{\n\t\tm_bSized = false;\t\n\t\tm_nZoomMode = ZOOMMODE_OFF;\n\t\tm_fZoomScaleMin = 1.0;\n\t\tm_fZoomScale = 1.0;\n\t}\n\n\tBEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl)\n\t\tMESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n\t\n\tLRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tSIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};\n\t\tPOINT ptOffset = m_ptOffset;\n\t\tSIZE sizeAll = m_sizeAll;\n\t\tSetScrollSize(sizeClient);\n\t\tif(sizeAll.cx > 0)\n\t\t\tptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx);\n\t\tif(sizeAll.cy > 0)\n\t\t\tptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy);\n\t\tSetScrollOffset(ptOffset);\n\t\tCScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled);\n\t\tif(!m_bSized)\n\t\t{\n\t\t\tm_bSized = true;\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->ShowScrollBar(SB_HORZ, TRUE);\n\t\t\tpT->ShowScrollBar(SB_VERT, TRUE);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rc = { 0 };\n\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tCDCHandle dc = (HDC)wParam;\n\t\t\tint nMapModeSav = dc.GetMapMode();\n\t\t\tdc.SetMapMode(MM_ANISOTROPIC);\n\t\t\tSIZE szWindowExt = { 0, 0 };\n\t\t\tdc.SetWindowExt(m_sizeLogAll, &szWindowExt);\n\t\t\tSIZE szViewportExt = { 0, 0 };\n\t\t\tdc.SetViewportExt(m_sizeAll, &szViewportExt);\n\t\t\tPOINT ptViewportOrg = { 0, 0 };\n\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\n\n\t\t\tpT->DoPrePaint(dc, rc);\n\t\t\tpT->DoPaint(dc, rc);\n\n\t\t\tdc.SetMapMode(nMapModeSav);\n\t\t\tdc.SetWindowExt(szWindowExt);\n\t\t\tdc.SetViewportExt(szViewportExt);\n\t\t\tdc.SetViewportOrg(ptViewportOrg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tpT->PrepareDC(dc.m_hDC);\n\t\t\tpT->DoPrePaint(dc.m_hDC, rc);\n\t\t\tpT->DoPaint(dc.m_hDC, rc);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t// Painting helpers\n\tvoid DoPaint(CDCHandle dc)\n\t{\n\t\t// this one is not used\n\t}\n\n\tvoid DoPrePaint(CDCHandle dc, RECT& rc)\n\t{\n\t\tRECT rcClient = { 0 };\n\t\tGetClientRect(&rcClient);\n\t\tRECT rcArea = rcClient;\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\t::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);\n\t\tif (rcArea.left > rcArea.right)\n\t\t\trcArea.right = rcArea.left;\n\t\tif (rcArea.top > rcArea.bottom)\n\t\t\trcArea.bottom = rcArea.top;\n\t\tGetPageRect(rcArea, &rc);\n\t\tHBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));\n\t\tdc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY);\n\t\tdc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY);\n\t\tdc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY);\n\t\tdc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY);\n\t\tdc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH));\n\t\tdc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);\n\t\tdc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW));\n\t\tdc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY);\n\t\tdc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY);\n\t\tdc.SelectBrush(hbrOld);\n\t}\n\n\tvoid DoPaint(CDCHandle dc, RECT& rc)\n\t{\n\t\tCEnhMetaFileInfo emfinfo(m_meta);\n\t\tENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();\n\t\tint nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);\n\t\tint nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);\n\n\t\tdc.OffsetWindowOrg(-nOffsetX, -nOffsetY);\n\t\tdc.PlayMetaFile(m_meta, &rc);\n\t}\n};\n\nclass CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl<CZoomPrintPreviewWindow>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_ZoomPrintPreview\"), CS_VREDRAW | CS_HREDRAW, -1)\n};\n\n#endif // __ATLSCRL_H__\n\n}; // namespace WTL\n\n#endif // __ATLPRINT_H__\n"
  },
  {
    "path": "WTL/atlres.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLRES_H__\n#define __ATLRES_H__\n\n#pragma once\n\n#if defined(_WIN32_WCE) && !defined(__ATLRESCE_H__)\n\t#error Use atlresCE.h instead of atlres.h for Windows CE\n#endif\n\n\n#ifdef RC_INVOKED\n#ifndef _INC_WINDOWS\n\n  #define _INC_WINDOWS\n\n  #ifndef _WIN32_WCE\n    #define VS_VERSION_INFO     1\n\n    #ifdef APSTUDIO_INVOKED\n      #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols\n    #endif // APSTUDIO_INVOKED\n\n    #ifndef WINVER\n      #define WINVER 0x0400   // default to Windows Version 4.0\n    #endif // !WINVER\n\n    #include <winresrc.h>\n\n    // operation messages sent to DLGINIT\n    #define LB_ADDSTRING    (WM_USER+1)\n    #define CB_ADDSTRING    (WM_USER+3)\n  #endif // !_WIN32_WCE\n\n  #ifdef APSTUDIO_INVOKED\n    #undef APSTUDIO_HIDDEN_SYMBOLS\n  #endif // APSTUDIO_INVOKED\n\n  #ifdef IDC_STATIC\n    #undef IDC_STATIC\n  #endif // IDC_STATIC\n  #define IDC_STATIC      (-1)\n\n#endif // !_INC_WINDOWS\n#endif // RC_INVOKED\n\n#ifdef APSTUDIO_INVOKED\n  #define APSTUDIO_HIDDEN_SYMBOLS\n#endif // APSTUDIO_INVOKED\n\n///////////////////////////////////////////////////////////////////////////////\n// ATL resource types\n\n#ifndef RC_INVOKED\n  #define RT_DLGINIT  MAKEINTRESOURCE(240)\n  #define RT_TOOLBAR  MAKEINTRESOURCE(241)\n#endif // RC_INVOKED\n\n///////////////////////////////////////////////////////////////////////////////\n\n#ifdef APSTUDIO_INVOKED\n  #undef APSTUDIO_HIDDEN_SYMBOLS\n#endif // APSTUDIO_INVOKED\n\n///////////////////////////////////////////////////////////////////////////////\n// Standard window components\n\n#define ID_SEPARATOR                    0       // special separator value\n#define ID_DEFAULT_PANE                 0       // default status bar pane\n\n#ifndef RC_INVOKED  // code only\n// standard control bars (IDW = window ID)\n  #define ATL_IDW_TOOLBAR               0xE800  // main Toolbar for window\n  #define ATL_IDW_STATUS_BAR            0xE801  // Status bar window\n  #define ATL_IDW_COMMAND_BAR           0xE802  // Command bar window\n\n// parts of a frame window\n  #define ATL_IDW_CLIENT                0xE900\n  #define ATL_IDW_PANE_FIRST            0xE900  // first pane (256 max)\n  #define ATL_IDW_PANE_LAST             0xE9FF\n  #define ATL_IDW_HSCROLL_FIRST         0xEA00  // first Horz scrollbar (16 max)\n  #define ATL_IDW_VSCROLL_FIRST         0xEA10  // first Vert scrollbar (16 max)\n\n  #define ATL_IDW_SIZE_BOX              0xEA20  // size box for splitters\n  #define ATL_IDW_PANE_SAVE             0xEA21  // to shift ATL_IDW_PANE_FIRST\n\n// bands for a rebar\n  #define ATL_IDW_BAND_FIRST            0xEB00\n  #define ATL_IDW_BAND_LAST             0xEBFF\n#endif // !RC_INVOKED\n\n///////////////////////////////////////////////////////////////////////////////\n// Standard Commands\n\n// File commands\n#define ID_FILE_NEW                     0xE100\n#define ID_FILE_OPEN                    0xE101\n#define ID_FILE_CLOSE                   0xE102\n#define ID_FILE_SAVE                    0xE103\n#define ID_FILE_SAVE_AS                 0xE104\n#define ID_FILE_PAGE_SETUP              0xE105\n#define ID_FILE_PRINT_SETUP             0xE106\n#define ID_FILE_PRINT                   0xE107\n#define ID_FILE_PRINT_DIRECT            0xE108\n#define ID_FILE_PRINT_PREVIEW           0xE109\n#define ID_FILE_UPDATE                  0xE10A\n#define ID_FILE_SAVE_COPY_AS            0xE10B\n#define ID_FILE_SEND_MAIL               0xE10C\n\n#define ID_FILE_MRU_FIRST               0xE110\n#define ID_FILE_MRU_FILE1               0xE110          // range - 16 max\n#define ID_FILE_MRU_FILE2               0xE111\n#define ID_FILE_MRU_FILE3               0xE112\n#define ID_FILE_MRU_FILE4               0xE113\n#define ID_FILE_MRU_FILE5               0xE114\n#define ID_FILE_MRU_FILE6               0xE115\n#define ID_FILE_MRU_FILE7               0xE116\n#define ID_FILE_MRU_FILE8               0xE117\n#define ID_FILE_MRU_FILE9               0xE118\n#define ID_FILE_MRU_FILE10              0xE119\n#define ID_FILE_MRU_FILE11              0xE11A\n#define ID_FILE_MRU_FILE12              0xE11B\n#define ID_FILE_MRU_FILE13              0xE11C\n#define ID_FILE_MRU_FILE14              0xE11D\n#define ID_FILE_MRU_FILE15              0xE11E\n#define ID_FILE_MRU_FILE16              0xE11F\n#define ID_FILE_MRU_LAST                0xE11F\n\n// Edit commands\n#define ID_EDIT_CLEAR                   0xE120\n#define ID_EDIT_CLEAR_ALL               0xE121\n#define ID_EDIT_COPY                    0xE122\n#define ID_EDIT_CUT                     0xE123\n#define ID_EDIT_FIND                    0xE124\n#define ID_EDIT_PASTE                   0xE125\n#define ID_EDIT_PASTE_LINK              0xE126\n#define ID_EDIT_PASTE_SPECIAL           0xE127\n#define ID_EDIT_REPEAT                  0xE128\n#define ID_EDIT_REPLACE                 0xE129\n#define ID_EDIT_SELECT_ALL              0xE12A\n#define ID_EDIT_UNDO                    0xE12B\n#define ID_EDIT_REDO                    0xE12C\n#define ID_EDIT_DELETE                  ID_EDIT_CLEAR\n#define ID_EDIT_FIND_NEXT               ID_EDIT_REPEAT\n#define ID_EDIT_FIND_PREVIOUS           0xE12D\n\n// Window commands\n#define ID_WINDOW_NEW                   0xE130\n#define ID_WINDOW_ARRANGE               0xE131\n#define ID_WINDOW_CASCADE               0xE132\n#define ID_WINDOW_TILE_HORZ             0xE133\n#define ID_WINDOW_TILE_VERT             0xE134\n#define ID_WINDOW_SPLIT                 0xE135\n#ifndef RC_INVOKED      // code only\n  #define ATL_IDM_WINDOW_FIRST          0xE130\n  #define ATL_IDM_WINDOW_LAST           0xE13F\n  #define ATL_IDM_FIRST_MDICHILD        0xFF00  // window list starts here\n  #define ATL_IDM_LAST_MDICHILD         0xFFFD\n#endif // !RC_INVOKED\n// TabView\n#define ID_WINDOW_TABFIRST              0xFF00\t// = ATL_IDM_FIRST_MDICHILD\n#define ID_WINDOW_TABLAST               0xFFFD\n#define ID_WINDOW_SHOWTABLIST           0xFFFE\n\n// Help and App commands\n#define ID_APP_ABOUT                    0xE140\n#define ID_APP_EXIT                     0xE141\n#define ID_HELP_INDEX                   0xE142\n#define ID_HELP_FINDER                  0xE143\n#define ID_HELP_USING                   0xE144\n#define ID_CONTEXT_HELP                 0xE145      // shift-F1\n// special commands for processing help\n#define ID_HELP                         0xE146      // first attempt for F1\n#define ID_DEFAULT_HELP                 0xE147      // last attempt\n\n// Misc\n#define ID_NEXT_PANE                    0xE150\n#define ID_PREV_PANE                    0xE151\n#define ID_PANE_CLOSE                   0xE152\n#define ID_PANE_NEXT                    ID_NEXT_PANE\n#define ID_PANE_PREVIOUS                ID_PREV_PANE\n\n// Format\n#define ID_FORMAT_FONT                  0xE160\n\n// Scroll\n#define ID_SCROLL_UP                    0xE170\n#define ID_SCROLL_DOWN                  0xE171\n#define ID_SCROLL_PAGE_UP               0xE172\n#define ID_SCROLL_PAGE_DOWN             0xE173\n#define ID_SCROLL_TOP                   0xE174\n#define ID_SCROLL_BOTTOM                0xE175\n#define ID_SCROLL_LEFT                  0xE176\n#define ID_SCROLL_RIGHT                 0xE177\n#define ID_SCROLL_PAGE_LEFT             0xE178\n#define ID_SCROLL_PAGE_RIGHT            0xE179\n#define ID_SCROLL_ALL_LEFT              0xE17A\n#define ID_SCROLL_ALL_RIGHT             0xE17B\n\n// OLE commands\n#define ID_OLE_INSERT_NEW               0xE200\n#define ID_OLE_EDIT_LINKS               0xE201\n#define ID_OLE_EDIT_CONVERT             0xE202\n#define ID_OLE_EDIT_CHANGE_ICON         0xE203\n#define ID_OLE_EDIT_PROPERTIES          0xE204\n#define ID_OLE_VERB_FIRST               0xE210     // range - 16 max\n#ifndef RC_INVOKED      // code only\n  #define ID_OLE_VERB_LAST              0xE21F\n#endif // !RC_INVOKED\n\n// View commands (same number used as IDW used for toolbar and status bar)\n#define ID_VIEW_TOOLBAR                 0xE800\n#define ID_VIEW_STATUS_BAR              0xE801\n#define ID_VIEW_REFRESH                 0xE803\n#define ID_VIEW_RIBBON                  0xE804\n\n///////////////////////////////////////////////////////////////////////////////\n// Standard control IDs\n\n#ifdef IDC_STATIC\n  #undef IDC_STATIC\n#endif // IDC_STATIC\n#define IDC_STATIC              (-1)     // all static controls\n\n///////////////////////////////////////////////////////////////////////////////\n// Standard string error/warnings\n\n// idle status bar message\n#define ATL_IDS_IDLEMESSAGE             0xE001\n\n#ifndef RC_INVOKED      // code only\n  #define ATL_IDS_SCFIRST               0xEF00\n#endif // !RC_INVOKED\n\n#define ATL_IDS_SCSIZE                  0xEF00\n#define ATL_IDS_SCMOVE                  0xEF01\n#define ATL_IDS_SCMINIMIZE              0xEF02\n#define ATL_IDS_SCMAXIMIZE              0xEF03\n#define ATL_IDS_SCNEXTWINDOW            0xEF04\n#define ATL_IDS_SCPREVWINDOW            0xEF05\n#define ATL_IDS_SCCLOSE                 0xEF06\n#define ATL_IDS_SCRESTORE               0xEF12\n#define ATL_IDS_SCTASKLIST              0xEF13\n\n#define ATL_IDS_MDICHILD                0xEF1F\n#define ATL_IDS_MRU_FILE                0xEFDA\n\n///////////////////////////////////////////////////////////////////////////////\n// Misc. control IDs\n\n// Property Sheet control id's (determined with Spy++)\n#define ID_APPLY_NOW                    0x3021\n#define ID_WIZBACK                      0x3023\n#define ID_WIZNEXT                      0x3024\n#define ID_WIZFINISH                    0x3025\n#define ATL_IDC_TAB_CONTROL             0x3020\n\n#endif // __ATLRES_H__\n"
  },
  {
    "path": "WTL/atlresce.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLRESCE_H__\n#define __ATLRESCE_H__\n\n#pragma once\n\n#ifndef _WIN32_WCE\n\t#error atlresCE.h is only for Windows CE\n#endif\n\n\n#ifdef RC_INVOKED\n#ifndef _INC_WINDOWS\n\n  #define VS_VERSION_INFO     1\n\n  #ifdef APSTUDIO_INVOKED\n    #define APSTUDIO_HIDDEN_SYMBOLS // Ignore following symbols\n  #endif // APSTUDIO_INVOKED\n\n  #ifndef WINVER\n    #define WINVER 0x0400   // default to Windows Version 4.0\n  #endif // !WINVER\n\n  #if !defined(WCEOLE_ENABLE_DIALOGEX)\n    #define DIALOGEX DIALOG DISCARDABLE\n  #endif\n\n  #include <commctrl.h>\n  #define  SHMENUBAR RCDATA\n\n  #if defined(SHELLSDK_MODULES_AYGSHELL)\n    #include <aygshell.h> \n  #else\n    #define NOMENU                 0xFFFF\n    #define IDS_SHNEW              1\n    #define IDM_SHAREDNEW          10\n    #define IDM_SHAREDNEWDEFAULT   11\n  #endif\n  #ifndef I_IMAGENONE\n\t#define I_IMAGENONE            (-2)\n  #endif\n\n  #include <windows.h>\n\n#endif // !_INC_WINDOWS\n#endif // RC_INVOKED\n\n#include \"atlres.h\"\n\n#ifdef APSTUDIO_INVOKED\n\t#undef APSTUDIO_HIDDEN_SYMBOLS\n#endif // APSTUDIO_INVOKED\n\n// Visual Studio dialog editor bug fix\n#ifndef DS_FIXEDSYS \n\t#define DS_FIXEDSYS 0\n#endif\n\n#define IDC_INFOSTATIC 0xFFFE   // == IDC_STATIC -1\n\n///////////////////////////////////////////////////////////////////////////////\n// Smartphone and PPC 2005 Resource IDs\n\n// Command and associated string resource IDs\n#define ID_MENU_OK                      0xE790\n#define ID_MENU_CANCEL                  0xE791\n#define ID_MENU\t\t\t\t\t\t\t0xE792\n#define ID_ACTION\t\t\t\t\t\t0xE793\n#define ID_VIEW_FULLSCREEN              0xE802\n\n// MenuBar resource IDs\n#define ATL_IDM_MENU_DONE               0xE701\n#define ATL_IDM_MENU_CANCEL             0xE702\n#define ATL_IDM_MENU_DONECANCEL         0xE703\n\n// Default device MenuBar control ID and MenuBar resource ID\n#define ATL_IDW_MENU_BAR\t\t\t\t0xE802  \n\n// SmartPhone spinned controls ID offset for CSpinCtrl\n#define ATL_IDW_SPIN_ID                 9999\n\n#endif // __ATLRESCE_H__\n"
  },
  {
    "path": "WTL/atlribbon.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLRIBBON_H__\n#define __ATLRIBBON_H__\n\n#pragma once\n\n#if (_MSC_VER < 1500)\n\t#error atlribbon.h requires Visual C++ 2008 compiler or higher\n#endif\n\n#ifndef _UNICODE\n\t#error atlribbon.h requires the Unicode character set\n#endif\n\n#if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7)\n\t#error atlribbon.h requires the Windows 7 SDK or higher\n#endif\n\n#ifdef _WIN32_WCE\n\t#error atlribbon.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLAPP_H__\n\t#error atlribbon.h requires atlapp.h to be included first\n#endif\n\n#if (_ATL_VER < 0x0700)\n  #include <shlwapi.h>\n  #pragma comment(lib, \"shlwapi.lib\")\n#endif\n\n#include <atlmisc.h>    // for RecentDocumentList classes\n#include <atlframe.h>   // for Frame and UpdateUI classes\n#include <atlctrls.h>   // required for atlctrlw.h\n#include <atlctrlw.h>   // for CCommandBarCtrl\n\n#if !defined(_WTL_USE_CSTRING) && !defined(__ATLSTR_H__)\n  #pragma warning(push)\n  #pragma warning(disable: 4530)   // unwind semantics not enabled\n  #include <string>\n  #pragma warning(pop)\n#endif\n\n#include <dwmapi.h>\n#pragma comment(lib, \"dwmapi.lib\")\n\n#include <UIRibbon.h>\n#include <UIRibbonPropertyHelpers.h>\n#pragma comment(lib, \"propsys.lib\")\n\n#include <Richedit.h>   // for CHARFORMAT2\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CRibbonUpdateUI : Automatic mapping of ribbon UI elements\n//\n// RibbonUI::Text\n// RibbonUI::CharFormat\n// RibbonUI::ICtrl\n// RibbonUI::CtrlImpl\n// RibbonUI::CommandCtrlImpl\n// RibbonUI::ItemProperty\n// RibbonUI::CollectionImplBase\n// RibbonUI::CollectionImpl\n// RibbonUI::TextCollectionImpl\n// RibbonUI::ItemCollectionImpl\n// RibbonUI::ComboCollectionImpl\n// RibbonUI::CommandCollectionImpl\n// RibbonUI::ToolbarCollectionImpl\n// RibbonUI::SimpleCollectionImpl\n// RibbonUI::CollectionCtrlImpl\n// RibbonUI::ToolbarGalleryCtrlImpl\n// RibbonUI::SimpleCollectionCtrlImpl\n// RibbonUI::RecentItemsCtrlImpl\n// RibbonUI::FontCtrlImpl\n// RibbonUI::ColorCtrlImpl\n// RibbonUI::SpinnerCtrlImpl\n//\n// RibbonUI::CRibbonImpl\n//\t CRibbonImpl::CRibbonComboCtrl\n//\t CRibbonImpl::CRibbonItemGalleryCtrl\n//\t CRibbonImpl::CRibbonCommandGalleryCtrl\n//\t CRibbonImpl::CRibbonToolbarGalleryCtrl\n//\t CRibbonImpl::CRibbonSimpleComboCtrl\n//\t CRibbonImpl::CRibbonSimpleGalleryCtrl\n//\t CRibbonImpl::CRibbonRecentItemsCtrl\n//\t CRibbonImpl::CRibbonColorCtrl\n//\t CRibbonImpl::CRibbonFontCtrl\n//\t CRibbonImpl::CRibbonSpinnerCtrl\n//\t CRibbonImpl::CRibbonFloatSpinnerCtrl\n//\t CRibbonImpl::CRibbonCommandCtrl\n//\n// CRibbonFrameWindowImplBase\n// CRibbonFrameWindowImpl\n// CRibbonMDIFrameWindowImpl\n// CRibbonPersist\n//\n// Global functions:\n//   RibbonUI::SetPropertyVal()\n//   RibbonUI::GetImage()\n\n\n// Constants\n\n#ifndef RIBBONUI_MAX_TEXT\n  #define RIBBONUI_MAX_TEXT 128\n#endif\n\n#define TWIPS_PER_POINT 20   // For font size\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CRibbonUpdateUI : Automatic mapping of ribbon UI elements\n\ntemplate <class T>\nclass CRibbonUpdateUI : public CAutoUpdateUI<T>\n{\npublic:\n\tenum\n\t{\n\t\tUPDUI_RIBBON = 0x0080, \n\t\tUPDUI_PERSIST = 0x0020\n\t};\n\n\tbool IsRibbonElement(const _AtlUpdateUIMap& UIMap)\n\t{\n\t\treturn (UIMap.m_wType & UPDUI_RIBBON) != 0;\n\t}\n\n\tbool IsRibbonID(UINT nID)\n\t{\n\t\tfor(int i = 0; i < m_arrUIMap.GetSize(); i++)\n\t\t{\n\t\t\tif(m_arrUIMap[i].m_nID == nID)\n\t\t\t\treturn IsRibbonElement(m_arrUIMap[i]);\n\t\t}\n\n\t\treturn false;\n\t}\n\n// Element\n\tbool UIAddRibbonElement(UINT nID)\n\t{\n\t\treturn UIAddElement<UPDUI_RIBBON>(nID);\n\t}\n\n\tbool UIRemoveRibbonElement(UINT nID)\n\t{\n\t\treturn UIRemoveElement<UPDUI_RIBBON>(nID);\n\t}\n\n\tbool UIPersistElement(UINT nID, bool bPersist = true)\n\t{\n\t\treturn bPersist ?\n\t\t\tUIAddElement<UPDUI_PERSIST>(nID) :\n\t\t\tUIRemoveElement<UPDUI_PERSIST>(nID);\n\t}\n\n// methods for Ribbon elements\n\tBOOL UISetText(int nID, LPCWSTR sText, BOOL bForceUpdate = FALSE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bRes = CUpdateUIBase::UISetText(nID, sText, bForceUpdate);\n\t\tif (pT->IsRibbonUI() && IsRibbonID(nID))\n\t\t\tbRes = SUCCEEDED(pT->InvalidateProperty(nID, UI_PKEY_Label));\n\t\treturn bRes;\n\t}\n\n\tBOOL UISetText(int nID, UINT uIdResource, BOOL bForceUpdate = FALSE)\n\t{\n\t\tCTempBuffer<WCHAR> sText(RIBBONUI_MAX_TEXT);\n\t\tint nRet = AtlLoadString(uIdResource, sText, RIBBONUI_MAX_TEXT);\n\t\tif(nRet > 0)\n\t\t\tUISetText(nID, sText, bForceUpdate);\n\t\treturn (nRet > 0) ? TRUE : FALSE;\n\t}\n\n\tLPCTSTR UIGetText(int nID)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLPCTSTR sUI = CAutoUpdateUI::UIGetText(nID);\n\t\t\n\t\t// replace 'tab' by 'space' for RibbonUI elements\n\t\tif (sUI && pT->IsRibbonUI() && IsRibbonID(nID) && wcschr(sUI, L'\\t'))\n\t\t{\n\t\t\tstatic WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };\n\t\t\twcscpy_s(sText, sUI);\n\t\t\tWCHAR* pch = wcschr(sText, L'\\t');\n\t\t\tif (pch != NULL)\n\t\t\t\t*pch = L' ';\n\t\t\treturn sText;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn sUI;\n\t\t}\n\t}\n\n\tBOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bRes = CUpdateUIBase::UIEnable(nID, bEnable, bForceUpdate);\n\t\tif (pT->IsRibbonUI() && IsRibbonID(nID))\n\t\t\tbRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_Enabled, bEnable));\n\t\treturn bRes;\n\t}\n\n\tBOOL UISetCheck(int nID, INT nCheck, BOOL bForceUpdate = FALSE)\n\t{\n\t\tif ((nCheck == 0) || (nCheck == 1))\n\t\t\treturn UISetCheck(nID, nCheck != 0, bForceUpdate);\n\t\telse\n\t\t\treturn CUpdateUIBase::UISetCheck(nID, nCheck, bForceUpdate);\n\t}\n\n\tBOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tBOOL bRes = CUpdateUIBase::UISetCheck(nID, bCheck, bForceUpdate);\n\t\tif (bRes && pT->IsRibbonUI() && IsRibbonID(nID))\n\t\t\tbRes = SUCCEEDED(pT->SetProperty((WORD)nID, UI_PKEY_BooleanValue, bCheck));\n\t\treturn bRes;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// RibbonUI namespace\n//\n\nnamespace RibbonUI\n{\n\n// Minimal string allocation support for various PROPERTYKEY values\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n  typedef _CSTRING_NS::CString Text;\n#else\n  class Text : public std::wstring\n  {\n  public:\n\tText(std::wstring& s) : std::wstring(s)\n\t{ }\n\tText(LPCWSTR s) : std::wstring(s)\n\t{ }\n\tText()\n\t{ }\n\tbool IsEmpty()\n\t{\n\t\treturn empty();\n\t}\n\toperator LPCWSTR()\n\t{\n\t\treturn c_str();\n\t}\n\tText& operator =(LPCWSTR s)\n\t{\n\t\treturn static_cast<Text&>(std::wstring::operator =(s));\n\t}\n  };\n#endif\n\n// PROPERTYKEY enum and helpers\nenum k_KEY\n{\n\t// state\n\tk_Enabled = 1, k_BooleanValue = 200, \n\t// text properties\n\tk_LabelDescription = 2, k_Keytip = 3, k_Label = 4, k_TooltipDescription = 5, k_TooltipTitle = 6, \n\t// image properties\n\tk_LargeImage = 7, k_LargeHighContrastImage = 8, k_SmallImage = 9, k_SmallHighContrastImage = 10,\n\t// collection properties\n\tk_ItemsSource = 101, k_Categories = 102, k_SelectedItem = 104,\n\t// collection item properties\n\tk_CommandId = 100, k_CategoryId = 103, k_CommandType = 105, k_ItemImage = 106,\n\t// combo control property\n\tk_StringValue = 202,\n\t// spinner control properties\n\tk_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces, k_FormatString, k_RepresentativeString = 208,\n\t// font control properties\n\tk_FontProperties = 300, k_FontProperties_Family, k_FontProperties_Size, k_FontProperties_Bold, k_FontProperties_Italic = 304, \n\tk_FontProperties_Underline = 305, k_FontProperties_Strikethrough, k_FontProperties_VerticalPositioning, k_FontProperties_ForegroundColor = 308, \n\tk_FontProperties_BackgroundColor = 309, k_FontProperties_ForegroundColorType, k_FontProperties_BackgroundColorType, k_FontProperties_ChangedProperties = 312, \n\tk_FontProperties_DeltaSize = 313, \n\t// recent items properties\n\tk_RecentItems = 350, k_Pinned = 351,\n\t// color control properties\n\tk_Color = 400, k_ColorType = 401, k_ColorMode, \n\tk_ThemeColorsCategoryLabel = 403, k_StandardColorsCategoryLabel, k_RecentColorsCategoryLabel = 405, k_AutomaticColorLabel = 406, \n\tk_NoColorLabel = 407, k_MoreColorsLabel = 408, \n\tk_ThemeColors = 409, k_StandardColors = 410, k_ThemeColorsTooltips = 411, k_StandardColorsTooltips = 412,\n\t// Ribbon state\n\tk_Viewable = 1000, k_Minimized = 1001, k_QuickAccessToolbarDock = 1002, k_ContextAvailable = 1100,\n\t// Ribbon UI colors\n\tk_GlobalBackgroundColor = 2000, k_GlobalHighlightColor, k_GlobalTextColor = 2002\n};\n\ninline k_KEY k_(REFPROPERTYKEY key)\n{\n\treturn (k_KEY)key.fmtid.Data1;\n}\n\n// PROPERTYKEY value assignment and specializations\n//\ntemplate <typename V>\nHRESULT SetPropertyVal(REFPROPERTYKEY key, V val, PROPVARIANT* ppv)\n{\n\tswitch (k_(key))\n\t{\n\tcase k_Enabled:\n\tcase k_BooleanValue:\n\t\treturn InitPropVariantFromBoolean(val, ppv);\n\tdefault:\n\t\treturn UIInitPropertyFromUInt32(key, val, ppv);\n\t}\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, DOUBLE val, PROPVARIANT* ppv)\n{\n\treturn SetPropertyVal(key, (LONG)val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUIImage* val, PROPVARIANT* ppv)\n{\n\tHRESULT hr = UIInitPropertyFromImage(key, val, ppv);\n\tATLVERIFY(val->Release() == 1);\n\treturn hr;\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, IUnknown* val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromInterface(key, val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, IPropertyStore* val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromInterface(key, val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, SAFEARRAY* val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromIUnknownArray(key, val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, DECIMAL* val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromDecimal(key, *val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, bool val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromBoolean(key, val, ppv);\n}\n\ninline HRESULT SetPropertyVal(REFPROPERTYKEY key, LPCWSTR val, PROPVARIANT* ppv)\n{\n\treturn UIInitPropertyFromString(key, val, ppv);\n}\n\n// CharFormat helper struct for RibbonUI font control\n//\nstruct CharFormat : CHARFORMAT2\n{\n\t// Default constructor\n\tCharFormat()\n\t{\n\t\tcbSize = sizeof(CHARFORMAT2);\n\t\tReset();\n\t}\n\n\t// Copy constructor\n\tCharFormat(const CharFormat& cf)\n\t{\n\t\t::CopyMemory(this, &cf, sizeof(CHARFORMAT2));\n\t}\n\n\t// Assign operator\n\tCharFormat& operator =(const CharFormat& cf)\n\t{\n\t\t::CopyMemory(this, &cf, sizeof(CHARFORMAT2));\n\t\treturn (*this);\n\t}\n\n\tvoid Reset()\n\t{\n\t\tuValue = dwMask = dwEffects = 0;\n\t\tPropVariantInit(&propvar);\n\t}\n\n\tvoid operator <<(IPropertyStore* pStore)\n\t{\n\t\tif (pStore == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn;\n\t\t}\n\n\t\tstatic void (CharFormat::*Getk_[])(IPropertyStore*) = \n\t\t{\n\t\t\t&CharFormat::Getk_Family, \n\t\t\t&CharFormat::Getk_FontProperties_Size, \n\t\t\t&CharFormat::Getk_MaskEffectBold,\n\t\t\t&CharFormat::Getk_MaskEffectItalic,\n\t\t\t&CharFormat::Getk_MaskEffectUnderline,\n\t\t\t&CharFormat::Getk_MaskEffectStrikeout,\n\t\t\t&CharFormat::Getk_VerticalPositioning,\n\t\t\t&CharFormat::Getk_Color, \n\t\t\t&CharFormat::Getk_ColorBack, \n\t\t\t&CharFormat::Getk_ColorType,\n\t\t\t&CharFormat::Getk_ColorTypeBack,\n\t\t};\n\n\t\tDWORD nProps = 0;\n\t\tReset();\n\n\t\tATLVERIFY(SUCCEEDED(pStore->GetCount(&nProps)));\n\t\tfor (DWORD iProp = 0; iProp < nProps; iProp++)\n\t\t{\n\t\t\tPROPERTYKEY key;\t\n\t\t\tATLVERIFY(SUCCEEDED(pStore->GetAt(iProp, &key)));\n\t\t\tATLASSERT(k_(key) >= k_FontProperties_Family);\n\n\t\t\tif (k_(key) <= k_FontProperties_BackgroundColorType)\n\t\t\t\t(this->*Getk_[k_(key) - k_FontProperties_Family])(pStore);\n\t\t}\n\t}\n\n\tvoid operator >>(IPropertyStore* pStore)\n\t{\n\t\tif (pStore == NULL)\n\t\t{\n\t\t\tATLASSERT(FALSE);\n\t\t\treturn;\n\t\t}\n\n\t\tPutFace(pStore);\n\t\tPutSize(pStore);\n\t\tPutMaskEffect(CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold, pStore);\n\t\tPutMaskEffect(CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic, pStore);\n\t\tPutMaskEffect(CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline, pStore);\n\t\tPutMaskEffect(CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough, pStore);\n\t\tPutVerticalPos(pStore);\n\t\tPutColor(pStore);\n\t\tPutBackColor(pStore);\n\t}\n\nprivate:\n\tPROPVARIANT propvar;\n\tUINT uValue;\n\n\t// Getk_ functions\n\tvoid Getk_Family(IPropertyStore* pStore)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Family, &propvar)))\n\t\t{\n\t\t\tPropVariantToString(propvar, szFaceName, LF_FACESIZE);\n\t\t\tif (*szFaceName)\n\t\t\t\tdwMask |= CFM_FACE;\n\t\t}\n\t}\n\n\tvoid Getk_FontProperties_Size(IPropertyStore* pStore)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_Size, &propvar)))\n\t\t{\n\t\t\tDECIMAL decSize = { 0 };\n\t\t\tUIPropertyToDecimal(UI_PKEY_FontProperties_Size, propvar, &decSize);\n\t\t\tDOUBLE dSize = 0;\n\t\t\tVarR8FromDec(&decSize, &dSize);\n\t\t\tif (dSize > 0)\n\t\t\t{\n\t\t\t\tdwMask |= CFM_SIZE;\n\t\t\t\tyHeight = (LONG)(dSize * TWIPS_PER_POINT);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Getk_MaskEffectBold(IPropertyStore* pStore)\n\t{\n\t\tGetk_MaskEffectAll(pStore, CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold);\n\t}\n\n\tvoid Getk_MaskEffectItalic(IPropertyStore* pStore)\n\t{\n\t\tGetk_MaskEffectAll(pStore, CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic);\n\t}\n\n\tvoid Getk_MaskEffectUnderline(IPropertyStore* pStore)\n\t{\n\t\tGetk_MaskEffectAll(pStore, CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline);\n\t}\n\n\tvoid Getk_MaskEffectStrikeout(IPropertyStore* pStore)\n\t{\n\t\tGetk_MaskEffectAll(pStore, CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough);\n\t}\n\n\tvoid Getk_MaskEffectAll(IPropertyStore* pStore, DWORD _dwMask, DWORD _dwEffects, REFPROPERTYKEY key)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(key, &propvar)))\n\t\t{\n\t\t\tUIPropertyToUInt32(key, propvar, &uValue);\n\t\t\tif ((UI_FONTPROPERTIES)uValue != UI_FONTPROPERTIES_NOTAVAILABLE)\n\t\t\t{\n\t\t\t\tdwMask |= _dwMask;\n\t\t\t\tdwEffects |= ((UI_FONTPROPERTIES)uValue == UI_FONTPROPERTIES_SET) ? _dwEffects : 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Getk_VerticalPositioning(IPropertyStore* pStore)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(UI_PKEY_FontProperties_VerticalPositioning, &propvar)))\n\t\t{\n\t\t\tUIPropertyToUInt32(UI_PKEY_FontProperties_VerticalPositioning, propvar, &uValue);\n\t\t\tUI_FONTVERTICALPOSITION uVerticalPosition = (UI_FONTVERTICALPOSITION) uValue;\n\t\t\tif ((uVerticalPosition != UI_FONTVERTICALPOSITION_NOTAVAILABLE))\n\t\t\t{\n\t\t\t\tdwMask |= (CFM_SUPERSCRIPT | CFM_SUBSCRIPT);\n\t\t\t\tif (uVerticalPosition != UI_FONTVERTICALPOSITION_NOTSET)\n\t\t\t\t{\n\t\t\t\t\tdwEffects |= (uVerticalPosition == UI_FONTVERTICALPOSITION_SUPERSCRIPT) ? CFE_SUPERSCRIPT : CFE_SUBSCRIPT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Getk_Color(IPropertyStore* pStore)\n\t{\n\t\tGetk_ColorAll(pStore, CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor);\n\t}\n\n\tvoid Getk_ColorBack(IPropertyStore* pStore)\n\t{\n\t\tGetk_ColorAll(pStore, CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor);\n\t}\n\t\t\n\tvoid Getk_ColorAll(IPropertyStore* pStore, DWORD _dwMask, REFPROPERTYKEY key)\n\t{\n\t\tUINT32 color = 0;\n\t\tif (SUCCEEDED(pStore->GetValue(key, &propvar)))\n\t\t{\n\t\t\tUIPropertyToUInt32(key, propvar, &color);\n\t\t\tdwMask |= _dwMask;\n\n\t\t\tif (_dwMask == CFM_COLOR)\n\t\t\t\tcrTextColor = color;\n\t\t\telse\n\t\t\t\tcrBackColor = color;\n\t\t}\n\t}\n\n\tvoid Getk_ColorType(IPropertyStore* pStore)\n\t{\n\t\tGetk_ColorTypeAll(pStore, CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColor);\n\n\t}\n\n\tvoid Getk_ColorTypeBack(IPropertyStore* pStore)\n\t{\n\t\tGetk_ColorTypeAll(pStore, CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColor);\n\t}\n\n\tvoid Getk_ColorTypeAll(IPropertyStore* pStore, DWORD _dwMask, DWORD _dwEffects, UI_SWATCHCOLORTYPE _type, REFPROPERTYKEY key)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(key, &propvar)))\n\t\t{\n\t\t\tUIPropertyToUInt32(key, propvar, &uValue);\n\t\t\tif (_type == (UI_SWATCHCOLORTYPE)uValue)\n\t\t\t{\n\t\t\t\tdwMask |= _dwMask;\n\t\t\t\tdwEffects |= _dwEffects;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Put functions\n\tvoid PutMaskEffect(WORD dwMaskVal, WORD dwEffectVal, REFPROPERTYKEY key, IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT var;\n\t\tUI_FONTPROPERTIES uProp = UI_FONTPROPERTIES_NOTAVAILABLE;\n\t\tif ((dwMask & dwMaskVal) != 0)\n\t\t\tuProp = dwEffects & dwEffectVal ? UI_FONTPROPERTIES_SET : UI_FONTPROPERTIES_NOTSET;\n\t\tSetPropertyVal(key, uProp, &var);\n\t\tpStore->SetValue(key, var);\n\t}\n\n\tvoid PutVerticalPos(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT var;\n\t\tUI_FONTVERTICALPOSITION uProp = UI_FONTVERTICALPOSITION_NOTAVAILABLE;\n\n\t\tif ((dwMask & CFE_SUBSCRIPT) != 0)\n\t\t{\n\t\t\tif ((dwMask & CFM_SUBSCRIPT) && (dwEffects & CFE_SUBSCRIPT))\n\t\t\t\tuProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;\n\t\t\telse\n\t\t\t\tuProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;\n\t\t}\n\t\telse if ((dwMask & CFM_OFFSET) != 0)\n\t\t{\n\t\t\tif (yOffset > 0)\n\t\t\t\tuProp = UI_FONTVERTICALPOSITION_SUPERSCRIPT;\n\t\t\telse if (yOffset < 0)\n\t\t\t\tuProp = UI_FONTVERTICALPOSITION_SUBSCRIPT;\n\t\t}\n\n\t\tSetPropertyVal(UI_PKEY_FontProperties_VerticalPositioning, uProp, &var);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, var);\n\t}\n\n\tvoid PutFace(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT var;\n\t\tSetPropertyVal(UI_PKEY_FontProperties_Family, \n\t\t\tdwMask & CFM_FACE ? szFaceName : L\"\", &var);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_Family, var);\n\t}\n\n\tvoid PutSize(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT var;\n\t\tDECIMAL decVal;\n\n\t\tif ((dwMask & CFM_SIZE) != 0)\n\t\t\tVarDecFromR8((DOUBLE)yHeight / TWIPS_PER_POINT, &decVal);\n\t\telse\n\t\t\tVarDecFromI4(0, &decVal);\n\n\t\tSetPropertyVal(UI_PKEY_FontProperties_Size, &decVal, &var);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_Size, var);\n\t}\n\n\tvoid PutColor(IPropertyStore* pStore)\n\t{\n\t\tif ((dwMask & CFM_COLOR) != 0)\n\t\t{\n\t\t\tif ((dwEffects & CFE_AUTOCOLOR) == 0)\n\t\t\t{\n\t\t\t\tSetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);\n\t\t\t\tpStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);\n\t\t\t\t\n\t\t\t\tSetPropertyVal(UI_PKEY_FontProperties_ForegroundColor, crTextColor, &propvar);\n\t\t\t\tpStore->SetValue(UI_PKEY_FontProperties_ForegroundColor, propvar);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSetPropertyVal(UI_PKEY_FontProperties_ForegroundColorType, UI_SWATCHCOLORTYPE_AUTOMATIC, &propvar);\n\t\t\t\tpStore->SetValue(UI_PKEY_FontProperties_ForegroundColorType, propvar);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid PutBackColor(IPropertyStore* pStore)\n\t{\n\t\tif (((dwMask & CFM_BACKCOLOR) != 0) && ((dwEffects & CFE_AUTOBACKCOLOR) == 0))\n\t\t{\n\t\t\tSetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_RGB, &propvar);\n\t\t\tpStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);\n\t\t\t\t\n\t\t\tSetPropertyVal(UI_PKEY_FontProperties_BackgroundColor, crBackColor, &propvar);\n\t\t\tpStore->SetValue(UI_PKEY_FontProperties_BackgroundColor, propvar);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSetPropertyVal(UI_PKEY_FontProperties_BackgroundColorType, UI_SWATCHCOLORTYPE_NOCOLOR, &propvar);\n\t\t\tpStore->SetValue(UI_PKEY_FontProperties_BackgroundColorType, propvar);\n\t\t}\n\t}\n};\n\n// IUIImage helper\n//\ninline IUIImage* GetImage(HBITMAP hbm, UI_OWNERSHIP owner)\n{\n\tATLASSERT(hbm);\n\tIUIImage* pIUII = NULL;\n\tATL::CComPtr<IUIImageFromBitmap> pIFB;\n\n\tif SUCCEEDED(pIFB.CoCreateInstance(CLSID_UIRibbonImageFromBitmapFactory))\n\t\tATLVERIFY(SUCCEEDED(pIFB->CreateImage(hbm, owner, &pIUII)));\n\n\treturn pIUII;\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Ribbon control classes\n\n// RibbonUI::ICtrl abstract interface of RibbonUI::CRibbonImpl and all RibbonUI control classes\n//\nstruct ICtrl\n{\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* pCommandExecutionProperties) = 0;\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue) = 0;\n};\n\n// RibbonUI::CtrlImpl base class for all ribbon controls\n//\ntemplate <class T, UINT t_ID>\nclass ATL_NO_VTABLE CtrlImpl : public ICtrl\n{\nprotected:\n\tT* m_pWndRibbon;\n\npublic:\n\ttypedef T WndRibbon;\n\n\tCtrlImpl() : m_pWndRibbon(T::pWndRibbon)\n\t{ }\n\n\tWndRibbon& GetWndRibbon()\n\t{\n\t\treturn *m_pWndRibbon;\n\t}\n\n\tstatic WORD GetID()\n\t{\n\t\treturn t_ID;\n\t}\n\n\tText m_sTxt[5];\n\n\t// Operations\n\tHRESULT Invalidate()\n\t{\n\t\treturn GetWndRibbon().InvalidateCtrl(GetID());\n\t}\n\n\tHRESULT Invalidate(REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)\n\t{\n\t\treturn GetWndRibbon().InvalidateProperty(GetID(), key, flags);\n\t}\n\n\tHRESULT SetText(REFPROPERTYKEY key, LPCWSTR sTxt, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));\n\n\t\tm_sTxt[k_(key) - k_LabelDescription] = sTxt;\n\n\t\treturn bUpdate ?\n\t\t\tGetWndRibbon().InvalidateProperty(GetID(), key) :\n\t\t\tS_OK;\n\t}\n\n\t// Implementation\n\ttemplate <typename V>\n\tHRESULT SetProperty(REFPROPERTYKEY key, V val)\n\t{\n\t\treturn GetWndRibbon().SetProperty(GetID(), key, val);\n\t}\n\n\tHRESULT OnGetText(REFPROPERTYKEY key, PROPVARIANT* ppv)\n\t{\n\t\tATLASSERT((k_(key) <= k_TooltipTitle) && (k_(key) >= k_LabelDescription));\n\n\t\tconst INT iText = k_(key) - k_LabelDescription;\n\t\tif (m_sTxt[iText].IsEmpty())\n\t\t\tif (LPCWSTR sText = GetWndRibbon().OnRibbonQueryText(GetID(), key))\n\t\t\t\tm_sTxt[iText] = sText;\n\n\t\treturn !m_sTxt[iText].IsEmpty() ?\n\t\t\tSetPropertyVal(key, (LPCWSTR)m_sTxt[iText], ppv) :\n\t\t\tS_OK;\n\t}\n\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* pCommandExecutionProperties)\n\t{\n\t\tATLASSERT(nCmdID == t_ID);\n\t\treturn GetWndRibbon().DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT(nCmdID == t_ID);\n\n\t\tconst INT iMax = k_TooltipTitle - k_LabelDescription;\n\t\tconst INT iVal = k_(key) - k_LabelDescription;\n\n\t\treturn (iVal <= iMax) && (iVal >= 0) ?\n\t\t\tOnGetText(key, ppropvarNewValue) :\n\t\t\tGetWndRibbon().DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t}\n};\n\n// CommandCtrlImpl base class for most ribbon controls\n//\ntemplate <class T, UINT t_ID>\nclass CommandCtrlImpl : public CtrlImpl<T, t_ID>\n{\npublic:\n\tCBitmap m_hbm[4];\n\n\tHRESULT SetImage(REFPROPERTYKEY key, HBITMAP hbm, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));\n\t\t\t\n\t\tm_hbm[k_(key) - k_LargeImage].Attach(hbm);\n\n\t\treturn bUpdate ?\n\t\t\tGetWndRibbon().InvalidateProperty(GetID(), key) :\n\t\t\tS_OK;\n\t}\n\n\tHRESULT OnGetImage(REFPROPERTYKEY key, PROPVARIANT* ppv)\n\t{\n\t\tATLASSERT((k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage));\n\n\t\tconst INT iImage = k_(key) - k_LargeImage;\n\n\t\tif (m_hbm[iImage].IsNull())\n\t\t\tm_hbm[iImage] = GetWndRibbon().OnRibbonQueryImage(GetID(), key);\n\n\t\treturn m_hbm[iImage].IsNull() ?\n\t\t\tE_NOTIMPL :\n\t\t\tSetPropertyVal(key, GetImage(m_hbm[iImage], UI_OWNERSHIP_COPY), ppv);\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\n\t\treturn (k_(key) <= k_SmallHighContrastImage) && (k_(key) >= k_LargeImage) ?\n\t\t\tOnGetImage(key, ppropvarNewValue) :\n\t\t\tCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Ribbon collection base classes\n\n// ItemProperty class: ribbon callback for each item in a collection\n//\n\n#pragma warning(push)\n#pragma warning(disable: 4512)   // assignment operator could not be generated\n\ntemplate <class TCollection>\nclass ItemProperty : public IUISimplePropertySet\n{\npublic:\n\tItemProperty(UINT i, TCollection* pCollection) : m_Index(i), m_pCollection(pCollection)\n\t{ }\n\n\tconst UINT m_Index;\n\tTCollection* m_pCollection;\n\n\t// IUISimplePropertySet method.\n\tSTDMETHODIMP GetValue(REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\treturn m_pCollection->OnGetItem(m_Index, key, value);\n\t}\n\n\t// IUnknown methods.\n\tSTDMETHODIMP_(ULONG) AddRef()\n\t{\n\t\treturn 1;\n\t}\n\n\tSTDMETHODIMP_(ULONG) Release()\n\t{\n\t\treturn 1;\n\t}\n\n\tSTDMETHODIMP QueryInterface(REFIID iid, void** ppv)\n\t{\n\t\tif ((iid == __uuidof(IUnknown)) || (iid == __uuidof(IUISimplePropertySet)))\n\t\t{\n\t\t\t*ppv = this;\n\t\t\treturn S_OK;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn E_NOINTERFACE;\n\t\t}\n\t}\n};\n\n#pragma warning(pop)\n\n\n// CollectionImplBase: base class for all RibbonUI collections\n//\ntemplate <class TCollection, size_t t_size>\nclass CollectionImplBase\n{\n\ttypedef CollectionImplBase<TCollection, t_size> thisClass;\n\npublic:\n\tCollectionImplBase()\n\t{\n\t\tfor (int i = 0; i < t_size; i++)\n\t\t\tm_apItems[i] = new ItemProperty<TCollection>(i, static_cast<TCollection*>(this));\n\t}\n\n\t~CollectionImplBase()\n\t{\n\t\tfor (int i = 0; i < t_size; i++)\n\t\t\tdelete m_apItems[i];\n\t}\n\n// Data members\n\tItemProperty<TCollection>* m_apItems[t_size];\n};\n\n// CollectionImpl: handles categories and collecton resizing\n//\ntemplate <class TCtrl, size_t t_items, size_t t_categories>\nclass CollectionImpl : public CollectionImplBase<CollectionImpl<TCtrl, t_items, t_categories>, t_items + t_categories>\n{\n\ttypedef CollectionImpl<TCtrl, t_items, t_categories> thisClass;\npublic:\n\ttypedef thisClass Collection;\n\n\tCollectionImpl() : m_size(t_items)\n\t{\n\t\t::FillMemory(m_auItemCat, sizeof(m_auItemCat), 0xff); // UI_COLLECTION_INVALIDINDEX\n\t}\n\n\tUINT32 m_auItemCat[t_items];\n\tText m_asCatName[__max(t_categories, 1)];\n\tsize_t m_size;\n\n// Operations\n\tHRESULT SetItemCategory(UINT uItem, UINT uCat, bool bUpdate = false)\n\t{\n\t\tATLASSERT((uItem < t_items) && (uCat < t_categories));\n\n\t\tm_auItemCat[uItem] = uCat;\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n\tHRESULT SetCategoryText(UINT uCat, LPCWSTR sText, bool bUpdate = false)\n\t{\n\t\tATLASSERT(uCat < t_categories);\n\n\t\tm_asCatName[uCat] = sText;\n\n\t\treturn bUpdate ? InvalidateCategories() : S_OK;\n\t}\n\n\tHRESULT Resize(size_t size, bool bUpdate = false)\n\t{\n\t\tATLASSERT(size <= t_items);\n\n\t\tm_size = size;\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n// Implementation\n\tHRESULT OnGetItem(UINT uIndex, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uIndex < t_items + t_categories);\n\t\tTCtrl* pCtrl = static_cast<TCtrl*>(this);\n\n\t\treturn uIndex < t_items ?\n\t\t\tpCtrl->DoGetItem(uIndex, key, value) :\n\t\t\tpCtrl->DoGetCategory(uIndex - t_items, key, value);\n\t}\n\n\tHRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(k_(key) == k_CategoryId);\n\t\tUINT32 uCat = UI_COLLECTION_INVALIDINDEX;\n\n\t\tif (t_categories != 0)\n\t\t{\n\t\t\tif (m_auItemCat[uItem] == UI_COLLECTION_INVALIDINDEX)\n\t\t\t{\n\t\t\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\t\t\tm_auItemCat[uItem] = ribbon.OnRibbonQueryItemCategory(TCtrl::GetID(), uItem);\n\t\t\t}\n\t\t\tuCat = m_auItemCat[uItem];\n\t\t}\n\n\t\treturn SetPropertyVal(key, uCat, value);\n\t}\n\n\tHRESULT DoGetCategory(UINT uCat, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tHRESULT hr = S_OK;\n\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_Label:\n\t\t\tif (m_asCatName[uCat].IsEmpty())\n\t\t\t{\n\t\t\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\t\t\tm_asCatName[uCat] = ribbon.OnRibbonQueryCategoryText(TCtrl::GetID(), uCat);\n\t\t\t}\n\t\t\thr = SetPropertyVal(key, (LPCWSTR)m_asCatName[uCat], value);\n\t\t\tbreak;\n\t\tcase k_CategoryId:\n\t\t\thr = SetPropertyVal(key, uCat, value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tHRESULT InvalidateItems()\n\t{\n\t\treturn static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_ItemsSource);\n\t}\n\n\tHRESULT InvalidateCategories()\n\t{\n\t\treturn static_cast<TCtrl*>(this)->Invalidate(UI_PKEY_Categories);\n\t}\n\n\tHRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                         const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* /*ppropvarNewValue*/)\n\t{\n\t\tATLASSERT(nCmdID == TCtrl::GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\n\t\tHRESULT hr = E_NOTIMPL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_ItemsSource:\n\t\t\t{\n\t\t\t\tATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);\n\t\t\t\tATLASSERT(pIUICollection);\n\t\t\t\thr = pIUICollection->Clear();\n\t\t\t\tfor (UINT i = 0; i < m_size; i++)\n\t\t\t\t{\n\t\t\t\t\tif FAILED(hr = pIUICollection->Add(m_apItems[i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tATLASSERT(SUCCEEDED(hr));\n\t\t\t}\n\t\t\tbreak;\n\t\tcase k_Categories:\n\t\t\tif (t_categories != 0)\n\t\t\t{\n\t\t\t\tATL::CComQIPtr<IUICollection> pIUICategory(ppropvarCurrentValue->punkVal);\n\t\t\t\tATLASSERT(pIUICategory.p);\n\t\t\t\thr = pIUICategory->Clear();\n\t\t\t\tfor (UINT i = t_items; i < (t_items + t_categories); i++)\n\t\t\t\t{\n\t\t\t\t\tif FAILED(hr = pIUICategory->Add(m_apItems[i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tATLASSERT(SUCCEEDED(hr));\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n// TextCollectionImpl: handles item labels and selection\n//\ntemplate <class TCtrl, size_t t_items, size_t t_categories = 0>\nclass TextCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>\n{\n\ttypedef TextCollectionImpl<TCtrl, t_items, t_categories> thisClass;\npublic:\n\ttypedef thisClass TextCollection;\n\n\tTextCollectionImpl() : m_uSelected(UI_COLLECTION_INVALIDINDEX)\n\t{ }\n\n\tText m_asText[t_items];\n\tUINT m_uSelected;\n\n\t// Operations\n\tHRESULT SetItemText(UINT uItem, LPCWSTR sText, bool bUpdate = false)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\n\t\tm_asText[uItem] = sText;\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n\tUINT GetSelected()\n\t{\n\t\treturn m_uSelected;\n\t}\n\n\tHRESULT Select(UINT uItem, bool bUpdate = false)\n\t{\n\t\tATLASSERT((uItem < t_items) || (uItem == UI_COLLECTION_INVALIDINDEX));\n\n\t\tm_uSelected = uItem;\n\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\treturn bUpdate ?\n\t\t\tribbon.SetProperty(TCtrl::GetID(), UI_PKEY_SelectedItem, uItem) : \n\t\t\tS_OK;\n\t}\n\n// Implementation\n \tHRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\n\t\tif (k_(key) == k_Label)\n\t\t{\n\t\t\tif (m_asText[uItem].IsEmpty())\n\t\t\t{\n\t\t\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\t\t\tm_asText[uItem] = ribbon.OnRibbonQueryItemText(TCtrl::GetID(), uItem);\n\t\t\t}\n\t\t\treturn SetPropertyVal(key, (LPCWSTR)m_asText[uItem], value);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn Collection::DoGetItem(uItem, key, value);\n\t\t}\n\t}\n\n\tHRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                         const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT(nCmdID == TCtrl::GetID());\n\n\t\tif (k_(key) == k_SelectedItem)\n\t\t{\n\t\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\t\tUINT uSel = UI_COLLECTION_INVALIDINDEX;\n\t\t\tif ((m_uSelected == UI_COLLECTION_INVALIDINDEX) &&\n\t\t\t    ribbon.OnRibbonQuerySelectedItem(TCtrl::GetID(), uSel))\n\t\t\t\tm_uSelected = uSel;\n\n\t\t\treturn SetPropertyVal(key, m_uSelected, ppropvarNewValue);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t}\n\t}\n};\n\n// ItemCollectionImpl: handles item image\n//\ntemplate <class TCtrl, size_t t_items, size_t t_categories = 0>\nclass ItemCollectionImpl : public TextCollectionImpl<TCtrl, t_items, t_categories>\n{\n\ttypedef ItemCollectionImpl<TCtrl, t_items, t_categories> thisClass;\npublic:\n\ttypedef thisClass ItemCollection;\n\t\n\tItemCollectionImpl()\n\t{\n\t\t::ZeroMemory(m_aBitmap, sizeof(m_aBitmap));\n\t}\n\n\tCBitmap m_aBitmap[t_items];\n\n\t// Operations\n\tHRESULT SetItemImage(UINT uIndex, HBITMAP hbm, bool bUpdate = false)\n\t{\n\t\tATLASSERT(uIndex < t_items);\n\n\t\tm_aBitmap[uIndex] = hbm;\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n// Implementation\n\tHRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\n\t\tif (k_(key) == k_ItemImage)\n\t\t{\n\t\t\tif (m_aBitmap[uItem].IsNull())\n\t\t\t{\n\t\t\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\t\t\tm_aBitmap[uItem] = ribbon.OnRibbonQueryItemImage(TCtrl::GetID(), uItem);\n\t\t\t}\n\t\t\treturn m_aBitmap[uItem].IsNull() ?\n\t\t\t\tE_NOTIMPL :\n\t\t\t\tSetPropertyVal(key, GetImage(m_aBitmap[uItem], UI_OWNERSHIP_COPY), value);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn TextCollection::DoGetItem(uItem, key, value);\n\t\t}\n\t}\n};\n\n// ComboCollectionImpl: handles combo text\n//\ntemplate <class TCtrl, size_t t_items, size_t t_categories = 0>\nclass ComboCollectionImpl : public ItemCollectionImpl<TCtrl, t_items, t_categories>\n{\n\ttypedef ComboCollectionImpl<TCtrl, t_items, t_categories> thisClass;\npublic:\n\ttypedef thisClass ComboCollection;\n\n\t// Operations\n\tHRESULT SetComboText(LPCWSTR sText)\n\t{\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\treturn ribbon.IsRibbonUI() ? \n\t\t\tribbon.SetProperty(TCtrl::GetID(), UI_PKEY_StringValue, sText) : \n\t\t\tS_OK;\n\t}\n\n\tLPCWSTR GetComboText()\n\t{\n\t\tstatic WCHAR sCombo[RIBBONUI_MAX_TEXT] = { 0 };\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\t\tPROPVARIANT var;\n\t\tif (ribbon.IsRibbonUI())\n\t\t{\n\t\t\tHRESULT hr = ribbon.GetIUIFrameworkPtr()->GetUICommandProperty(TCtrl::GetID(), UI_PKEY_StringValue, &var);\n\t\t\thr = PropVariantToString(var, sCombo, RIBBONUI_MAX_TEXT);\n\t\t\treturn sCombo;\n\t\t}\n\t\treturn NULL;\n\t}\n};\n\n// CommandCollectionImpl: handles RibbonUI command collection controls\n//\ntemplate <class TCtrl, size_t t_items, size_t t_categories = 0>\nclass CommandCollectionImpl : public CollectionImpl<TCtrl, t_items, t_categories>\n{\n\ttypedef CommandCollectionImpl<TCtrl, t_items, t_categories> thisClass;\npublic:\n\ttypedef thisClass CommandCollection;\n\n\tCommandCollectionImpl()\n\t{\n\t\t::ZeroMemory(m_auCmd, sizeof(m_auCmd));\n\t\t::ZeroMemory(m_aCmdType, sizeof(m_aCmdType));\n\t}\n\n\tUINT32 m_auCmd[t_items];\n\tBYTE m_aCmdType[t_items];\n\n\t// Operations\n\tHRESULT SetItemCommand(UINT uItem, UINT32 uCommandID, bool bUpdate = false)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\n\t\tif (uCommandID == m_auCmd[uItem])\n\t\t\treturn S_OK;\n\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\n\t\tm_auCmd[uItem] = uCommandID;\n\t\tif (uCommandID != 0)\n\t\t\tribbon.UIAddRibbonElement(uCommandID);\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n\tHRESULT SetItemCommandType(UINT uItem, UI_COMMANDTYPE type, bool bUpdate = false)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\n\t\tm_aCmdType[uItem] = (BYTE)type;\n\n\t\treturn bUpdate ? InvalidateItems() : S_OK;\n\t}\n\n// Implementation\n \tHRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uItem < t_items);\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\n\t\tHRESULT hr = E_FAIL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_CommandId:\n\t\t\tif (m_auCmd[uItem] == 0)\n\t\t\t\tSetItemCommand(uItem, ribbon.OnRibbonQueryItemCommand(TCtrl::GetID(), uItem));\n\t\t\thr = SetPropertyVal(key, m_auCmd[uItem], value);\n\t\t\tbreak;\n\t\tcase k_CommandType:\n\t\t\tif (m_aCmdType[uItem] == UI_COMMANDTYPE_UNKNOWN)\n\t\t\t\tSetItemCommandType(uItem, ribbon.OnRibbonQueryItemCommandType(TCtrl::GetID(), uItem));\n\t\t\thr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);\n\t\t\tbreak;\n\t\tcase k_CategoryId:\n\t\tdefault:\n\t\t\thr = Collection::DoGetItem(uItem, key, value);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tHRESULT Select(UINT /*uItem*/, bool /*bUpdate*/ = false)\n\t{\n\t\tATLASSERT(FALSE);\n\t\treturn S_OK;\n\t}\n};\n\n// SimpleCollectionImpl: collection class for ribbon simple collection controls\n//\ntemplate <class TCtrl, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>\nclass SimpleCollectionImpl : public CollectionImplBase<SimpleCollectionImpl<TCtrl, t_size>, t_size>\n{\n\ttypedef SimpleCollectionImpl<TCtrl, t_size, t_CommandType> thisClass;\npublic:\n\ttypedef CollectionImplBase<thisClass, t_size> CollectionBase;\n\ttypedef thisClass SimpleCollection;\n\n// Implementation\n\tHRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uItem < t_size);\n\t\tTCtrl::WndRibbon& ribbon = static_cast<TCtrl*>(this)->GetWndRibbon();\n\n\t\tHRESULT hr = E_NOTIMPL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_ItemImage:\n\t\t\tif (HBITMAP hbm = ribbon.DefRibbonQueryItemImage(TCtrl::GetID(), uItem))\n\t\t\t\thr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), value);\n\t\t\tbreak;\n\t\tcase k_Label:\n\t\t\tif (LPCWSTR sText = ribbon.DefRibbonQueryItemText(TCtrl::GetID(), uItem))\n\t\t\t\thr = SetPropertyVal(key, (LPCWSTR)sText, value);\n\t\t\tbreak;\n\t\tcase k_CommandType:\n\t\t\thr = SetPropertyVal(key, t_CommandType, value);\n\t\t\tbreak;\n\t\tcase k_CommandId:\n\t\t\thr = SetPropertyVal(key, ribbon.DefRibbonQueryItemCommand(TCtrl::GetID(), uItem), value);\n\t\t\tbreak;\n\t\tcase k_CategoryId:\n\t\t\thr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Ribbon collection control classes\n\n// CollectionCtrlImpl: specializable class for ribbon collection controls\n//\ntemplate <class T, UINT t_ID, class TCollection>\nclass CollectionCtrlImpl : public CommandCtrlImpl<T, t_ID>, public TCollection\n{\n\ttypedef CollectionCtrlImpl<T, t_ID, TCollection> thisClass;\npublic:\n\ttypedef CommandCtrlImpl<T, t_ID> CommandCtrl;\n\ttypedef TCollection Collection;\n\n\t// Implementation\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT(nCmdID == GetID());\n\t\tATLASSERT(ppropvarNewValue);\n\n\t\tHRESULT hr = Collection::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\tif FAILED(hr)\n\t\t\thr = CommandCtrl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* /*pCommandExecutionProperties*/)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\t\tnCmdID; // avoid level4 warning\n\n\t\tif (key == NULL) // gallery button pressed\n\t\t{\n\t\t\tGetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);\n\t\t\treturn S_OK;\n\t\t}\n\n\t\tATLASSERT(k_(*key) == k_SelectedItem);\n\t\tATLASSERT(ppropvarValue);\n\n\t\tHRESULT hr = S_OK;\n\t\tUINT32 uSel = 0xffff;\n\t\thr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);\n\n\t\tif (SUCCEEDED(hr))\n\t\t{\n\t\t\tif (GetWndRibbon().OnRibbonItemSelected(GetID(), verb, uSel))\n\t\t\t\tTCollection::Select(uSel);\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n// ToolbarGalleryCtrlImpl: base class for ribbon toolbar gallery controls\n//\ntemplate <class T, UINT t_ID, UINT t_idTB, size_t t_size>\nclass ToolbarGalleryCtrlImpl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>, t_size>>\n{\npublic:\n\tToolbarGalleryCtrlImpl()\n\t{\n\t\tCResource tbres;\n\t\tATLVERIFY(tbres.Load(RT_TOOLBAR, t_idTB));\n\t\t_AtlToolBarData* pData = (_AtlToolBarData*)tbres.Lock();\n\t\tATLASSERT(pData);\n\t\tATLASSERT(pData->wVersion == 1);\n\n\t\tWORD* pItems = pData->items();\n\t\tINT j = 0;\n\t\tfor (int i = 0; (i < pData->wItemCount) && (j < t_size); i++)\n\t\t{\n\t\t\tif (pItems[i] != 0)\n\t\t\t{\n\t\t\t\tm_aCmdType[j] = UI_COMMANDTYPE_ACTION;\n\t\t\t\tm_auCmd[j++] = pItems[i];\n\t\t\t}\n\t\t}\n\n\t\tif (j < t_size)\n\t\t\tResize(j);\n\t}\n\n \tHRESULT DoGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT(uItem < m_size);\n\t\tATLASSERT(m_auCmd[uItem]);\n\n\t\tHRESULT hr = E_FAIL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_CommandId:\n\t\t\thr = SetPropertyVal(key, m_auCmd[uItem], value);\n\t\t\tbreak;\n\t\tcase k_CommandType:\n\t\t\thr = SetPropertyVal(key, UINT32(m_aCmdType[uItem]), value);\n\t\t\tbreak;\n\t\tcase k_CategoryId:\n\t\t\thr = SetPropertyVal(key, UI_COLLECTION_INVALIDINDEX, value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n\n// SimpleCollectionCtrlImpl: base class for simple gallery and listbox controls\n//\ntemplate <class T, UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>\nclass SimpleCollectionCtrlImpl : \n\t\tpublic CommandCtrlImpl<T, t_ID>,\n\t\tpublic SimpleCollectionImpl<SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>, t_size, t_CommandType>\n{\n\ttypedef SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType> thisClass;\npublic:\n\ttypedef thisClass SimpleCollection;\n\n\tSimpleCollectionCtrlImpl() : m_uSelected(0)\n\t{ }\n\n\tUINT m_uSelected;\n\n\tHRESULT Select(UINT uItem, bool bUpdate = false)\n\t{\n\t\tATLASSERT((uItem < t_size) || (uItem == UI_COLLECTION_INVALIDINDEX));\n\n\t\tm_uSelected = uItem;\n\n\t\treturn bUpdate ? \n\t\t\tGetWndRibbon().SetProperty(GetID(), UI_PKEY_SelectedItem, uItem) : \n\t\t\tS_OK;\n\t}\n\n\t// Implementation\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT(nCmdID == GetID());\n\t\tATLASSERT(ppropvarNewValue != NULL);\n\n\t\tHRESULT hr = S_OK;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_ItemsSource:\n\t\t\t{\n\t\t\t\tATL::CComQIPtr<IUICollection> pIUICollection(ppropvarCurrentValue->punkVal);\n\t\t\t\tATLASSERT(pIUICollection.p);\n\t\t\t\thr = pIUICollection->Clear();\n\t\t\t\tfor (UINT i = 0; i < t_size; i++)\n\t\t\t\t{\n\t\t\t\t\tif FAILED(hr = pIUICollection->Add(m_apItems[i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tATLASSERT(SUCCEEDED(hr));\n\t\t\t}\n\t\t\tbreak;\n\t\tcase k_SelectedItem:\n\t\t\thr = SetPropertyVal(UI_PKEY_SelectedItem, m_uSelected, ppropvarNewValue);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\thr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* /*pCommandExecutionProperties*/)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\t\t\n\t\tHRESULT hr = S_OK;\n\t\tif (key == NULL) // gallery button pressed\n\t\t{\n\t\t\tGetWndRibbon().OnRibbonItemSelected(GetID(), UI_EXECUTIONVERB_EXECUTE, UI_COLLECTION_INVALIDINDEX);\n\t\t\treturn hr;\n\t\t}\n\t\tATLASSERT(k_(*key) == k_SelectedItem);\n\t\tATLASSERT(ppropvarValue);\n\n\t\tif SUCCEEDED(hr = UIPropertyToUInt32(*key, *ppropvarValue, &m_uSelected))\n\t\t\tGetWndRibbon().OnRibbonItemSelected(GetID(), verb, m_uSelected);\n\n\t\treturn hr;\n\t}\n};\n\n// RecentItemsCtrlImpl\n//\ntemplate <class T, UINT t_ID, class TDocList = CRecentDocumentList>\nclass RecentItemsCtrlImpl : \n\t\tpublic CtrlImpl<T, t_ID>,\n\t\tpublic CollectionImplBase<RecentItemsCtrlImpl<T, t_ID, TDocList>, TDocList::m_nMaxEntries_Max>,\n\t\tpublic TDocList\n{\n\ttypedef RecentItemsCtrlImpl<T, t_ID, TDocList> thisClass;\npublic:\n\ttypedef thisClass RecentItems;\n\n\t// Implementation\n\tHRESULT OnGetItem(UINT uItem, REFPROPERTYKEY key, PROPVARIANT *value)\n\t{\n\t\tATLASSERT((INT)uItem < GetMaxEntries());\n\n\t\tLPCWSTR sPath = m_arrDocs[uItem].szDocName;\n\t\tHRESULT hr = E_NOTIMPL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_Label:\n\t\t\thr = SetPropertyVal(key, GetWndRibbon().OnRibbonQueryRecentItemName(sPath), value);\n\t\t\tbreak;\n\t\tcase k_LabelDescription:\n\t\t\thr = SetPropertyVal(key, sPath, value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT(nCmdID == GetID());\n\t\tATLASSERT(ppropvarNewValue);\n\n\t\tHRESULT hr = S_OK;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_RecentItems:\n\t\t\tif (SAFEARRAY* psa = SafeArrayCreateVector(VT_UNKNOWN, 0, m_arrDocs.GetSize()))\n\t\t\t{\n\t\t\t\tconst int iLastIndex = m_arrDocs.GetSize() - 1;\n\t\t\t\tfor (LONG i = 0; i <= iLastIndex; i++)\n\t\t\t\t\tSafeArrayPutElement(psa, &i, m_apItems[iLastIndex - i]); // reverse order\n\n\t\t\t\thr = SetPropertyVal(key, psa, ppropvarNewValue);\n\t\t\t\tSafeArrayDestroy(psa);\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\thr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* /*pCommandExecutionProperties*/)\n\t{\n\t\tATLASSERT(nCmdID == GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\t\tATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);\n\t\tverb;   // avoid level 4 warning\n\t\tATLASSERT((key) && (k_(*key) == k_SelectedItem));\n\t\tATLASSERT(ppropvarValue);\n\n\t\tUINT32 uSel = 0xffff;\n\t\tHRESULT hr = UIPropertyToUInt32(*key, *ppropvarValue, &uSel);\n\t\tif SUCCEEDED(hr)\n\t\t{\n\t\t\tATLASSERT(uSel < (UINT)GetMaxEntries());\n\t\t\tGetWndRibbon().DefCommandExecute(ID_FILE_MRU_FIRST + uSel);\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Ribbon stand-alone control classes\n\n// FontCtrlImpl\n//\ntemplate <class T, UINT t_ID>\nclass FontCtrlImpl : public CtrlImpl<T, t_ID>\n{\npublic:\n\n\tCharFormat m_cf;\n\n// Implementation\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* pCommandExecutionProperties)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\t\tATLASSERT ((key) && (k_(*key) == k_FontProperties));\n\t\tkey;   // avoid level 4 warning\n\n\t\tHRESULT hr = E_INVALIDARG;\n\t\tswitch (verb)\n\t\t{\n\t\t\tcase UI_EXECUTIONVERB_PREVIEW:\n\t\t\tcase UI_EXECUTIONVERB_EXECUTE:\n\t\t\t\tATLASSERT(pCommandExecutionProperties);\n\t\t\t\tPROPVARIANT propvar;\n\n\t\t\t\tif (SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_FontProperties_ChangedProperties, &propvar)))\n\t\t\t\t\tm_cf << ATL::CComQIPtr<IPropertyStore>(propvar.punkVal);\n\t\t\t\tbreak;\n\n\t\t\tcase UI_EXECUTIONVERB_CANCELPREVIEW:\n\t\t\t\tATLASSERT(ppropvarValue);\n\t\t\t\tATL::CComPtr<IPropertyStore> pStore;\n\n\t\t\t\tif (SUCCEEDED(hr = UIPropertyToInterface(UI_PKEY_FontProperties, *ppropvarValue, &pStore)))\n\t\t\t\t\tm_cf << pStore;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (SUCCEEDED(hr))\n\t\t\tGetWndRibbon().OnRibbonFontCtrlExecute(GetID(), verb, &m_cf);\n\t\telse\n\t\t\tATLASSERT(FALSE);\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tif ((k_(key) == k_FontProperties) && (GetWndRibbon().OnRibbonQueryFont(t_ID, m_cf)))\n\t\t{\n\t\t\tATL::CComQIPtr<IPropertyStore> pStore(ppropvarCurrentValue->punkVal);\n\t\t\tm_cf >> pStore;\n\t\t\treturn SetPropertyVal(key, pStore.p, ppropvarNewValue);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t}\n\t}\n};\n\n// ColorCtrlImpl\n//\ntemplate <class T, UINT t_ID>\nclass ColorCtrlImpl : public CommandCtrlImpl<T, t_ID>\n{\npublic:\n\tColorCtrlImpl() : m_colorType(UI_SWATCHCOLORTYPE_NOCOLOR), m_color(0x800080) /*MAGENTA*/\n\t{ }\n\n\tCOLORREF m_color;\n\tUINT32 m_colorType; // value in UI_SWATCHCOLORTYPE\n\tText m_sLabels[6]; // k_MoreColorsLabel to k_ThemeColorsCategoryLabel\n\tATL::CSimpleArray<COLORREF> m_aColors[2];\n\tATL::CSimpleArray<LPCWSTR> m_aTooltips[2];\n\n\t// Operations\n\tHRESULT SetColor(COLORREF color, bool bUpdate = false)\n\t{\n\t\tif (m_colorType != UI_SWATCHCOLORTYPE_RGB)\n\t\t\tSetColorType(UI_SWATCHCOLORTYPE_RGB, bUpdate);\n\t\tm_color = color;\n\t\treturn bUpdate ? SetProperty(UI_PKEY_Color, color) : S_OK;\n\t}\n\n\tHRESULT SetColorType(UI_SWATCHCOLORTYPE type, bool bUpdate = false)\n\t{\n\t\tm_colorType = type;\n\t\treturn bUpdate ? SetProperty(UI_PKEY_ColorType, type) : S_OK;\n\t}\n\n\tHRESULT SetColorLabel(REFPROPERTYKEY key, LPCWSTR sLabel, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) >= k_ThemeColorsCategoryLabel) && (k_(key) <= k_MoreColorsLabel));\n\t\tm_sLabels[k_(key) - k_ThemeColorsCategoryLabel] = sLabel;\n\t\treturn bUpdate ? SetProperty(key, sLabel) : S_OK;\n\t}\n\n\tHRESULT SetColorArray(REFPROPERTYKEY key, COLORREF* pColor, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) == k_ThemeColors) || (k_(key) == k_StandardColors));\n\n\t\tconst INT ic = k_(key) - k_ThemeColors;\n\t\tm_aColors[ic].RemoveAll();\n\t\twhile (*pColor != 0x800080) /*MAGENTA*/\n\t\t\tm_aColors[ic].Add(*pColor++);\n\n\t\tif (bUpdate)\n\t\t{\n\t\t\tPROPVARIANT var;\n\t\t\tif SUCCEEDED(InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), m_aColors[ic].GetSize(), &var))\n\t\t\t\treturn SetProperty(key, var);\n\t\t\telse\n\t\t\t\treturn E_INVALIDARG;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn S_OK;\n\t\t}\n\t}\n\n\tHRESULT SetColorTooltips(REFPROPERTYKEY key, LPCWSTR* ppsTT, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) == k_ThemeColorsTooltips) || (k_(key) == k_StandardColorsTooltips));\n\n\t\tconst INT ic = k_(key) - k_ThemeColorsTooltips;\n\t\tm_aTooltips[ic].RemoveAll();\n\t\twhile (*ppsTT)\n\t\t\tm_aTooltips[ic].Add(*ppsTT++);\n\n\t\tif (bUpdate)\n\t\t{\n\t\t\tPROPVARIANT var;\n\t\t\tif SUCCEEDED(InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), m_aTooltips[ic].GetSize(), &var))\n\t\t\t\treturn SetProperty(key, var);\n\t\t\telse\n\t\t\t\treturn E_INVALIDARG;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn S_OK;\n\t\t}\n\t}\n\n\t// Implementation\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* pCommandExecutionProperties)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\t\tATLASSERT (key && (k_(*key) == k_ColorType));\n\t\tkey;   // avoid level 4 warning\n\t\tATLASSERT (ppropvarValue);\n\n\t\tHRESULT hr = PropVariantToUInt32(*ppropvarValue, &m_colorType);\n\t\tATLASSERT(SUCCEEDED(hr));\n\n\t\tif (SUCCEEDED(hr) && (m_colorType == UI_SWATCHCOLORTYPE_RGB))\n\t\t{\n\t\t\tATLASSERT(pCommandExecutionProperties);\n\t\t\tPROPVARIANT var;\n\t\t\tif SUCCEEDED(hr = pCommandExecutionProperties->GetValue(UI_PKEY_Color, &var))\n\t\t\t\thr = PropVariantToUInt32(var, &m_color);\n\t\t}\n\n\t\tif SUCCEEDED(hr)\n\t\t\tGetWndRibbon().OnRibbonColorCtrlExecute(GetID(), verb, (UI_SWATCHCOLORTYPE)m_colorType/*uType*/, m_color);\n\t\telse\n\t\t\tATLASSERT(FALSE); // something was wrong\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\n\t\tHRESULT hr = E_NOTIMPL;\n\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_ColorType:\n\t\t\thr = SetPropertyVal(key, m_colorType, ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_Color:\n\t\t\tif (m_color == 0x800080) /*MAGENTA*/\n\t\t\t\tm_color = GetWndRibbon().OnRibbonQueryColor(GetID());\n\t\t\thr = SetPropertyVal(key, m_color, ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_ColorMode:\n\t\t\tbreak;\n\t\tcase k_ThemeColorsCategoryLabel:\n\t\tcase k_StandardColorsCategoryLabel:\n\t\tcase k_RecentColorsCategoryLabel:\n\t\tcase k_AutomaticColorLabel:\n\t\tcase k_NoColorLabel:\n\t\tcase k_MoreColorsLabel:\n\t\t\t{\n\t\t\t\tconst UINT iLabel = k_(key) - k_ThemeColorsCategoryLabel;\n\t\t\t\tif (m_sLabels[iLabel].IsEmpty())\n\t\t\t\t\tif (LPCWSTR psLabel = GetWndRibbon().OnRibbonQueryColorLabel(GetID(), key))\n\t\t\t\t\t\tm_sLabels[iLabel] = psLabel;\n\t\t\t\tif (!m_sLabels[iLabel].IsEmpty())\n\t\t\t\t\thr = SetPropertyVal(key, (LPCWSTR)m_sLabels[iLabel], ppropvarNewValue);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase k_ThemeColors:\n\t\tcase k_StandardColors:\n\t\t\t{\n\t\t\t\tconst INT ic = k_(key) - k_ThemeColors;\n\t\t\t\tif (!m_aColors[ic].GetSize())\n\t\t\t\t\tif (COLORREF* pColor = GetWndRibbon().OnRibbonQueryColorArray(GetID(), key))\n\t\t\t\t\t\tSetColorArray(key, pColor);\n\t\t\t\tif (INT iMax = m_aColors[ic].GetSize())\n\t\t\t\t\thr = InitPropVariantFromUInt32Vector(m_aColors[ic].GetData(), iMax, ppropvarNewValue);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase k_ThemeColorsTooltips:\n\t\tcase k_StandardColorsTooltips:\n\t\t\t{\n\t\t\t\tconst INT ic = k_(key) - k_ThemeColorsTooltips;\n\t\t\t\tif (m_aTooltips[ic].GetSize() == 0)\n\t\t\t\t\tif (LPCWSTR* ppsTT = GetWndRibbon().OnRibbonQueryColorTooltips(GetID(), key))\n\t\t\t\t\t\tSetColorTooltips(key, ppsTT);\n\t\t\t\tif (INT iMax = m_aTooltips[ic].GetSize())\n\t\t\t\t\thr = InitPropVariantFromStringVector(m_aTooltips[ic].GetData(), iMax, ppropvarNewValue);\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\thr = CommandCtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n};\n\n// SpinnerCtrlImpl\n//\ntemplate <class T, UINT t_ID, typename V = LONG>\nclass SpinnerCtrlImpl : public CtrlImpl<T, t_ID>\n{\npublic:\n\tSpinnerCtrlImpl()\n\t{\n\t\tm_Values[0] = m_Values[2] = m_Values[4] = 0;\n\t\tm_Values[1] = 100;\n\t\tm_Values[3] = 1;\n\t}\n\n\tV m_Values[5];\n\t\t// k_DecimalValue = 201, k_MaxValue = 203, k_MinValue, k_Increment, k_DecimalPlaces\n\t\t\n\tText m_FormatString;\n\tText m_RepresentativeString;\n\n\t// Operations\n\tHRESULT SetDecimalPlaces(V vPlaces, bool bUpdate = false)\n\t{\n\t\treturn SetValue(UI_PKEY_DecimalPlaces, vPlaces, bUpdate);\n\t}\n\n\tHRESULT SetMin(V vMin, bool bUpdate = false)\n\t{\n\t\treturn SetValue(UI_PKEY_MinValue, vMin, bUpdate);\n\t}\n\n\tHRESULT SetMax(V vMax, bool bUpdate = false)\n\t{\n\t\treturn SetValue(UI_PKEY_MaxValue, vMax, bUpdate);\n\t}\n\n\tHRESULT SetVal(V vVal, bool bUpdate = false)\n\t{\n\t\treturn SetValue(UI_PKEY_DecimalValue, vVal, bUpdate);\n\t}\n\n\tHRESULT SetIncrement(V vIncrement, bool bUpdate = false)\n\t{\n\t\treturn SetValue(UI_PKEY_Increment, vIncrement, bUpdate);\n\t}\n\n\tHRESULT SetFormatString(LPCWSTR sFormat, bool bUpdate = false)\n\t{\n\t\treturn SetText(UI_PKEY_FormatString, sFormat, bUpdate);\n\t}\n\n\tHRESULT SetRepresentativeString(LPCWSTR sRepresentative, bool bUpdate = false)\n\t{\n\t\treturn SetText(UI_PKEY_RepresentativeString, sRepresentative, bUpdate);\n\t}\n\n\t// Implementation\n\tHRESULT SetText(REFPROPERTYKEY key, LPCWSTR sText, bool bUpdate = false)\n\t{\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_FormatString:\n\t\t\tm_FormatString = sText;\n\t\t\tbreak;\n\t\tcase k_RepresentativeString:\n\t\t\tm_RepresentativeString = sText;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn CtrlImpl::SetText(key, sText, bUpdate);\n\t\t}\n\n\t\treturn bUpdate ?\n\t\t\tGetWndRibbon().InvalidateProperty(GetID(), key) :\n\t\t\tS_OK;\n\t}\n\n\tHRESULT SetValue(REFPROPERTYKEY key, V val, bool bUpdate = false)\n\t{\n\t\tATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));\n\n\t\tconst INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;\n\t\tm_Values[iVal] = val;\n\n\t\tif (bUpdate)\n\t\t{\n\t\t\tif(k_(key) == k_DecimalValue)\n\t\t\t{\n\t\t\t\tDECIMAL decVal;\n\t\t\t\tInitDecimal(val, &decVal);\n\t\t\t\treturn SetProperty(key, &decVal);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn GetWndRibbon().InvalidateProperty(GetID(), key);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn S_OK;\n\t\t}\n\t}\n\n\tHRESULT QueryValue(REFPROPERTYKEY key, LONG* plVal)\n\t{\n\t\treturn GetWndRibbon().OnRibbonQuerySpinnerValue(GetID(), key, plVal) ? S_OK : S_FALSE;\n\t}\n\n\tHRESULT QueryValue(REFPROPERTYKEY key, DOUBLE* pdVal)\n\t{\n\t\treturn GetWndRibbon().OnRibbonQueryFloatSpinnerValue(GetID(), key, pdVal) ? S_OK : S_FALSE;\n\t}\n\n\tHRESULT OnGetValue(REFPROPERTYKEY key, PROPVARIANT* ppv)\n\t{\n\t\tATLASSERT((k_(key) <= k_DecimalPlaces) && (k_(key) >= k_DecimalValue));\n\n\t\tconst INT iVal = k_(key) == k_DecimalValue ? 0 : k_(key) - k_StringValue;\n\n\t\tQueryValue(key, m_Values + iVal);\n\n\t\tif (k_(key) == k_DecimalPlaces)\n\t\t{\n\t\t\treturn SetPropertyVal(key, m_Values[iVal], ppv);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDECIMAL decVal;\n\t\t\tInitDecimal(m_Values[iVal], &decVal);\n\t\t\treturn SetPropertyVal(key, &decVal, ppv);\n\t\t}\n\t}\n\n\tHRESULT OnGetText(REFPROPERTYKEY key, Text& sVal, PROPVARIANT* ppv)\n\t{\n\t\tif (LPCWSTR sNew = GetWndRibbon().OnRibbonQueryText(GetID(), key))\n\t\t\tsVal = sNew;\n\t\treturn SetPropertyVal(key, (LPCWSTR)sVal, ppv);\n\t}\n\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* /*pCommandExecutionProperties*/)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\t\tnCmdID;   // avoid level 4 warning\n\t\tATLASSERT (key && (k_(*key) == k_DecimalValue));\n\t\tkey;   // avoid level 4 warning\n\t\tATLASSERT (verb == UI_EXECUTIONVERB_EXECUTE);\n\t\tverb;   // avoid level 4 warning\n\n\t\tDECIMAL decVal;\n\n\t\tHRESULT hr = UIPropertyToDecimal(UI_PKEY_DecimalValue, *ppropvarValue, &decVal);\n\t\thr = InitVal(m_Values[0], &decVal);\n\n\t\tGetWndRibbon().OnRibbonSpinnerCtrlExecute(GetID(), &m_Values[0]);\n\n\t\treturn hr;\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                                 const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tATLASSERT (nCmdID == GetID());\n\n\t\tHRESULT hr = E_NOTIMPL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_DecimalPlaces:\n\t\tcase k_DecimalValue:\n\t\tcase k_Increment:\n\t\tcase k_MaxValue:\n\t\tcase k_MinValue:\n\t\t\thr = OnGetValue(key, ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_FormatString:\n\t\t\tif (m_FormatString.IsEmpty())\n\t\t\t\treturn OnGetText(key, m_FormatString, ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_RepresentativeString:\n\t\t\tif (m_RepresentativeString.IsEmpty())\n\t\t\t\treturn OnGetText(key, m_RepresentativeString, ppropvarNewValue);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\thr = CtrlImpl::DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\t// decimal conversion helpers\n\tstatic HRESULT InitDecimal(LONG& val, DECIMAL* pDecimal)\n\t{\n\t\treturn ::VarDecFromI4(val, pDecimal);\n\t}\n\n\tstatic HRESULT InitDecimal(DOUBLE& val, DECIMAL* pDecimal)\n\t{\n\t\treturn ::VarDecFromR8(val, pDecimal);\n\t}\n\n\tstatic HRESULT InitVal(LONG& val, const DECIMAL* pDecimal)\n\t{\n\t\treturn ::VarI4FromDec(pDecimal, &val);\n\t}\n\n\tstatic HRESULT InitVal(DOUBLE& val, const DECIMAL* pDecimal)\n\t{\n\t\treturn ::VarR8FromDec(pDecimal, &val);\n\t}\n};\n\n// CRibbonImpl Ribbon implementation class\n//\ntemplate <class T>\nclass CRibbonImpl : \n\t\tpublic CRibbonUpdateUI<T>,\n\t\tpublic ICtrl,\n\t\tpublic IUIApplication,\n\t\tpublic IUICommandHandler\n{\n\ttypedef CRibbonImpl<T> thisClass;\npublic:\n\ttypedef thisClass Ribbon;\n\ttypedef T WndRibbon;\n\n\tCRibbonImpl() : m_bRibbonUI(false), m_hgRibbonSettings(NULL)\n\t{\n#ifdef _DEBUG\n\t\tm_cRef = 1;\n#endif\n\t\tpWndRibbon = static_cast<T*>(this);\n\t\tHRESULT hr = ::CoInitialize(NULL);\n\t\tif(SUCCEEDED(hr))\n\t\t\tif (RunTimeHelper::IsRibbonUIAvailable())\n\t\t\t\thr = m_pIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework);\n\t\t\telse\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Ribbon UI not available\\n\"));\n\n\t\tif FAILED(hr)\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Ribbon construction failed\\n\"));\n\n\t\tATLASSERT(SUCCEEDED(hr));\n\t}\n\n\t~CRibbonImpl()\n\t{\n\t\t::GlobalFree(m_hgRibbonSettings);\n\t\tm_pIUIFramework.Release();\n\t\t::CoUninitialize();\n\t}\n\n\tICtrl& GetRibbonCtrl(UINT)\n\t{\n\t\treturn static_cast<ICtrl&>(*this);\n\t}\n\n\tATL::CComPtr<IUIFramework> m_pIUIFramework;\n\tHGLOBAL m_hgRibbonSettings;\n\tbool m_bRibbonUI;\n\n\tbool IsRibbonUI()\n\t{\n\t\treturn m_bRibbonUI;\n\t}\n\n\tIUIFramework* GetIUIFrameworkPtr()\n\t{\n\t\treturn m_pIUIFramework;\n\t}\n\n\ttemplate <typename I>\n\tI* GetRibbonViewPtr(UINT32 uID)\n\t{\n\t\tATLASSERT(m_pIUIFramework);\n\t\tATL::CComPtr<I> pI;\n\t\treturn m_pIUIFramework->GetView(uID, __uuidof(I), (void**) &pI) == S_OK ?\n\t\t\tpI : \n\t\t\tNULL;\n\t}\n\n\tIUIRibbon* GetRibbonPtr()\n\t{\n\t\treturn GetRibbonViewPtr<IUIRibbon>(0);\n\t}\n\n\tIUIContextualUI* GetMenuPtr(UINT32 uID)\n\t{\n\t\tATLASSERT(uID);\n\t\treturn GetRibbonViewPtr<IUIContextualUI>(uID);\n\t}\n\n\tUINT GetRibbonHeight()\n\t{\n\t\tATLASSERT(IsRibbonUI());\n\n\t\tUINT32 cy = 0;\n\t\tif (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())\n\t\t\tpIUIRibbon->GetHeight(&cy);\n\t\treturn cy;\n\t}\n\n\tHRESULT CreateRibbon(LPCWSTR sResName = L\"APPLICATION_RIBBON\")\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(GetIUIFrameworkPtr() && !IsRibbonUI());\n\t\tATLASSERT(pT->IsWindow());\n\n\t\tHRESULT hr = m_pIUIFramework->Initialize(pT->m_hWnd, this);\n\n\t\tif (hr == S_OK)\n\t\t\thr = m_pIUIFramework->LoadUI(ModuleHelper::GetResourceInstance(), sResName);\n\t\t\t\n\t\treturn hr;\n\t}\n\n\tHRESULT DestroyRibbon()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(GetIUIFrameworkPtr() && IsRibbonUI());\n\t\tATLASSERT(pT->IsWindow());\n\n\t\tHRESULT hRes = m_pIUIFramework->Destroy();\n\t\tif (!RunTimeHelper::IsWin7())\n\t\t\tpT->SetWindowRgn(NULL, TRUE); // Vista Basic bug workaround\n\t\treturn hRes;\n\t}\n\n// Ribbon persistency\n\tHRESULT operator >>(IStream* pIStream)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(pIStream);\n\n\t\tHRESULT hr = E_FAIL;\n\t\tif (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())\n\t\t{\n\t\t\tconst LARGE_INTEGER li0 = { 0 };\n\t\t\tpIStream->Seek(li0, STREAM_SEEK_SET, NULL);\n\t\t\thr = pIUIRibbon->SaveSettingsToStream(pIStream);\n\t\t\tpIStream->Commit(STGC_DEFAULT);\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tHRESULT operator <<(IStream* pIStream)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(pIStream);\n\n\t\tHRESULT hr = E_FAIL;\n\t\tif (ATL::CComPtr<IUIRibbon> pIUIRibbon = GetRibbonPtr())\n\t\t{\n\t\t\tconst LARGE_INTEGER li0 = { 0 };\n\t\t\tpIStream->Seek(li0, STREAM_SEEK_SET, NULL);\n\t\t\thr = pIUIRibbon->LoadSettingsFromStream(pIStream);\n\t\t}\n\n\t\treturn hr;\n\t}\n\n\tvoid ResetRibbonSettings()\n\t{\n\t\tif (m_hgRibbonSettings != NULL)\n\t\t{\n\t\t\t::GlobalFree(m_hgRibbonSettings);\n\t\t\tm_hgRibbonSettings = NULL;\n\t\t}\n\t}\n\n\tHRESULT SaveRibbonSettings()\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(static_cast<T*>(this)->IsWindow());\n\n\t\tHRESULT hr = E_FAIL;\n\t\tATL::CComPtr<IStream> pIStream;\n\n\t\tif SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))\n\t\t\thr = *this >> pIStream;\n\n\t\tif (SUCCEEDED(hr) && (m_hgRibbonSettings == NULL))\n\t\t\thr = ::GetHGlobalFromStream(pIStream, &m_hgRibbonSettings);\n\n\t\tif FAILED(hr)\n\t\t\tResetRibbonSettings();\n\n\t\treturn hr;\n\t}\n\n\tHRESULT RestoreRibbonSettings()\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(m_hgRibbonSettings);\n\t\tATLASSERT(static_cast<T*>(this)->IsWindow());\n\n\t\tHRESULT hr = E_FAIL;\n\t\tATL::CComPtr<IStream> pIStream;\n\n\t\tif SUCCEEDED(hr = ::CreateStreamOnHGlobal(m_hgRibbonSettings, FALSE, &pIStream))\n\t\t\thr = *this << pIStream;\n\n\t\tif FAILED(hr)\n\t\t\tResetRibbonSettings();\n\n\t\treturn hr;\n\t}\n\n// QAT dock states\n\tUI_CONTROLDOCK GetQATDock()\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\n\t\tUINT32 uDock = 0;\n\t\tPROPVARIANT propvar;\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());\n\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(UI_PKEY_QuickAccessToolbarDock, &propvar)) &&\n\t\t\tSUCCEEDED(UIPropertyToUInt32(UI_PKEY_QuickAccessToolbarDock, propvar, &uDock)))\n\t\t\t\treturn (UI_CONTROLDOCK)uDock;\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn (UI_CONTROLDOCK)0;\n\t}\n\n\tbool SetQATDock(UI_CONTROLDOCK dockState)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\n\t\tPROPVARIANT propvar;\n\t\tATLVERIFY(SUCCEEDED(SetPropertyVal(UI_PKEY_QuickAccessToolbarDock, dockState, &propvar)));\n\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(UI_PKEY_QuickAccessToolbarDock, propvar)))\n\t\t{\n\t\t\tpIPS->Commit();\n\t\t\treturn true;\n\t\t}\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn false;\n\t}\n\n// Ribbon display states\n\tbool GetRibbonDisplayState(REFPROPERTYKEY key)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\t\tATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));\n\n\t\tPROPVARIANT propvar;\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());\n\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))\n\t\t{\n\t\t\tBOOL bState = FALSE;\n\t\t\tif SUCCEEDED(UIPropertyToBoolean(key, propvar, &bState))\n\t\t\t\treturn (bState != FALSE);\n\t\t}\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn false;\n\t}\n\n\tbool SetRibbonDisplayState(REFPROPERTYKEY key, bool bState = true)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\t\tATLASSERT((k_(key) == k_Viewable) || (k_(key) == k_Minimized));\n\n\t\tPROPVARIANT propvar;\n\t\tATLVERIFY(SUCCEEDED(SetPropertyVal(key, bState, &propvar)));\n\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetRibbonPtr());\n\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))\n\t\t{\n\t\t\tpIPS->Commit();\n\t\t\treturn true;\n\t\t}\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn false;\n\t}\n\n\tbool IsRibbonMinimized()\n\t{\n\t\treturn GetRibbonDisplayState(UI_PKEY_Minimized);\n\t}\n\n\tbool MinimizeRibbon(bool bMinimize = true)\n\t{\n\t\treturn SetRibbonDisplayState(UI_PKEY_Minimized, bMinimize);\n\t}\n\n\tbool IsRibbonHidden()\n\t{\n\t\treturn !GetRibbonDisplayState(UI_PKEY_Viewable);\n\t}\n\n\tbool HideRibbon(bool bHide = true)\n\t{\n\t\treturn SetRibbonDisplayState(UI_PKEY_Viewable, !bHide);\n\t}\n\n// Ribbon colors\n\tUI_HSBCOLOR GetRibbonColor(REFPROPERTYKEY key)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\t\tATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));\n\n\t\tPROPVARIANT propvar;\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());\n\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->GetValue(key, &propvar)))\n\t\t{\n\t\t\tUINT32 color = 0;\n\t\t\tif SUCCEEDED(UIPropertyToUInt32(key, propvar, &color))\n\t\t\t\treturn color;\n\t\t}\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn 0;\n\t}\n\n\tbool SetRibbonColor(REFPROPERTYKEY key, UI_HSBCOLOR color)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\t\tATLASSERT(IsRibbonUI());\n\t\tATLASSERT((k_(key) >= k_GlobalBackgroundColor) && (k_(key) <= k_GlobalTextColor));\n\n\t\tPROPVARIANT propvar;\n\t\tATLVERIFY(SUCCEEDED(SetPropertyVal(key, color, &propvar)));\n\n\t\tATL::CComQIPtr<IPropertyStore>pIPS(GetIUIFrameworkPtr());\n\n\t\tif ((pIPS != NULL) && SUCCEEDED(pIPS->SetValue(key, propvar)))\n\t\t{\n\t\t\tpIPS->Commit();\n\t\t\treturn true;\n\t\t}\n\n\t\tATLASSERT(FALSE); // something was wrong\n\t\treturn false;\n\t}\n\n// Ribbon modes\n\tHRESULT SetRibbonModes(INT32 iModes)\n\t{\n\t\tATLASSERT(IsRibbonUI());\n\t\treturn GetIUIFrameworkPtr()->SetModes(iModes);\n\t}\n\n// Ribbon contextual tab\n\tUI_CONTEXTAVAILABILITY GetRibbonContextAvail(UINT32 uID)\n\t{\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\n\t\tPROPVARIANT propvar;\n\t\tif (IsRibbonUI() && \n\t\t    SUCCEEDED(GetIUIFrameworkPtr()->GetUICommandProperty(uID, UI_PKEY_ContextAvailable, &propvar)))\n\t\t{\n\t\t\tUINT uav;\n\t\t\tif (SUCCEEDED(PropVariantToUInt32(propvar, &uav)))\n\t\t\t{\n\t\t\t\tCUpdateUIBase::UIEnable(uID, uav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);\n\t\t\t\tCUpdateUIBase::UISetCheck(uID, uav == UI_CONTEXTAVAILABILITY_ACTIVE);\n\t\t\t\treturn (UI_CONTEXTAVAILABILITY)uav;\n\t\t\t}\n\t\t}\n\n\t\treturn UI_CONTEXTAVAILABILITY_NOTAVAILABLE;\n\t}\n\n\tHRESULT SetRibbonContextAvail(UINT32 uID, UI_CONTEXTAVAILABILITY cav)\n\t{\n\t\tCUpdateUIBase::UIEnable(uID, cav != UI_CONTEXTAVAILABILITY_NOTAVAILABLE);\n\t\tCUpdateUIBase::UISetCheck(uID, cav == UI_CONTEXTAVAILABILITY_ACTIVE);\n\t\t\n\t\treturn SetProperty((WORD)uID, UI_PKEY_ContextAvailable, UINT32(cav));\n\t}\n\n// Ribbon context menu\n\tbool HasRibbonMenu(UINT32 uID)\n\t{\n\t\tATL::CComPtr<IUIContextualUI> pI = GetMenuPtr(uID);\n\t\treturn pI != NULL;\n\t}\n\n\tHRESULT TrackRibbonMenu(UINT32 uID, INT32 x, INT32 y)\n\t{\n\t\tATLASSERT(HasRibbonMenu(uID));\n\n\t\treturn IsRibbonUI() ?\n\t\t\tATL::CComPtr<IUIContextualUI>(GetMenuPtr(uID))->ShowAtLocation(x, y) :\n\t\t\tE_FAIL;\n\t}\n\n\tHRESULT TrackRibbonMenu(UINT32 uID, LPARAM lParam)\n\t{\n\t\treturn TrackRibbonMenu(uID, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n\t}\n\n// Overrideables\n\tHBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY /*key*/)\n\t{\n\t\treturn DefRibbonQueryImage(nCmdID);\n\t}\n\n\tLPCWSTR OnRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)\n\t{\n\t\treturn DefRibbonQueryText(nCmdID, key);\n\t}\n\n\tbool OnRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)\n\t{\n\t\treturn DefRibbonQueryState(nCmdID, key);\n\t}\n\n\tUI_CONTEXTAVAILABILITY OnRibbonQueryTabAvail(UINT nCmdID)\n\t{\n\t\tDWORD dwState = UIGetState(nCmdID);\n\t\treturn ((dwState & UPDUI_DISABLED) == UPDUI_DISABLED) ? \n\t\t\tUI_CONTEXTAVAILABILITY_NOTAVAILABLE :\n\t\t\t(((dwState & UPDUI_CHECKED) == UPDUI_CHECKED) ? \n\t\t\t\tUI_CONTEXTAVAILABILITY_ACTIVE : \n\t\t\t\tUI_CONTEXTAVAILABILITY_AVAILABLE);\n\t}\n\n\tLPCWSTR OnRibbonQueryComboText(UINT32 /*uCtrlID*/)\n\t{\n\t\treturn NULL;\n\t}\n\n\tLPCWSTR OnRibbonQueryCategoryText(UINT32 /*uCtrlID*/, UINT32 /*uCat*/)\n\t{\n\t\treturn L\"Category\";\n\t}\n\n\tUINT32 OnRibbonQueryItemCategory(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)\n\t{\n\t\treturn 0;\n\t}\n\n\tLPCWSTR OnRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn DefRibbonQueryItemText(uCtrlID, uItem);\n\t}\n\n\tbool OnRibbonQuerySelectedItem(UINT32 /*uCtrlID*/, UINT32& /*uSel*/)\n\t{\n\t\treturn false;\n\t}\n\n\tHBITMAP OnRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn DefRibbonQueryItemImage(uCtrlID, uItem);\n\t}\n\n\tUINT32 OnRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn DefRibbonQueryItemCommand(uCtrlID, uItem);\n\t}\n\n\tUI_COMMANDTYPE OnRibbonQueryItemCommandType(UINT32 /*uCtrlID*/, UINT32 /*uItem*/)\n\t{\n\t\treturn UI_COMMANDTYPE_ACTION;\n\t}\n\n\tLPCWSTR OnRibbonQueryRecentItemName(LPCWSTR sPath)\n\t{\n\t\treturn ::PathFindFileName(sPath);\n\t}\n\n\tbool OnRibbonQueryFont(UINT /*nId*/, CHARFORMAT2& /*cf*/)\n\t{\n\t\treturn false;\n\t}\n\n\tbool OnRibbonQuerySpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, LONG* /*pVal*/)\n\t{\n\t\treturn false;\n\t}\n\n\tbool OnRibbonQueryFloatSpinnerValue(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/, DOUBLE* /*pVal*/)\n\t{\n\t\treturn false;\n\t}\n\n\tCOLORREF OnRibbonQueryColor(UINT /*nCmdID*/)\n\t{\n\t\treturn 0x800080; /*MAGENTA*/\n\t}\n\n\tLPCWSTR OnRibbonQueryColorLabel(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)\n\t{\n\t\treturn NULL;\n\t}\n\n\tCOLORREF* OnRibbonQueryColorArray(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)\n\t{\n\t\treturn NULL;\n\t}\n\n\tLPCWSTR* OnRibbonQueryColorTooltips(UINT /*nCmdID*/, REFPROPERTYKEY /*key*/)\n\t{\n\t\treturn NULL;\n\t}\n\n\tbool OnRibbonItemSelected(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UINT32 uItem)\n\t{\n\t\tDefCommandExecute(MAKELONG(uCtrlID, verb), uItem);\n\t\treturn true;\n\t}\n\n\tvoid OnRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)\n\t{\n\t\tDefRibbonColorCtrlExecute(uCtrlID, verb, uType, color);\n\t}\n\n\tvoid OnRibbonFontCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, CHARFORMAT2* pcf)\n\t{\n\t\tDefCommandExecute(MAKELONG(uCtrlID, verb), (LPARAM)pcf);\n\t}\n\n\tvoid OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, LONG* pVal)\n\t{\n\t\tDefCommandExecute(uCtrlID, *pVal);\n\t}\n\n\tvoid OnRibbonSpinnerCtrlExecute(UINT32 uCtrlID, DOUBLE* pVal)\n\t{\n\t\tDefCommandExecute(uCtrlID, (LPARAM)pVal);\n\t}\n\n\tvoid OnRibbonCommandExecute(UINT32 uCmdID)\n\t{\n\t\tDefCommandExecute(uCmdID);\n\t}\n\n// Default implementations\n\tHBITMAP DefRibbonQueryImage(UINT nCmdID)\n\t{\n\t\treturn AtlLoadBitmapImage(nCmdID, LR_CREATEDIBSECTION);\n\t}\n\n\tbool DefRibbonQueryState(UINT nCmdID, REFPROPERTYKEY key)\n\t{\n\t\tDWORD dwState = UIGetState(nCmdID);\n\t\tbool bRet = false;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_BooleanValue:\n\t\t\tbRet = (dwState & UPDUI_CHECKED) == UPDUI_CHECKED;\n\t\t\tbreak;\n\t\tcase k_Enabled:\n\t\t\tbRet = (dwState & UPDUI_DISABLED) != UPDUI_DISABLED;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tLPCTSTR DefRibbonQueryText(UINT nCmdID, REFPROPERTYKEY key)\n\t{\n\t\tstatic WCHAR sText[RIBBONUI_MAX_TEXT] = { 0 };\n\n\t\tif (k_(key) == k_Label)\n\t\t\t return UIGetText(nCmdID);\n\n\t\tif (AtlLoadString(nCmdID, sText, RIBBONUI_MAX_TEXT))\n\t\t{\n\t\t\tPWCHAR pTitle = wcschr(sText, L'\\n');\n\t\t\tswitch (k_(key))\n\t\t\t{\n\t\t\tcase k_Keytip:\n\t\t\t\tif (PWCHAR pAmp = wcschr(sText, L'&'))\n\t\t\t\t\tpTitle = pAmp;\n\t\t\t\tif (pTitle != NULL)\n\t\t\t\t\t*(pTitle + 2) = NULL; // fall through\n\t\t\tcase k_TooltipTitle:\n\t\t\t\treturn pTitle ? ++pTitle : NULL;\n\t\t\tcase k_TooltipDescription:\n\t\t\tcase k_LabelDescription:\n\t\t\t\tif (pTitle != NULL)\n\t\t\t\t\t*pTitle = NULL;\n\t\t\t\treturn sText;\n\t\t\t}\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tLPCWSTR DefRibbonQueryItemText(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn DefRibbonQueryText(uCtrlID + 1 + uItem, UI_PKEY_LabelDescription);\n\t}\n\n\tHBITMAP DefRibbonQueryItemImage(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn DefRibbonQueryImage(uCtrlID + 1 + uItem);\n\t}\n\n\tUINT32 DefRibbonQueryItemCommand(UINT32 uCtrlID, UINT32 uItem)\n\t{\n\t\treturn uCtrlID + 1 + uItem;\n\t}\n\n\tvoid DefRibbonColorCtrlExecute(UINT32 uCtrlID, UI_EXECUTIONVERB verb, UI_SWATCHCOLORTYPE uType, COLORREF color)\n\t{\n\t\tswitch(uType)\n\t\t{\n\t\tcase UI_SWATCHCOLORTYPE_RGB:\n\t\t\tbreak;\n\t\tcase UI_SWATCHCOLORTYPE_AUTOMATIC:\n\t\t\tcolor = ::GetSysColor(COLOR_WINDOWTEXT);\n\t\t\tbreak;\n\t\tcase UI_SWATCHCOLORTYPE_NOCOLOR:\n\t\t\tcolor = ::GetSysColor(COLOR_WINDOW);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tATLASSERT(FALSE);\n\t\t\tbreak;\n\t\t}\n\n\t\tDefCommandExecute(MAKELONG(uCtrlID, verb), color);\n\t}\n\n\tvoid DefCommandExecute(UINT32 uCmd, LPARAM lParam = 0)\n\t{\n\t\tstatic_cast<T*>(this)->PostMessage(WM_COMMAND, uCmd, lParam);\n\t}\n\n// Elements setting helpers\n\tHRESULT InvalidateCtrl(UINT32 nID)\n\t{\n\t\treturn IsRibbonUI() ?\n\t\t\tGetIUIFrameworkPtr()->InvalidateUICommand(nID, UI_INVALIDATIONS_ALLPROPERTIES, NULL) :\n\t\t\tE_FAIL;\n\t}\n\n\tHRESULT InvalidateProperty(UINT32 nID, REFPROPERTYKEY key, UI_INVALIDATIONS flags = UI_INVALIDATIONS_PROPERTY)\n\t{\n\t\treturn IsRibbonUI() ?\n\t\t\tGetIUIFrameworkPtr()->InvalidateUICommand(nID, flags, &key) :\n\t\t\tE_FAIL;\n\t}\n\n\ttemplate <typename V>\n\tHRESULT SetProperty(WORD wID, REFPROPERTYKEY key, V val)\n\t{\n\t\tif (IsRibbonUI())\n\t\t{\n\t\t\tPROPVARIANT var;\n\t\t\tif (SUCCEEDED(RibbonUI::SetPropertyVal(key, val, &var)))\n\t\t\t{\n\t\t\t\treturn SetProperty(wID, key, var);\n\t\t\t}\n\t\t\treturn E_INVALIDARG;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn E_FAIL;\n\t\t}\n\t}\n\n\ttemplate <>\n\tHRESULT SetProperty(WORD nID, REFPROPERTYKEY key, PROPVARIANT var)\n\t{\n\t\treturn IsRibbonUI() ?\n\t\t\tGetIUIFrameworkPtr()->SetUICommandProperty(nID, key, var) :\n\t\t\tE_FAIL;\n\t}\n\n// Interfaces\n\t// IUIApplication\n\tSTDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB verb, INT32)\n\t{\n\t\tswitch (verb)\n\t\t{\t\t\t\n\t\tcase UI_VIEWVERB_CREATE:\n\t\t\tm_bRibbonUI = true;\n\t\t\tif (m_hgRibbonSettings != NULL)\n\t\t\t\tRestoreRibbonSettings();\n\t\t\tbreak;\n\t\tcase UI_VIEWVERB_SIZE:\n\t\t\tstatic_cast<T*>(this)->UpdateLayout(FALSE);\n\t\t\tbreak;\n\t\tcase UI_VIEWVERB_DESTROY:\n\t\t\tSaveRibbonSettings();\n\t\t\tm_bRibbonUI = false;\n\t\t\tbreak;\n\t\t}\n\n\t\treturn S_OK;\n\t}\n\n\tSTDMETHODIMP OnCreateUICommand(UINT32 nCmdID, UI_COMMANDTYPE typeID, IUICommandHandler** ppCommandHandler)\n\t{\n\t\tUIAddRibbonElement(nCmdID);\n\t\tif (typeID == UI_COMMANDTYPE_CONTEXT)\n\t\t\tCUpdateUIBase::UIEnable(nCmdID, false);\n\t\t*ppCommandHandler = this;\n\t\treturn S_OK;\n\t}\n\n\tSTDMETHODIMP OnDestroyUICommand(UINT32 nCmdID, UI_COMMANDTYPE, IUICommandHandler*)\n\t{\n\t\tUIRemoveRibbonElement(nCmdID);\n\t\treturn S_OK;\n\t}\n\n\t// IUICommandHandler\n\tSTDMETHODIMP Execute(UINT nCmdID,\n\t\tUI_EXECUTIONVERB verb, \n\t\tconst PROPERTYKEY* key,\n\t\tconst PROPVARIANT* ppropvarValue,\n\t\tIUISimplePropertySet* pCommandExecutionProperties)\n\t{\n\t\tT* pT =static_cast<T*>(this);\n\t\treturn pT->GetRibbonCtrl(nCmdID).DoExecute(nCmdID, verb, key, ppropvarValue, pCommandExecutionProperties);\t\n\t}\n\n\tSTDMETHODIMP UpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t                            const PROPVARIANT* ppropvarCurrentValue, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tT* pT =static_cast<T*>(this);\n\t\treturn pT->GetRibbonCtrl(nCmdID).DoUpdateProperty(nCmdID, key, ppropvarCurrentValue, ppropvarNewValue);\t\n\t}\n\n#ifdef _DEBUG\n\t// IUnknown methods (heavyweight)\n\tSTDMETHODIMP_(ULONG) AddRef()\n\t{\n\t\treturn InterlockedIncrement(&m_cRef);\n\t}\n\n\tSTDMETHODIMP_(ULONG) Release()\n\t{\n\t\tLONG cRef = InterlockedDecrement(&m_cRef);\n\t\tif (cRef == 0) // NoOp for breakpoint\n\t\t{\n\t\t\tcRef = 0;\n\t\t}\n\n\t\treturn cRef;\n\t}\n\n\tSTDMETHODIMP QueryInterface(REFIID iid, void** ppv)\n\t{\n\t\tif (ppv == NULL)\n\t\t{\n\t\t\treturn E_POINTER;\n\t\t}\n\t\telse if ((iid == __uuidof(IUnknown)) ||\n\t\t         (iid == __uuidof(IUICommandHandler)) ||\n\t\t         (iid == __uuidof(IUIApplication)))\n\t\t{\n\t\t\t*ppv = this;\n\t\t\tAddRef();\n\t\t\treturn S_OK;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn E_NOINTERFACE;\n\t\t}\n\t}\n\n\tLONG m_cRef;\n#else\n\t// IUnknown methods (lightweight)\n\tSTDMETHODIMP QueryInterface(REFIID iid, void** ppv)\n\t{\n\t\tif ((iid == __uuidof(IUnknown)) ||\n\t\t    (iid == __uuidof(IUICommandHandler)) ||\n\t\t    (iid == __uuidof(IUIApplication)))\n\t\t{\n\t\t\t*ppv = this;\n\t\t\treturn S_OK;\n\t\t}\n\t\treturn E_NOINTERFACE;\n\t}\n\tULONG STDMETHODCALLTYPE AddRef()\n\t{\n\t\treturn 1;\n\t}\n\tULONG STDMETHODCALLTYPE Release()\n\t{\n\t\treturn 1;\n\t}\n#endif\n\n// CRibbonImpl ICtrl implementation\n\tvirtual HRESULT DoExecute(UINT nCmdID, UI_EXECUTIONVERB verb, \n\t                          const PROPERTYKEY* key, const PROPVARIANT* ppropvarValue,\n\t                          IUISimplePropertySet* /*pCommandExecutionProperties*/)\n\t{\n\t\tif (key != NULL)\n\t\t{\n\t\t\tif(k_(*key) != k_BooleanValue)\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Control ID %d is not handled\\n\"), nCmdID);\n\t\t\t\treturn E_NOTIMPL;\n\t\t\t}\n\t\t\tBOOL bChecked = FALSE;\n\t\t\tATLVERIFY(SUCCEEDED(PropVariantToBoolean(*ppropvarValue, &bChecked)));\n\t\t\tCUpdateUIBase::UISetCheck(nCmdID, bChecked);\n\t\t}\n\n\t\tATLASSERT(verb == UI_EXECUTIONVERB_EXECUTE);\n\t\tverb;   // avoid level 4 warning\n\n\t\tstatic_cast<T*>(this)->OnRibbonCommandExecute(nCmdID);\n\t\t\n\t\treturn S_OK;\n\t}\n\n\tvirtual HRESULT DoUpdateProperty(UINT nCmdID, REFPROPERTYKEY key, \n\t\tconst PROPVARIANT* /*ppropvarCurrentValue*/, PROPVARIANT* ppropvarNewValue)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tHRESULT hr = E_NOTIMPL;\n\t\tswitch (k_(key))\n\t\t{\n\t\tcase k_LargeImage:\n\t\tcase k_LargeHighContrastImage:\n\t\tcase k_SmallImage:\n\t\tcase k_SmallHighContrastImage:\n\t\t\tif (HBITMAP hbm = pT->OnRibbonQueryImage(nCmdID, key))\n\t\t\t\thr = SetPropertyVal(key, GetImage(hbm, UI_OWNERSHIP_TRANSFER), ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_Label:\n\t\tcase k_Keytip:\n\t\tcase k_TooltipTitle:\n\t\tcase k_TooltipDescription:\n\t\tcase k_LabelDescription:\n\t\t\tif (LPCWSTR sText = pT->OnRibbonQueryText(nCmdID, key))\n\t\t\t\thr = SetPropertyVal(key, sText, ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_BooleanValue:\n\t\tcase k_Enabled:\n\t\t\thr = SetPropertyVal(key, pT->OnRibbonQueryState(nCmdID, key), ppropvarNewValue);\n\t\t\tbreak;\n\t\tcase k_ContextAvailable:\n\t\t\thr = SetPropertyVal(key, pT->OnRibbonQueryTabAvail(nCmdID), ppropvarNewValue);\n\t\t\tbreak;\n\t\t}\n\n\t\treturn hr;\n\t}\n\n// CRibbonImpl::CRibbonXXXCtrl specialized classes\n\t //CRibbonComboCtrl\n\ttemplate <UINT t_ID, size_t t_items, size_t t_categories = 0>\n\tclass CRibbonComboCtrl : public CollectionCtrlImpl<T, t_ID, ComboCollectionImpl<CRibbonComboCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>\n\t{\n\tpublic:\n\t\tCRibbonComboCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonItemGalleryCtrl\n\ttemplate <UINT t_ID, size_t t_items, size_t t_categories = 0>\n\tclass CRibbonItemGalleryCtrl : public CollectionCtrlImpl<T, t_ID, ItemCollectionImpl<CRibbonItemGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>\n\t{\n\tpublic:\n\t\tCRibbonItemGalleryCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonCommandGalleryCtrl\n\ttemplate <UINT t_ID, size_t t_items, size_t t_categories = 0>\n\tclass CRibbonCommandGalleryCtrl : public CollectionCtrlImpl<T, t_ID, CommandCollectionImpl<CRibbonCommandGalleryCtrl<t_ID, t_items, t_categories>, t_items, t_categories>>\n\t{\n\tpublic:\n\t\tCRibbonCommandGalleryCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonToolbarGalleryCtrl\n\ttemplate <UINT t_ID, UINT t_idTB, size_t t_size>\n\tclass CRibbonToolbarGalleryCtrl : public ToolbarGalleryCtrlImpl<T, t_ID, t_idTB, t_size>\n\t{ };\n\n\t// CRibbonSimpleComboCtrl\n\ttemplate <UINT t_ID, size_t t_size>\n\tclass CRibbonSimpleComboCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size>\n\t{ };\n\n\t// CRibbonSimpleGalleryCtrl\n\ttemplate <UINT t_ID, size_t t_size, UI_COMMANDTYPE t_CommandType = UI_COMMANDTYPE_ACTION>\n\tclass CRibbonSimpleGalleryCtrl : public SimpleCollectionCtrlImpl<T, t_ID, t_size, t_CommandType>\n\t{ };\n\n\t//CRibbonRecentItemsCtrl\n\ttemplate <UINT t_ID, class TDocList = CRecentDocumentList>\n\tclass CRibbonRecentItemsCtrl : public RecentItemsCtrlImpl<T, t_ID, TDocList>\n\t{\n\tpublic:\n\t\tCRibbonRecentItemsCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonColorCtrl\n\ttemplate <UINT t_ID>\n\tclass CRibbonColorCtrl : public ColorCtrlImpl<T, t_ID>\n\t{\n\tpublic:\n\t\tCRibbonColorCtrl()\n\t\t{ }\n\t};\n\n\t //CRibbonFontCtrl\n\ttemplate <UINT t_ID>\n\tclass CRibbonFontCtrl : public FontCtrlImpl<T, t_ID>\n\t{\n\tpublic:\n\t\tCRibbonFontCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonSpinnerCtrl\n\ttemplate <UINT t_ID>\n\tclass CRibbonSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, LONG>\n\t{\n\tpublic:\n\t\tCRibbonSpinnerCtrl()\n\t\t{ }\n\t};\n\n\t// CRibbonFloatSpinnerCtrl\n\ttemplate <UINT t_ID>\n\tclass CRibbonFloatSpinnerCtrl : public SpinnerCtrlImpl<T, t_ID, DOUBLE>\n\t{\n\tpublic:\n\t\tCRibbonFloatSpinnerCtrl()\n\t\t{\n\t\t\tm_Values[4] = 1; // 1 decimal\n\t\t}\n\t};\n\n\t// CRibbonCommandCtrl\n\ttemplate <UINT t_ID>\n\tclass CRibbonCommandCtrl : public CommandCtrlImpl<T, t_ID>\n\t{\n\tpublic:\n\t\tCRibbonCommandCtrl()\n\t\t{ }\n\t};\n\n// Control classes access to T instance (re-initialized in constructor)\n\tstatic T* pWndRibbon;\n};\n\ntemplate <class T>\n__declspec(selectany) T* CRibbonImpl<T>::pWndRibbon;\n\n// Control map element\n#pragma warning(push)\n#pragma warning(disable: 4510 610 4512)   // missing default constructor, can't be instatiated, assignment operator could not be generated\ntypedef struct\n{\n\tUINT uID;\n\tICtrl& ctrl;\n} _ribbonCtrl;\n#pragma warning(pop)\n\n}; // namespace RibbonUI\n\n\n///////////////////////////////////////////////////////////////////////////////\n// RibbonUI Control map\n\n// Control map macros\n#define BEGIN_RIBBON_CONTROL_MAP(theClass) \\\n\tWTL::RibbonUI::ICtrl& GetRibbonCtrl(UINT id) \\\n\t{ \\\n\t\tWTL::RibbonUI::_ribbonCtrl _ctrls[] = \\\n\t\t{\n\n#define RIBBON_CONTROL(member) {member.GetID(), static_cast<WTL::RibbonUI::ICtrl&>(member)},\n\n#define END_RIBBON_CONTROL_MAP() \\\n\t\t{0, *this} \\\n\t}; \\\n\tint i = 0; \\\n\tfor(; i < _countof(_ctrls) - 1; i++) \\\n\t\tif (_ctrls[i].uID == id) \\\n\t\t\tbreak; \\\n\treturn _ctrls[i].ctrl; \\\n}\n\n// Control message map macros\n#define RIBBON_GALLERY_CONTROL_HANDLER(id, func) \\\n\tif(uMsg == WM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (UINT)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define RIBBON_COMBO_CONTROL_HANDLER(id, func) \\\n\tRIBBON_GALLERY_CONTROL_HANDLER(id, func)\t\n\n#define RIBBON_FONT_CONTROL_HANDLER(id, func) \\\n\tif(uMsg == WM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (CHARFORMAT2*)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define RIBBON_COLOR_CONTROL_HANDLER(id, func) \\\n\tif(uMsg == WM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((UI_EXECUTIONVERB)HIWORD(wParam), LOWORD(wParam), (COLORREF)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define RIBBON_SPINNER_CONTROL_HANDLER(id, func) \\\n\tif(uMsg == WM_COMMAND && id == wParam) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((WORD)wParam, (LONG)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define RIBBON_FLOATSPINNER_CONTROL_HANDLER(id, func) \\\n\tif(uMsg == WM_COMMAND && id == wParam) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((WORD)wParam, (DOUBLE*)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n// Handler prototypes\n/*\n\tLRESULT OnRibbonGalleryCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);\n\tLRESULT OnRibbonComboCtrl(UI_EXECUTIONVERB verb, WORD wID, UINT uSel, BOOL& bHandled);\n\tLRESULT OnRibbonFontCtrl(UI_EXECUTIONVERB verb, WORD wID, CHARFORMAT2* pcf, BOOL& bHandled);\n\tLRESULT OnRibbonColorCtrl(UI_EXECUTIONVERB verb, WORD wID, COLORREF color, BOOL& bHandled);\n\tLRESULT OnRibbonSpinnerCtrl(WORD wID, LONG lVal, BOOL& bHandled);\n\tLRESULT OnRibbonFloatSpinnerCtrl(WORD wID, DOUBLE* pdVal, BOOL& bHandled);\n*/\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Ribbon frame classes\n\n// CRibbonFrameWindowImplBase\n//\ntemplate <class T, class TFrameImpl>\nclass ATL_NO_VTABLE CRibbonFrameWindowImplBase : public TFrameImpl, public RibbonUI::CRibbonImpl<T>\n{\n\ttypedef TFrameImpl baseFrame;\n\tbool m_bUseCommandBarBitmaps;\n\tbool m_bWin7Fix;\n\npublic:\n// Construction\n\tCRibbonFrameWindowImplBase(bool bUseCommandBarBitmaps = true) : \n\t\t\tm_bUseCommandBarBitmaps(bUseCommandBarBitmaps), m_bWin7Fix(false)\n\t{\n\t\t__if_not_exists(T::m_CmdBar)\n\t\t{\n\t\t\tm_bUseCommandBarBitmaps = false;\n\t\t}\n\t}\n\n// Win7 Aero fix helpers\n\tvoid ResetFrame()\n\t{\n\t\tconst MARGINS margins = { 0 };\n\t\t::DwmExtendFrameIntoClientArea(m_hWnd, &margins);\n\t}\n\n\tINT CalcWin7Fix()\n\t{\n\t\tResetFrame();\n\t\tRECT rc = { 0 };\n\t\t::AdjustWindowRectEx(&rc, T::GetWndStyle(0), GetMenu() != NULL, T::GetWndExStyle(0));\n\t\treturn -rc.top;\n\t}\n\n\tbool NeedWin7Fix()\n\t{\n\t\tBOOL bComp = FALSE;\n\t\treturn m_bWin7Fix && RunTimeHelper::IsWin7() && SUCCEEDED(DwmIsCompositionEnabled(&bComp)) && bComp;\n\t}\n\n// Operations\n\tbool UseCommandBarBitmaps(bool bUse)\n\t{\n\t\t__if_exists(T::m_CmdBar)\n\t\t{\n\t\t\treturn m_bUseCommandBarBitmaps = bUse;\n\t\t}\n\t\t__if_not_exists(T::m_CmdBar)\n\t\t{\n\t\t\tbUse;   // avoid level 4 warning\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tbool ShowRibbonUI(bool bShow, INT32 imodes = UI_MAKEAPPMODE(0), LPCWSTR sResName = L\"APPLICATION_RIBBON\")\n\t{\n\t\tif (!RunTimeHelper::IsRibbonUIAvailable())\n\t\t\treturn false;\n\n\t\tATLASSERT(GetIUIFrameworkPtr());\n\n\t\tif (IsRibbonUI() == bShow)\n\t\t\treturn bShow;\n\n\t\tbool bVisible = (IsWindowVisible() != FALSE);\n\t\tif(bVisible && !bShow)\n\t\t\tSetRedraw(FALSE);\n\n\t\tif (bShow && ::IsWindow(m_hWndToolBar))\n\t\t{\n\t\t\t::ShowWindow(m_hWndToolBar, SW_HIDE);\n\t\t\tUpdateLayout();\n\t\t}\n\n\t\tm_bWin7Fix = !bShow;\n\n\t\tHRESULT hr = bShow ? CreateRibbon(sResName) : DestroyRibbon();\n\n\t\tm_bWin7Fix = SUCCEEDED(hr) && !bShow;\n\n\t\tif (SUCCEEDED(hr))\n\t\t{\n\t\t\tif(::IsWindow(m_hWndToolBar) && !bShow)\n\t\t\t{\n\t\t\t\t::ShowWindow(m_hWndToolBar, SW_SHOWNA);\n\t\t\t\tUpdateLayout(); \n\t\t\t}\n\t\t\telse if (bShow)\n\t\t\t{\n\t\t\t\tPostMessage(WM_SIZE); \n\t\t\t\tSetRibbonModes(imodes);\n\t\t\t}\n\t\t}\n\n\t\tif(bVisible && !bShow)\n\t\t{\n\t\t\tSetRedraw(TRUE);\n\t\t\tRedrawWindow(NULL, NULL, RDW_FRAME | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);\n\t\t}\n\n\t\treturn SUCCEEDED(hr) ? bShow : !bShow;\n\t}\n\n// Overrideables\n\tHBITMAP OnRibbonQueryImage(UINT nCmdID, REFPROPERTYKEY key)\n\t{\n\t\tif ((key == UI_PKEY_SmallImage) && m_bUseCommandBarBitmaps)\n\t\t{\n\t\t\tif (HBITMAP hbm = GetCommandBarBitmap(nCmdID))\n\t\t\t\treturn (HBITMAP)::CopyImage(hbm, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);\n\t\t}\n\n\t\treturn DefRibbonQueryImage(nCmdID);\n\t}\n\n\tBEGIN_MSG_MAP(CRibbonFrameWindowImplBase)\n\t\tif (!IsRibbonUI() && NeedWin7Fix())\n\t\t{\n\t\t\tMESSAGE_HANDLER(WM_SIZING, OnSizing)\n\t\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnActivate)\n\t\t\tMESSAGE_HANDLER(WM_NCCALCSIZE, OnNCCalcSize)\n\t\t}\n\t\tCHAIN_MSG_MAP(CRibbonUpdateUI<T>)\n\t\tCHAIN_MSG_MAP(baseFrame)\n\tEND_MSG_MAP()\n\n// Message handlers for Win7 Aero\n\tLRESULT OnSizing(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tswitch (wParam)\n\t\t{\t\t\n\t\tcase WMSZ_TOP:\n\t\tcase WMSZ_TOPLEFT:\n\t\tcase WMSZ_TOPRIGHT:\n\t\t\tSetWindowPos(NULL, (LPRECT)lParam, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tDefWindowProc();\n\t\t\tbreak;\n\t\t}\n\n\t\treturn 1; // handled\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif (wParam != SIZE_MINIMIZED)\n\t\t\tSetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam != WA_INACTIVE)\n\t\t\tSetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnNCCalcSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tATLASSERT(!IsRibbonUI() && NeedWin7Fix());\n\n\t\tLRESULT lRet = DefWindowProc();\n\n\t\tif(wParam)\n\t\t{\n\t\t\tLPNCCALCSIZE_PARAMS pParams = (LPNCCALCSIZE_PARAMS)lParam;\n\t\t\tpParams->rgrc[0].top = pParams->rgrc[1].top + CalcWin7Fix();\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n// Overrides\n\tvoid UpdateLayout(BOOL bResizeBars = TRUE)\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\n\t\tif (IsRibbonUI() && !IsRibbonHidden())\n\t\t{\n\t\t\trect.top += GetRibbonHeight(); \n\t\t}\n\t\telse if (!IsRibbonUI() && NeedWin7Fix())\n\t\t{\n\t\t\tResetFrame();\n\t\t}\n\n\t\t// position bars and offset their dimensions\n\t\tUpdateBarsPosition(rect, bResizeBars);\n\n\t\t// resize client window\n\t\tif(m_hWndClient != NULL)\n\t\t\t::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,\n\t\t\t\trect.right - rect.left, rect.bottom - rect.top,\n\t\t\t\tSWP_NOZORDER | SWP_NOACTIVATE);\n\t}\n\n\t// Implementation\n\tHBITMAP GetCommandBarBitmap(UINT nCmdID)\n\t{\n\t\t__if_exists (T::m_CmdBar)\n\t\t{\n\t\t\tATLASSERT(RunTimeHelper::IsVista());\n\t\t\tT* pT =static_cast<T*>(this);\n\t\t\tint nIndex = pT->m_CmdBar.m_arrCommand.Find((WORD&)nCmdID);\n\t\t\treturn (nIndex == -1) ? NULL : pT->m_CmdBar.m_arrVistaBitmap[nIndex];\n\t\t}\n\t\t__if_not_exists (T::m_CmdBar)\n\t\t{\n\t\t\tnCmdID;   // avoid level 4 warning\n\t\t\treturn NULL;\n\t\t}\n\t}\n};\n\n// CRibbonFrameWindowImpl\n//\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>\nclass ATL_NO_VTABLE CRibbonFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CFrameWindowImpl<T, TBase, TWinTraits>>\n{ };\n\n// CRibbonMDIFrameWindowImpl\n//\ntemplate <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>\nclass ATL_NO_VTABLE CRibbonMDIFrameWindowImpl : public CRibbonFrameWindowImplBase<T, CMDIFrameWindowImpl<T, TBase, TWinTraits>>\n{ };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CRibbonPersist helper for RibbonUI persistency\n\nclass CRibbonPersist\n{\npublic:\n\tCRibbonPersist(LPCWSTR sAppKey)\n\t{\n\t\tATLASSERT(sAppKey && *sAppKey);\n\t\tm_Key.Create(HKEY_CURRENT_USER, sAppKey);\n\t\tATLASSERT(m_Key.m_hKey);\n\t}\n\n\tCRegKeyEx m_Key;\n\n\tLONG Save(bool bRibbonUI, HGLOBAL hgSettings = NULL)\n\t{\n\t\tCRegKeyEx key;\n\t\tconst DWORD dwUI = bRibbonUI;\n\n\t\tLONG lRet = key.Create(m_Key, L\"Ribbon\");\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn lRet;\n\t\t\n\t\tlRet = key.SetDWORDValue(L\"UI\", dwUI);\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn lRet;\n\n\t\tif (hgSettings != NULL)\n\t\t{\n\t\t\tLPBYTE pVal = (LPBYTE)::GlobalLock(hgSettings);\n\t\t\tif (pVal != NULL)\n\t\t\t{\n\t\t\t\tlRet = key.SetBinaryValue(L\"Settings\", pVal, (ULONG)::GlobalSize(hgSettings));\n\t\t\t\t::GlobalUnlock(hgSettings);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlRet = GetLastError();\n\t\t\t}\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n\tLONG Restore(bool& bRibbonUI, HGLOBAL& hgSettings)\n\t{\n\t\tATLASSERT(hgSettings == NULL);\n\n\t\tCRegKeyEx key;\n\n\t\tLONG lRet = key.Open(m_Key, L\"Ribbon\");\n\t\tif(lRet != ERROR_SUCCESS)\n\t\t\treturn lRet;\n\t\t\n\t\tDWORD dwUI = 0xffff;\n\t\tlRet = key.QueryDWORDValue(L\"UI\", dwUI);\n\t\tif(lRet == ERROR_SUCCESS)\n\t\t\tbRibbonUI = dwUI == 1;\n\t\telse\n\t\t\treturn lRet;\n\n\t\tULONG ulSize = 0;\n\t\tlRet = key.QueryBinaryValue(L\"Settings\", NULL, &ulSize);\n\t\tif (lRet == ERROR_SUCCESS)\n\t\t{\n\t\t\tATLASSERT(ulSize != 0);\n\t\t\t\n\t\t\thgSettings = ::GlobalAlloc(GHND, ulSize);\n\t\t\tif (hgSettings != NULL)\n\t\t\t{\n\t\t\t\tLPBYTE pData = (LPBYTE)::GlobalLock(hgSettings);\n\t\t\t\tif (pData != NULL)\n\t\t\t\t{\n\t\t\t\t\tlRet = key.QueryBinaryValue(L\"Settings\", pData, &ulSize);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlRet = GetLastError();\n\t\t\t\t\t::GlobalFree(hgSettings);\n\t\t\t\t\thgSettings = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlRet = GetLastError();\n\t\t\t}\n\t\t}\n\t\treturn lRet;\n\t}\n\n\tLONG Delete()\n\t{\n\t\treturn m_Key.DeleteSubKey(L\"Ribbon\");\n\t}\n};\n\n} // namespace WTL\n\n#endif // __ATLRIBBON_H__\n"
  },
  {
    "path": "WTL/atlscrl.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLSCRL_H__\n#define __ATLSCRL_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlscrl.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlscrl.h requires atlwin.h to be included first\n#endif\n\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n  #include <zmouse.h>\n#endif\n\n#ifndef GET_WHEEL_DELTA_WPARAM\n  #define GET_WHEEL_DELTA_WPARAM(wParam)  ((short)HIWORD(wParam))\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CScrollImpl<T>\n// CScrollWindowImpl<T, TBase, TWinTraits>\n// CMapScrollImpl<T>\n// CMapScrollWindowImpl<T, TBase, TWinTraits>\n// CFSBWindowT<TBase>\n// CZoomScrollImpl<T>\n// CZoomScrollWindowImpl<T, TBase, TWinTraits>\n// CScrollContainerImpl<T, TBase, TWinTraits>\n// CScrollContainer\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CScrollImpl - Provides scrolling support to any window\n\n// Scroll extended styles\n#define SCRL_SCROLLCHILDREN\t0x00000001\n#define SCRL_ERASEBACKGROUND\t0x00000002\n#define SCRL_NOTHUMBTRACKING\t0x00000004\n#if (WINVER >= 0x0500)\n#define SCRL_SMOOTHSCROLL\t0x00000008\n#endif // (WINVER >= 0x0500)\n#define SCRL_DISABLENOSCROLLV\t0x00000010\n#define SCRL_DISABLENOSCROLLH\t0x00000020\n#define SCRL_DISABLENOSCROLL\t(SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH)\n\n\ntemplate <class T>\nclass CScrollImpl\n{\npublic:\n\tenum { uSCROLL_FLAGS = SW_INVALIDATE };\n\n\tPOINT m_ptOffset;\n\tSIZE m_sizeAll;\n\tSIZE m_sizeLine;\n\tSIZE m_sizePage;\n\tSIZE m_sizeClient;\n\tint m_zDelta;              // current wheel value\n\tint m_nWheelLines;         // number of lines to scroll on wheel\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t// Note that this message must be forwarded from a top level window\n\tUINT m_uMsgMouseWheel;     // MSH_MOUSEWHEEL\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\tint m_zHDelta;              // current horizontal wheel value\n\tint m_nHWheelChars;         // number of chars to scroll on horizontal wheel\n\tUINT m_uScrollFlags;\n\tDWORD m_dwExtendedStyle;   // scroll specific extended styles\n\n// Constructor\n\tCScrollImpl() : m_zDelta(0), m_nWheelLines(3), \n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\t\tm_uMsgMouseWheel(0U), \n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\t\tm_zHDelta(0), m_nHWheelChars(3), \n\t\t\tm_uScrollFlags(0U), m_dwExtendedStyle(0)\n\t{\n\t\tm_ptOffset.x = 0;\n\t\tm_ptOffset.y = 0;\n\t\tm_sizeAll.cx = 0;\n\t\tm_sizeAll.cy = 0;\n\t\tm_sizePage.cx = 0;\n\t\tm_sizePage.cy = 0;\n\t\tm_sizeLine.cx = 0;\n\t\tm_sizeLine.cy = 0;\n\t\tm_sizeClient.cx = 0;\n\t\tm_sizeClient.cy = 0;\n\n\t\tSetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND);\n\t}\n\n// Attributes & Operations\n\tDWORD GetScrollExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\t\t// cache scroll flags\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tm_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0);\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\t\tm_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0);\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\t\treturn dwPrevStyle;\n\t}\n\n\t// offset operations\n\tvoid SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tpT->AdjustScrollOffset(x, y);\n\n\t\tint dx = m_ptOffset.x - x;\n\t\tint dy = m_ptOffset.y - y;\n\t\tm_ptOffset.x = x;\n\t\tm_ptOffset.y = y;\n\n\t\t// block: set horizontal scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_POS;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nPos = m_ptOffset.x;\n\t\t\tpT->SetScrollInfo(SB_HORZ, &si, bRedraw);\n\t\t}\n\n\t\t// block: set vertical scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_POS;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nPos = m_ptOffset.y;\n\t\t\tpT->SetScrollInfo(SB_VERT, &si, bRedraw);\n\t\t}\n\n\t\t// Move all children if needed\n\t\tif(IsScrollingChildren() && (dx != 0 || dy != 0))\n\t\t{\n\t\t\tfor(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\t::GetWindowRect(hWndChild, &rect);\n\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);\n\t\t\t\t::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\n\t\t\t}\n\t\t}\n\n\t\tif(bRedraw)\n\t\t\tpT->Invalidate();\n\t}\n\n\tvoid SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)\n\t{\n\t\tSetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);\n\t}\n\n\tvoid GetScrollOffset(POINT& ptOffset) const\n\t{\n\t\tptOffset = m_ptOffset;\n\t}\n\n\t// size operations\n\tvoid SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tm_sizeAll.cx = cx;\n\t\tm_sizeAll.cy = cy;\n\n\t\tint x = 0;\n\t\tint y = 0;\n\t\tif(!bResetOffset)\n\t\t{\n\t\t\tx = m_ptOffset.x;\n\t\t\ty = m_ptOffset.y;\n\t\t\tpT->AdjustScrollOffset(x, y);\n\t\t}\n\n\t\tint dx = m_ptOffset.x - x;\n\t\tint dy = m_ptOffset.y - y;\n\t\tm_ptOffset.x = x;\n\t\tm_ptOffset.y = y;\n\n\t\t// block: set horizontal scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nMin = 0;\n\t\t\tsi.nMax = m_sizeAll.cx - 1;\n\t\t\tsi.nPage = m_sizeClient.cx;\n\t\t\tsi.nPos = m_ptOffset.x;\n\t\t\tpT->SetScrollInfo(SB_HORZ, &si, bRedraw);\n\t\t}\n\n\t\t// block: set vertical scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nMin = 0;\n\t\t\tsi.nMax = m_sizeAll.cy - 1;\n\t\t\tsi.nPage = m_sizeClient.cy;\n\t\t\tsi.nPos = m_ptOffset.y;\n\t\t\tpT->SetScrollInfo(SB_VERT, &si, bRedraw);\n\t\t}\n\n\t\t// Move all children if needed\n\t\tif(IsScrollingChildren() && (dx != 0 || dy != 0))\n\t\t{\n\t\t\tfor(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\t::GetWindowRect(hWndChild, &rect);\n\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);\n\t\t\t\t::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\n\t\t\t}\n\t\t}\n\n\t\tSetScrollLine(0, 0);\n\t\tSetScrollPage(0, 0);\n\n\t\tif(bRedraw)\n\t\t\tpT->Invalidate();\n\t}\n\n\tvoid SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tSetScrollSize(size.cx, size.cy, bRedraw, bResetOffset);\n\t}\n\n\tvoid GetScrollSize(SIZE& sizeWnd) const\n\t{\n\t\tsizeWnd = m_sizeAll;\n\t}\n\n\t// line operations\n\tvoid SetScrollLine(int cxLine, int cyLine)\n\t{\n\t\tATLASSERT(cxLine >= 0 && cyLine >= 0);\n\t\tATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);\n\n\t\tm_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100);\n\t\tm_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100);\n\t}\n\n\tvoid SetScrollLine(SIZE sizeLine)\n\t{\n\t\tSetScrollLine(sizeLine.cx, sizeLine.cy);\n\t}\n\n\tvoid GetScrollLine(SIZE& sizeLine) const\n\t{\n\t\tsizeLine = m_sizeLine;\n\t}\n\n\t// page operations\n\tvoid SetScrollPage(int cxPage, int cyPage)\n\t{\n\t\tATLASSERT(cxPage >= 0 && cyPage >= 0);\n\t\tATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);\n\n\t\tm_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10);\n\t\tm_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10);\n\t}\n\n\tvoid SetScrollPage(SIZE sizePage)\n\t{\n\t\tSetScrollPage(sizePage.cx, sizePage.cy);\n\t}\n\n\tvoid GetScrollPage(SIZE& sizePage) const\n\t{\n\t\tsizePage = m_sizePage;\n\t}\n\n\t// commands\n\tvoid ScrollLineDown()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollLineUp()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollPageDown()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollPageUp()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollTop()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollBottom()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t}\n\n\tvoid ScrollLineRight()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\tvoid ScrollLineLeft()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\tvoid ScrollPageRight()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\tvoid ScrollPageLeft()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\tvoid ScrollAllLeft()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\tvoid ScrollAllRight()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t}\n\n\t// scroll to make point/view/window visible\n\tvoid ScrollToView(POINT pt)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tRECT rect = { pt.x, pt.y, pt.x, pt.y };\n\t\tpT->ScrollToView(rect);\n\t}\n\n\tvoid ScrollToView(RECT& rect)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tRECT rcClient = { 0 };\n\t\tpT->GetClientRect(&rcClient);\n\n\t\tint x = m_ptOffset.x;\n\t\tif(rect.left < m_ptOffset.x)\n\t\t\tx = rect.left;\n\t\telse if(rect.right > (m_ptOffset.x + rcClient.right))\n\t\t\tx = rect.right - rcClient.right;\n\n\t\tint y = m_ptOffset.y;\n\t\tif(rect.top < m_ptOffset.y)\n\t\t\ty = rect.top;\n\t\telse if(rect.bottom > (m_ptOffset.y + rcClient.bottom))\n\t\t\ty = rect.bottom - rcClient.bottom;\n\n\t\tSetScrollOffset(x, y);\n\t}\n\n\tvoid ScrollToView(HWND hWnd)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tRECT rect = { 0 };\n\t\t::GetWindowRect(hWnd, &rect);\n\t\t::OffsetRect(&rect, m_ptOffset.x, m_ptOffset.y);\n\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2);\n\t\tScrollToView(rect);\n\t}\n\n\tBEGIN_MSG_MAP(CScrollImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n#endif // !_WIN32_WCE\n\t// standard scroll commands\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->GetSystemSettings();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t\treturn 0;\n\t}\n\n\tLRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tpT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)\n\t\tuMsg;\n\t\tint zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);\n#else\n\t\tint zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam;\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE))\n\t\tint nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN);\n\t\tm_zDelta += zDelta;   // cumulative\n\t\tint zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines;\n\t\tif(m_sizeAll.cy > m_sizeClient.cy)\n\t\t{\n\t\t\tfor(int i = 0; i < zTotal; i += WHEEL_DELTA)\n\t\t\t{\n\t\t\t\tpT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\n\t\t\t\tpT->UpdateWindow();\n\t\t\t}\n\t\t}\n\t\telse if(m_sizeAll.cx > m_sizeClient.cx)   // can't scroll vertically, scroll horizontally\n\t\t{\n\t\t\tfor(int i = 0; i < zTotal; i += WHEEL_DELTA)\n\t\t\t{\n\t\t\t\tpT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t\t\t\tpT->UpdateWindow();\n\t\t\t}\n\t\t}\n\t\tm_zDelta %= WHEEL_DELTA;\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tint zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);\n\t\tint nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT);\n\t\tm_zHDelta += zDelta;   // cumulative\n\t\tint zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars;\n\t\tif(m_sizeAll.cx > m_sizeClient.cx)\n\t\t{\n\t\t\tfor(int i = 0; i < zTotal; i += WHEEL_DELTA)\n\t\t\t{\n\t\t\t\tpT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\n\t\t\t\tpT->UpdateWindow();\n\t\t\t}\n\t\t}\n\t\tm_zHDelta %= WHEEL_DELTA;\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tGetSystemSettings();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tpT->DoSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tCDCHandle dc = (HDC)wParam;\n\t\t\tPOINT ptViewportOrg = { 0, 0 };\n\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\n\t\t\tpT->DoPaint(dc);\n\t\t\tdc.SetViewportOrg(ptViewportOrg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\n\t\t\tpT->DoPaint(dc.m_hDC);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// scrolling handlers\n\tLRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollLineUp();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollLineDown();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollPageUp();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollPageDown();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollTop();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollBottom();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollLineLeft();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollLineRight();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollPageLeft();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollPageRight();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollAllLeft();\n\t\treturn 0;\n\t}\n\n\tLRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tScrollAllRight();\n\t\treturn 0;\n\t}\n\n// Overrideables\n\tvoid DoPaint(CDCHandle /*dc*/)\n\t{\n\t\t// must be implemented in a derived class\n\t\tATLASSERT(FALSE);\n\t}\n\n// Implementation\n\tvoid DoSize(int cx, int cy)\n\t{\n\t\tm_sizeClient.cx = cx;\n\t\tm_sizeClient.cy = cy;\n\n\t\tT* pT = static_cast<T*>(this);\n\n\t\t// block: set horizontal scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\n\t\t\tsi.nMin = 0;\n\t\t\tsi.nMax = m_sizeAll.cx - 1;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nPage = m_sizeClient.cx;\n\t\t\tsi.nPos = m_ptOffset.x;\n\t\t\tpT->SetScrollInfo(SB_HORZ, &si, TRUE);\n\t\t}\n\n\t\t// block: set vertical scroll bar\n\t\t{\n\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO) };\n\t\t\tsi.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\n\t\t\tsi.nMin = 0;\n\t\t\tsi.nMax = m_sizeAll.cy - 1;\n\t\t\tif((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\n\t\t\t\tsi.fMask |= SIF_DISABLENOSCROLL;\n\t\t\tsi.nPage = m_sizeClient.cy;\n\t\t\tsi.nPos = m_ptOffset.y;\n\t\t\tpT->SetScrollInfo(SB_VERT, &si, TRUE);\n\t\t}\n\n\t\tint x = m_ptOffset.x;\n\t\tint y = m_ptOffset.y;\n\t\tif(pT->AdjustScrollOffset(x, y))\n\t\t{\n\t\t\t// Children will be moved in SetScrollOffset, if needed\n\t\t\tpT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN));\n\t\t\tSetScrollOffset(x, y, FALSE);\n\t\t}\n\t}\n\n\tvoid DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rect = { 0 };\n\t\tpT->GetClientRect(&rect);\n\t\tint cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right;\n\t\tint cxyMax = cxySizeAll - cxyClient;\n\n\t\tif(cxyMax < 0)   // can't scroll, client area is bigger\n\t\t\treturn;\n\n\t\tbool bUpdate = true;\n\t\tint cxyScroll = 0;\n\n\t\tswitch(nScrollCode)\n\t\t{\n\t\tcase SB_TOP:\t\t// top or all left\n\t\t\tcxyScroll = cxyOffset;\n\t\t\tcxyOffset = 0;\n\t\t\tbreak;\n\t\tcase SB_BOTTOM:\t\t// bottom or all right\n\t\t\tcxyScroll = cxyOffset - cxyMax;\n\t\t\tcxyOffset = cxyMax;\n\t\t\tbreak;\n\t\tcase SB_LINEUP:\t\t// line up or line left\n\t\t\tif(cxyOffset >= cxySizeLine)\n\t\t\t{\n\t\t\t\tcxyScroll = cxySizeLine;\n\t\t\t\tcxyOffset -= cxySizeLine;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcxyScroll = cxyOffset;\n\t\t\t\tcxyOffset = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SB_LINEDOWN:\t// line down or line right\n\t\t\tif(cxyOffset < cxyMax - cxySizeLine)\n\t\t\t{\n\t\t\t\tcxyScroll = -cxySizeLine;\n\t\t\t\tcxyOffset += cxySizeLine;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcxyScroll = cxyOffset - cxyMax;\n\t\t\t\tcxyOffset = cxyMax;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SB_PAGEUP:\t\t// page up or page left\n\t\t\tif(cxyOffset >= cxySizePage)\n\t\t\t{\n\t\t\t\tcxyScroll = cxySizePage;\n\t\t\t\tcxyOffset -= cxySizePage;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcxyScroll = cxyOffset;\n\t\t\t\tcxyOffset = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SB_PAGEDOWN:\t// page down or page right\n\t\t\tif(cxyOffset < cxyMax - cxySizePage)\n\t\t\t{\n\t\t\t\tcxyScroll = -cxySizePage;\n\t\t\t\tcxyOffset += cxySizePage;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcxyScroll = cxyOffset - cxyMax;\n\t\t\t\tcxyOffset = cxyMax;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SB_THUMBTRACK:\n\t\t\tif(IsNoThumbTracking())\n\t\t\t\tbreak;\n\t\t\t// else fall through\n\t\tcase SB_THUMBPOSITION:\n\t\t\t{\n\t\t\t\tSCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS };\n\t\t\t\tif(pT->GetScrollInfo(nType, &si))\n\t\t\t\t{\n\t\t\t\t\tcxyScroll = cxyOffset - si.nTrackPos;\n\t\t\t\t\tcxyOffset = si.nTrackPos;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SB_ENDSCROLL:\n\t\tdefault:\n\t\t\tbUpdate = false;\n\t\t\tbreak;\n\t\t}\n\n\t\tif(bUpdate && cxyScroll != 0)\n\t\t{\n\t\t\tpT->SetScrollPos(nType, cxyOffset, TRUE);\n\t\t\tif(nType == SB_VERT)\n\t\t\t\tpT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags);\n\t\t\telse\n\t\t\t\tpT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags);\n\t\t}\n\t}\n\n\tstatic int CalcLineOrPage(int nVal, int nMax, int nDiv)\n\t{\n\t\tif(nVal == 0)\n\t\t{\n\t\t\tnVal = nMax / nDiv;\n\t\t\tif(nVal < 1)\n\t\t\t\tnVal = 1;\n\t\t}\n\t\telse if(nVal > nMax)\n\t\t{\n\t\t\tnVal = nMax;\n\t\t}\n\n\t\treturn nVal;\n\t}\n\n\tbool AdjustScrollOffset(int& x, int& y)\n\t{\n\t\tint xOld = x;\n\t\tint yOld = y;\n\n\t\tint cxMax = m_sizeAll.cx - m_sizeClient.cx;\n\t\tif(x > cxMax)\n\t\t\tx = (cxMax >= 0) ? cxMax : 0;\n\t\telse if(x < 0)\n\t\t\tx = 0;\n\n\t\tint cyMax = m_sizeAll.cy - m_sizeClient.cy;\n\t\tif(y > cyMax)\n\t\t\ty = (cyMax >= 0) ? cyMax : 0;\n\t\telse if(y < 0)\n\t\t\ty = 0;\n\n\t\treturn (x != xOld || y != yOld);\n\t}\n\n\tvoid GetSystemSettings()\n\t{\n#ifndef _WIN32_WCE\n#ifndef SPI_GETWHEELSCROLLLINES\n\t\tconst UINT SPI_GETWHEELSCROLLLINES = 104;\n#endif // !SPI_GETWHEELSCROLLLINES\n\t\t::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0);\n\n#ifndef SPI_GETWHEELSCROLLCHARS\n\t\tconst UINT SPI_GETWHEELSCROLLCHARS = 0x006C;\n#endif // !SPI_GETWHEELSCROLLCHARS\n\t\t::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0);\n\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tif(m_uMsgMouseWheel != 0)\n\t\t\tm_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL);\n\n\t\tHWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);\n\t\tif(::IsWindow(hWndWheel))\n\t\t{\n\t\t\tUINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);\n\t\t\tif(uMsgScrollLines != 0)\n\t\t\t\tm_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L);\n\t\t}\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n#endif // !_WIN32_WCE\n\t}\n\n\tbool IsScrollingChildren() const\n\t{\n\t\treturn (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0;\n\t}\n\n\tbool IsErasingBackground() const\n\t{\n\t\treturn (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0;\n\t}\n\n\tbool IsNoThumbTracking() const\n\t{\n\t\treturn (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0;\n\t}\n\n#if (WINVER >= 0x0500)\n\tbool IsSmoothScroll() const\n\t{\n\t\treturn (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0;\n\t}\n#endif // (WINVER >= 0x0500)\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CScrollWindowImpl - Implements a scrollable window\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CScrollImpl< T >\n{\npublic:\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings();\n\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\t\t\tpT->DoSize(rect.right, rect.bottom);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tBEGIN_MSG_MAP(CScrollWindowImpl)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint)\n#endif // !_WIN32_WCE\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMapScrollImpl - Provides mapping and scrolling support to any window\n\n#ifndef _WIN32_WCE\n\ntemplate <class T>\nclass CMapScrollImpl : public CScrollImpl< T >\n{\npublic:\n\tint m_nMapMode;\n\tRECT m_rectLogAll;\n\tSIZE m_sizeLogLine;\n\tSIZE m_sizeLogPage;\n\n// Constructor\n\tCMapScrollImpl() : m_nMapMode(MM_TEXT)\n\t{\n\t\t::SetRectEmpty(&m_rectLogAll);\n\t\tm_sizeLogPage.cx = 0;\n\t\tm_sizeLogPage.cy = 0;\n\t\tm_sizeLogLine.cx = 0;\n\t\tm_sizeLogLine.cy = 0;\n\t}\n\n// Attributes & Operations\n\t// mapping mode operations\n\tvoid SetScrollMapMode(int nMapMode)\n\t{\n\t\tATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE);\n\t\tm_nMapMode = nMapMode;\n\t}\n\n\tint GetScrollMapMode() const\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\treturn m_nMapMode;\n\t}\n\n\t// offset operations\n\tvoid SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\tPOINT ptOff = { x, y };\n\t\t// block: convert logical to device units\n\t\t{\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tdc.LPtoDP(&ptOff);\n\t\t}\n\t\tCScrollImpl< T >::SetScrollOffset(ptOff, bRedraw);\n\t}\n\n\tvoid SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)\n\t{\n\t\tSetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);\n\t}\n\n\tvoid GetScrollOffset(POINT& ptOffset) const\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\tptOffset = m_ptOffset;\n\t\t// block: convert device to logical units\n\t\t{\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tdc.DPtoLP(&ptOffset);\n\t\t}\n\t}\n\n\t// size operations\n\tvoid SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tATLASSERT(xMax > xMin && yMax > yMin);\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\n\t\t::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax);\n\n\t\tSIZE sizeAll = { 0 };\n\t\tsizeAll.cx = xMax - xMin + 1;\n\t\tsizeAll.cy = yMax - yMin + 1;\n\t\t// block: convert logical to device units\n\t\t{\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tdc.LPtoDP(&sizeAll);\n\t\t}\n\t\tCScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);\n\t\tSetScrollLine(0, 0);\n\t\tSetScrollPage(0, 0);\n\t}\n\n\tvoid SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tSetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset);\n\t}\n\n\tvoid SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tSetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset);\n\t}\n\n\tvoid SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tSetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset);\n\t}\n\n\tvoid GetScrollSize(RECT& rcScroll) const\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\trcScroll = m_rectLogAll;\n\t}\n\n\t// line operations\n\tvoid SetScrollLine(int cxLine, int cyLine)\n\t{\n\t\tATLASSERT(cxLine >= 0 && cyLine >= 0);\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\n\t\tm_sizeLogLine.cx = cxLine;\n\t\tm_sizeLogLine.cy = cyLine;\n\t\tSIZE sizeLine = m_sizeLogLine;\n\t\t// block: convert logical to device units\n\t\t{\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tdc.LPtoDP(&sizeLine);\n\t\t}\n\t\tCScrollImpl< T >::SetScrollLine(sizeLine);\n\t}\n\n\tvoid SetScrollLine(SIZE sizeLine)\n\t{\n\t\tSetScrollLine(sizeLine.cx, sizeLine.cy);\n\t}\n\n\tvoid GetScrollLine(SIZE& sizeLine) const\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\tsizeLine = m_sizeLogLine;\n\t}\n\n\t// page operations\n\tvoid SetScrollPage(int cxPage, int cyPage)\n\t{\n\t\tATLASSERT(cxPage >= 0 && cyPage >= 0);\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\n\t\tm_sizeLogPage.cx = cxPage;\n\t\tm_sizeLogPage.cy = cyPage;\n\t\tSIZE sizePage = m_sizeLogPage;\n\t\t// block: convert logical to device units\n\t\t{\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tdc.LPtoDP(&sizePage);\n\t\t}\n\t\tCScrollImpl< T >::SetScrollPage(sizePage);\n\t}\n\n\tvoid SetScrollPage(SIZE sizePage)\n\t{\n\t\tSetScrollPage(sizePage.cx, sizePage.cy);\n\t}\n\n\tvoid GetScrollPage(SIZE& sizePage) const\n\t{\n\t\tATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\n\t\tsizePage = m_sizeLogPage;\n\t}\n\n\tBEGIN_MSG_MAP(CMapScrollImpl)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tCDCHandle dc = (HDC)wParam;\n\t\t\tint nMapModeSav = dc.GetMapMode();\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tPOINT ptViewportOrg = { 0, 0 };\n\t\t\tif(m_nMapMode == MM_TEXT)\n\t\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\n\t\t\telse\n\t\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg);\n\t\t\tPOINT ptWindowOrg = { 0, 0 };\n\t\t\tdc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg);\n\n\t\t\tpT->DoPaint(dc);\n\n\t\t\tdc.SetMapMode(nMapModeSav);\n\t\t\tdc.SetViewportOrg(ptViewportOrg);\n\t\t\tdc.SetWindowOrg(ptWindowOrg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tdc.SetMapMode(m_nMapMode);\n\t\t\tif(m_nMapMode == MM_TEXT)\n\t\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\n\t\t\telse\n\t\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy);\n\t\t\tdc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top);\n\t\t\tpT->DoPaint(dc.m_hDC);\n\t\t}\n\t\treturn 0;\n\t}\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMapScrollWindowImpl - Implements scrolling window with mapping\n\n#ifndef _WIN32_WCE\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T >\n{\npublic:\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings();\n\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\t\t\tpT->DoSize(rect.right, rect.bottom);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tBEGIN_MSG_MAP(CMapScrollWindowImpl)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support\n\n#if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\ntemplate <class TBase = ATL::CWindow>\nclass CFSBWindowT : public TBase, public CFlatScrollBarImpl<CFSBWindowT< TBase > >\n{\npublic:\n// Constructors\n\tCFSBWindowT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCFSBWindowT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n// CWindow overrides that use flat scroll bar API\n// (only those methods that are used by scroll window classes)\n\tint SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn FlatSB_SetScrollPos(nBar, nPos, bRedraw);\n\t}\n\n\tBOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn FlatSB_GetScrollInfo(nBar, lpScrollInfo);\n\t}\n\n\tBOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw);\n\t}\n};\n\ntypedef CFSBWindowT<ATL::CWindow>   CFSBWindow;\n\n#endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CZoomScrollImpl - Provides zooming and scrolling support to any window\n\n#ifndef _WIN32_WCE\n\n// The zoom modes that can be set with the SetZoomMode method\nenum\n{\n\tZOOMMODE_OFF, \n\tZOOMMODE_IN,   // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged.\n\tZOOMMODE_OUT   // If left mouse button clicked, zoom out on point clicked.\n};\n\n// Notification to parent that zoom scale changed as a result of user mouse action.\n#define ZSN_ZOOMCHANGED\t(NM_FIRST - 50) \n\ntemplate <class T>\nclass CZoomScrollImpl : public CScrollImpl< T >\n{\npublic:\n\tenum { m_cxyMinZoomRect = 12 };   // min rect size to zoom in on rect.\n\n\tstruct _ChildPlacement\n\t{\n\t\tHWND hWnd;\n\t\tint x;\n\t\tint y;\n\t\tint cx;\n\t\tint cy;\n\n\t\tbool operator ==(const _ChildPlacement& cp) const { return (memcmp(this, &cp, sizeof(_ChildPlacement)) == 0); }\n\t};\n\n// Data members\n\tSIZE m_sizeLogAll;\t\t\n\tSIZE m_sizeLogLine;\t\n\tSIZE m_sizeLogPage;\n\tfloat m_fZoomScale;\n\tfloat m_fZoomScaleMin;\n\tfloat m_fZoomScaleMax;\n\tfloat m_fZoomDelta;   // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click.\n\tint m_nZoomMode;\t\t\n\tRECT m_rcTrack;\n\tbool m_bTracking;\n\n\tbool m_bZoomChildren;\n\tATL::CSimpleArray<_ChildPlacement> m_arrChildren;\n\n// Constructor\n\tCZoomScrollImpl(): m_fZoomScale(1.0f), m_fZoomScaleMin(0.1f), m_fZoomScaleMax(100.0f), m_fZoomDelta(0.5f), \n\t                   m_nZoomMode(ZOOMMODE_OFF), m_bTracking(false), m_bZoomChildren(false)\n\t{\n\t\tm_sizeLogAll.cx = 0;\n\t\tm_sizeLogAll.cy = 0;\n\t\tm_sizeLogPage.cx = 0;\n\t\tm_sizeLogPage.cy = 0;\n\t\tm_sizeLogLine.cx = 0;\n\t\tm_sizeLogLine.cy = 0;\n\t\t::SetRectEmpty(&m_rcTrack);\n\t}\n\n// Attributes & Operations\n\t// size operations\n\tvoid SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tATLASSERT(cxLog >= 0 && cyLog >= 0);\n\n\t\t// Set up the defaults\n\t\tif((cxLog == 0) && (cyLog == 0))\n\t\t{\n\t\t\tcxLog = 1;\n\t\t\tcyLog = 1;\n\t\t}\n\n\t\tm_sizeLogAll.cx = cxLog;\n\t\tm_sizeLogAll.cy = cyLog;\n\t\tSIZE sizeAll = { 0 };\n\t\tsizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale);\n\t\tsizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale);\n\n\t\tCScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);\n\t}\n\n\tvoid SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true)\n\t{\n\t\tSetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset);\n\t}\n\n\tvoid GetScrollSize(SIZE& sizeLog) const\n\t{\n\t\tsizeLog = m_sizeLogAll;\n\t}\n\n\t// line operations\n\tvoid SetScrollLine(int cxLogLine, int cyLogLine)\n\t{\n\t\tATLASSERT(cxLogLine >= 0 && cyLogLine >= 0);\n\n\t\tm_sizeLogLine.cx = cxLogLine;\n\t\tm_sizeLogLine.cy = cyLogLine;\n\n\t\tSIZE sizeLine = { 0 };\n\t\tsizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale);\n\t\tsizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale);\n\t\tCScrollImpl< T >::SetScrollLine(sizeLine);\n\t}\n\n\tvoid SetScrollLine(SIZE sizeLogLine)\n\t{\n\t\tSetScrollLine(sizeLogLine.cx, sizeLogLine.cy);\n\t}\n\n\tvoid GetScrollLine(SIZE& sizeLogLine) const\n\t{\n\t\tsizeLogLine = m_sizeLogLine;\n\t}\n\n\t// page operations\n\tvoid SetScrollPage(int cxLogPage, int cyLogPage)\n\t{\n\t\tATLASSERT((cxLogPage >= 0) && (cyLogPage >= 0));\n\n\t\tm_sizeLogPage.cx = cxLogPage;\n\t\tm_sizeLogPage.cy = cyLogPage;\n\n\t\tSIZE sizePage = { 0 };\n\t\tsizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale);\n\t\tsizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale);\n\n\t\tCScrollImpl< T >::SetScrollPage(sizePage);\n\t}\n\n\tvoid SetScrollPage(SIZE sizeLogPage)\n\t{\n\t\tSetScrollPage(sizeLogPage.cx, sizeLogPage.cy);\n\t}\n\n\tvoid GetScrollPage(SIZE& sizeLogPage) const\n\t{\n\t\tsizeLogPage = m_sizeLogPage;\n\t}\n\n\tvoid SetZoomScale(float fZoomScale)\n\t{\n\t\tATLASSERT(fZoomScale > 0.0f);\n\t\tif(fZoomScale <= 0.0f)\n\t\t\treturn;\n\n\t\tm_fZoomScale = fZoomScale;\n\t\tif(m_fZoomScale < m_fZoomScaleMin)\n\t\t\tm_fZoomScale = m_fZoomScaleMin;\n\t\telse if(m_fZoomScale > m_fZoomScaleMax)\n\t\t\tm_fZoomScale = m_fZoomScaleMax;\n\t}\n\n\tfloat GetZoomScale() const\n\t{\n\t\treturn m_fZoomScale;\n\t}\n\n\tvoid SetZoomScaleMin(float fZoomScaleMin)\n\t{\n\t\tATLASSERT(fZoomScaleMin > 0.0f);\n\t\tATLASSERT(fZoomScaleMin <= m_fZoomScaleMax);\n\n\t\tm_fZoomScaleMin = fZoomScaleMin;\n\t}\n\n\tfloat GetZoomScaleMin() const\n\t{\n\t\treturn m_fZoomScaleMin;\n\t}\n\n\tvoid SetZoomScaleMax(float fZoomScaleMax)\n\t{\n\t\tATLASSERT(fZoomScaleMax > 0.0f);\n\t\tATLASSERT(m_fZoomScaleMin <= fZoomScaleMax);\n\n\t\tm_fZoomScaleMax = fZoomScaleMax;\n\t}\n\n\tfloat GetZoomScaleMax() const\n\t{\n\t\treturn m_fZoomScaleMax;\n\t}\n\n\tvoid SetZoomDelta(float fZoomDelta)\n\t{\n\t\tATLASSERT(fZoomDelta >= 0.0f);\n\n\t\tif(fZoomDelta >= 0.0f)\n\t\t\tm_fZoomDelta = fZoomDelta;\n\t}\n\n\tfloat GetZoomDelta() const\n\t{\n\t\treturn m_fZoomDelta;\n\t}\n\n\tvoid SetZoomMode(int nZoomMode)\n\t{\n\t\tm_nZoomMode = nZoomMode;\n\t}\n\n\tint GetZoomMode() const\n\t{\n\t\treturn m_nZoomMode;\n\t}\n\n\tvoid SetZoomChildren(bool bEnable = true)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tm_bZoomChildren = bEnable;\n\n\t\tm_arrChildren.RemoveAll();\n\t\tif(m_bZoomChildren)\n\t\t{\n\t\t\tfor(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\t::GetWindowRect(hWndChild, &rect);\n\t\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2);\n\n\t\t\t\t_ChildPlacement cp = { 0 };\n\t\t\t\tcp.hWnd = hWndChild;\n\t\t\t\tcp.x = rect.left;\n\t\t\t\tcp.y = rect.top;\n\t\t\t\tcp.cx = rect.right - rect.left;\n\t\t\t\tcp.cy = rect.bottom - rect.top;\n\t\t\t\tm_arrChildren.Add(cp);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool GetZoomChildren() const\n\t{\n\t\treturn m_bZoomChildren;\n\t}\n\n\tvoid Zoom(int x, int y, float fZoomScale)\n\t{\n\t\tif(fZoomScale <= 0.0f)\n\t\t\treturn;\n\n\t\tif(fZoomScale < m_fZoomScaleMin)\n\t\t\tfZoomScale = m_fZoomScaleMin;\n\t\telse if(fZoomScale > m_fZoomScaleMax)\n\t\t\tfZoomScale = m_fZoomScaleMax;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tPOINT pt = { x, y };\n\t\tif(!pT->PtInDevRect(pt))\n\t\t\treturn;\n\n\t\tpT->ViewDPtoLP(&pt);\n\t\tpT->Zoom(fZoomScale, false);\n\t\tpT->CenterOnLogicalPoint(pt);\n\t}\n\n\tvoid Zoom(POINT pt, float fZoomScale)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Zoom(pt.x, pt.y, fZoomScale);\n\t}\n\n\tvoid Zoom(RECT& rc)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rcZoom = rc;\n\t\tpT->NormalizeRect(rcZoom);\n\t\tSIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top };\n\t\tPOINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 };\n\t\tif(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect)\n\t\t{\n\t\t\tpT->Zoom(pt, m_fZoomScale + m_fZoomDelta);\n\t\t\treturn;\n\t\t}\n\n\t\tATLASSERT((size.cx > 0) && (size.cy > 0));\n\t\t\n\t\tfloat fScaleH = (float)(m_sizeClient.cx  + 1) / (float)size.cx;\n\t\tfloat fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy;\n\t\tfloat fZoomScale = __min(fScaleH, fScaleV) * m_fZoomScale;\n\t\tpT->Zoom(pt, fZoomScale);\t\t\n\t}\n\n\tvoid Zoom(float fZoomScale, bool bCenter = true)\n\t{\n\t\tif(fZoomScale <= 0.0f)\n\t\t\treturn;\n\n\t\tif(fZoomScale < m_fZoomScaleMin)\n\t\t\tfZoomScale = m_fZoomScaleMin;\n\t\telse if(fZoomScale > m_fZoomScaleMax)\n\t\t\tfZoomScale = m_fZoomScaleMax;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tPOINT pt = { 0 };\n\t\tif(bCenter)\n\t\t{\n\t\t\tRECT rcClient = { 0 };\n\t\t\t::GetClientRect(pT->m_hWnd, &rcClient);\n\t\t\tpt.x = rcClient.right / 2;\n\t\t\tpt.y = rcClient.bottom / 2;\n\t\t\tpT->ViewDPtoLP(&pt);\n\t\t}\n\n\t\t// Modify the Viewport extent\n\t\tSIZE sizeAll = { 0 };\n\t\tsizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale);\n\t\tsizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale);\n\t\t\n\t\t// Update scroll bars and window\n\t\tCScrollImpl< T >::SetScrollSize(sizeAll);\n\n\t\t// Zoom all children if needed\n\t\tif(m_bZoomChildren && (m_fZoomScale != fZoomScale))\n\t\t{\n\t\t\tfor(int i = 0; i < m_arrChildren.GetSize(); i++)\n\t\t\t{\n\t\t\t\tATLASSERT(::IsWindow(m_arrChildren[i].hWnd));\n\n\t\t\t\t::SetWindowPos(m_arrChildren[i].hWnd, NULL, \n\t\t\t\t\t(int)((float)m_arrChildren[i].x * fZoomScale + 0.5f), \n\t\t\t\t\t(int)((float)m_arrChildren[i].y * fZoomScale + 0.5f), \n\t\t\t\t\t(int)((float)m_arrChildren[i].cx * fZoomScale + 0.5f), \n\t\t\t\t\t(int)((float)m_arrChildren[i].cy * fZoomScale + 0.5f), \n\t\t\t\t\tSWP_NOZORDER | SWP_NOACTIVATE);\n\t\t\t}\n\t\t}\n\n\t\t// Set new zoom scale\n\t\tm_fZoomScale = fZoomScale;\n\n\t\tif(bCenter)\n\t\t\tpT->CenterOnLogicalPoint(pt);\n\t}\n\n\t// Helper functions\n\tvoid PrepareDC(CDCHandle dc)\n\t{\n\t\tATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);\n\t\tdc.SetMapMode(MM_ANISOTROPIC);\n\t\tdc.SetWindowExt(m_sizeLogAll);\n\t\tdc.SetViewportExt(m_sizeAll);\n\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\n\t}\n\n\tvoid ViewDPtoLP(LPPOINT lpPoints, int nCount = 1)\n\t{\n\t\tATLASSERT(lpPoints);\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\n\t\tCWindowDC dc(pT->m_hWnd);\n\t\tpT->PrepareDC(dc.m_hDC);\n\t\tdc.DPtoLP(lpPoints, nCount);\n\t}\n\n\tvoid ViewLPtoDP(LPPOINT lpPoints, int nCount = 1)\n\t{\n\t\tATLASSERT(lpPoints);\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\n\t\tCWindowDC dc(pT->m_hWnd);\n\t\tpT->PrepareDC(dc.m_hDC);\n\t\tdc.LPtoDP(lpPoints, nCount);\n\t}\n\n\tvoid ClientToDevice(POINT &pt)\n\t{\n\t\tpt.x += m_ptOffset.x;\n\t\tpt.y += m_ptOffset.y;\n\t}\t \n\n\tvoid DeviceToClient(POINT &pt)\n\t{\n\t\tpt.x -= m_ptOffset.x;\n\t\tpt.y -= m_ptOffset.y;\n\t}\n\n\tvoid CenterOnPoint(POINT pt)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rect = { 0 };\n\t\tpT->GetClientRect(&rect);\n\n\t\tint xOfs = pt.x - (rect.right / 2) + m_ptOffset.x;\n\t\tif(xOfs < 0)\n\t\t{\n\t\t\txOfs = 0;\n\t\t}\n\t\telse \n\t\t{\n\t\t\tint xMax = __max((int)(m_sizeAll.cx - rect.right), 0);\n\t\t\tif(xOfs > xMax)\n\t\t\t\txOfs = xMax;\n\t\t}\n\t\t\n\t\tint yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y;\n\t\tif(yOfs < 0)\n\t\t{\n\t\t\tyOfs = 0;\n\t\t}\n\t\telse \n\t\t{\n\t\t\tint yMax = __max((int)(m_sizeAll.cy - rect.bottom), 0);\n\t\t\tif(yOfs > yMax)\n\t\t\t\tyOfs = yMax;\n\t\t}\n\n\t\tCScrollImpl< T >::SetScrollOffset(xOfs, yOfs);\n\t}\n\n\tvoid CenterOnLogicalPoint(POINT ptLog)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->ViewLPtoDP(&ptLog);\n\t\tpT->DeviceToClient(ptLog);\n\t\tpT->CenterOnPoint(ptLog);\n\t}\n\n\tBOOL PtInDevRect(POINT pt)\n\t{\n\t\tRECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy };\n\t\t::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y);\n\t\treturn ::PtInRect(&rc, pt);\n\t}\n\n\tvoid NormalizeRect(RECT& rc)\n\t{\n\t\tif(rc.left > rc.right) \n\t\t{\n\t\t\tint r = rc.right;\n\t\t\trc.right = rc.left;\n\t\t\trc.left = r;\n\t\t}\n\n\t\tif(rc.top > rc.bottom)\n\t\t{\n\t\t\tint b = rc.bottom;\n\t\t\trc.bottom = rc.top;\n\t\t\trc.top = b;\n\t\t}\n\t}\n\n\tvoid DrawTrackRect()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tconst SIZE sizeLines = { 2, 2 };\n\t\tRECT rc = m_rcTrack;\n\t\tpT->NormalizeRect(rc);\n\t\tif(!::IsRectEmpty(&rc))\n\t\t{\n\t\t\t::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2);\n\t\t\tCWindowDC dc(NULL);\n\t\t\tdc.DrawDragRect(&rc, sizeLines, NULL, sizeLines);\n\t\t}\n\t}\n\n\tvoid NotifyParentZoomChanged()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tint nId = pT->GetDlgCtrlID();\n\t\tNMHDR nmhdr = { pT->m_hWnd, (UINT_PTR)nId, ZSN_ZOOMCHANGED };\n\t\t::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr);\n\t}\n\n\tBEGIN_MSG_MAP(CZoomScrollImpl)\n\t\tMESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tATLASSERT((m_sizeLogAll.cx >= 0) && (m_sizeLogAll.cy >= 0));\n\t\tATLASSERT((m_sizeAll.cx >= 0) && (m_sizeAll.cy >= 0));\n\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tCDCHandle dc = (HDC)wParam;\n\t\t\tint nMapModeSav = dc.GetMapMode();\n\t\t\tdc.SetMapMode(MM_ANISOTROPIC);\n\t\t\tSIZE szWindowExt = { 0, 0 };\n\t\t\tdc.SetWindowExt(m_sizeLogAll, &szWindowExt);\n\t\t\tSIZE szViewportExt = { 0, 0 };\n\t\t\tdc.SetViewportExt(m_sizeAll, &szViewportExt);\n\t\t\tPOINT ptViewportOrg = { 0, 0 };\n\t\t\tdc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\n\n\t\t\tpT->DoPaint(dc);\n\n\t\t\tdc.SetMapMode(nMapModeSav);\n\t\t\tdc.SetWindowExt(szWindowExt);\n\t\t\tdc.SetViewportExt(szViewportExt);\n\t\t\tdc.SetViewportOrg(ptViewportOrg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tpT->PrepareDC(dc.m_hDC);\n\t\t\tpT->DoPaint(dc.m_hDC);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(m_nZoomMode == ZOOMMODE_IN && !m_bTracking)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\t\tif(pT->PtInDevRect(pt))\n\t\t\t{\n\t\t\t\tpT->SetCapture();\n\t\t\t\tm_bTracking = true;\n\t\t\t\t::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y);\n\t\t\t}\t\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(m_bTracking)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tPOINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\n\t\t\tif(pT->PtInDevRect(pt))\n\t\t\t{\n\t\t\t\tpT->DrawTrackRect();\n\t\t\t\tm_rcTrack.right = pt.x;\n\t\t\t\tm_rcTrack.bottom = pt.y;\n\t\t\t\tpT->DrawTrackRect();\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\t::ReleaseCapture();\n\t\tif(m_nZoomMode == ZOOMMODE_OUT)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta);\n\t\t\tpT->NotifyParentZoomChanged();\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_bTracking)\n\t\t{\n\t\t\tm_bTracking = false;\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->DrawTrackRect();\n\t\t\tpT->Zoom(m_rcTrack);\n\t\t\tpT->NotifyParentZoomChanged();\n\t\t\t::SetRectEmpty(&m_rcTrack);\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\t\n\n\tLRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tif((HWND)wParam == pT->m_hWnd)\n\t\t\t{\n\t\t\t\tDWORD dwPos = ::GetMessagePos();\n\t\t\t\tPOINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };\n\t\t\t\tpT->ScreenToClient(&pt);\n\t\t\t\tif(pT->PtInDevRect(pt))\n\t\t\t\t{\n\t\t\t\t\t::SetCursor(::LoadCursor(NULL, IDC_CROSS));\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CZoomScrollWindowImpl - Implements scrolling window with zooming\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >\n{\npublic:\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings();\n\n\t\t\tRECT rect = { 0 };\n\t\t\tGetClientRect(&rect);\n\t\t\tpT->DoSize(rect.right, rect.bottom);\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tBEGIN_MSG_MAP(CZoomScrollWindowImpl)\n\t\tMESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)\n\t\tMESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\n\t\tMESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\n\t\tMESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\n#if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\n#endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\n\t\tMESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\n\t\tMESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint)\n\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)\n\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)\n\t\tMESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)\n\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)\n\tALT_MSG_MAP(1)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\n\t\tCOMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\n\tEND_MSG_MAP()\n};\n\n#endif // !_WIN32_WCE\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CScrollContainer\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits >\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, 0, -1)\n\n\ttypedef CScrollWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\n// Data members\n\tATL::CWindow m_wndClient;\n\tbool m_bAutoSizeClient;\n\tbool m_bDrawEdgeIfEmpty;\n\n// Constructor\n\tCScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false)\n\t{\n\t\t// Set CScrollWindowImpl extended style\n\t\tSetScrollExtendedStyle(SCRL_SCROLLCHILDREN);\n\t}\n\n// Attributes\n\tHWND GetClient() const\n\t{\n\t\treturn m_wndClient;\n\t}\n\n\tHWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tHWND hWndOldClient = m_wndClient;\n\t\tm_wndClient = hWndClient;\n\n\t\tSetRedraw(FALSE);\n\t\tSetScrollSize(1, 1, FALSE);\n\n\t\tif(m_wndClient.m_hWnd != NULL)\n\t\t{\n\t\t\tm_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);\n\n\t\t\tif(bClientSizeAsMin)\n\t\t\t{\n\t\t\t\tRECT rect = { 0 };\n\t\t\t\tm_wndClient.GetWindowRect(&rect);\n\t\t\t\tif((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0)\n\t\t\t\t\tSetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE);\n\t\t\t}\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateLayout();\n\t\t}\n\n\t\tSetRedraw(TRUE);\n\t\tRedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);\n\n\t\treturn hWndOldClient;\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CScrollContainerImpl)\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tCHAIN_MSG_MAP(_baseClass)\n\t\tFORWARD_NOTIFICATIONS()\n\tALT_MSG_MAP(1)\n\t\tCHAIN_MSG_MAP_ALT(_baseClass, 1)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(m_wndClient.m_hWnd != NULL)\n\t\t\tm_wndClient.SetFocus();\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background needed\n\t}\n\n// Overrides for CScrollWindowImpl\n\tvoid DoSize(int cx, int cy)\n\t{\n\t\t_baseClass::DoSize(cx, cy);\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->UpdateLayout();\n\t}\n\n\tvoid DoPaint(CDCHandle dc)\n\t{\n\t\tif(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetContainerRect(rect);\n\n\t\t\tif(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL)\n\t\t\t\tdc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);\n\n\t\t\tdc.FillRect(&rect, COLOR_APPWORKSPACE);\n\t\t}\n\t}\n\n\tvoid ScrollToView(POINT pt)\n\t{\n\t\tCScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt);\n\t}\n\n\tvoid ScrollToView(RECT& rect)\n\t{\n\t\tCScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect);\n\t}\n\n\tvoid ScrollToView(HWND hWnd)   // client window coordinates\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tATLASSERT(m_wndClient.IsWindow());\n\n\t\tRECT rect = { 0 };\n\t\t::GetWindowRect(hWnd, &rect);\n\t\t::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2);\n\t\tScrollToView(rect);\n\t}\n\n// Implementation - overrideable methods\n\tvoid UpdateLayout()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\n\t\tif(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetContainerRect(rect);\n\n\t\t\tm_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tInvalidate();\n\t\t}\n\t}\n\n\tvoid GetContainerRect(RECT& rect)\n\t{\n\t\tGetClientRect(&rect);\n\n\t\tif(rect.right < m_sizeAll.cx)\n\t\t\trect.right = m_sizeAll.cx;\n\n\t\tif(rect.bottom < m_sizeAll.cy)\n\t\t\trect.bottom = m_sizeAll.cy;\n\t}\n};\n\nclass CScrollContainer : public CScrollContainerImpl<CScrollContainer>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_ScrollContainer\"), 0, -1)\n};\n\n}; // namespace WTL\n\n#endif // __ATLSCRL_H__\n"
  },
  {
    "path": "WTL/atlsplit.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLSPLIT_H__\n#define __ATLSPLIT_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlsplit.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlsplit.h requires atlwin.h to be included first\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CSplitterImpl<T>\n// CSplitterWindowImpl<T, TBase, TWinTraits>\n// CSplitterWindowT<t_bVertical> - CSplitterWindow, CHorSplitterWindow\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CSplitterImpl - Provides splitter support to any window\n\n// Splitter panes constants\n#define SPLIT_PANE_LEFT\t\t\t 0\n#define SPLIT_PANE_RIGHT\t\t 1\n#define SPLIT_PANE_TOP\t\t\t SPLIT_PANE_LEFT\n#define SPLIT_PANE_BOTTOM\t\t SPLIT_PANE_RIGHT\n#define SPLIT_PANE_NONE\t\t\t-1\n\n// Splitter extended styles\n#define SPLIT_PROPORTIONAL\t\t0x00000001\n#define SPLIT_NONINTERACTIVE\t\t0x00000002\n#define SPLIT_RIGHTALIGNED\t\t0x00000004\n#define SPLIT_BOTTOMALIGNED\t\tSPLIT_RIGHTALIGNED\n#define SPLIT_GRADIENTBAR\t\t0x00000008\n#define SPLIT_FIXEDBARSIZE\t\t0x00000010\n\n// Note: SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED/SPLIT_BOTTOMALIGNED are \n// mutually exclusive. If both are set, splitter defaults to SPLIT_PROPORTIONAL.\n// SPLIT_GRADIENTBAR doesn't work with _ATL_NO_MSIMG\n\n\ntemplate <class T>\nclass CSplitterImpl\n{\npublic:\n\tenum { m_nPanesCount = 2, m_nPropMax = 10000, m_cxyStep = 10 };\n\n\tbool m_bVertical;\n\tHWND m_hWndPane[m_nPanesCount];\n\tRECT m_rcSplitter;\n\tint m_xySplitterPos;            // splitter bar position\n\tint m_xySplitterPosNew;         // internal - new position while moving\n\tHWND m_hWndFocusSave;\n\tint m_nDefActivePane;\n\tint m_cxySplitBar;              // splitter bar width/height\n\tHCURSOR m_hCursor;\n\tint m_cxyMin;                   // minimum pane size\n\tint m_cxyBarEdge;              \t// splitter bar edge\n\tbool m_bFullDrag;\n\tint m_cxyDragOffset;\t\t// internal\n\tint m_nProportionalPos;\n\tbool m_bUpdateProportionalPos;\n\tDWORD m_dwExtendedStyle;        // splitter specific extended styles\n\tint m_nSinglePane;              // single pane mode\n\tint m_xySplitterDefPos;         // default position\n\tbool m_bProportionalDefPos;     // porportinal def pos\n\n// Constructor\n\tCSplitterImpl(bool bVertical = true) : \n\t              m_bVertical(bVertical), m_xySplitterPos(-1), m_xySplitterPosNew(-1), m_hWndFocusSave(NULL), \n\t              m_nDefActivePane(SPLIT_PANE_NONE), m_cxySplitBar(4), m_hCursor(NULL), m_cxyMin(0), m_cxyBarEdge(0), \n\t              m_bFullDrag(true), m_cxyDragOffset(0), m_nProportionalPos(0), m_bUpdateProportionalPos(true),\n\t              m_dwExtendedStyle(SPLIT_PROPORTIONAL), m_nSinglePane(SPLIT_PANE_NONE), \n\t              m_xySplitterDefPos(-1), m_bProportionalDefPos(false)\n\t{\n\t\tm_hWndPane[SPLIT_PANE_LEFT] = NULL;\n\t\tm_hWndPane[SPLIT_PANE_RIGHT] = NULL;\n\n\t\t::SetRectEmpty(&m_rcSplitter);\n\t}\n\n// Attributes\n\tvoid SetSplitterRect(LPRECT lpRect = NULL, bool bUpdate = true)\n\t{\n\t\tif(lpRect == NULL)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetClientRect(&m_rcSplitter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_rcSplitter = *lpRect;\n\t\t}\n\n\t\tif(IsProportional())\n\t\t\tUpdateProportionalPos();\n\t\telse if(IsRightAligned())\n\t\t\tUpdateRightAlignPos();\n\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\t}\n\n\tvoid GetSplitterRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(lpRect != NULL);\n\t\t*lpRect = m_rcSplitter;\n\t}\n\n\tbool SetSplitterPos(int xyPos = -1, bool bUpdate = true)\n\t{\n\t\tif(xyPos == -1)   // -1 == default position\n\t\t{\n\t\t\tif(m_bProportionalDefPos)\n\t\t\t{\n\t\t\t\tATLASSERT((m_xySplitterDefPos >= 0) && (m_xySplitterDefPos <= m_nPropMax));\n\n\t\t\t\tif(m_bVertical)\n\t\t\t\t\txyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);\n\t\t\t\telse\n\t\t\t\t\txyPos = ::MulDiv(m_xySplitterDefPos, m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge, m_nPropMax);\n\t\t\t}\n\t\t\telse if(m_xySplitterDefPos != -1)\n\t\t\t{\n\t\t\t\txyPos = m_xySplitterDefPos;\n\t\t\t}\n\t\t\telse   // not set, use middle position\n\t\t\t{\n\t\t\t\tif(m_bVertical)\n\t\t\t\t\txyPos = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;\n\t\t\t\telse\n\t\t\t\t\txyPos = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;\n\t\t\t}\n\t\t}\n\n\t\t// Adjust if out of valid range\n\t\tint cxyMax = 0;\n\t\tif(m_bVertical)\n\t\t\tcxyMax = m_rcSplitter.right - m_rcSplitter.left;\n\t\telse\n\t\t\tcxyMax = m_rcSplitter.bottom - m_rcSplitter.top;\n\n\t\tif(xyPos < m_cxyMin + m_cxyBarEdge)\n\t\t\txyPos = m_cxyMin;\n\t\telse if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))\n\t\t\txyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;\n\n\t\t// Set new position and update if requested\n\t\tbool bRet = (m_xySplitterPos != xyPos);\n\t\tm_xySplitterPos = xyPos;\n\n\t\tif(m_bUpdateProportionalPos)\n\t\t{\n\t\t\tif(IsProportional())\n\t\t\t\tStoreProportionalPos();\n\t\t\telse if(IsRightAligned())\n\t\t\t\tStoreRightAlignPos();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_bUpdateProportionalPos = true;\n\t\t}\n\n\t\tif(bUpdate && bRet)\n\t\t\tUpdateSplitterLayout();\n\n\t\treturn bRet;\n\t}\n\n\tint GetSplitterPos() const\n\t{\n\t\treturn m_xySplitterPos;\n\t}\n\n\tvoid SetSplitterPosPct(int nPct, bool bUpdate = true)\n\t{\n\t\tATLASSERT((nPct >= 0) && (nPct <= 100));\n\n\t\tm_nProportionalPos = ::MulDiv(nPct, m_nPropMax, 100);\n\t\tUpdateProportionalPos();\n\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\t}\n\n\tint GetSplitterPosPct() const\n\t{\n\t\tint cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);\n\t\treturn ((cxyTotal > 0) && (m_xySplitterPos >= 0)) ? (::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal) / 100) : -1;\n\t}\n\n\tbool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE));\n\t\tif(!((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT) || (nPane == SPLIT_PANE_NONE)))\n\t\t\treturn false;\n\n\t\tif(nPane != SPLIT_PANE_NONE)\n\t\t{\n\t\t\tif(::IsWindowVisible(m_hWndPane[nPane]) == FALSE)\n\t\t\t\t::ShowWindow(m_hWndPane[nPane], SW_SHOW);\n\t\t\tint nOtherPane = (nPane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;\n\t\t\t::ShowWindow(m_hWndPane[nOtherPane], SW_HIDE);\n\t\t\tif(m_nDefActivePane != nPane)\n\t\t\t\tm_nDefActivePane = nPane;\n\t\t}\n\t\telse if(m_nSinglePane != SPLIT_PANE_NONE)\n\t\t{\n\t\t\tint nOtherPane = (m_nSinglePane == SPLIT_PANE_LEFT) ? SPLIT_PANE_RIGHT : SPLIT_PANE_LEFT;\n\t\t\t::ShowWindow(m_hWndPane[nOtherPane], SW_SHOW);\n\t\t}\n\n\t\tm_nSinglePane = nPane;\n\t\tUpdateSplitterLayout();\n\n\t\treturn true;\n\t}\n\n\tint GetSinglePaneMode() const\n\t{\n\t\treturn m_nSinglePane;\n\t}\n\n\tDWORD GetSplitterExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n\tDWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\n#ifdef _DEBUG\n\t\tif(IsProportional() && IsRightAligned())\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"CSplitterImpl::SetSplitterExtendedStyle - SPLIT_PROPORTIONAL and SPLIT_RIGHTALIGNED are mutually exclusive, defaulting to SPLIT_PROPORTIONAL.\\n\"));\n#endif // _DEBUG\n\n\t\treturn dwPrevStyle;\n\t}\n\n\tvoid SetSplitterDefaultPos(int xyPos = -1)\n\t{\n\t\tm_xySplitterDefPos = xyPos;\n\t\tm_bProportionalDefPos = false;\n\t}\n\n\tvoid SetSplitterDefaultPosPct(int nPct)\n\t{\n\t\tATLASSERT((nPct >= 0) && (nPct <= 100));\n\n\t\tm_xySplitterDefPos = ::MulDiv(nPct, m_nPropMax, 100);\n\t\tm_bProportionalDefPos = true;\n\t}\n\n// Splitter operations\n\tvoid SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)\n\t{\n\t\tm_hWndPane[SPLIT_PANE_LEFT] = hWndLeftTop;\n\t\tm_hWndPane[SPLIT_PANE_RIGHT] = hWndRightBottom;\n\t\tATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]));\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\t}\n\n\tbool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));\n\t\tif((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))\n\t\t\treturn false;\n\n\t\tm_hWndPane[nPane] = hWnd;\n\t\tATLASSERT((m_hWndPane[SPLIT_PANE_LEFT] == NULL) || (m_hWndPane[SPLIT_PANE_RIGHT] == NULL) || (m_hWndPane[SPLIT_PANE_LEFT] != m_hWndPane[SPLIT_PANE_RIGHT]));\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\n\t\treturn true;\n\t}\n\n\tHWND GetSplitterPane(int nPane) const\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));\n\t\tif((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))\n\t\t\treturn NULL;\n\n\t\treturn m_hWndPane[nPane];\n\t}\n\n\tbool SetActivePane(int nPane)\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));\n\t\tif((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))\n\t\t\treturn false;\n\t\tif((m_nSinglePane != SPLIT_PANE_NONE) && (nPane != m_nSinglePane))\n\t\t\treturn false;\n\n\t\t::SetFocus(m_hWndPane[nPane]);\n\t\tm_nDefActivePane = nPane;\n\n\t\treturn true;\n\t}\n\n\tint GetActivePane() const\n\t{\n\t\tint nRet = SPLIT_PANE_NONE;\n\t\tHWND hWndFocus = ::GetFocus();\n\t\tif(hWndFocus != NULL)\n\t\t{\n\t\t\tfor(int nPane = 0; nPane < m_nPanesCount; nPane++)\n\t\t\t{\n\t\t\t\tif((hWndFocus == m_hWndPane[nPane]) || (::IsChild(m_hWndPane[nPane], hWndFocus) != FALSE))\n\t\t\t\t{\n\t\t\t\t\tnRet = nPane;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn nRet;\n\t}\n\n\tbool ActivateNextPane(bool bNext = true)\n\t{\n\t\tint nPane = m_nSinglePane;\n\t\tif(nPane == SPLIT_PANE_NONE)\n\t\t{\n\t\t\tswitch(GetActivePane())\n\t\t\t{\n\t\t\tcase SPLIT_PANE_LEFT:\n\t\t\t\tnPane = SPLIT_PANE_RIGHT;\n\t\t\t\tbreak;\n\t\t\tcase SPLIT_PANE_RIGHT:\n\t\t\t\tnPane = SPLIT_PANE_LEFT;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tnPane = bNext ? SPLIT_PANE_LEFT : SPLIT_PANE_RIGHT;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn SetActivePane(nPane);\n\t}\n\n\tbool SetDefaultActivePane(int nPane)\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));\n\t\tif((nPane != SPLIT_PANE_LEFT) && (nPane != SPLIT_PANE_RIGHT))\n\t\t\treturn false;\n\n\t\tm_nDefActivePane = nPane;\n\n\t\treturn true;\n\t}\n\n\tbool SetDefaultActivePane(HWND hWnd)\n\t{\n\t\tfor(int nPane = 0; nPane < m_nPanesCount; nPane++)\n\t\t{\n\t\t\tif(hWnd == m_hWndPane[nPane])\n\t\t\t{\n\t\t\t\tm_nDefActivePane = nPane;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;   // not found\n\t}\n\n\tint GetDefaultActivePane() const\n\t{\n\t\treturn m_nDefActivePane;\n\t}\n\n\tvoid DrawSplitter(CDCHandle dc)\n\t{\n\t\tATLASSERT(dc.m_hDC != NULL);\n\t\tif((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))\n\t\t\treturn;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(m_nSinglePane == SPLIT_PANE_NONE)\n\t\t{\n\t\t\tpT->DrawSplitterBar(dc);\n\n\t\t\tfor(int nPane = 0; nPane < m_nPanesCount; nPane++)\n\t\t\t{\n\t\t\t\tif(m_hWndPane[nPane] == NULL)\n\t\t\t\t\tpT->DrawSplitterPane(dc, nPane);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(m_hWndPane[m_nSinglePane] == NULL)\n\t\t\t\tpT->DrawSplitterPane(dc, m_nSinglePane);\n\t\t}\n\t}\n\n\t// call to initiate moving splitter bar with keyboard\n\tvoid MoveSplitterBar()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\tint x = 0;\n\t\tint y = 0;\n\t\tif(m_bVertical)\n\t\t{\n\t\t\tx = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;\n\t\t\ty = (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge) / 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx = (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) / 2;\n\t\t\ty = m_xySplitterPos + (m_cxySplitBar / 2) + m_cxyBarEdge;\n\t\t}\n\n\t\tPOINT pt = { x, y };\n\t\tpT->ClientToScreen(&pt);\n\t\t::SetCursorPos(pt.x, pt.y);\n\n\t\tm_xySplitterPosNew = m_xySplitterPos;\n\t\tpT->SetCapture();\n\t\tm_hWndFocusSave = pT->SetFocus();\n\t\t::SetCursor(m_hCursor);\n\t\tif(!m_bFullDrag)\n\t\t\tDrawGhostBar();\n\t\tif(m_bVertical)\n\t\t\tm_cxyDragOffset = x - m_rcSplitter.left - m_xySplitterPos;\n\t\telse\n\t\t\tm_cxyDragOffset = y - m_rcSplitter.top - m_xySplitterPos;\n\t}\n\n\tvoid SetOrientation(bool bVertical, bool bUpdate = true)\n\t{\n\t\tif(m_bVertical != bVertical)\n\t\t{\n\t\t\tm_bVertical = bVertical;\n\n\t\t\tm_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);\n\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->GetSystemSettings(false);\n\n\t\t\tif(m_bVertical)\n\t\t\t\tm_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.right - m_rcSplitter.left, m_rcSplitter.bottom - m_rcSplitter.top);\n\t\t\telse\n\t\t\t\tm_xySplitterPos = ::MulDiv(m_xySplitterPos, m_rcSplitter.bottom - m_rcSplitter.top, m_rcSplitter.right - m_rcSplitter.left);\n\t\t}\n\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\t}\n\n// Overrideables\n\tvoid DrawSplitterBar(CDCHandle dc)\n\t{\n\t\tRECT rect = { 0 };\n\t\tif(GetSplitterBarRect(&rect))\n\t\t{\n\t\t\tdc.FillRect(&rect, COLOR_3DFACE);\n\n#if (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\t\t\tif((m_dwExtendedStyle & SPLIT_GRADIENTBAR) != 0)\n\t\t\t{\n\t\t\t\tRECT rect2 = rect;\n\t\t\t\tif(m_bVertical)\n\t\t\t\t\trect2.left = (rect.left + rect.right) / 2 - 1;\n\t\t\t\telse\n\t\t\t\t\trect2.top = (rect.top + rect.bottom) / 2 - 1;\n\n\t\t\t\tdc.GradientFillRect(rect2, ::GetSysColor(COLOR_3DFACE), ::GetSysColor(COLOR_3DSHADOW), m_bVertical);\n\t\t\t}\n#endif // (!defined(_WIN32_WCE) && !defined(_ATL_NO_MSIMG)) || (_WIN32_WCE >= 420)\n\n\t\t\t// draw 3D edge if needed\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tif((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)\n\t\t\t\tdc.DrawEdge(&rect, EDGE_RAISED, m_bVertical ? (BF_LEFT | BF_RIGHT) : (BF_TOP | BF_BOTTOM));\n\t\t}\n\t}\n\n\t// called only if pane is empty\n\tvoid DrawSplitterPane(CDCHandle dc, int nPane)\n\t{\n\t\tRECT rect = { 0 };\n\t\tif(GetSplitterPaneRect(nPane, &rect))\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tif((pT->GetExStyle() & WS_EX_CLIENTEDGE) == 0)\n\t\t\t\tdc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);\n\t\t\tdc.FillRect(&rect, COLOR_APPWORKSPACE);\n\t\t}\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CSplitterImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n#endif // !_WIN32_WCE\n\t\tif(IsInteractive())\n\t\t{\n\t\t\tMESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)\n\t\t\tMESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n\t\t\tMESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n\t\t\tMESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\n\t\t\tMESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDoubleClick)\n\t\t\tMESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\n\t\t\tMESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n\t\t}\n\t\tMESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\n#ifndef _WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)\n#endif // !_WIN32_WCE\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->Init();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\n\t\t// try setting position if not set\n\t\tif((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))\n\t\t\tpT->SetSplitterPos();\n\n\t\t// do painting\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tpT->DrawSplitter((HDC)wParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tpT->DrawSplitter(dc.m_hDC);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(((HWND)wParam == pT->m_hWnd) && (LOWORD(lParam) == HTCLIENT))\n\t\t{\n\t\t\tDWORD dwPos = ::GetMessagePos();\n\t\t\tPOINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };\n\t\t\tpT->ScreenToClient(&ptPos);\n\t\t\tif(IsOverSplitterBar(ptPos.x, ptPos.y))\n\t\t\t\treturn 1;\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 0;\n\t}\n\n\tLRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tint xPos = GET_X_LPARAM(lParam);\n\t\tint yPos = GET_Y_LPARAM(lParam);\n\t\tif(::GetCapture() == pT->m_hWnd)\n\t\t{\n\t\t\tint xyNewSplitPos = 0;\n\t\t\tif(m_bVertical)\n\t\t\t\txyNewSplitPos = xPos - m_rcSplitter.left - m_cxyDragOffset;\n\t\t\telse\n\t\t\t\txyNewSplitPos = yPos - m_rcSplitter.top - m_cxyDragOffset;\n\n\t\t\tif(xyNewSplitPos == -1)   // avoid -1, that means default position\n\t\t\t\txyNewSplitPos = -2;\n\n\t\t\tif(m_xySplitterPos != xyNewSplitPos)\n\t\t\t{\n\t\t\t\tif(m_bFullDrag)\n\t\t\t\t{\n\t\t\t\t\tif(pT->SetSplitterPos(xyNewSplitPos, true))\n\t\t\t\t\t\tpT->UpdateWindow();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDrawGhostBar();\n\t\t\t\t\tpT->SetSplitterPos(xyNewSplitPos, false);\n\t\t\t\t\tDrawGhostBar();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\t\t// not dragging, just set cursor\n\t\t{\n\t\t\tif(IsOverSplitterBar(xPos, yPos))\n\t\t\t\t::SetCursor(m_hCursor);\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tint xPos = GET_X_LPARAM(lParam);\n\t\tint yPos = GET_Y_LPARAM(lParam);\n\t\tif((::GetCapture() != pT->m_hWnd) && IsOverSplitterBar(xPos, yPos))\n\t\t{\n\t\t\tm_xySplitterPosNew = m_xySplitterPos;\n\t\t\tpT->SetCapture();\n\t\t\tm_hWndFocusSave = pT->SetFocus();\n\t\t\t::SetCursor(m_hCursor);\n\t\t\tif(!m_bFullDrag)\n\t\t\t\tDrawGhostBar();\n\t\t\tif(m_bVertical)\n\t\t\t\tm_cxyDragOffset = xPos - m_rcSplitter.left - m_xySplitterPos;\n\t\t\telse\n\t\t\t\tm_cxyDragOffset = yPos - m_rcSplitter.top - m_xySplitterPos;\n\t\t}\n\t\telse if((::GetCapture() == pT->m_hWnd) && !IsOverSplitterBar(xPos, yPos))\n\t\t{\n\t\t\t::ReleaseCapture();\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(::GetCapture() == pT->m_hWnd)\n\t\t{\n\t\t\tm_xySplitterPosNew = m_xySplitterPos;\n\t\t\t::ReleaseCapture();\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnLButtonDoubleClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetSplitterPos();   // default\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tif(!m_bFullDrag)\n\t\t\tDrawGhostBar();\n\n\t\tif((m_xySplitterPosNew != -1) && (!m_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew)))\n\t\t{\n\t\t\tm_xySplitterPos = m_xySplitterPosNew;\n\t\t\tm_xySplitterPosNew = -1;\n\t\t\tUpdateSplitterLayout();\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->UpdateWindow();\n\t\t}\n\n\t\tif(m_hWndFocusSave != NULL)\n\t\t\t::SetFocus(m_hWndFocusSave);\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(::GetCapture() == pT->m_hWnd)\n\t\t{\n\t\t\tswitch(wParam)\n\t\t\t{\n\t\t\tcase VK_RETURN:\n\t\t\t\tm_xySplitterPosNew = m_xySplitterPos;\n\t\t\tcase VK_ESCAPE:\n\t\t\t\t::ReleaseCapture();\n\t\t\t\tbreak;\n\t\t\tcase VK_LEFT:\n\t\t\tcase VK_RIGHT:\n\t\t\t\tif(m_bVertical)\n\t\t\t\t{\n\t\t\t\t\tPOINT pt = { 0, 0 };\n\t\t\t\t\t::GetCursorPos(&pt);\n\t\t\t\t\tint xyPos = m_xySplitterPos + ((wParam == VK_LEFT) ? -pT->m_cxyStep : pT->m_cxyStep);\n\t\t\t\t\tint cxyMax = m_rcSplitter.right - m_rcSplitter.left;\n\t\t\t\t\tif(xyPos < (m_cxyMin + m_cxyBarEdge))\n\t\t\t\t\t\txyPos = m_cxyMin;\n\t\t\t\t\telse if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))\n\t\t\t\t\t\txyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;\n\t\t\t\t\tpt.x += xyPos - m_xySplitterPos;\n\t\t\t\t\t::SetCursorPos(pt.x, pt.y);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase VK_UP:\n\t\t\tcase VK_DOWN:\n\t\t\t\tif(!m_bVertical)\n\t\t\t\t{\n\t\t\t\t\tPOINT pt = { 0, 0 };\n\t\t\t\t\t::GetCursorPos(&pt);\n\t\t\t\t\tint xyPos = m_xySplitterPos + ((wParam == VK_UP) ? -pT->m_cxyStep : pT->m_cxyStep);\n\t\t\t\t\tint cxyMax = m_rcSplitter.bottom - m_rcSplitter.top;\n\t\t\t\t\tif(xyPos < (m_cxyMin + m_cxyBarEdge))\n\t\t\t\t\t\txyPos = m_cxyMin;\n\t\t\t\t\telse if(xyPos > (cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin))\n\t\t\t\t\t\txyPos = cxyMax - m_cxySplitBar - m_cxyBarEdge - m_cxyMin;\n\t\t\t\t\tpt.y += xyPos - m_xySplitterPos;\n\t\t\t\t\t::SetCursorPos(pt.x, pt.y);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tLRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(::GetCapture() != pT->m_hWnd)\n\t\t{\n\t\t\tif(m_nSinglePane == SPLIT_PANE_NONE)\n\t\t\t{\n\t\t\t\tif((m_nDefActivePane == SPLIT_PANE_LEFT) || (m_nDefActivePane == SPLIT_PANE_RIGHT))\n\t\t\t\t\t::SetFocus(m_hWndPane[m_nDefActivePane]);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t::SetFocus(m_hWndPane[m_nSinglePane]);\n\t\t\t}\n\t\t}\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n#ifndef _WIN32_WCE\n\tLRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tLRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);\n\t\tif((lRet == MA_ACTIVATE) || (lRet == MA_ACTIVATEANDEAT))\n\t\t{\n\t\t\tDWORD dwPos = ::GetMessagePos();\n\t\t\tPOINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };\n\t\t\tpT->ScreenToClient(&pt);\n\t\t\tRECT rcPane = { 0 };\n\t\t\tfor(int nPane = 0; nPane < m_nPanesCount; nPane++)\n\t\t\t{\n\t\t\t\tif(GetSplitterPaneRect(nPane, &rcPane) && (::PtInRect(&rcPane, pt) != FALSE))\n\t\t\t\t{\n\t\t\t\t\tm_nDefActivePane = nPane;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lRet;\n\t}\n#endif // !_WIN32_WCE\n\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->GetSystemSettings(true);\n\n\t\treturn 0;\n\t}\n\n// Implementation - internal helpers\n\tvoid Init()\n\t{\n\t\tm_hCursor = ::LoadCursor(NULL, m_bVertical ? IDC_SIZEWE : IDC_SIZENS);\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->GetSystemSettings(false);\n\t}\n\n\tvoid UpdateSplitterLayout()\n\t{\n\t\tif((m_nSinglePane == SPLIT_PANE_NONE) && (m_xySplitterPos == -1))\n\t\t\treturn;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tRECT rect = { 0 };\n\t\tif(m_nSinglePane == SPLIT_PANE_NONE)\n\t\t{\n\t\t\tif(GetSplitterBarRect(&rect))\n\t\t\t\tpT->InvalidateRect(&rect);\n\n\t\t\tfor(int nPane = 0; nPane < m_nPanesCount; nPane++)\n\t\t\t{\n\t\t\t\tif(GetSplitterPaneRect(nPane, &rect))\n\t\t\t\t{\n\t\t\t\t\tif(m_hWndPane[nPane] != NULL)\n\t\t\t\t\t\t::SetWindowPos(m_hWndPane[nPane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);\n\t\t\t\t\telse\n\t\t\t\t\t\tpT->InvalidateRect(&rect);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(GetSplitterPaneRect(m_nSinglePane, &rect))\n\t\t\t{\n\t\t\t\tif(m_hWndPane[m_nSinglePane] != NULL)\n\t\t\t\t\t::SetWindowPos(m_hWndPane[m_nSinglePane], NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);\n\t\t\t\telse\n\t\t\t\t\tpT->InvalidateRect(&rect);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool GetSplitterBarRect(LPRECT lpRect) const\n\t{\n\t\tATLASSERT(lpRect != NULL);\n\t\tif((m_nSinglePane != SPLIT_PANE_NONE) || (m_xySplitterPos == -1))\n\t\t\treturn false;\n\n\t\tif(m_bVertical)\n\t\t{\n\t\t\tlpRect->left = m_rcSplitter.left + m_xySplitterPos;\n\t\t\tlpRect->top = m_rcSplitter.top;\n\t\t\tlpRect->right = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;\n\t\t\tlpRect->bottom = m_rcSplitter.bottom;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlpRect->left = m_rcSplitter.left;\n\t\t\tlpRect->top = m_rcSplitter.top + m_xySplitterPos;\n\t\t\tlpRect->right = m_rcSplitter.right;\n\t\t\tlpRect->bottom = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool GetSplitterPaneRect(int nPane, LPRECT lpRect) const\n\t{\n\t\tATLASSERT((nPane == SPLIT_PANE_LEFT) || (nPane == SPLIT_PANE_RIGHT));\n\t\tATLASSERT(lpRect != NULL);\n\t\tbool bRet = true;\n\t\tif(m_nSinglePane != SPLIT_PANE_NONE)\n\t\t{\n\t\t\tif(nPane == m_nSinglePane)\n\t\t\t\t*lpRect = m_rcSplitter;\n\t\t\telse\n\t\t\t\tbRet = false;\n\t\t}\n\t\telse if(nPane == SPLIT_PANE_LEFT)\n\t\t{\n\t\t\tif(m_bVertical)\n\t\t\t{\n\t\t\t\tlpRect->left = m_rcSplitter.left;\n\t\t\t\tlpRect->top = m_rcSplitter.top;\n\t\t\t\tlpRect->right = m_rcSplitter.left + m_xySplitterPos;\n\t\t\t\tlpRect->bottom = m_rcSplitter.bottom;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlpRect->left = m_rcSplitter.left;\n\t\t\t\tlpRect->top = m_rcSplitter.top;\n\t\t\t\tlpRect->right = m_rcSplitter.right;\n\t\t\t\tlpRect->bottom = m_rcSplitter.top + m_xySplitterPos;\n\t\t\t}\n\t\t}\n\t\telse if(nPane == SPLIT_PANE_RIGHT)\n\t\t{\n\t\t\tif(m_bVertical)\n\t\t\t{\n\t\t\t\tlpRect->left = m_rcSplitter.left + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;\n\t\t\t\tlpRect->top = m_rcSplitter.top;\n\t\t\t\tlpRect->right = m_rcSplitter.right;\n\t\t\t\tlpRect->bottom = m_rcSplitter.bottom;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlpRect->left = m_rcSplitter.left;\n\t\t\t\tlpRect->top = m_rcSplitter.top + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge;\n\t\t\t\tlpRect->right = m_rcSplitter.right;\n\t\t\t\tlpRect->bottom = m_rcSplitter.bottom;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbRet = false;\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tbool IsOverSplitterRect(int x, int y) const\n\t{\n\t\t// -1 == don't check\n\t\treturn ((x == -1 || (x >= m_rcSplitter.left && x <= m_rcSplitter.right)) &&\n\t\t\t(y == -1 || (y >= m_rcSplitter.top && y <= m_rcSplitter.bottom)));\n\t}\n\n\tbool IsOverSplitterBar(int x, int y) const\n\t{\n\t\tif(m_nSinglePane != SPLIT_PANE_NONE)\n\t\t\treturn false;\n\t\tif((m_xySplitterPos == -1) || !IsOverSplitterRect(x, y))\n\t\t\treturn false;\n\t\tint xy = m_bVertical ? x : y;\n\t\tint xyOff = m_bVertical ? m_rcSplitter.left : m_rcSplitter.top;\n\n\t\treturn ((xy >= (xyOff + m_xySplitterPos)) && (xy < xyOff + m_xySplitterPos + m_cxySplitBar + m_cxyBarEdge));\n\t}\n\n\tvoid DrawGhostBar()\n\t{\n\t\tRECT rect = { 0 };\n\t\tif(GetSplitterBarRect(&rect))\n\t\t{\n\t\t\t// convert client to window coordinates\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tRECT rcWnd = { 0 };\n\t\t\tpT->GetWindowRect(&rcWnd);\n\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcWnd, 2);\n\t\t\t::OffsetRect(&rect, -rcWnd.left, -rcWnd.top);\n\n\t\t\t// invert the brush pattern (looks just like frame window sizing)\n\t\t\tCWindowDC dc(pT->m_hWnd);\n\t\t\tCBrush brush = CDCHandle::GetHalftoneBrush();\n\t\t\tif(brush.m_hBrush != NULL)\n\t\t\t{\n\t\t\t\tCBrushHandle brushOld = dc.SelectBrush(brush);\n\t\t\t\tdc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);\n\t\t\t\tdc.SelectBrush(brushOld);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid GetSystemSettings(bool bUpdate)\n\t{\n\t\tif((m_dwExtendedStyle & SPLIT_FIXEDBARSIZE) == 0)\n\t\t{\n#ifndef _WIN32_WCE\n\t\t\tm_cxySplitBar = ::GetSystemMetrics(m_bVertical ? SM_CXSIZEFRAME : SM_CYSIZEFRAME);\n#else // CE specific\n\t\t\tm_cxySplitBar = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);\n#endif // _WIN32_WCE\n\t\t}\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)\n\t\t{\n\t\t\tm_cxyBarEdge = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);\n\t\t\tm_cxyMin = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_cxyBarEdge = 0;\n\t\t\tm_cxyMin = 2 * ::GetSystemMetrics(m_bVertical ? SM_CXEDGE : SM_CYEDGE);\n\t\t}\n\n#ifndef _WIN32_WCE\n\t\t::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bFullDrag, 0);\n#endif // !_WIN32_WCE\n\n\t\tif(bUpdate)\n\t\t\tUpdateSplitterLayout();\n\t}\n\n\tbool IsProportional() const\n\t{\n\t\treturn ((m_dwExtendedStyle & SPLIT_PROPORTIONAL) != 0);\n\t}\n\n\tvoid StoreProportionalPos()\n\t{\n\t\tint cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);\n\t\tif(cxyTotal > 0)\n\t\t\tm_nProportionalPos = ::MulDiv(m_xySplitterPos, m_nPropMax, cxyTotal);\n\t\telse\n\t\t\tm_nProportionalPos = 0;\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CSplitterImpl::StoreProportionalPos - %i\\n\"), m_nProportionalPos);\n\t}\n\n\tvoid UpdateProportionalPos()\n\t{\n\t\tint cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);\n\t\tif(cxyTotal > 0)\n\t\t{\n\t\t\tint xyNewPos = ::MulDiv(m_nProportionalPos, cxyTotal, m_nPropMax);\n\t\t\tm_bUpdateProportionalPos = false;\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->SetSplitterPos(xyNewPos, false);\n\t\t}\n\t}\n\n\tbool IsRightAligned() const\n\t{\n\t\treturn ((m_dwExtendedStyle & SPLIT_RIGHTALIGNED) != 0);\n\t}\n\n\tvoid StoreRightAlignPos()\n\t{\n\t\tint cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);\n\t\tif(cxyTotal > 0)\n\t\t\tm_nProportionalPos = cxyTotal - m_xySplitterPos;\n\t\telse\n\t\t\tm_nProportionalPos = 0;\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"CSplitterImpl::StoreRightAlignPos - %i\\n\"), m_nProportionalPos);\n\t}\n\n\tvoid UpdateRightAlignPos()\n\t{\n\t\tint cxyTotal = m_bVertical ? (m_rcSplitter.right - m_rcSplitter.left - m_cxySplitBar - m_cxyBarEdge) : (m_rcSplitter.bottom - m_rcSplitter.top - m_cxySplitBar - m_cxyBarEdge);\n\t\tif(cxyTotal > 0)\n\t\t{\n\t\t\tm_bUpdateProportionalPos = false;\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->SetSplitterPos(cxyTotal - m_nProportionalPos, false);\n\t\t}\n\t}\n\n\tbool IsInteractive() const\n\t{\n\t\treturn ((m_dwExtendedStyle & SPLIT_NONINTERACTIVE) == 0);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CSplitterWindowImpl - Implements a splitter window\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CSplitterWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CSplitterImpl< T >\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, COLOR_WINDOW)\n\n\tCSplitterWindowImpl(bool bVertical = true) : CSplitterImpl< T >(bVertical)\n\t{ }\n\n\tBOOL SubclassWindow(HWND hWnd)\n\t{\n#if (_MSC_VER >= 1300)\n\t\tBOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);\n#else // !(_MSC_VER >= 1300)\n\t\ttypedef ATL::CWindowImpl< T, TBase, TWinTraits >   _baseClass;\n\t\tBOOL bRet = _baseClass::SubclassWindow(hWnd);\n#endif // !(_MSC_VER >= 1300)\n\t\tif(bRet != FALSE)\n\t\t{\n\t\t\tT* pT = static_cast<T*>(this);\n\t\t\tpT->Init();\n\n\t\t\tSetSplitterRect();\n\t\t}\n\n\t\treturn bRet;\n\t}\n\n\tBEGIN_MSG_MAP(CSplitterWindowImpl)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_SIZE, OnSize)\n\t\tCHAIN_MSG_MAP(CSplitterImpl< T >)\n\t\tFORWARD_NOTIFICATIONS()\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\t// handled, no background painting needed\n\t\treturn 1;\n\t}\n\n\tLRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(wParam != SIZE_MINIMIZED)\n\t\t\tSetSplitterRect();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CSplitterWindow/CHorSplitterWindow - Implements splitter windows to be used as is\n\ntemplate <bool t_bVertical = true>\nclass CSplitterWindowT : public CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_SplitterWindow\"), CS_DBLCLKS, COLOR_WINDOW)\n\n\tCSplitterWindowT() : CSplitterWindowImpl<CSplitterWindowT<t_bVertical> >(t_bVertical)\n\t{ }\n};\n\ntypedef CSplitterWindowT<true>    CSplitterWindow;\ntypedef CSplitterWindowT<false>   CHorSplitterWindow;\n\n}; // namespace WTL\n\n#endif // __ATLSPLIT_H__\n"
  },
  {
    "path": "WTL/atltheme.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLTHEME_H__\n#define __ATLTHEME_H__\n\n#pragma once\n\n#ifdef _WIN32_WCE\n\t#error atltheme.h is not supported on Windows CE\n#endif\n\n#ifndef __ATLAPP_H__\n\t#error atltheme.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atltheme.h requires atlwin.h to be included first\n#endif\n\n#if (_WIN32_WINNT < 0x0501)\n\t#error atltheme.h requires _WIN32_WINNT >= 0x0501\n#endif // (_WIN32_WINNT < 0x0501)\n\n#if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN))\n  #include <vssym32.h>\n#else\n  #ifndef TMSCHEMA_H\n    #include <tmschema.h>\n  #endif\n#endif\n\n#include <uxtheme.h>\n#pragma comment(lib, \"uxtheme.lib\")\n\n// Note: To create an application that also runs on older versions of Windows,\n// use delay load of uxtheme.dll and ensure that no calls to the Theme API are\n// made if theming is not supported. It is enough to check if m_hTheme is NULL.\n// Example:\n//\tif(m_hTheme != NULL)\n//\t{\n//\t\tDrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL);\n//\t\tDrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L\"Button\", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect);\n//\t}\n//\telse\n//\t{\n//\t\tdc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH);\n//\t\tdc.DrawText(_T(\"Button\"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);\n//\t}\n//\n// Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib, \n// and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the \n// project properties.\n#if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)\n  #pragma comment(lib, \"delayimp.lib\")\n  #pragma comment(linker, \"/delayload:uxtheme.dll\")\n#endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)\n\n// Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h\n// is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE\n// Note: In WinSDK 7.0 (and higher) they are defined with #if (_WIN32_WINNT >= 0x0600),\n// so you have to compile with _WTL_NEW_UXTHEME defined for _WIN32_WINNT < 0x0600\n#ifndef _WTL_NEW_UXTHEME\n  #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)\n    #define _WTL_NEW_UXTHEME\n  #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)\n#endif // _WTL_NEW_UXTHEME\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CTheme\n// CThemeImpl<T, TBase>\n//\n// CBufferedPaint\n// CBufferedPaintImpl<T>\n// CBufferedPaintWindowImpl<T, TBase, TWinTraits>\n// CBufferedAnimation\n// CBufferedAnimationImpl<T, TState>\n// CBufferedAnimationWindowImpl<T, TState, TBase, TWinTraits>\n//\n// Global functions:\n//   AtlDrawThemeClientEdge()\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// CTheme - wrapper for theme handle\n\nclass CTheme\n{\npublic:\n// Data members\n\tHTHEME m_hTheme;\n\tstatic int m_nIsThemingSupported;\n\n// Constructor\n\tCTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme)\n\t{\n\t\tIsThemingSupported();\n\t}\n\n// Operators and helpers\n\tbool IsThemeNull() const\n\t{\n\t\treturn (m_hTheme == NULL);\n\t}\n\n\tCTheme& operator =(HTHEME hTheme)\n\t{\n\t\tm_hTheme = hTheme;\n\t\treturn *this;\n\t}\n\n\toperator HTHEME() const\n\t{\n\t\treturn m_hTheme;\n\t}\n\n\tvoid Attach(HTHEME hTheme)\n\t{\n\t\tm_hTheme = hTheme;\n\t}\n\n\tHTHEME Detach()\n\t{\n\t\tHTHEME hTheme = m_hTheme;\n\t\tm_hTheme = NULL;\n\t\treturn hTheme;\n\t}\n\n// Theme support helper\n\tstatic bool IsThemingSupported()\n\t{\n\t\tif(m_nIsThemingSupported == -1)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif(m_nIsThemingSupported == -1)\n\t\t\t{\n\t\t\t\tHMODULE hThemeDLL = ::LoadLibrary(_T(\"uxtheme.dll\"));\n\t\t\t\tm_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0;\n\t\t\t\tif(hThemeDLL != NULL)\n\t\t\t\t\t::FreeLibrary(hThemeDLL);\n\t\t\t}\n\n\t\t\tlock.Unlock();\n\t\t}\n\n\t\tATLASSERT(m_nIsThemingSupported != -1);\n\t\treturn (m_nIsThemingSupported == 1);\n\t}\n\n// Operations and theme properties\n\tHTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn NULL;\n\n\t\tATLASSERT(m_hTheme == NULL);\n\t\tm_hTheme = ::OpenThemeData(hWnd, pszClassList);\n\t\treturn m_hTheme;\n\t}\n\n\tHRESULT CloseThemeData()\n\t{\n\t\tHRESULT hRet = S_FALSE;\n\t\tif(m_hTheme != NULL)\n\t\t{\n\t\t\thRet = ::CloseThemeData(m_hTheme);\n\t\t\tif(SUCCEEDED(hRet))\n\t\t\t\tm_hTheme = NULL;\n\t\t}\n\t\treturn hRet;\n\t}\n\n\tHRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect);\n\t}\n\n// Missing in original uxtheme.h\n#ifdef DTBG_CLIPRECT\n\tHRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions);\n\t}\n#endif // DTBG_CLIPRECT\n\n\tHRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect);\n\t}\n\n\tHRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID,  LPCRECT pBoundingRect, LPRECT pContentRect) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID,  pBoundingRect, pContentRect);\n\t}\n\n\tHRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect);\n\t}\n\n\tHRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize);\n#else // !_WTL_NEW_UXTHEME\n\t\t// Note: The cast to LPRECT is because uxtheme.h incorrectly uses it instead of LPCRECT\n\t\treturn ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, (LPRECT)pRect, eSize, pSize);\n#endif // !_WTL_NEW_UXTHEME\n\t}\n\n\tHRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT  pBoundingRect, LPRECT pExtentRect) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect);\n\t}\n\n\tHRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric);\n#else // !_WTL_NEW_UXTHEME\n\t\t// Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW\n\t\treturn ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric);\n#endif // !_WTL_NEW_UXTHEME\n\t}\n\n\tHRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion);\n\t}\n\n\tHRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode);\n\t}\n\n\tHRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect);\n\t}\n\n\tHRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex);\n\t}\n\n\tBOOL IsThemePartDefined(int nPartID, int nStateID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::IsThemePartDefined(m_hTheme, nPartID, nStateID);\n\t}\n\n\tBOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID);\n\t}\n\n\tHRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor);\n\t}\n\n\tHRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal);\n\t}\n\n\tHRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars);\n\t}\n\n\tHRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal);\n\t}\n\n\tHRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal);\n\t}\n\n\tHRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal);\n\t}\n\n\tHRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint);\n\t}\n\n\t// deprecated\n\tHRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);\n#else // !_WTL_NEW_UXTHEME\n\t\t// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*\n\t\treturn ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);\n#endif // !_WTL_NEW_UXTHEME\n\t}\n\n\tHRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);\n#else // !_WTL_NEW_UXTHEME\n\t\t// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*\n\t\treturn ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);\n#endif // !_WTL_NEW_UXTHEME\n\t}\n\n\tHRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect);\n\t}\n\n\tHRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins);\n\t}\n\n\tHRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList);\n\t}\n\n\tHRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin);\n\t}\n\n\tHRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars);\n\t}\n\n\tCOLORREF GetThemeSysColor(int nColorID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysColor(m_hTheme, nColorID);\n\t}\n\n\tHBRUSH GetThemeSysColorBrush(int nColorID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysColorBrush(m_hTheme, nColorID);\n\t}\n\n\tint GetThemeSysSize(int nSizeID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysSize(m_hTheme, nSizeID);\n\t}\n\n\tBOOL GetThemeSysBool(int nBoolID) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysBool(m_hTheme, nBoolID);\n\t}\n\n\tHRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::GetThemeSysFont(m_hTheme, nFontID, plf);\n#else // !_WTL_NEW_UXTHEME\n\t\t// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*\n\t\treturn ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf);\n#endif // !_WTL_NEW_UXTHEME\n\t}\n\n\tHRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars);\n\t}\n\n\tHRESULT GetThemeSysInt(int nIntID, int* pnValue) const\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeSysInt(m_hTheme, nIntID, pnValue);\n\t}\n\n#ifdef _WTL_NEW_UXTHEME\n\tHTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn NULL;\n\n\t\tATLASSERT(m_hTheme == NULL);\n\t\tm_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags);\n\t\treturn m_hTheme;\n\t}\n\n#if (_WIN32_WINNT >= 0x0600)\n\tHRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions);\n\t}\n\n\tHRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n#endif // _WTL_NEW_UXTHEME\n\n#if (_WIN32_WINNT >= 0x0600)\n\tHRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap);\n\t}\n\n\tHRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n#if (_WIN32_WINNT >= 0x0602)\n\tHRESULT GetThemeAnimationProperty(int iStoryboardId, int iTargetId, TA_PROPERTY eProperty, VOID* pvProperty, DWORD cbSize, DWORD* pcbSizeOut)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeAnimationProperty(m_hTheme, iStoryboardId, iTargetId, eProperty, pvProperty, cbSize, pcbSizeOut);\n\t}\n\n\tHRESULT GetThemeAnimationTransform(int iStoryboardId, int iTargetId, DWORD dwTransformIndex, TA_TRANSFORM* pTransform, DWORD cbSize, DWORD* pcbSizeOut)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeAnimationTransform(m_hTheme, iStoryboardId, iTargetId, dwTransformIndex, pTransform, cbSize, pcbSizeOut);\n\t}\n\n\tHRESULT GetThemeTimingFunction(int iTimingFunctionId, TA_TIMINGFUNCTION* pTimingFunction, DWORD cbSize, DWORD* pcbSizeOut)\n\t{\n\t\tATLASSERT(m_hTheme != NULL);\n\t\treturn ::GetThemeTimingFunction(m_hTheme, iTimingFunctionId, pTimingFunction, cbSize, pcbSizeOut);\n\t}\n#endif // (_WIN32_WINNT >= 0x0602)\n};\n\n__declspec(selectany) int CTheme::m_nIsThemingSupported = -1;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CThemeImpl - theme support implementation\n\n// Derive from this class to implement window with theme support.\n// Example:\n//\tclass CMyThemeWindow : public CWindowImpl<CMyThemeWindow>, public CThemeImpl<CMyThemeWindow>\n//\t{\n//\t...\n//\t\tBEGIN_MSG_MAP(CMyThemeWindow)\n//\t\t\tCHAIN_MSG_MAP(CThemeImpl<CMyThemeWindow>)\n//\t\t\t...\n//\t\tEND_MSG_MAP()\n//\t...\n//\t};\n//\n// If you set theme class list, the class will automaticaly open/close/reopen theme data.\n\n\n// Helper for drawing theme client edge\ninline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0)\n{\n\tATLASSERT(hTheme != NULL);\n\tATLASSERT(::IsWindow(hWnd));\n\n\tCWindowDC dc(hWnd);\n\tif(dc.IsNull())\n\t\treturn false;\n\n\t// Get border size\n\tint cxBorder = ::GetSystemMetrics(SM_CXBORDER);\n\tint cyBorder = ::GetSystemMetrics(SM_CYBORDER);\n\tif(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder)))\n\t\tcyBorder = cxBorder;\n\n\tRECT rect = { 0 };\n\t::GetWindowRect(hWnd, &rect);            \n\n\t// Remove the client edge from the update region\n\tint cxEdge = ::GetSystemMetrics(SM_CXEDGE);\n\tint cyEdge = ::GetSystemMetrics(SM_CYEDGE);\n\t::InflateRect(&rect, -cxEdge, -cyEdge);\n\tCRgn rgn;\n\trgn.CreateRectRgnIndirect(&rect);\n\tif(rgn.IsNull())\n\t\treturn false;\n\n\tif(hRgnUpdate != NULL)\n\t\trgn.CombineRgn(hRgnUpdate, rgn, RGN_AND);\n\n\t::OffsetRect(&rect, -rect.left, -rect.top);\n\n\t::OffsetRect(&rect, cxEdge, cyEdge);\n\tdc.ExcludeClipRect(&rect);\n\t::InflateRect(&rect, cxEdge, cyEdge);\n\n\t::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL);\n\n\t// Use background brush too, since theme border might not cover everything\n\tif((cxBorder < cxEdge) && (cyBorder < cyEdge))\n\t{\n\t\tif(hBrush == NULL)\n// need conditional code because types don't match in winuser.h\n#ifdef _WIN64\n\t\t\thBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND);\n#else\n\t\t\thBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND));\n#endif\n\n\t\t::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge);\n\t\tdc.FillRect(&rect, hBrush);\n\t}\n\n\t::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L);\n\n\treturn true;\n}\n\n\n// Theme extended styles\n#define THEME_EX_3DCLIENTEDGE\t\t0x00000001\n#define THEME_EX_THEMECLIENTEDGE\t0x00000002\n\ntemplate <class T, class TBase = CTheme>\nclass CThemeImpl : public TBase\n{\npublic:\n// Data members\n\tLPWSTR m_lpstrThemeClassList;\n\tDWORD m_dwExtendedStyle;   // theme specific extended styles\n\n// Constructor & destructor\n\tCThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0)\n\t{ }\n\n\t~CThemeImpl()\n\t{\n\t\tdelete [] m_lpstrThemeClassList;\n\t}\n\n// Attributes\n\tbool SetThemeClassList(LPCWSTR lpstrThemeClassList)\n\t{\n\t\tif(m_lpstrThemeClassList != NULL)\n\t\t{\n\t\t\tdelete [] m_lpstrThemeClassList;\n\t\t\tm_lpstrThemeClassList = NULL;\n\t\t}\n\n\t\tif(lpstrThemeClassList == NULL)\n\t\t\treturn true;\n\n\t\tint cchLen = lstrlenW(lpstrThemeClassList) + 1;\n\t\tATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]);\n\t\tif(m_lpstrThemeClassList == NULL)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList);\n\n\t\treturn true;\n\t}\n\n\tbool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const\n\t{\n\t\tint cchLen = lstrlenW(m_lpstrThemeClassList) + 1;\n\t\tif(cchListBuffer < cchLen)\n\t\t\treturn false;\n\n\t\tSecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList);\n\n\t\treturn true;\n\t}\n\n\tLPCWSTR GetThemeClassList() const\n\t{\n\t\treturn m_lpstrThemeClassList;\n\t}\n\n\tDWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\n\t{\n\t\tDWORD dwPrevStyle = m_dwExtendedStyle;\n\t\tif(dwMask == 0)\n\t\t\tm_dwExtendedStyle = dwExtendedStyle;\n\t\telse\n\t\t\tm_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\n\n\t\treturn dwPrevStyle;\n\t}\n\n\tDWORD GetThemeExtendedStyle() const\n\t{\n\t\treturn m_dwExtendedStyle;\n\t}\n\n// Operations\n\tHTHEME OpenThemeData()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tATLASSERT(m_lpstrThemeClassList != NULL);\n\t\tif(m_lpstrThemeClassList == NULL)\n\t\t\treturn NULL;\n\t\tCloseThemeData();\n\n\t\treturn TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList);\n\t}\n\n\tHTHEME OpenThemeData(LPCWSTR pszClassList)\n\t{\n\t\tif(!SetThemeClassList(pszClassList))\n\t\t\treturn NULL;\n\n\t\treturn OpenThemeData();\n\t}\n\n\tHRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList);\n\t}\n\n\tHTHEME GetWindowTheme() const\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn NULL;\n\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::GetWindowTheme(pT->m_hWnd);\n\t}\n\n\tHRESULT EnableThemeDialogTexture(DWORD dwFlags)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags);\n\t}\n\n\tBOOL IsThemeDialogTextureEnabled() const\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn FALSE;\n\n\t\tconst T* pT = static_cast<const T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::IsThemeDialogTextureEnabled(pT->m_hWnd);\n\t}\n\n\tHRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n#ifdef _WTL_NEW_UXTHEME\n\t\treturn ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect);\n#else\n\t\treturn ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect);\n#endif\n\t}\n\n#if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)\n\tHRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute);\n\t}\n\n\tHRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tWTA_OPTIONS opt = { dwAttributes, dwMask };\n\t\treturn ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt));\n\t}\n\n\tHRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL)\n\t{\n\t\tif(!IsThemingSupported())\n\t\t\treturn S_FALSE;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\treturn ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect);\n\t}\n#endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)\n\n// Message map and handlers\n\t// Note: If you handle any of these messages in your derived class,\n\t// it is better to put CHAIN_MSG_MAP at the start of your message map.\n\tBEGIN_MSG_MAP(CThemeImpl)\n\t\tMESSAGE_HANDLER(WM_CREATE, OnCreate)\n\t\tMESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n\t\tMESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)\n\t\tMESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)\n\tEND_MSG_MAP()\n\n\tLRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif(m_lpstrThemeClassList != NULL)\n\t\t\tOpenThemeData();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tCloseThemeData();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tCloseThemeData();\n\t\tif(m_lpstrThemeClassList != NULL)\n\t\t\tOpenThemeData();\n\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tLRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tLRESULT lRet = 0;\n\t\tbHandled = FALSE;\n\t\tif(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0))\n\t\t{\n\t\t\tif((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0)\n\t\t\t{\n\t\t\t\tlRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam);\n\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t\telse if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0))\n\t\t\t{\n\t\t\t\tHRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL;\n\t\t\t\tif(pT->DrawThemeClientEdge(hRgn))\n\t\t\t\t\tbHandled = TRUE;\n\t\t\t}\n\t\t}\n\n\t\treturn lRet;\n\t}\n\n// Drawing helper\n\tbool DrawThemeClientEdge(HRGN hRgnUpdate)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0);\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Buffered Paint and Animation\n\n#if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedPaintBase - Buffered Paint support for othe classes\n\nclass CBufferedPaintBase\n{\npublic:\n\tstatic int m_nIsBufferedPaintSupported;\n\n\tCBufferedPaintBase()\n\t{\n\t\tif(IsBufferedPaintSupported())\n\t\t\tATLVERIFY(SUCCEEDED(::BufferedPaintInit()));\n\t}\n\n\t~CBufferedPaintBase()\n\t{\n\t\tif(IsBufferedPaintSupported())\n\t\t\tATLVERIFY(SUCCEEDED(::BufferedPaintUnInit()));\n\t}\n\n\tstatic bool IsBufferedPaintSupported()\n\t{\n\t\tif(m_nIsBufferedPaintSupported == -1)\n\t\t{\n\t\t\tCStaticDataInitCriticalSectionLock lock;\n\t\t\tif(FAILED(lock.Lock()))\n\t\t\t{\n\t\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\\n\"));\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif(m_nIsBufferedPaintSupported == -1)\n\t\t\t\tm_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0;\n\n\t\t\tlock.Unlock();\n\t\t}\n\n\t\tATLASSERT(m_nIsBufferedPaintSupported != -1);\n\t\treturn (m_nIsBufferedPaintSupported == 1);\n\t}\n};\n\n__declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedPaint - support for buffered paint functions\n\nclass CBufferedPaint\n{\npublic:\n\tHPAINTBUFFER m_hPaintBuffer;\n\n\tCBufferedPaint() : m_hPaintBuffer(NULL)\n\t{ }\n\n\t~CBufferedPaint()\n\t{\n\t\tATLVERIFY(SUCCEEDED(End()));\n\t}\n\n\tbool IsNull() const\n\t{\n\t\treturn (m_hPaintBuffer == NULL);\n\t}\n\n\tHPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint)\n\t{\n\t\tATLASSERT(m_hPaintBuffer == NULL);\n\t\tm_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint);\n\t\treturn m_hPaintBuffer;\n\t}\n\n\tHRESULT End(BOOL bUpdate = TRUE)\n\t{\n\t\tHRESULT hRet = S_FALSE;\n\t\tif(m_hPaintBuffer != NULL)\n\t\t{\n\t\t\thRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate);\n\t\t\tm_hPaintBuffer = NULL;\n\t\t}\n\t\treturn hRet;\n\t}\n\n\tHRESULT GetTargetRect(LPRECT pRect) const\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect);\n\t}\n\n\tHDC GetTargetDC() const\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::GetBufferedPaintTargetDC(m_hPaintBuffer);\n\t}\n\n\tHDC GetPaintDC() const\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::GetBufferedPaintDC(m_hPaintBuffer);\n\t}\n\n\tHRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow);\n\t}\n\n\tHRESULT Clear(const RECT* pRect = NULL)\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::BufferedPaintClear(m_hPaintBuffer, pRect);\n\t}\n\n\tHRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL)\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha);\n\t}\n\n\tHRESULT MakeOpaque(const RECT* pRect = NULL)\n\t{\n\t\tATLASSERT(m_hPaintBuffer != NULL);\n\t\treturn ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedPaintImpl - provides buffered paint for any window\n\ntemplate <class T>\nclass ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase\n{\npublic:\n\tCBufferedPaint m_BufferedPaint;\n\tBP_BUFFERFORMAT m_dwFormat;\n\tBP_PAINTPARAMS m_PaintParams;\n\n\tCBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB)\n\t{\n\t\tmemset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));\n\t\tm_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CBufferedPaintImpl)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background needed\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetClientRect(&rect);\n\t\t\tpT->DoPaint((HDC)wParam, rect);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tpT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n// Overrideables\n\tvoid DoBufferedPaint(CDCHandle dc, RECT& rect)\n\t{\n\t\tHDC hDCPaint = NULL;\n\t\tif(IsBufferedPaintSupported())\n\t\t\tm_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint);\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(hDCPaint != NULL)\n\t\t\tpT->DoPaint(hDCPaint, rect);\n\t\telse\n\t\t\tpT->DoPaint(dc.m_hDC, rect);\n\n\t\tif(IsBufferedPaintSupported())\n\t\t\tm_BufferedPaint.End();\n\t}\n\n\tvoid DoPaint(CDCHandle /*dc*/, RECT& /*rect*/)\n\t{\n\t\t// must be implemented in a derived class\n\t\tATLASSERT(FALSE);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedPaintWindowImpl - implements a window that uses buffered paint\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CBufferedPaintWindowImpl : \n\t\tpublic ATL::CWindowImpl<T, TBase, TWinTraits>, \n\t\tpublic CBufferedPaintImpl< T >\n{\npublic:\n\tBEGIN_MSG_MAP(CBufferedPaintWindowImpl)\n\t\tCHAIN_MSG_MAP(CBufferedPaintImpl< T >)\n\tEND_MSG_MAP()\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedAnimation - support for buffered animation\n\nclass CBufferedAnimation\n{\npublic:\n\tHANIMATIONBUFFER m_hAnimationBuffer;\n\n\tCBufferedAnimation() : m_hAnimationBuffer(NULL)\n\t{ }\n\n\t~CBufferedAnimation()\n\t{\n\t\tATLVERIFY(SUCCEEDED(End()));\n\t}\n\n\tbool IsNull() const\n\t{\n\t\treturn (m_hAnimationBuffer == NULL);\n\t}\n\n\tHANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo)\n\t{\n\t\tATLASSERT(m_hAnimationBuffer == NULL);\n\t\tm_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo);\n\t\treturn m_hAnimationBuffer;\n\t}\n\n\tHRESULT End(BOOL bUpdate = TRUE)\n\t{\n\t\tHRESULT hRet = S_FALSE;\n\t\tif(m_hAnimationBuffer != NULL)\n\t\t{\n\t\t\thRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate);\n\t\t\tm_hAnimationBuffer = NULL;\n\t\t}\n\t\treturn hRet;\n\t}\n\n\tstatic bool IsRendering(HWND hWnd, HDC hDC)\n\t{\n\t\treturn (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE);\n\t}\n\n\tstatic HRESULT StopAllAnimations(HWND hWnd)\n\t{\n\t\treturn ::BufferedPaintStopAllAnimations(hWnd);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedAnimationImpl - provides buffered animation support for any window\n\n// Note: You can either use m_State and m_NewState to store the state information\n// for the animation change, or map your state to those data members. DoPaint()\n// should only rely on the state information that is passed to it.\n\ntemplate <class T, class TState = DWORD_PTR>\nclass ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase\n{\npublic:\n\tBP_BUFFERFORMAT m_dwFormat;\n\tBP_PAINTPARAMS m_PaintParams;\n\tBP_ANIMATIONPARAMS m_AnimationParams;\n\n\tTState m_State;\n\tTState m_NewState;\n\n\tCBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB)\n\t{\n\t\tmemset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));\n\t\tm_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);\n\n\t\tmemset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS));\n\t\tm_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS);\n\t\tm_AnimationParams.style = BPAS_LINEAR;\n\t\tm_AnimationParams.dwDuration = 500;\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetState(InitialState);\n\t\tpT->SetNewState(InitialState);\n\t}\n\n\tDWORD GetDuration() const\n\t{\n\t\treturn m_AnimationParams.dwDuration;\n\t}\n\n\tvoid SetDuration(DWORD dwDuration)\n\t{\n\t\tm_AnimationParams.dwDuration = dwDuration;\n\t}\n\n\tvoid DoAnimation(TState NewState, const RECT* pRect = NULL)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->SetNewState(NewState);\n\n\t\tpT->InvalidateRect(pRect, FALSE);\n\t\tpT->UpdateWindow();\n\n\t\tpT->SetState(NewState);\n\t}\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CBufferedAnimationImpl)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaint)\n\t\tMESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\n\tEND_MSG_MAP()\n\n\tLRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\treturn 1;   // no background needed\n\t}\n\n\tLRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(wParam != NULL)\n\t\t{\n\t\t\tRECT rect = { 0 };\n\t\t\tpT->GetClientRect(&rect);\n\t\t\tpT->DoPaint((HDC)wParam, rect, m_NewState);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPaintDC dc(pT->m_hWnd);\n\t\t\tpT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n// Overrideables\n\tvoid SetState(TState State)\n\t{\n\t\tm_State = State;\n\t}\n\n\tvoid SetNewState(TState State)\n\t{\n\t\tm_NewState = State;\n\t}\n\n\tbool AreStatesEqual() const\n\t{\n\t\treturn (m_State == m_NewState);\n\t}\n\n\tvoid DoAnimationPaint(CDCHandle dc, RECT& rect)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc))\n\t\t\treturn;\n\n\t\tDWORD dwDurationSave = m_AnimationParams.dwDuration;\n\t\tif(pT->AreStatesEqual())\n\t\t\tm_AnimationParams.dwDuration = 0;\n\n\t\tHDC hdcFrom = NULL, hdcTo = NULL;\n\t\tCBufferedAnimation ba;\n\t\tif(IsBufferedPaintSupported())\n\t\t\tba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo);\n\n\t\tif(!ba.IsNull())\n\t\t{\n\t\t\tif(hdcFrom != NULL)\n\t\t\t\tpT->DoPaint(hdcFrom, rect, m_State);\n\n\t\t\tif (hdcTo != NULL)\n\t\t\t\tpT->DoPaint(hdcTo, rect, m_NewState);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpT->DoPaint(dc.m_hDC, rect, m_NewState);\n\t\t}\n\n\t\tm_AnimationParams.dwDuration = dwDurationSave;\n\t}\n\n\tvoid DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/)\n\t{\n\t\t// must be implemented in a derived class\n\t\tATLASSERT(FALSE);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CBufferedAnimationWindowImpl - implements a window that uses buffered animation\n\ntemplate <class T, class TState = DWORD_PTR, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CBufferedAnimationWindowImpl : \n\t\tpublic ATL::CWindowImpl<T, TBase, TWinTraits>, \n\t\tpublic CBufferedAnimationImpl< T, TState >\n{\npublic:\n\tCBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState)\n\t{ }\n\n\ttypedef CBufferedAnimationImpl< T, TState >   _baseBufferedAnimation;\n\tBEGIN_MSG_MAP(CBufferedAnimationWindowImpl)\n\t\tCHAIN_MSG_MAP(_baseBufferedAnimation)\n\tEND_MSG_MAP()\n};\n\n#endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)\n\n}; // namespace WTL\n\n#endif // __ATLTHEME_H__\n"
  },
  {
    "path": "WTL/atluser.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLUSER_H__\n#define __ATLUSER_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atluser.h requires atlapp.h to be included first\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CMenuItemInfo\n// CMenuT<t_bManaged>\n// CAcceleratorT<t_bManaged>\n// CIconT<t_bManaged>\n// CCursorT<t_bManaged>\n// CResource\n//\n// Global functions:\n//   AtlMessageBox()\n//\n//   AtlLoadAccelerators()\n//   AtlLoadMenu()\n//   AtlLoadBitmap()\n//   AtlLoadSysBitmap()\n//   AtlLoadCursor()\n//   AtlLoadSysCursor()\n//   AtlLoadIcon()\n//   AtlLoadSysIcon()\n//   AtlLoadBitmapImage()\n//   AtlLoadCursorImage()\n//   AtlLoadIconImage()\n//   AtlLoadSysBitmapImage()\n//   AtlLoadSysCursorImage()\n//   AtlLoadSysIconImage()\n//   AtlLoadString()\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// AtlMessageBox - accepts both memory and resource based strings\n\ninline int AtlMessageBox(HWND hWndOwner, ATL::_U_STRINGorID message, ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uType = MB_OK | MB_ICONINFORMATION)\n{\n\tATLASSERT(hWndOwner == NULL || ::IsWindow(hWndOwner));\n\n\tLPTSTR lpstrMessage = NULL;\n\tif(IS_INTRESOURCE(message.m_lpstr))\n\t{\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tATLTRY(lpstrMessage = new TCHAR[nLen]);\n\t\t\tif(lpstrMessage == NULL)\n\t\t\t{\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tint nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(message.m_lpstr), lpstrMessage, nLen);\n\t\t\tif(nRes < nLen - 1)\n\t\t\t\tbreak;\n\t\t\tdelete [] lpstrMessage;\n\t\t\tlpstrMessage = NULL;\n\t\t}\n\n\t\tmessage.m_lpstr = lpstrMessage;\n\t}\n\n\tLPTSTR lpstrTitle = NULL;\n\tif(IS_INTRESOURCE(title.m_lpstr) && LOWORD(title.m_lpstr) != 0)\n\t{\n\t\tfor(int nLen = 256; ; nLen *= 2)\n\t\t{\n\t\t\tATLTRY(lpstrTitle = new TCHAR[nLen]);\n\t\t\tif(lpstrTitle == NULL)\n\t\t\t{\n\t\t\t\tATLASSERT(FALSE);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tint nRes = ::LoadString(ModuleHelper::GetResourceInstance(), LOWORD(title.m_lpstr), lpstrTitle, nLen);\n\t\t\tif(nRes < nLen - 1)\n\t\t\t\tbreak;\n\t\t\tdelete [] lpstrTitle;\n\t\t\tlpstrTitle = NULL;\n\t\t}\n\n\t\ttitle.m_lpstr = lpstrTitle;\n\t}\n\n\tint nRet = ::MessageBox(hWndOwner, message.m_lpstr, title.m_lpstr, uType);\n\n\tdelete [] lpstrMessage;\n\tdelete [] lpstrTitle;\n\n\treturn nRet;\n}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CMenu\n\n#if (WINVER >= 0x0500)\n  #ifndef MII_SIZEOF_STRUCT\n    #define MII_SIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))\n  #endif\n  #define MENUITEMINFO_SIZE_VERSION_400A  MII_SIZEOF_STRUCT(MENUITEMINFOA, cch)\n  #define MENUITEMINFO_SIZE_VERSION_400W  MII_SIZEOF_STRUCT(MENUITEMINFOW, cch)\n  #ifdef UNICODE\n    #define MENUITEMINFO_SIZE_VERSION_400  MENUITEMINFO_SIZE_VERSION_400W\n  #else\n    #define MENUITEMINFO_SIZE_VERSION_400  MENUITEMINFO_SIZE_VERSION_400A\n  #endif // !UNICODE\n#endif // (WINVER >= 0x0500)\n\nclass CMenuItemInfo : public MENUITEMINFO\n{\npublic:\n\tCMenuItemInfo()\n\t{\n\t\tmemset(this, 0, sizeof(MENUITEMINFO));\n\t\tcbSize = sizeof(MENUITEMINFO);\n#if (WINVER >= 0x0500)\n\t\t// adjust struct size if running on older version of Windows\n\t\tif(AtlIsOldWindows())\n\t\t{\n\t\t\tATLASSERT(cbSize > MENUITEMINFO_SIZE_VERSION_400);   // must be\n\t\t\tcbSize = MENUITEMINFO_SIZE_VERSION_400;\n\t\t}\n#endif // (WINVER >= 0x0500)\n\t}\n};\n\n\n// forward declarations\ntemplate <bool t_bManaged> class CMenuT;\ntypedef CMenuT<false>   CMenuHandle;\ntypedef CMenuT<true>    CMenu;\n\n\ntemplate <bool t_bManaged>\nclass CMenuT\n{\npublic:\n// Data members\n\tHMENU m_hMenu;\n\n// Constructor/destructor/operators\n\tCMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu)\n\t{ }\n\n\t~CMenuT()\n\t{\n\t\tif(t_bManaged && m_hMenu != NULL)\n\t\t\tDestroyMenu();\n\t}\n\n\tCMenuT<t_bManaged>& operator =(HMENU hMenu)\n\t{\n\t\tAttach(hMenu);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HMENU hMenuNew)\n\t{\n\t\tATLASSERT(::IsMenu(hMenuNew));\n\t\tif(t_bManaged && m_hMenu != NULL && m_hMenu != hMenuNew)\n\t\t\t::DestroyMenu(m_hMenu);\n\t\tm_hMenu = hMenuNew;\n\t}\n\n\tHMENU Detach()\n\t{\n\t\tHMENU hMenu = m_hMenu;\n\t\tm_hMenu = NULL;\n\t\treturn hMenu;\n\t}\n\n\toperator HMENU() const { return m_hMenu; }\n\n\tbool IsNull() const { return (m_hMenu == NULL); }\n\n\tBOOL IsMenu() const\n\t{\n\t\treturn ::IsMenu(m_hMenu);\n\t}\n\n// Create/destroy methods\n\tBOOL CreateMenu()\n\t{\n\t\tATLASSERT(m_hMenu == NULL);\n\t\tm_hMenu = ::CreateMenu();\n\t\treturn (m_hMenu != NULL) ? TRUE : FALSE;\n\t}\n\n\tBOOL CreatePopupMenu()\n\t{\n\t\tATLASSERT(m_hMenu == NULL);\n\t\tm_hMenu = ::CreatePopupMenu();\n\t\treturn (m_hMenu != NULL) ? TRUE : FALSE;\n\t}\n\n\tBOOL LoadMenu(ATL::_U_STRINGorID menu)\n\t{\n\t\tATLASSERT(m_hMenu == NULL);\n\t\tm_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);\n\t\treturn (m_hMenu != NULL) ? TRUE : FALSE;\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL LoadMenuIndirect(const void* lpMenuTemplate)\n\t{\n\t\tATLASSERT(m_hMenu == NULL);\n\t\tm_hMenu = ::LoadMenuIndirect(lpMenuTemplate);\n\t\treturn (m_hMenu != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DestroyMenu()\n\t{\n\t\tif (m_hMenu == NULL)\n\t\t\treturn FALSE;\n\t\tBOOL bRet = ::DestroyMenu(m_hMenu);\n\t\tif(bRet)\n\t\t\tm_hMenu = NULL;\n\t\treturn bRet;\n\t}\n\n// Menu Operations\n\tBOOL DeleteMenu(UINT nPosition, UINT nFlags)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::DeleteMenu(m_hMenu, nPosition, nFlags);\n\t}\n\n\tBOOL TrackPopupMenu(UINT nFlags, int x, int y, HWND hWnd, LPCRECT lpRect = NULL)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n#ifndef _WIN32_WCE\n#if (WINVER >= 0x0500)\n\t\tx = _FixTrackMenuPopupX(x, y);\n#endif // !(WINVER >= 0x0500)\n\t\treturn ::TrackPopupMenu(m_hMenu, nFlags, x, y, 0, hWnd, lpRect);\n#else // CE specific\n\t\tlpRect;\n\t\treturn ::TrackPopupMenuEx(m_hMenu, nFlags, x, y, hWnd, NULL);\n#endif // _WIN32_WCE\n\t}\n\n\tBOOL TrackPopupMenuEx(UINT uFlags, int x, int y, HWND hWnd, LPTPMPARAMS lptpm = NULL)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\t\tx = _FixTrackMenuPopupX(x, y);\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\t\treturn ::TrackPopupMenuEx(m_hMenu, uFlags, x, y, hWnd, lptpm);\n\t}\n\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\t// helper that fixes popup menu X position when it's off-screen\n\tstatic int _FixTrackMenuPopupX(int x, int y)\n\t{\n\t\tPOINT pt = { x, y };\n\t\tHMONITOR hMonitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);\n\t\tif(hMonitor == NULL)\n\t\t{\n\t\t\tHMONITOR hMonitorNear = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);\n\t\t\tif(hMonitorNear != NULL)\n\t\t\t{\n\t\t\t\tMONITORINFO mi = { sizeof(MONITORINFO) };\n\t\t\t\tif(::GetMonitorInfo(hMonitorNear, &mi) != FALSE)\n\t\t\t\t{\n\t\t\t\t\tif(x < mi.rcWork.left)\n\t\t\t\t\t\tx = mi.rcWork.left;\n\t\t\t\t\telse if(x > mi.rcWork.right)\n\t\t\t\t\t\tx = mi.rcWork.right;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn x;\n\t}\n\n\tBOOL GetMenuInfo(LPMENUINFO lpMenuInfo) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuInfo(m_hMenu, lpMenuInfo);\n\t}\n\n\tBOOL SetMenuInfo(LPCMENUINFO lpMenuInfo)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::SetMenuInfo(m_hMenu, lpMenuInfo);\n\t}\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\n// Menu Item Operations\n\tBOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem);\n\t}\n\n\tBOOL AppendMenu(UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::AppendMenu(m_hMenu, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::AppendMenu(m_hMenu, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);\n\t}\n\n\tBOOL AppendMenu(UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::AppendMenu(m_hMenu, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);\n\t}\n#endif // !_WIN32_WCE\n\n\tUINT CheckMenuItem(UINT nIDCheckItem, UINT nCheck)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn (UINT)::CheckMenuItem(m_hMenu, nIDCheckItem, nCheck);\n\t}\n\n\tUINT EnableMenuItem(UINT nIDEnableItem, UINT nEnable)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::EnableMenuItem(m_hMenu, nIDEnableItem, nEnable);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL HiliteMenuItem(HWND hWnd, UINT uIDHiliteItem, UINT uHilite)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::HiliteMenuItem(hWnd, m_hMenu, uIDHiliteItem, uHilite);\n\t}\n\n\tint GetMenuItemCount() const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuItemCount(m_hMenu);\n\t}\n\n\tUINT GetMenuItemID(int nPos) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuItemID(m_hMenu, nPos);\n\t}\n\n\tUINT GetMenuState(UINT nID, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuState(m_hMenu, nID, nFlags);\n\t}\n\n\tint GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags);\n\t}\n\n\tint GetMenuStringLen(UINT nIDItem, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags);\n\t}\n\n#ifndef _ATL_NO_COM\n\tBOOL GetMenuString(UINT nIDItem, BSTR& bstrText, UINT nFlags) const\n\t{\n\t\tUSES_CONVERSION;\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(bstrText == NULL);\n\n\t\tint nLen = GetMenuStringLen(nIDItem, nFlags);\n\t\tif(nLen == 0)\n\t\t{\n\t\t\tbstrText = ::SysAllocString(OLESTR(\"\"));\n\t\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t\t}\n\n\t\tnLen++;   // increment to include terminating NULL char\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tLPTSTR lpszText = buff.Allocate(nLen);\n\t\tif(lpszText == NULL)\n\t\t\treturn FALSE;\n\n\t\tif(!GetMenuString(nIDItem, lpszText, nLen, nFlags))\n\t\t\treturn FALSE;\n\n\t\tbstrText = ::SysAllocString(T2OLE(lpszText));\n\t\treturn (bstrText != NULL) ? TRUE : FALSE;\n\t}\n#endif // !_ATL_NO_COM\n\n#elif (_ATL_VER >= 0x0800)\n\tint GetMenuItemCount() const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ATL::GetMenuItemCount(m_hMenu);\n\t}\n\n\tUINT GetMenuItemID(int nPos) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ATL::GetMenuItemID(m_hMenu, nPos);\n\t}\n\n\tUINT GetMenuState(UINT nID, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ATL::GetMenuState(m_hMenu, nID, nFlags);\n\t}\n\n\tint GetMenuString(UINT nIDItem, LPTSTR lpString, int nMaxCount, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ATL::GetMenuString(m_hMenu, nIDItem, lpString, nMaxCount, nFlags);\n\t}\n\n\tint GetMenuStringLen(UINT nIDItem, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ATL::GetMenuString(m_hMenu, nIDItem, NULL, 0, nFlags);\n\t}\n#endif // (_ATL_VER >= 0x0800)\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tint GetMenuString(UINT nIDItem, _CSTRING_NS::CString& strText, UINT nFlags) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\n\t\tint nLen = GetMenuStringLen(nIDItem, nFlags);\n\t\tif(nLen == 0)\n\t\t\treturn 0;\n\n\t\tnLen++;   // increment to include terminating NULL char\n\t\tLPTSTR lpstr = strText.GetBufferSetLength(nLen);\n\t\tif(lpstr == NULL)\n\t\t\treturn 0;\n\t\tint nRet = GetMenuString(nIDItem, lpstr, nLen, nFlags);\n\t\tstrText.ReleaseBuffer();\n\t\treturn nRet;\n\t}\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\n\tCMenuHandle GetSubMenu(int nPos) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn CMenuHandle(::GetSubMenu(m_hMenu, nPos));\n\t}\n\n\tBOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::InsertMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);\n\t}\n\n\tBOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::InsertMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL InsertMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::InsertMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);\n\t}\n\n\tBOOL InsertMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::InsertMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);\n\t}\n\n\tBOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::ModifyMenu(m_hMenu, nPosition, nFlags, nIDNewItem, lpszNewItem);\n\t}\n\n\tBOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, LPCTSTR lpszNewItem)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_POPUP, (UINT_PTR)hSubMenu, lpszNewItem);\n\t}\n\n\tBOOL ModifyMenu(UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::ModifyMenu(m_hMenu, nPosition, nFlags | MF_BITMAP, nIDNewItem, (LPCTSTR)hBmp);\n\t}\n\n\tBOOL ModifyMenu(UINT nPosition, UINT nFlags, HMENU hSubMenu, HBITMAP hBmp)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\tATLASSERT(::IsMenu(hSubMenu));\n\t\treturn ::ModifyMenu(m_hMenu, nPosition, nFlags | (MF_BITMAP | MF_POPUP), (UINT_PTR)hSubMenu, (LPCTSTR)hBmp);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL RemoveMenu(UINT nPosition, UINT nFlags)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::RemoveMenu(m_hMenu, nPosition, nFlags);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL SetMenuItemBitmaps(UINT nPosition, UINT nFlags, HBITMAP hBmpUnchecked, HBITMAP hBmpChecked)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::SetMenuItemBitmaps(m_hMenu, nPosition, nFlags, hBmpUnchecked, hBmpChecked);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL CheckMenuRadioItem(UINT nIDFirst, UINT nIDLast, UINT nIDItem, UINT nFlags)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::CheckMenuRadioItem(m_hMenu, nIDFirst, nIDLast, nIDItem, nFlags);\n\t}\n\n\tBOOL GetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn (BOOL)::GetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii);\n\t}\n\n\tBOOL SetMenuItemInfo(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn (BOOL)::SetMenuItemInfo(m_hMenu, uItem, bByPosition, lpmii);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL InsertMenuItem(UINT uItem, BOOL bByPosition, LPMENUITEMINFO lpmii)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn (BOOL)::InsertMenuItem(m_hMenu, uItem, bByPosition, lpmii);\n\t}\n\n\tUINT GetMenuDefaultItem(BOOL bByPosition = FALSE, UINT uFlags = 0U) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuDefaultItem(m_hMenu, (UINT)bByPosition, uFlags);\n\t}\n\n\tBOOL SetMenuDefaultItem(UINT uItem = (UINT)-1,  BOOL bByPosition = FALSE)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::SetMenuDefaultItem(m_hMenu, uItem, (UINT)bByPosition);\n\t}\n\n\tBOOL GetMenuItemRect(HWND hWnd, UINT uItem, LPRECT lprcItem) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuItemRect(hWnd, m_hMenu, uItem, lprcItem);\n\t}\n\n\tint MenuItemFromPoint(HWND hWnd, POINT point) const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::MenuItemFromPoint(hWnd, m_hMenu, point);\n\t}\n\n// Context Help Functions\n\tBOOL SetMenuContextHelpId(DWORD dwContextHelpId)\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::SetMenuContextHelpId(m_hMenu, dwContextHelpId);\n\t}\n\n\tDWORD GetMenuContextHelpId() const\n\t{\n\t\tATLASSERT(::IsMenu(m_hMenu));\n\t\treturn ::GetMenuContextHelpId(m_hMenu);\n\t}\n#endif // !_WIN32_WCE\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAccelerator\n\ntemplate <bool t_bManaged>\nclass CAcceleratorT\n{\npublic:\n\tHACCEL m_hAccel;\n\n// Constructor/destructor/operators\n\tCAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel)\n\t{ }\n\n\t~CAcceleratorT()\n\t{\n\t\tif(t_bManaged && m_hAccel != NULL)\n\t\t\t::DestroyAcceleratorTable(m_hAccel);\n\t}\n\n\tCAcceleratorT<t_bManaged>& operator =(HACCEL hAccel)\n\t{\n\t\tAttach(hAccel);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HACCEL hAccel)\n\t{\n\t\tif(t_bManaged && m_hAccel != NULL)\n\t\t\t::DestroyAcceleratorTable(m_hAccel);\n\t\tm_hAccel = hAccel;\n\t}\n\n\tHACCEL Detach()\n\t{\n\t\tHACCEL hAccel = m_hAccel;\n\t\tm_hAccel = NULL;\n\t\treturn hAccel;\n\t}\n\n\toperator HACCEL() const { return m_hAccel; }\n\n\tbool IsNull() const { return m_hAccel == NULL; }\n\n// Create/destroy methods\n\tHACCEL LoadAccelerators(ATL::_U_STRINGorID accel)\n\t{\n\t\tATLASSERT(m_hAccel == NULL);\n\t\tm_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), accel.m_lpstr);\n\t\treturn m_hAccel;\n\t}\n\n\tHACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries)\n\t{\n\t\tATLASSERT(m_hAccel == NULL);\n\t\tATLASSERT(pAccel != NULL);\n\t\tm_hAccel = ::CreateAcceleratorTable(pAccel, cEntries);\n\t\treturn m_hAccel;\n\t}\n\n\tvoid DestroyObject()\n\t{\n\t\tif(m_hAccel != NULL)\n\t\t{\n\t\t\t::DestroyAcceleratorTable(m_hAccel);\n\t\t\tm_hAccel = NULL;\n\t\t}\n\t}\n\n// Operations\n#ifndef _WIN32_WCE\n\tint CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries)\n\t{\n\t\tATLASSERT(m_hAccel != NULL);\n\t\tATLASSERT(lpAccelDst != NULL);\n\t\treturn ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries);\n\t}\n\n\tint GetEntriesCount() const\n\t{\n\t\tATLASSERT(m_hAccel != NULL);\n\t\treturn ::CopyAcceleratorTable(m_hAccel, NULL, 0);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg)\n\t{\n\t\tATLASSERT(m_hAccel != NULL);\n\t\tATLASSERT(::IsWindow(hWnd));\n\t\tATLASSERT(pMsg != NULL);\n\t\treturn ::TranslateAccelerator(hWnd, m_hAccel, pMsg);\n\t}\n};\n\ntypedef CAcceleratorT<false>   CAcceleratorHandle;\ntypedef CAcceleratorT<true>    CAccelerator;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CIcon\n\ntemplate <bool t_bManaged>\nclass CIconT\n{\npublic:\n\tHICON m_hIcon;\n\n// Constructor/destructor/operators\n\tCIconT(HICON hIcon = NULL) : m_hIcon(hIcon)\n\t{ }\n\n\t~CIconT()\n\t{\n\t\tif(t_bManaged && m_hIcon != NULL)\n\t\t\t::DestroyIcon(m_hIcon);\n\t}\n\n\tCIconT<t_bManaged>& operator =(HICON hIcon)\n\t{\n\t\tAttach(hIcon);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HICON hIcon)\n\t{\n\t\tif(t_bManaged && m_hIcon != NULL)\n\t\t\t::DestroyIcon(m_hIcon);\n\t\tm_hIcon = hIcon;\n\t}\n\n\tHICON Detach()\n\t{\n\t\tHICON hIcon = m_hIcon;\n\t\tm_hIcon = NULL;\n\t\treturn hIcon;\n\t}\n\n\toperator HICON() const { return m_hIcon; }\n\n\tbool IsNull() const { return m_hIcon == NULL; }\n\n// Create/destroy methods\n\tHICON LoadIcon(ATL::_U_STRINGorID icon)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tm_hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\n\t\treturn m_hIcon;\n\t}\n\n\tHICON LoadIcon(ATL::_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tm_hIcon = (HICON) ::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);\n\t\treturn m_hIcon;\n\t}\n\n#ifndef _WIN32_WCE\n\tHICON LoadOEMIcon(LPCTSTR lpstrIconName)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(IsOEMIcon(lpstrIconName));\n\t\tm_hIcon = ::LoadIcon(NULL, lpstrIconName);\n\t\treturn m_hIcon;\n\t}\n\n\tHICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDbits, CONST BYTE *lpbXORbits)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(lpbANDbits != NULL);\n\t\tATLASSERT(lpbXORbits != NULL);\n\t\tm_hIcon = ::CreateIcon(ModuleHelper::GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits);\n\t\treturn m_hIcon;\n\t}\n\n\tHICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(pBits != NULL);\n\t\tm_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion);\n\t\treturn m_hIcon;\n\t}\n\n\tHICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(pbBits != NULL);\n\t\tATLASSERT(cbBits > 0);\n\t\tm_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags);\n\t\treturn m_hIcon;\n\t}\n#endif // !_WIN32_WCE\n\n\tHICON CreateIconIndirect(PICONINFO pIconInfo)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(pIconInfo != NULL);\n\t\tm_hIcon = ::CreateIconIndirect(pIconInfo);\n\t\treturn m_hIcon;\n\t}\n\n#ifndef _WIN32_WCE\n\tHICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(lpszExeFileName != NULL);\n\t\tm_hIcon = ::ExtractIcon(ModuleHelper::GetModuleInstance(), lpszExeFileName, nIconIndex);\n\t\treturn m_hIcon;\n\t}\n\n\tHICON ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, LPWORD lpiIcon)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(lpIconPath != NULL);\n\t\tATLASSERT(lpiIcon != NULL);\n\t\tm_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon);\n\t\treturn m_hIcon;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DestroyIcon()\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\tBOOL bRet = ::DestroyIcon(m_hIcon);\n\t\tif(bRet != FALSE)\n\t\t\tm_hIcon = NULL;\n\t\treturn bRet;\n\t}\n\n// Operations\n#ifndef _WIN32_WCE\n\tHICON CopyIcon()\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\treturn ::CopyIcon(m_hIcon);\n\t}\n\n\tHICON DuplicateIcon()\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\treturn ::DuplicateIcon(NULL, m_hIcon);\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DrawIcon(HDC hDC, int x, int y)\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n#ifndef _WIN32_WCE\n\t\treturn ::DrawIcon(hDC, x, y, m_hIcon);\n#else // CE specific\n\t\treturn ::DrawIconEx(hDC, x, y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL);\n#endif // _WIN32_WCE\n\t}\n\n\tBOOL DrawIcon(HDC hDC, POINT pt)\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n#ifndef _WIN32_WCE\n\t\treturn ::DrawIcon(hDC, pt.x, pt.y, m_hIcon);\n#else // CE specific\n\t\treturn ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, 0, 0, 0, NULL, DI_NORMAL);\n#endif // _WIN32_WCE\n\t}\n\n\tBOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\treturn ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);\n\t}\n\n\tBOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL)\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\treturn ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags);\n\t}\n\n#ifndef _WIN32_WCE\n\tBOOL GetIconInfo(PICONINFO pIconInfo) const\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\tATLASSERT(pIconInfo != NULL);\n\t\treturn ::GetIconInfo(m_hIcon, pIconInfo);\n\t}\n\n#if (_WIN32_WINNT >= 0x0600)\n\tBOOL GetIconInfoEx(PICONINFOEX pIconInfo) const\n\t{\n\t\tATLASSERT(m_hIcon != NULL);\n\t\tATLASSERT(pIconInfo != NULL);\n\t\treturn ::GetIconInfoEx(m_hIcon, pIconInfo);\n\t}\n#endif // (_WIN32_WINNT >= 0x0600)\n\n#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\tHRESULT LoadIconMetric(ATL::_U_STRINGorID icon, int lims)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tUSES_CONVERSION;\n\t\treturn ::LoadIconMetric(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), lims, &m_hIcon);\n\t}\n\n\tHRESULT LoadIconWithScaleDown(ATL::_U_STRINGorID icon, int cx, int cy)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tUSES_CONVERSION;\n\t\treturn ::LoadIconWithScaleDown(ModuleHelper::GetResourceInstance(), T2CW(icon.m_lpstr), cx, cy, &m_hIcon);\n\t}\n\n\tHRESULT LoadOEMIconMetric(LPCTSTR lpstrIconName, int lims)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(IsOEMIcon(lpstrIconName));\n\t\treturn ::LoadIconMetric(NULL, (LPCWSTR)lpstrIconName, lims, &m_hIcon);\n\t}\n\n\tHRESULT LoadOEMIconWithScaleDown(LPCTSTR lpstrIconName, int cx, int cy)\n\t{\n\t\tATLASSERT(m_hIcon == NULL);\n\t\tATLASSERT(IsOEMIcon(lpstrIconName));\n\t\tUSES_CONVERSION;\n\t\treturn ::LoadIconWithScaleDown(NULL, (LPCWSTR)lpstrIconName, cx, cy, &m_hIcon);\n\t}\n#endif // defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n#endif // !_WIN32_WCE\n\n\t// Helper\n#ifndef _WIN32_WCE\n\tstatic bool IsOEMIcon(LPCTSTR lpstrIconName)\n\t{\n#if (WINVER >= 0x0600)\n\t\treturn (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION ||\n\t\t          lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO ||\n\t\t          lpstrIconName == IDI_SHIELD);\n#else // !(WINVER >= 0x0600)\n\t\treturn (lpstrIconName == IDI_APPLICATION || lpstrIconName == IDI_ASTERISK || lpstrIconName == IDI_EXCLAMATION ||\n\t\t          lpstrIconName == IDI_HAND || lpstrIconName == IDI_QUESTION || lpstrIconName == IDI_WINLOGO);\n#endif // !(WINVER >= 0x0600)\n\t}\n#endif // !_WIN32_WCE\n};\n\ntypedef CIconT<false>   CIconHandle;\ntypedef CIconT<true>    CIcon;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCursor\n\n// protect template member from a winuser.h macro\n#ifdef CopyCursor\n  #undef CopyCursor\n#endif\n\ntemplate <bool t_bManaged>\nclass CCursorT\n{\npublic:\n\tHCURSOR m_hCursor;\n\n// Constructor/destructor/operators\n\tCCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor)\n\t{ }\n\n\t~CCursorT()\n\t{\n\t\tif(t_bManaged && m_hCursor != NULL)\n\t\t\tDestroyCursor();\n\t}\n\n\tCCursorT<t_bManaged>& operator =(HCURSOR hCursor)\n\t{\n\t\tAttach(hCursor);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HCURSOR hCursor)\n\t{\n\t\tif(t_bManaged && m_hCursor != NULL)\n\t\t\tDestroyCursor();\n\t\tm_hCursor = hCursor;\n\t}\n\n\tHCURSOR Detach()\n\t{\n\t\tHCURSOR hCursor = m_hCursor;\n\t\tm_hCursor = NULL;\n\t\treturn hCursor;\n\t}\n\n\toperator HCURSOR() const { return m_hCursor; }\n\n\tbool IsNull() const { return m_hCursor == NULL; }\n\n// Create/destroy methods\n\tHCURSOR LoadCursor(ATL::_U_STRINGorID cursor)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tm_hCursor = ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr);\n\t\treturn m_hCursor;\n\t}\n\n\tHCURSOR LoadSysCursor(LPCTSTR lpstrCursorName)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n#if (WINVER >= 0x0500)\n\t\tATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT ||\n\t\t\tlpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE ||\n\t\t\tlpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW ||\n\t\t\tlpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL ||\n\t\t\tlpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP ||\n\t\t\tlpstrCursorName == IDC_HAND);\n#else // !(WINVER >= 0x0500)\n\t\tATLASSERT(lpstrCursorName == IDC_ARROW || lpstrCursorName == IDC_IBEAM || lpstrCursorName == IDC_WAIT ||\n\t\t\tlpstrCursorName == IDC_CROSS || lpstrCursorName == IDC_UPARROW || lpstrCursorName == IDC_SIZE ||\n\t\t\tlpstrCursorName == IDC_ICON || lpstrCursorName == IDC_SIZENWSE || lpstrCursorName == IDC_SIZENESW ||\n\t\t\tlpstrCursorName == IDC_SIZEWE || lpstrCursorName == IDC_SIZENS || lpstrCursorName == IDC_SIZEALL ||\n\t\t\tlpstrCursorName == IDC_NO || lpstrCursorName == IDC_APPSTARTING || lpstrCursorName == IDC_HELP);\n#endif // !(WINVER >= 0x0500)\n\t\tm_hCursor = ::LoadCursor(NULL, lpstrCursorName);\n\t\treturn m_hCursor;\n\t}\n\n\t// deprecated\n\tHCURSOR LoadOEMCursor(LPCTSTR lpstrCursorName)\n\t{\n\t\treturn LoadSysCursor(lpstrCursorName);\n\t}\n\n\tHCURSOR LoadCursor(ATL::_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tm_hCursor = (HCURSOR) ::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);\n\t\treturn m_hCursor;\n\t}\n\n#ifndef _WIN32_WCE\n\tHCURSOR LoadCursorFromFile(LPCTSTR pstrFilename)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tATLASSERT(pstrFilename != NULL);\n\t\tm_hCursor = ::LoadCursorFromFile(pstrFilename);\n\t\treturn m_hCursor;\n\t}\n#endif // !_WIN32_WCE\n\n#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))\n\tHCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tm_hCursor = ::CreateCursor(ModuleHelper::GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane);\n\t\treturn m_hCursor;\n\t}\n#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))\n\n#ifndef _WIN32_WCE\n\tHCURSOR CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tATLASSERT(pBits != NULL);\n\t\tm_hCursor = (HCURSOR)::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion);\n\t\treturn m_hCursor;\n\t}\n\n\tHCURSOR CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR)\n\t{\n\t\tATLASSERT(m_hCursor == NULL);\n\t\tATLASSERT(pbBits != NULL);\n\t\tATLASSERT(cbBits > 0);\n\t\tm_hCursor = (HCURSOR)::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags);\n\t\treturn m_hCursor;\n\t}\n#endif // !_WIN32_WCE\n\n\tBOOL DestroyCursor()\n\t{\n\t\tATLASSERT(m_hCursor != NULL);\n#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))\n\t\tBOOL bRet = ::DestroyCursor(m_hCursor);\n\t\tif(bRet != FALSE)\n\t\t\tm_hCursor = NULL;\n\t\treturn bRet;\n#else // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))))\n\t\tATLTRACE2(atlTraceUI, 0, _T(\"Warning: This version of Windows CE does not have ::DestroyCursor()\\n\"));\n\t\treturn FALSE;\n#endif // !(!defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))))\n\t}\n\n// Operations\n#ifndef _WIN32_WCE\n\tHCURSOR CopyCursor()\n\t{\n\t\tATLASSERT(m_hCursor != NULL);\n\t\treturn (HCURSOR)::CopyIcon((HICON)m_hCursor);\n\t}\n#endif // !_WIN32_WCE\n\n#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n\tBOOL GetCursorInfo(LPCURSORINFO pCursorInfo)\n\t{\n\t\tATLASSERT(m_hCursor != NULL);\n\t\tATLASSERT(pCursorInfo != NULL);\n\t\treturn ::GetCursorInfo(pCursorInfo);\n\t}\n#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\n};\n\ntypedef CCursorT<false>   CCursorHandle;\ntypedef CCursorT<true>    CCursor;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CResource - Wraps a generic Windows resource.\n//             Use it with custom resource types other than the\n//             standard RT_CURSOR, RT_BITMAP, etc.\n\nclass CResource\n{\npublic:\n\tHGLOBAL m_hGlobal;\n\tHRSRC m_hResource;\n\n// Constructor/destructor\n\tCResource() : m_hGlobal(NULL), m_hResource(NULL)\n\t{ }\n\n\t~CResource()\n\t{\n\t\tRelease();\n\t}\n\n// Load methods\n\tbool Load(ATL::_U_STRINGorID Type, ATL::_U_STRINGorID ID)\n\t{\n\t\tATLASSERT(m_hResource == NULL);\n\t\tATLASSERT(m_hGlobal == NULL);\n\n\t\tm_hResource = ::FindResource(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.m_lpstr);\n\t\tif(m_hResource == NULL)\n\t\t\treturn false;\n\n\t\tm_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource);\n\t\tif(m_hGlobal == NULL)\n\t\t{\n\t\t\tm_hResource = NULL;\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n#ifndef _WIN32_WCE\n\tbool LoadEx(ATL::_U_STRINGorID ID, ATL::_U_STRINGorID Type, WORD wLanguage)\n\t{\n\t\tATLASSERT(m_hResource == NULL);\n\t\tATLASSERT(m_hGlobal == NULL);\n\n\t\tm_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), Type.m_lpstr, ID.m_lpstr, wLanguage);\n\t\tif(m_hResource == NULL)\n\t\t\treturn false;\n\n\t\tm_hGlobal = ::LoadResource(ModuleHelper::GetResourceInstance(), m_hResource);\n\t\tif(m_hGlobal == NULL)\n\t\t{\n\t\t\tm_hResource = NULL;\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n#endif // !_WIN32_WCE\n\n// Misc. operations\n\tDWORD GetSize() const\n\t{\n\t\tATLASSERT(m_hResource != NULL);\n\t\treturn ::SizeofResource(ModuleHelper::GetResourceInstance(), m_hResource);\n\t}\n\n\tLPVOID Lock()\n\t{\n\t\tATLASSERT(m_hResource != NULL);\n\t\tATLASSERT(m_hGlobal != NULL);\n\t\tLPVOID pVoid = ::LockResource(m_hGlobal);\n\t\tATLASSERT(pVoid != NULL);\n\t\treturn pVoid;\n\t}\n\n\tvoid Release()\n\t{\n\t\tif(m_hGlobal != NULL)\n\t\t{\n\t\t\tFreeResource(m_hGlobal);\n\t\t\tm_hGlobal = NULL;\n\t\t\tm_hResource = NULL;\n\t\t}\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Toolbar resource descriptor\n\nstruct _AtlToolBarData\n{\n\tWORD wVersion;\n\tWORD wWidth;\n\tWORD wHeight;\n\tWORD wItemCount;\n\n\tWORD* items()\n\t\t{ return (WORD*)(this+1); }\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Global functions for loading resources\n\ninline HACCEL AtlLoadAccelerators(ATL::_U_STRINGorID table)\n{\n\treturn ::LoadAccelerators(ModuleHelper::GetResourceInstance(), table.m_lpstr);\n}\n\ninline HMENU AtlLoadMenu(ATL::_U_STRINGorID menu)\n{\n\treturn ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);\n}\n\ninline HBITMAP AtlLoadBitmap(ATL::_U_STRINGorID bitmap)\n{\n\treturn ::LoadBitmap(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr);\n}\n\n#ifdef OEMRESOURCE\ninline HBITMAP AtlLoadSysBitmap(ATL::_U_STRINGorID bitmap)\n{\n#ifdef _DEBUG\n\tWORD wID = LOWORD(bitmap.m_lpstr);\n\tATLASSERT(wID >= 32734 && wID <= 32767);\n#endif // _DEBUG\n\treturn ::LoadBitmap(NULL, bitmap.m_lpstr);\n}\n#endif // OEMRESOURCE\n\ninline HCURSOR AtlLoadCursor(ATL::_U_STRINGorID cursor)\n{\n\treturn ::LoadCursor(ModuleHelper::GetResourceInstance(), cursor.m_lpstr);\n}\n\ninline HCURSOR AtlLoadSysCursor(LPCTSTR lpCursorName)\n{\n#if (WINVER >= 0x0500)\n\tATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT ||\n\t\tlpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE ||\n\t\tlpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW ||\n\t\tlpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL ||\n\t\tlpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP ||\n\t\tlpCursorName == IDC_HAND);\n#else // !(WINVER >= 0x0500)\n\tATLASSERT(lpCursorName == IDC_ARROW || lpCursorName == IDC_IBEAM || lpCursorName == IDC_WAIT ||\n\t\tlpCursorName == IDC_CROSS || lpCursorName == IDC_UPARROW || lpCursorName == IDC_SIZE ||\n\t\tlpCursorName == IDC_ICON || lpCursorName == IDC_SIZENWSE || lpCursorName == IDC_SIZENESW ||\n\t\tlpCursorName == IDC_SIZEWE || lpCursorName == IDC_SIZENS || lpCursorName == IDC_SIZEALL ||\n\t\tlpCursorName == IDC_NO || lpCursorName == IDC_APPSTARTING || lpCursorName == IDC_HELP);\n#endif // !(WINVER >= 0x0500)\n\treturn ::LoadCursor(NULL, lpCursorName);\n}\n\ninline HICON AtlLoadIcon(ATL::_U_STRINGorID icon)\n{\n\treturn ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);\n}\n\n#ifndef _WIN32_WCE\ninline HICON AtlLoadSysIcon(LPCTSTR lpIconName)\n{\n#if (WINVER >= 0x0600)\n\tATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION ||\n\t          lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO ||\n\t          lpIconName == IDI_SHIELD);\n#else // !(WINVER >= 0x0600)\n\tATLASSERT(lpIconName == IDI_APPLICATION || lpIconName == IDI_ASTERISK || lpIconName == IDI_EXCLAMATION ||\n\t          lpIconName == IDI_HAND || lpIconName == IDI_QUESTION || lpIconName == IDI_WINLOGO);\n#endif // !(WINVER >= 0x0600)\n\treturn ::LoadIcon(NULL, lpIconName);\n}\n#endif // !_WIN32_WCE\n\ninline HBITMAP AtlLoadBitmapImage(ATL::_U_STRINGorID bitmap, UINT fuLoad = LR_DEFAULTCOLOR)\n{\n\treturn (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), bitmap.m_lpstr, IMAGE_BITMAP, 0, 0, fuLoad);\n}\n\ninline HCURSOR AtlLoadCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)\n{\n\treturn (HCURSOR)::LoadImage(ModuleHelper::GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);\n}\n\ninline HICON AtlLoadIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)\n{\n\treturn (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);\n}\n\n#ifdef OEMRESOURCE\ninline HBITMAP AtlLoadSysBitmapImage(WORD wBitmapID, UINT fuLoad = LR_DEFAULTCOLOR)\n{\n\tATLASSERT(wBitmapID >= 32734 && wBitmapID <= 32767);\n\tATLASSERT((fuLoad & LR_LOADFROMFILE) == 0);   // this one doesn't load from a file\n\treturn (HBITMAP)::LoadImage(NULL, MAKEINTRESOURCE(wBitmapID), IMAGE_BITMAP, 0, 0, fuLoad);\n}\n#endif // OEMRESOURCE\n\ninline HCURSOR AtlLoadSysCursorImage(ATL::_U_STRINGorID cursor, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)\n{\n#ifdef _DEBUG\n\tWORD wID = LOWORD(cursor.m_lpstr);\n\tATLASSERT((wID >= 32512 && wID <= 32516) || (wID >= 32640 && wID <= 32648) || (wID == 32650) || (wID == 32651));\n\tATLASSERT((fuLoad & LR_LOADFROMFILE) == 0);   // this one doesn't load from a file\n#endif // _DEBUG\n\treturn (HCURSOR)::LoadImage(NULL, cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);\n}\n\ninline HICON AtlLoadSysIconImage(ATL::_U_STRINGorID icon, UINT fuLoad = LR_DEFAULTCOLOR | LR_DEFAULTSIZE, int cxDesired = 0, int cyDesired = 0)\n{\n#ifdef _DEBUG\n\tWORD wID = LOWORD(icon.m_lpstr);\n\tATLASSERT(wID >= 32512 && wID <= 32517);\n\tATLASSERT((fuLoad & LR_LOADFROMFILE) == 0);   // this one doesn't load from a file\n#endif // _DEBUG\n\treturn (HICON)::LoadImage(NULL, icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);\n}\n\n#if (_ATL_VER < 0x0700)\ninline int AtlLoadString(UINT uID, LPTSTR lpBuffer, int nBufferMax)\n{\n\treturn ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpBuffer, nBufferMax);\n}\n#else\n    \nusing ATL::AtlLoadString;\n\n#endif // (_ATL_VER < 0x0700)\n\n#ifdef _WIN32_WCE // CE only direct access to the resource\ninline LPCTSTR AtlLoadString(UINT uID)\n{\n\tLPCTSTR s = (LPCTSTR)::LoadString(ModuleHelper::GetResourceInstance(), uID, NULL, 0);\n#ifdef DEBUG // Check for null-termination\n\tif(s != NULL)\n\t\t// Note: RC -n <file.rc> compiles null-terminated resource strings\n\t\tATLASSERT(s[*((WORD*)s -1) - 1] == L'\\0');\n#endif\n\treturn s;\n}\n#endif // _WIN32_WCE\n\ninline bool AtlLoadString(UINT uID, BSTR& bstrText)\n{\n\tUSES_CONVERSION;\n\tATLASSERT(bstrText == NULL);\n\n\tLPTSTR lpstrText = NULL;\n\tint nRes = 0;\n\tfor(int nLen = 256; ; nLen *= 2)\n\t{\n\t\tATLTRY(lpstrText = new TCHAR[nLen]);\n\t\tif(lpstrText == NULL)\n\t\t\tbreak;\n\t\tnRes = ::LoadString(ModuleHelper::GetResourceInstance(), uID, lpstrText, nLen);\n\t\tif(nRes < nLen - 1)\n\t\t\tbreak;\n\t\tdelete [] lpstrText;\n\t\tlpstrText = NULL;\n\t}\n\n\tif(lpstrText != NULL)\n\t{\n\t\tif(nRes != 0)\n\t\t\tbstrText = ::SysAllocString(T2OLE(lpstrText));\n\t\tdelete [] lpstrText;\n\t}\n\n\treturn (bstrText != NULL) ? true : false;\n}\n\n}; // namespace WTL\n\n#endif // __ATLUSER_H__\n"
  },
  {
    "path": "WTL/atlwince.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLWINCE_H__\n#define __ATLWINCE_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlwince.h requires atlapp.h to be included first\n#endif\n\n#ifndef __ATLWIN_H__\n\t#error atlwince.h requires atlwin.h to be included first\n#endif\n\n#ifndef _WIN32_WCE\n\t#error atlwince.h compiles under Windows CE only\n#endif\n\n#if (_WIN32_WCE < 300)\n\t#error atlwince.h requires Windows CE 3.0 or higher.\n#endif\n\n#if defined(WIN32_PLATFORM_WFSP) &&  _MSC_VER < 1400 // EVC compiling SmartPhone code\n  #if (WIN32_PLATFORM_WFSP < 200)\n\t#error atlwince.h requires Smartphone 2003 or higher\n  #endif\n#endif // WIN32_PLATFORM_WFSP\n\n#if defined(WIN32_PLATFORM_PSPC) &&  _MSC_VER < 1400 // EVC compiling Pocket PC code\n  #if (WIN32_PLATFORM_PSPC < 310)\n\t#error atlwince.h requires Pocket PC 2002 or higher\n  #endif\n#endif // WIN32_PLATFORM_PSPC\n\n#if !defined(_AYGSHELL_H_) && !defined(__AYGSHELL_H__)\n\t#error atlwince.h requires aygshell.h to be included first\n#else\n  #if defined(WIN32_PLATFORM_WFSP) && !defined(_TPCSHELL_H_)\n\t#error SmartPhone dialog classes require tpcshell.h to be included first\n  #endif\n#endif\n\n#if (_MSC_VER >= 1400) // VS2005\n  #include <DeviceResolutionAware.h>\n  #define _WTL_CE_DRA\n#endif // (_MSC_VER >= 1400)\n\n#if !defined(_WTL_CE_NO_DIALOGS) &&  !defined(__ATLFRAME_H__)\n\t#error Orientation aware dialog classes require atlframe.h to be included first\n#endif\n\n#if !defined(_WTL_CE_NO_APPWINDOW) &&  !defined(__ATLFRAME_H__)\n\t#error Application window class require atlframe.h to be included first\n#endif\n\n#if !defined(_WTL_CE_NO_ZOOMSCROLL) &&  !defined(__ATLSCRL_H__)\n\t#error ZoomScroll implementation requires atlscrl.h to be included first\n#endif\n\n#if !defined(_WTL_CE_NO_ZOOMSCROLL)\n  #if !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES)))\n\t#error ZoomScroll requires _WTL_NO_WTYPES not to be defined and either atlmisc.h or atltypes.h to be included first\n  #endif // !(defined(__ATLTYPES_H__) || (defined(__ATLMISC_H__) && !defined(_WTL_NO_WTYPES)))\n#endif // !defined(_WTL_CE_NO_ZOOMSCROLL)\n\n#if !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC)\n  #define _WTL_CE_NO_CONTROLS\n#endif // !defined(WIN32_PLATFORM_WFSP) && !defined(WIN32_PLATFORM_PSPC)\n\n#ifndef _WTL_CE_NO_CONTROLS\n  #ifndef __ATLCTRLS_H__\n\t#error The PPC/SmartPhone controls classes require atlctrls.h to be included first\n  #endif\n\n  #include <htmlctrl.h>\n  #pragma comment(lib, \"htmlview.lib\")\n\n  #include <voicectl.h>\n  #pragma comment(lib, \"voicectl.lib\")\n\n  #ifdef WIN32_PLATFORM_PSPC\n    #include <richink.h>\n    #pragma comment(lib, \"richink.lib\")\n\n    #include <inkx.h>\n    #pragma comment(lib, \"inkx.lib\")\n\n    #include <doclist.h>\n    #pragma comment(lib, \"doclist.lib\")\n  #endif\n#endif\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// CStdDialogBase<T, t_shidiFlags, t_bModal> : Standard PPC/SmartPhone dialog base class\n// CStdDialogImplBase - Base implementation of standard dialog\n// CStdDialogImpl<T, t_shidiFlags, t_bModal> : Standard dialog implementation\n// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog\n// CStdAxDialogImpl<T, t_shidiFlags, t_bModal> : Standard AxDialog implementation\n// CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags> : Standard simple dialog\n// CStdDialogResizeImplBase - Base implementation of orientation resizing standard dialog\n// CStdDialogResizeImpl<T, t_shidiFlags, t_bModal> : Orientation resizing standard dialog implementation\n// CStdAxDialogResizeImpl - implementation of orientation resizing standard AxDialog\n// CStdSimpleDialogResizeImpl<T, t_wDlgTemplateID, t_shidiFlags> : Standard resizing simple dialog implementation\n// CStdOrientedDialogBase - Oriented PPC standard dialog base class\n// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation\n// CStdOrientedDialogImpl<T, t_shidiFlags, t_bModal> : Oriented PPC standard dialog implementation\n// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation\n// CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> : Standard simple orientable dialog\n//\n// CAppInfoBase\t : Helper for application state save/restore to registry\n// CAppInfoT<T> : CAppInfoBase constructed from a CAppWindow<T>\n// CAppWindowBase<T> : Base class for PPC/SmartPhone well-behaved application window or dialog\n// CAppWindow<T> : PPC/SmartPhone well-behaved application window class\n// CAppDialog<T> : PPC/SmartPhone well-behaved application dialog class\n// CAppStdDialogImplBase - Base implementation of standard application dialogs\n// CAppStdDialogImpl<T, t_shidiFlags, t_bModal> : Implementation of standard application dialog\n// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog\n// CAppStdAxDialogImpl - Implementation of standard application AxDialog \n// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog\n// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog\n// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog\n//\n// CFullScreenFrame<T, t_bHasSip> : Full screen frame class\n//\n// CZoomScrollImpl<T> : WinCE zooming implementation\n//\n// CBottomTabViewImpl<T, TBase, TWinTraits> - CBottomTabView \n// CHtmlCtrlT<TBase> - CHtmlCtrl\n// CRichInkCtrlT<TBase> - CRichInkCtrl\n// CInkXCtrlT<TBase> - CInkXCtrl\n// CVoiceRecorderCtrlT<TBase> - CVoiceRecorderCtrl\n// CDocListCtrlT<TBase> - CDocListCtrl\n// CCapEditT<TBase> - CCapEdit\n// CTTStaticT<TBase> - CTTStatic\n// CTTButtonT<TBase> - CTTButton\n//\n// CSpinCtrlT<TBase> - CSpinCtrl : SmartPhone specific UpDown control\n// CSpinned<TBase, t_bExpandOnly> : SmartPhone association of control and Spin\n// CSpinListBox : SmartPhone spinned ListBox control\n// CExpandListBox : SmartPhone expandable ListBox control\n// CExpandEdit : SmartPhone expandable Edit control\n// CExpandCapEdit : SmartPhone expandable CapEdit control\n//\n// Global functions:\n//   AtlCreateMenuBar()\n//   AtlCreateEmptyMenuBar()\n//   AtlIsEditFocus()\n//   AtlActivateBackKey()\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// MenuBar creation functions for property sheets and dialogs\n// Frame windows use CreateSimpleCEMenuBar\n\ninline HWND AtlCreateMenuBar(SHMENUBARINFO& mbi)\n{\n\tATLASSERT(::IsWindow(mbi.hwndParent));\n\tATLVERIFY(::SHCreateMenuBar(&mbi) != FALSE);\n\treturn mbi.hwndMB;\n};\n\ninline HWND AtlCreateMenuBar(HWND hWnd, UINT nToolBarId = ATL_IDW_TOOLBAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0, COLORREF clrBk = 0)\n{\n\tSHMENUBARINFO mbi = { sizeof(mbi), hWnd, dwFlags, nToolBarId, ModuleHelper::GetResourceInstance(), nBmpId, cBmpImages, 0, clrBk };\n\treturn AtlCreateMenuBar(mbi);\n}\n\ninline HWND AtlCreateEmptyMenuBar(HWND hWnd, bool bSip = true)\n{\n\tSHMENUBARINFO embi = { sizeof(SHMENUBARINFO), hWnd, SHCMBF_EMPTYBAR };\n\tif (!bSip)\n\t\tembi.dwFlags |= SHCMBF_HIDESIPBUTTON;\n\t\n\treturn AtlCreateMenuBar(embi);\n}\n\t\n///////////////////////////////////////////////////////////////////////////////\n// Helper functions for SmartPhone back key handling\n\ninline bool AtlIsEditFocus()\n{\n\tATL::CWindow wCtrl = GetFocus();\n\tif (wCtrl.IsWindow())\n\t{\n\t\tTCHAR szClassName[8] = {0};\n\t\tATLVERIFY(::GetClassName(wCtrl.m_hWnd, szClassName, 8));\n\t\treturn !_tcscmp(szClassName, _T(\"Edit\")) || !_tcscmp(szClassName, WC_CAPEDIT);\n\t}\n\treturn false;\n}\n\n#if defined WIN32_PLATFORM_WFSP\ninline void AtlActivateBackKey(HWND hMenuBar)\n{\n\tATLASSERT(::IsWindow(hMenuBar));\n\t::SendMessage(hMenuBar, SHCMBM_OVERRIDEKEY, VK_TBACK,\n\t\tMAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY));\n}\n#endif // WIN32_PLATFORM_WFSP\n\n// --- Standard PPC/SmartPhone dialogs ---\n\n#ifndef _WTL_CE_NO_DIALOGS\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogBase - base class for standard PPC/SmartPhone dialogs\n\n#define WTL_STD_SHIDIF   SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN\n#define WTL_SP_SHIDIF    SHIDIF_SIZEDLGFULLSCREEN\n\n// Title setting macros\n#define WTL_DLG_TITLEHEIGHT(iHeight) static const int GetTitleHeight(){return iHeight;}\n#define WTL_DLG_NOTITLE\t WTL_DLG_TITLEHEIGHT(0)\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogBase - Base class for standard PPC/SmartPhone dialog\n\ntemplate <class T, UINT t_shidiFlags, bool t_bModal = true>\nclass CStdDialogBase\n{\npublic:\n#ifdef WIN32_PLATFORM_PSPC\n// Pocket PC only Dialog title handling\n\tconst int nTitleHeight;\n\n\tCStdDialogBase() : nTitleHeight(T::GetTitleHeight())\n\t{ }\n\n// Overloads\n\tBOOL GetClientRect(LPRECT lpRect) \n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tBOOL bRes = ::GetClientRect(pT->m_hWnd, lpRect);\n\t\tif (nTitleHeight)\n\t\t\tlpRect->top += nTitleHeight + 1;\n\t\treturn bRes;\n\t}\n\n\tBOOL SetWindowText(LPCTSTR lpszString)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tBOOL bRes = ::SetWindowText(pT->m_hWnd, lpszString);\n\t\tif (nTitleHeight != 0)\n\t\t\tpT->DoPaintTitle();\n\t\treturn bRes;\n\t}\n\n// Overrideables\n\tstatic const int GetTitleHeight()\n\t{\n\t#ifdef _WTL_CE_DRA\n\t\treturn DRA::SCALEY(24);\n\t#else // !_WTL_CE_DRA\n\t\tCWindowDC dc(NULL);\n\t\treturn dc.GetDeviceCaps(LOGPIXELSY) >> 2; // LOGPIXELSY * 24 / 96,\n\t#endif // !_WTL_CE_DRA\n\t}\n\n\t// Title painting\n\tbool DoPaintTitle()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tTCHAR sTitle[48] = { 0 };\n\n\t\t// Preparation\n\t\tCPaintDC dc(pT->m_hWnd);\n\t\tCFont fontTitle = AtlCreateBoldFont();\n\t\tCFontHandle fontOld = dc.SelectFont(fontTitle);\n\t\tdc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT));\n\t\tint nLen = pT->GetWindowText(sTitle, 48);\n\t\tint nWidth = dc.GetDeviceCaps(HORZRES);\n\n\t\t// Display title text\n\t\tRECT rTitle = { 0, 0, nWidth, nTitleHeight };\n\t\tdc.FillRect(&rTitle, COLOR_3DHIGHLIGHT);\n\t#ifdef _WTL_CE_DRA\n\t\trTitle.left = DRA::SCALEX(8);\n\t#else // !_WTL_CE_DRA\n\t\trTitle.left = nTitleHeight / 3; // 8 == 24 / 3\n\t#endif // !_WTL_CE_DRA\n\t\tdc.DrawText(sTitle, nLen, &rTitle, DT_VCENTER | DT_SINGLELINE);\n\t\tdc.SelectFont(fontOld);\n\n\t\t// Draw bottom line, 2 pixels thick if HI_RES_AWARE\n\t\tCPenHandle penOld = dc.SelectStockPen(BLACK_PEN);\n\t\tPOINT line[4] = {{0, nTitleHeight}, {nWidth, nTitleHeight}, {0, nTitleHeight - 1}, {nWidth, nTitleHeight - 1}};\n\n\t#ifdef _WTL_CE_DRA\n\t\tint nSeg = DRA::SCALEY(1);\n\t#else // !_WTL_CE_DRA\n\t\tint nSeg = nTitleHeight / 24; \n\t#endif // !_WTL_CE_DRA\n\n\t\tdc.Polyline(line, nSeg <= 2 ? nSeg * 2 : 4);\n\t\tdc.SelectPen(penOld);\n\n\t\treturn false;\n\t}\n\n\t// Title preparation: move the dialog controls down to make room for title\n\tvoid DialogTitleInit()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\n\t\tATL::CWindow wCtl = pT->GetWindow(GW_CHILD);\n\t\twhile (wCtl.IsWindow())\n\t\t{\n\t\t\tRECT rCtl = { 0 };\n\t\t\twCtl.GetWindowRect(&rCtl);\n\t\t\t::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rCtl, 2);\n\t\t\t::OffsetRect(&rCtl, 0, nTitleHeight);\n\t\t\twCtl.MoveWindow(&rCtl, FALSE);\n\t\t\twCtl = wCtl.GetWindow(GW_HWNDNEXT);\n\t\t}\n\t}\n\n\t// SIP management\n\tvoid DoSipInfo()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\n\t\tSIPINFO si = {sizeof(SIPINFO)};\n\t\tSipGetInfo(&si);\n\t\tif ((si.fdwFlags & SIPF_ON) ^ SIPF_ON) \n\t\t\tsi.rcVisibleDesktop.bottom = si.rcSipRect.bottom;\n\t\tpT->MoveWindow(&si.rcVisibleDesktop, FALSE);\n\t}\n\n// Title painting handler\n\tLRESULT OnPaintTitle(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn bHandled = nTitleHeight ? pT->DoPaintTitle() : FALSE;\n\t}\n\n// SIP handler\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif (wParam == SPI_SETSIPINFO)\n\t\t{\n\t\t\tpT->DoSipInfo();\n\t\t\treturn TRUE;\n\t\t}\n\t\treturn bHandled = FALSE;\n\t}\n\n#elif defined WIN32_PLATFORM_WFSP\n// SmartPhone VK_TBACK key standard management\n\tLRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tconst UINT uModif = (UINT)LOWORD(lParam);\n\t\tconst UINT uVirtKey = (UINT)HIWORD(lParam);\n\n\t\tif(uVirtKey == VK_TBACK)\n\t\t\tif (AtlIsEditFocus())\n\t\t\t\t::SHSendBackToFocusWindow(uMsg, wParam, lParam);\n\t\t\telse if (uModif & MOD_KEYUP)\n\t\t\t\t\tpT->StdCloseDialog(IDCANCEL);\n\t\treturn 1;\n\t}\n\n // SmartPhone MenuBar and VK_TBACK key initialization\n\tvoid StdSPInit()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tHWND hMenuBar = ::SHFindMenuBar(pT->m_hWnd);\n\n\t\tif (!hMenuBar && (t_shidiFlags & SHIDIF_DONEBUTTON))\n\t\t\thMenuBar = CreateMenuBar(ATL_IDM_MENU_DONE);\n\n\t\tif(hMenuBar != NULL)\n\t\t\tAtlActivateBackKey(hMenuBar);\n\t}\n\n\tvoid SetStaticBold()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\n\t\tCFontHandle fontBold = AtlCreateBoldFont(pT->GetFont());\n\n\t\tATL::CWindow wCtl = pT->GetWindow(GW_CHILD);\n\n\t\twhile (wCtl.IsWindow())\n\t\t{\n\t\t\tif ((short int)wCtl.GetDlgCtrlID() == IDC_STATIC)\n\t\t\t\twCtl.SetFont(fontBold);\n\t\t\twCtl = wCtl.GetWindow(GW_HWNDNEXT);\n\t\t}\n\t}\n#endif // WIN32_PLATFORM_WFSP\n\n// Platform dependant initialization\n\tvoid StdPlatformInit()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC title initialization\n\t\tif (nTitleHeight != 0)\n\t\t\tpT->DialogTitleInit();\n#elif defined(WIN32_PLATFORM_WFSP)\n\t\tpT->StdSPInit();\n\t\tSetStaticBold();\n#endif // WIN32_PLATFORM_WFSP\n\t}\n\n\t// Menu bar creation\n\tHWND CreateMenuBar(UINT uiMB = T::IDD, int nBmpImages = 0)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn AtlCreateMenuBar(pT->m_hWnd, uiMB, 0, nBmpImages ? uiMB : 0, nBmpImages);\n\t}\n\n\t// Dialog closing\n\tvoid StdCloseDialog(WORD wID)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif (t_bModal)\n\t\t\t::EndDialog(pT->m_hWnd, wID);\n\t\telse\n\t\t\tpT->DestroyWindow();\n\t}\n\n\t// Shell dialog layout initialization\n\tvoid StdShidInit()\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tSHINITDLGINFO shidi = { SHIDIM_FLAGS, pT->m_hWnd, t_shidiFlags };\n\t\t::SHInitDialog(&shidi);\n\t}\n\n// IDC_INFOSTATIC background setting\n\tLRESULT OnColorStatic(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tif (::GetDlgCtrlID((HWND)lParam) == IDC_INFOSTATIC)\n\t\t{\n\t\t\t::SetBkMode((HDC)wParam, TRANSPARENT);\n\t\t\treturn (LRESULT)::GetSysColorBrush(COLOR_INFOBK);\n\t\t}\n\t\treturn bHandled = FALSE;\n\t}\n\n// Menu dialog ending\n\tLRESULT OnMenuClose(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->StdCloseDialog((WORD)(wID - ID_MENU_OK + IDOK));\n\t\treturn 0;\n\t}\n\n// Standard dialog ending: may be used with any command\n\tLRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->StdCloseDialog(wID);\n\t\treturn 0;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogImplBase - Base implementation of standard PPC/SmartPhone dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl< T > >\nclass ATL_NO_VTABLE CStdDialogImplBase :\n\t\tpublic TBase,\n\t\tpublic CStdDialogBase<T, t_shidiFlags, t_bModal>\n{\npublic:\n#ifdef WIN32_PLATFORM_PSPC\n\tBOOL GetClientRect(LPRECT lpRect) \n\t{\n\t\treturn CStdDialogBase<T, t_shidiFlags, t_bModal>::GetClientRect(lpRect);\n\t}\n\n\tBOOL SetWindowText(LPCTSTR lpszString)\n\t{\n\t\treturn CStdDialogBase<T, t_shidiFlags, t_bModal>::SetWindowText(lpszString);\n\t}\n#endif\n\n\tBEGIN_MSG_MAP(CStdDialogImplBase)\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key\n\t\tMESSAGE_HANDLER(WM_HOTKEY, OnHotKey)\n#endif\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\tEND_MSG_MAP()\n\t\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(t_bModal == pT->m_bModal);\n\t\tpT->StdPlatformInit();\n\t\tpT->StdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogImpl - implementation of standard PPC/SmartPhone dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal>\n{};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdIndirectDialogImpl - implementation of standard indirect PPC/SmartPhone dialog\n\n#if defined __ATLDLGS_H__ \n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true>\nclass ATL_NO_VTABLE CStdIndirectDialogImpl : \n\tpublic CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl<T, t_shidiFlags, t_bModal> >\n{\npublic:\n\ttypedef CIndirectDialogImpl< T, CMemDlgTemplate, CStdDialogImpl<T, t_shidiFlags, t_bModal> >\t_baseClass;\n\ttypedef CStdDialogImpl<T, t_shidiFlags, t_bModal> _baseStd;\n\n\tvoid CheckStyle()\n\t{\n\t\t// Mobile devices don't support DLGTEMPLATEEX\n\t\tATLASSERT(!m_Template.IsTemplateEx());\n\n\t\t// Standard dialogs need only DS_CENTER\n\t\tDWORD &dwStyle = m_Template.GetTemplatePtr()->style; \n\t\tif (dwStyle & DS_CENTER)\n\t\t\tif(t_bModal)\n\t\t\t{\n\t\t\t\tATLASSERT((dwStyle & WS_CHILD) != WS_CHILD);\n\t\t\t\tdwStyle |= WS_POPUP;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif((dwStyle & WS_CHILD) != WS_CHILD)\n\t\t\t\t\tdwStyle |= WS_POPUP;\n\t\t\t}\n\t}\n\n\tINT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)\n\t{\n\t\tATLASSERT(t_bModal);\n\n\t\tif (!m_Template.IsValid())\n\t\t\tCreateTemplate();\n\n\t\tCheckStyle();\n\n\t\treturn _baseClass::DoModal(hWndParent, dwInitParam);\n\t}\n\n\tHWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)\n\t{\n\t\tATLASSERT(!t_bModal);\n\n\t\tif (!m_Template.IsValid())\n\t\t\tCreateTemplate();\n\n\t\tCheckStyle();\n\n\t\treturn _baseClass::Create(hWndParent, dwInitParam);\n\t}\n\n\tBEGIN_MSG_MAP(CStdIndirectDialogImpl)\n\t\tCHAIN_MSG_MAP(_baseStd)\n\tEND_MSG_MAP()\n\n};\n \n#endif // defined __ATLDLGS_H__ \n\n#ifndef _ATL_NO_HOSTING\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdAxDialogImpl - implementation of standard  PPC/SmartPhone AxDialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdAxDialogImpl : public CStdDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl< T > >\n{};\n#endif // _ATL_NO_HOSTING\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdSimpleDialog - standard PPC/SmartPhone simple dialog with SHIDIF_xxx flags\n\ntemplate <WORD t_wDlgTemplateID, UINT t_shidiFlags = WTL_STD_SHIDIF>\nclass CStdSimpleDialog :\n\t\tpublic ATL::CSimpleDialog<t_wDlgTemplateID, FALSE>,\n\t\tpublic CStdDialogBase<CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>, t_shidiFlags>\n{\npublic:\n\ttypedef CStdDialogBase<CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>, t_shidiFlags> baseClass;\n\n#ifdef WIN32_PLATFORM_PSPC\n\tBOOL GetClientRect(LPRECT lpRect) \n\t{\n\t\treturn baseClass::GetClientRect(lpRect);\n\t}\n\n\tBOOL SetWindowText(LPCTSTR lpszString)\n\t{\n\t\treturn baseClass::SetWindowText(lpszString);\n\t}\n#endif\n\n\tBEGIN_MSG_MAP(CStdSimpleDialog)\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC title and SIP\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key\n\t\tMESSAGE_HANDLER(WM_HOTKEY, OnHotKey)\n#endif\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tStdPlatformInit();\n\t\tStdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogResizeImplBase - Base implementation of orientation resizing standard PPC/SmartPhone dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl<T> >\nclass ATL_NO_VTABLE CStdDialogResizeImplBase :\n\t\tpublic CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>,\n\t\tpublic CDialogResize<T>\n{\npublic:\n\t// Note: BEGIN_DLGRESIZE_MAP is required in the derived class.\n\n\tBEGIN_MSG_MAP(CStdResizeDialogImplBase)\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC title\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key\n\t\tMESSAGE_HANDLER(WM_HOTKEY, OnHotKey)\n#endif\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\t\tCHAIN_MSG_MAP(CDialogResize< T >)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(t_bModal == pT->m_bModal);\n\t\tpT->StdPlatformInit();\n\t\tpT->DlgResize_Init(FALSE);\n\t\tpT->StdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal>\n{};\n\n#ifndef _ATL_NO_HOSTING\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdAxDialogResizeImpl - implementation of orientation resizing standard PPC/SmartPhone AxDialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdAxDialogResizeImpl : public CStdDialogResizeImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl<T> >\n{};\n#endif // _ATL_NO_HOSTING\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdSimpleDialogResizeImpl - implementation of standard resizing simple dialog with SHIDIF_xxx flags\n\n// Usage:\n//\tclass CMyDlg : public CStdSimpleDialogResize<CMyDlg,\n//\t\tIDD_MYDLG, SHIDIF_DONEBUTTON | SHIDIF_FULLSCREENNOMENUBAR>\n//\t{\n//\tpublic:\n//\t\tBEGIN_DLGRESIZE_MAP(CMyDlg)\n//\t\t...\n//\t\tEND_DLGRESIZE_MAP()\n//\t};\n\ntemplate <class T, WORD t_wDlgTemplateID, UINT t_shidiFlags = WTL_STD_SHIDIF>\nclass ATL_NO_VTABLE CStdSimpleDialogResizeImpl :\n\t\tpublic CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>,\n\t\tpublic CDialogResize< T >\n{\npublic:\n\ttypedef CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>::baseClass baseClass;\n\n\tBEGIN_MSG_MAP(CStdSimpleDialogResizeImpl)\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC title\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n#elif defined(WIN32_PLATFORM_WFSP) // SmartPhone VK_TBACK key\n\t\tMESSAGE_HANDLER(WM_HOTKEY, OnHotKey)\n#endif\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\t\tCHAIN_MSG_MAP(CDialogResize< T >)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->StdPlatformInit();\n\t\tpT->DlgResize_Init(FALSE);\n\t\tpT->StdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdOrientedDialogBase - Oriented PPC standard dialog base class\n\ntemplate <class T>\nclass CStdOrientedDialogBase\n{\npublic:\n// Operation\n\tBOOL SetOrientation(DRA::DisplayMode mode)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tATLASSERT(mode == DRA::GetDisplayMode());\n\t\t\n\t\t// Derived dialog must enumerate TWO dialog templates with the same control ids and types ie:\n\t\t// enum { IDD = IDD_MYDLG, IDD_LANDSCAPE = IDD_MYDLG_L };\n\t\tUINT iResource = (mode == DRA::Landscape)? T::IDD_LANDSCAPE : T::IDD;\n\n\t\tBOOL bRes = DRA::RelayoutDialog(ModuleHelper::GetResourceInstance(), pT->m_hWnd, MAKEINTRESOURCE(iResource));\n\t\tpT->OnOrientation(mode);\n\t\treturn bRes;\n\t}\n\n// Override\n\tvoid OnOrientation(DRA::DisplayMode /*mode*/)\n\t{}\n\n// Message handlers\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tif (wParam == SETTINGCHANGE_RESET)\n\t\t{\n\t\t\tpT->SetOrientation(DRA::GetDisplayMode());\n\t\t\tpT->StdPlatformInit();\n\t\t\tpT->StdShidInit();\n\t\t}\n\t\telse if (wParam == SPI_SETSIPINFO)\n\t\t{\n\t\t\tpT->DoSipInfo();\n\t\t\treturn TRUE;\n\t\t}\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdOrientedDialogImplBase - Oriented PPC standard dialog base implementation\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true, class TBase = ATL::CDialogImpl<T> >\nclass ATL_NO_VTABLE CStdOrientedDialogImplBase :\n\t\tpublic CStdDialogImplBase< T, t_shidiFlags, t_bModal, TBase>,\n\t\tpublic CStdOrientedDialogBase<T>\n{\npublic:\n\tBEGIN_MSG_MAP(CStdOrientedDialogImpl)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, CStdOrientedDialogBase<T>::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, OnCloseCmd)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\tEND_MSG_MAP()\n\n\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n#ifdef _DEBUG\n\t\tATLASSERT(t_bModal == pT->m_bModal);\n#endif\n\t\tif (DRA::GetDisplayMode() == DRA::Landscape)\n\t\t\tpT->SetOrientation(DRA::Landscape);\n\t\tpT->StdPlatformInit();\n\t\tpT->StdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdOrientedDialogImpl - Oriented PPC standard dialog implementation\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal>\n{};\n\n#ifndef _ATL_NO_HOSTING\n///////////////////////////////////////////////////////////////////////////////\n// CStdAxOrientedDialogImpl - Oriented PPC standard AxDialog implementation\n\ntemplate <class T, UINT t_shidiFlags = WTL_STD_SHIDIF, bool t_bModal = true >\nclass ATL_NO_VTABLE CStdAxOrientedDialogImpl : public CStdOrientedDialogImplBase< T, t_shidiFlags, t_bModal, ATL::CAxDialogImpl<T> >\n{};\n#endif // _ATL_NO_HOSTING\n\n///////////////////////////////////////////////////////////////////////////////\n// CStdSimpleOrientedDialog - Standard simple orientable dialog\n\ntemplate <WORD t_wDlgTemplateID, WORD t_wDlgLandscapeID, UINT t_shidiFlags = WTL_STD_SHIDIF>\nclass CStdSimpleOrientedDialog :\n\t\tpublic CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>,\n\t\tpublic CStdOrientedDialogBase<CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> >\n{\npublic:\n\ttypedef CStdSimpleDialog<t_wDlgTemplateID, t_shidiFlags>::baseClass baseClass;\n\ttypedef CStdOrientedDialogBase<CStdSimpleOrientedDialog<t_wDlgTemplateID, t_wDlgLandscapeID, t_shidiFlags> > baseOriented;\n\n\tenum {IDD = t_wDlgTemplateID, IDD_LANDSCAPE = t_wDlgLandscapeID};\n\n\tBEGIN_MSG_MAP(CStdSimpleDialog)\n\t\tMESSAGE_HANDLER(WM_PAINT, OnPaintTitle)\n\t\tMESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorStatic)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, baseOriented::OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)\n\t\tCOMMAND_RANGE_HANDLER(IDOK, IDCANCEL, baseClass::OnCloseCmd)\n\t\tCOMMAND_RANGE_HANDLER(ID_MENU_OK, ID_MENU_CANCEL, OnMenuClose)\n\tEND_MSG_MAP()\n\n\t\tLRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif (DRA::GetDisplayMode() == DRA::Landscape)\n\t\t\tSetOrientation(DRA::Landscape);\n\t\tStdPlatformInit();\n\t\tStdShidInit();\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n#endif // _WTL_CE_DRA\n\n\n#endif // _WTL_CE_NO_DIALOGS\n\n\n// --- PPC/SmartPhone application window and helpers ---\n\n#ifndef _WTL_CE_NO_APPWINDOW\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppInfoBase - Helper for application state save/restore to registry\n\nclass CAppInfoBase\n{\npublic:\n\tCRegKeyEx m_Key;\n\n\tCAppInfoBase(ATL::_U_STRINGorID sAppKey)\n\t{\n\t\tm_Key.Create(HKEY_CURRENT_USER, sAppKey.m_lpstr);\n\t\tATLASSERT(m_Key.m_hKey);\n\t}\n\n\ttemplate <class V>\n\tLONG Save(V& val, ATL::_U_STRINGorID sName)\n\t{\n\t\treturn m_Key.SetBinaryValue(sName.m_lpstr, &val, sizeof(V));\n\t}\n\n\ttemplate <class V>\n\tLONG Save(int nb, V& val0, ATL::_U_STRINGorID sName)\n\t{\n\t\treturn m_Key.SetBinaryValue(sName.m_lpstr, &val0, nb * sizeof(V));\n\t}\n\n\ttemplate <class V>\n\tLONG Restore(V& val, ATL::_U_STRINGorID sName)\n\t{\n\t\tULONG bufSize = sizeof(V);\n\t\treturn m_Key.QueryBinaryValue(sName.m_lpstr, &val, &bufSize);\n\t}\n\n\ttemplate <class V>\n\tLONG Restore(int nb, V& val0, ATL::_U_STRINGorID sName)\n\t{\n\t\tULONG bufSize = nb * sizeof(V);\n\t\treturn m_Key.QueryBinaryValue(sName.m_lpstr, &val0, &bufSize);\n\t}\n\n#if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\tLONG Save(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName)\n\t{\n\t\treturn m_Key.SetStringValue(sName.m_lpstr, sval);\n\t}\n\n\tLONG Restore(_CSTRING_NS::CString& sval, ATL::_U_STRINGorID sName)\n\t{\n\t\tDWORD size = MAX_PATH;\n\t\tLONG res = m_Key.QueryStringValue(sName.m_lpstr, sval.GetBuffer(size), &size);\n\t\tsval.ReleaseBuffer();\n\t\treturn res;\n\t}\n#else\n  #pragma message(\"Warning: CAppInfoBase compiles without CString support. Do not use CString in Save or Restore.\")\n#endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)\n\t\n\tLONG Save(LPCTSTR sval, ATL::_U_STRINGorID sName)\n\t{\n\t\treturn m_Key.SetStringValue(sName.m_lpstr, sval);\n\t}\n\n\tLONG Restore(LPTSTR sval, ATL::_U_STRINGorID sName, DWORD *plength)\n\t{\n\t\treturn m_Key.QueryStringValue(sName.m_lpstr, sval, plength);\n\t}\n\t\n\tLONG Delete(ATL::_U_STRINGorID sName)\n\t{\n\t\treturn  m_Key.DeleteValue(sName.m_lpstr);\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppInfoT - CAppInfoBase constructed from a class with T::GetAppKey() \n\n// Macro for declaring AppKey\n#define DECLARE_APPKEY(uAppKey) \\\n\tstatic LPCTSTR GetAppKey() \\\n\t{ \\\n\t\tstatic LPCTSTR sAppKey = ATL::_U_STRINGorID(uAppKey).m_lpstr; \\\n\t\treturn sAppKey; \\\n\t}\n\ntemplate <class T>\nclass CAppInfoT : public CAppInfoBase\n{\npublic:\n\tCAppInfoT() : CAppInfoBase(T::GetAppKey()){}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppWindowBase - Base class for PPC/SmartPhone \"well-behaved\" application window or dialog\n\n// Macros for declaring frame WNDCLASS and AppKey\n#define DECLARE_APP_FRAME_CLASS(WndClassName, uCommonResourceID, uAppKey) \\\n\tDECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \\\n\tDECLARE_APPKEY(uAppKey)\n\n#define DECLARE_APP_FRAME_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd, uAppKey) \\\n\tDECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \\\n\tDECLARE_APPKEY(uAppKey)\n\ntemplate <class T>\nclass CAppWindowBase\n{\npublic:\n\ttypedef class CAppInfoT< T > CAppInfo;\n\n#ifndef WIN32_PLATFORM_WFSP\n\tSHACTIVATEINFO m_sai; // NoOp on SmartPhones\n#endif // WIN32_PLATFORM_WFSP\n\n\tbool m_bHibernate;\n\n\tCAppWindowBase< T >() : m_bHibernate(false)\n\t{\n#ifndef WIN32_PLATFORM_WFSP\n\t\tSHACTIVATEINFO sai = { sizeof(SHACTIVATEINFO) };\n\t\tm_sai = sai;\n#endif // WIN32_PLATFORM_WFSP\n\t};\n\n\t// Same as WTL 7.1 AppWizard generated ActivatePreviousInstance + SendMessage WM_COPYDATA\n\tstatic HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR  lpstrCmdLine, bool bDialog)\n\t{\n\t\t// requires T does DECLARE_APP_FRAME_CLASS, DECLARE_APP_FRAME_CLASS_EX or DECLARE_APP_DLG_CLASS\n\t\tCFrameWndClassInfo& classInfo = T::GetWndClassInfo();\n\n\t\tATLVERIFY(::LoadString(hInstance, classInfo.m_uCommonResourceID, classInfo.m_szAutoName, sizeof(classInfo.m_szAutoName)/sizeof(classInfo.m_szAutoName[0])) != 0);\n\n\t\tclassInfo.m_wc.lpszClassName = classInfo.m_szAutoName;\n\n\t\tconst TCHAR* pszClass = classInfo.m_wc.lpszClassName;\n\n\t\tif(NULL == pszClass || '\\0' == *pszClass)\n\t\t{\n\t\t\treturn E_FAIL;\n\t\t}\n\n\t\tconst DWORD dRetryInterval = 100;\n\t\tconst int iMaxRetries = 25;\n\n\t\tfor(int i = 0; i < iMaxRetries; ++i)\n\t\t{\n\t\t\tHANDLE hMutex = CreateMutex(NULL, FALSE, pszClass);\n\n\t\t\tDWORD dw = GetLastError();\n\n\t\t\tif(NULL == hMutex)\n\t\t\t{\n\t\t\t\tHRESULT hr;\n\n\t\t\t\tswitch(dw)\n\t\t\t\t{\n\t\t\t\tcase ERROR_INVALID_HANDLE:\n\t\t\t\t\t// A non-mutext object with this name already exists.\n\t\t\t\t\thr = E_INVALIDARG;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// This should never happen...\n\t\t\t\t\thr = E_FAIL;\n\t\t\t\t}\n\n\t\t\t\treturn hr;\n\t\t\t}\n\n\t\t\t// If the mutex already exists, then there should be another instance running\n\t\t\tif(dw == ERROR_ALREADY_EXISTS)\n\t\t\t{\n\t\t\t\tCloseHandle(hMutex);\n\t\t\t\t\n\t\t\t\tHWND hwnd = NULL;\n\t\t\t\tif (bDialog)\n\t\t\t\t\thwnd = FindWindow(NULL, pszClass);\n\t\t\t\telse\n\t\t\t\t\thwnd = FindWindow(pszClass, NULL);\n\n\t\t\t\tif(hwnd == NULL)\n\t\t\t\t{\n\t\t\t\t\tSleep(dRetryInterval);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Transmit our params to previous instance\n\t\t\t\t\tif (lpstrCmdLine && *lpstrCmdLine)\n\t\t\t\t\t{\n\t\t\t\t\t\tCOPYDATASTRUCT cd = { NULL, sizeof(TCHAR) * (wcslen(lpstrCmdLine) + 1), (PVOID)lpstrCmdLine };\n\t\t\t\t\t\t::SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cd);\n\t\t\t\t\t}\n\t\t\t\t\t// Set the previous instance as the foreground window\n\t\t\t\t\tif(0 != SetForegroundWindow(reinterpret_cast<HWND>(reinterpret_cast<ULONG>(hwnd) | 0x1)))\n\t\t\t\t\t\treturn S_FALSE;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn S_OK;\n\t\t\t}\n\t\t}\n\t\treturn S_OK;\n\t}\n\n// Operations overriden in derived class\n\tbool AppHibernate(bool /*bHibernate*/)\n\t{\n\t\treturn false;\n\t}\n\n\tbool AppNewInstance(LPCTSTR /*lpstrCmdLine*/)\n\t{\n\t\treturn false;\n\t}\n\n\tvoid AppSave()\n\t{\n\t}\n\n#ifdef WIN32_PLATFORM_WFSP \n\tvoid AppBackKey() \n\t{\n\t\t::SHNavigateBack();\n\t}\n#endif\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CAppWindowBase)\n\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnActivate)\n#ifdef WIN32_PLATFORM_WFSP\n\t\tMESSAGE_HANDLER(WM_HOTKEY, OnHotKey)\n#else\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n#endif // WIN32_PLATFORM_WFSP\n\t\tMESSAGE_HANDLER(WM_HIBERNATE, OnHibernate)\n\t\tMESSAGE_HANDLER(WM_COPYDATA, OnNewInstance)\n\t\tMESSAGE_HANDLER(WM_CLOSE, OnClose)\n\tEND_MSG_MAP()\n\n\tLRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif (m_bHibernate)\n\t\t\tm_bHibernate = pT->AppHibernate(false);\n#ifndef WIN32_PLATFORM_WFSP\n\t\t::SHHandleWMActivate(pT->m_hWnd, wParam, lParam, &m_sai, 0);\n#else\n\t\twParam;\n\t\tlParam;\n#endif // WIN32_PLATFORM_WFSP\n\t\t return bHandled = FALSE;\n\t}\n\n#ifdef WIN32_PLATFORM_WFSP\n// SmartPhone VK_TBACK key standard management\n\tLRESULT OnHotKey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tconst UINT uModif = (UINT)LOWORD(lParam);\n\t\tconst UINT uVirtKey = (UINT)HIWORD(lParam);\n\t\tif(uVirtKey == VK_TBACK)\n\t\t\tif (AtlIsEditFocus())\n\t\t\t\t::SHSendBackToFocusWindow(uMsg, wParam, lParam);\n\t\t\telse if (uModif & MOD_KEYUP)\n\t\t\t\tpT->AppBackKey();\n\t\treturn 1;\n\t}\n\n#else // !WIN32_PLATFORM_WFSP\n// PPC SIP handling\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tbHandled = FALSE;\n\t\treturn ::SHHandleWMSettingChange(pT->m_hWnd, wParam, lParam, &m_sai);\n\t}\n#endif // !WIN32_PLATFORM_WFSP\n\n\tLRESULT OnHibernate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\treturn m_bHibernate = pT->AppHibernate(true);\n\t}\n\n\tLRESULT OnNewInstance(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tPCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;\n\t\treturn pT->AppNewInstance((LPCTSTR)pcds->lpData);\n\t}\n\n\tLRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->AppSave();\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppWindow - PPC/SmartPhone \"well-behaved\" application window class\n\ntemplate <class T>\nclass CAppWindow : public CAppWindowBase< T >\n{\npublic:\n\t// Same as WTL 7.1 AppWizard generated Run + lpstrCmdLine in CreateEx\n\tstatic int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL)\n\t{\n\t\tCMessageLoop theLoop;\n\t\t_Module.AddMessageLoop(&theLoop);\n\n\t\tT wndMain;\n\n\t\tif(wndMain.CreateEx(NULL, NULL, 0, 0, lpstrCmdLine) == NULL)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Main window creation failed!\\n\"));\n\t\t\treturn 0;\n\t\t}\n\n\t\twndMain.ShowWindow(nCmdShow);\n\n\t\tint nRet = theLoop.Run();\n\n\t\t_Module.RemoveMessageLoop();\n\t\treturn nRet;\n\t}\n\n\tstatic HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR  lpstrCmdLine)\n\t{\n\t\treturn CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, false);\n\t}\n};\n\n\n#ifndef _WTL_CE_NO_DIALOGS\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppDialog - PPC/SmartPhone \"well-behaved\" dialog application class\n\n// Macro for declaring dialog WNDCLASS and AppKey\n#define DECLARE_APP_DLG_CLASS(WndClassName, uCommonResourceID, uAppKey) \\\n\tstatic WTL::CFrameWndClassInfo& GetWndClassInfo() \\\n\t{ \\\n\t\tstatic WTL::CFrameWndClassInfo wc = \\\n\t\t{ \\\n\t\t\t{ 0, (WNDPROC)StartDialogProc, \\\n\t\t\t0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \\\n\t\t\tNULL, NULL, IDC_ARROW, TRUE, 0, _T(\"\"), uCommonResourceID \\\n\t\t}; \\\n\t\treturn wc; \\\n\t}; \\\n\tDECLARE_APPKEY(uAppKey)\n\ntemplate <class T>\nclass CAppDialog : public CAppWindowBase< T >\n{\npublic:\n\tstatic int AppRun(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWNORMAL)\n\t{\n\t\tCMessageLoop theLoop;\n\t\t_Module.AddMessageLoop(&theLoop);\n\n\t\tT dlgMain;\n\n\t\tif(dlgMain.Create(NULL, (LPARAM)lpstrCmdLine) == NULL)\n\t\t{\n\t\t\tATLTRACE2(atlTraceUI, 0, _T(\"Main dialog creation failed!\\n\"));\n\t\t\treturn 0;\n\t\t}\n\n\t\tdlgMain.ShowWindow(nCmdShow);\n\n\t\tint nRet = theLoop.Run();\n\n\t\t_Module.RemoveMessageLoop();\n\t\treturn nRet;\n\t}\n\n\tstatic HRESULT ActivatePreviousInstance(HINSTANCE hInstance, LPCTSTR  lpstrCmdLine)\n\t{\n\t\treturn CAppWindowBase< T >::ActivatePreviousInstance(hInstance, lpstrCmdLine, true);\n\t};\n};\n\n// PPC/SmartPhone standard application dialogs\n\n#ifdef WIN32_PLATFORM_WFSP\n#define WTL_APP_SHIDIF WTL_SP_SHIDIF\n#else\n#define WTL_APP_SHIDIF WTL_STD_SHIDIF\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdDialogImplBase - Base implementation of standard application dialogs\n\ntemplate <class T, class TImplBase, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdDialogImplBase :\n\t\tpublic TImplBase, \n\t\tpublic CAppDialog< T >\n{ \npublic:\n\tWTL_DLG_NOTITLE;\n\n\tvoid StdCloseDialog(int nVal)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tif (nVal != IDCANCEL)\n\t\t\tpT->AppSave();\n\t\tif (t_bModal == false)\n\t\t{\n\t\t\tpT->DestroyWindow();\n\t\t\t::PostQuitMessage(nVal);\n\t\t}\n\t\telse\n\t\t\t::EndDialog(pT->m_hWnd, nVal);\n\t}\n\t\n\tBEGIN_MSG_MAP(CAppStdDialogImplBase)\n\t\tMESSAGE_HANDLER(WM_CLOSE, OnSystemClose)\n\t\tCHAIN_MSG_MAP(TImplBase)\n\t\tCHAIN_MSG_MAP(CAppDialog< T >)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSystemClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT->StdCloseDialog(IDCANCEL);\n\t\treturn 0;\n\t}\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdDialogImpl - Implementation of standard application dialog \n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdDialogImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdDialogResizeImpl - implementation of orientation resizing standard application dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdDialogResizeImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdDialogResizeImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n\n#ifndef _ATL_NO_HOSTING\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdAxDialogImpl - Implementation of standard application AxDialog \n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdAxDialogImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdAxDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdAxDialogResizeImpl - implementation of orientation resizing standard application AxDialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdAxDialogResizeImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdAxDialogResizeImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n#endif // _ATL_NO_HOSTING\n\n#if defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdOrientedDialogImpl - implementation of oriented PPC standard application dialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdOrientedDialogImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdOrientedDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n\n#ifndef _ATL_NO_HOSTING\n///////////////////////////////////////////////////////////////////////////////\n// CAppStdAxOrientedDialogImpl - implementation of oriented PPC standard application AxDialog\n\ntemplate <class T, UINT t_shidiFlags = WTL_APP_SHIDIF, bool t_bModal = false>\nclass ATL_NO_VTABLE CAppStdAxOrientedDialogImpl :\n\t\tpublic CAppStdDialogImplBase<T, CStdAxOrientedDialogImpl<T, t_shidiFlags, t_bModal>, t_shidiFlags, t_bModal>\n{};\n#endif // _ATL_NO_HOSTING\n\n#endif // defined(_WTL_CE_DRA) && defined(WIN32_PLATFORM_PSPC)\n\n#endif // _WTL_CE_NO_DIALOGS\n\n#endif // _WTL_CE_NO_APPWINDOW\n\n\n// --- Full screen support ---\n\n#ifndef _WTL_CE_NO_FULLSCREEN\n\n///////////////////////////////////////////////////////////////////////////////\n// CFullScreenFrame - full screen frame implementation\n\ntemplate <class T, bool t_bHasSip = true>\nclass CFullScreenFrame\n{\npublic:\n\tbool m_bFullScreen;\n\n\tCFullScreenFrame() : m_bFullScreen(false)\n\t{ }\n\n// Operation\t\n\tvoid SetFullScreen(bool bFull)\n\t{\n\t\tm_bFullScreen = bFull;\n\t\tShowTaskBar(!bFull, false);\n\t\tShowMenuBar(!bFull);\n\t}\n\n// Manage TaskBar for modal dialogs and property sheets\n\ttemplate <class D>\n\tint FSDoModal(D& dlg)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tpT;   // avoid level 4 warning\n\t\tATLASSERT(pT->IsWindow());\n\t\tif (m_bFullScreen)   // Show taskbar if hidden\n\t\t\tShowTaskBar(true, false);\n\t\tint iRet = dlg.DoModal();\n\t\tif (m_bFullScreen)   // Hide taskbar if restored\n\t\t\tShowTaskBar(false);\n\t\treturn iRet;\n\t}\n\n// Implementation\n\tvoid ShowMenuBar(bool bShow)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tATL::CWindow MenuBar = pT->m_hWndCECommandBar;\n\t\tATLASSERT(MenuBar.IsWindow());\n\t\tMenuBar.ShowWindow(bShow ? SW_SHOWNORMAL : SW_HIDE);\n\t\tpT->SizeToMenuBar();\n\t}\n\t\n\tvoid ShowTaskBar(bool bShow, bool bRepaint = true)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(pT->IsWindow());\n\t\tRECT rect = { 0 };\n\t\tSystemParametersInfo(SPI_GETWORKAREA, NULL, &rect, FALSE);\n\t\tif (!bShow)\n\t\t\trect.top = 0;\n\n#ifdef WIN32_PLATFORM_PSPC // Pocket PC code\n\t\tUINT uShow = t_bHasSip ? SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON : SHFS_SHOWTASKBAR | SHFS_HIDESIPBUTTON;\t\t\n\t\tSHFullScreen(pT->m_hWnd, bShow ? uShow : SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON);\n#elif _WIN32_WCE > 0x500 // Smartphone 2005 code\n\t\tSHFullScreen(pT->m_hWnd, bShow ? SHFS_SHOWTASKBAR : SHFS_HIDETASKBAR);\n#else // Smartphone 2003\n\t\tHWND hTaskBar = FindWindow(_T(\"tray\"), NULL);\n\t\tATLASSERT(::IsWindow(hTaskBar));\n\t\t::ShowWindow(hTaskBar, bShow ? SW_SHOW : SW_HIDE);\n#endif // WIN32_PLATFORM_PSPC\n\n\t\tpT->MoveWindow(&rect, bRepaint);\n\t}\n\n// Message map and handler\n\tBEGIN_MSG_MAP(CFullScreenFrame)\n\t\tMESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\n\t\tMESSAGE_HANDLER(WM_ACTIVATE, OnActivate)\n\tEND_MSG_MAP()\n\n\tLRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n#ifndef SETTINGCHANGE_RESET // not defined for PPC 2002\n\t#define SETTINGCHANGE_RESET SPI_SETWORKAREA\n#endif\n\t\tif (m_bFullScreen && (wParam == SETTINGCHANGE_RESET))\n\t\t\tSetFullScreen(m_bFullScreen);\n\t\treturn bHandled = FALSE;\n\t}\n\n\tLRESULT OnActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tif (m_bFullScreen)\n\t\t{\n\t\t\tShowTaskBar(!wParam);\n\t\t\tShowMenuBar(!wParam);\n\t\t}\n\t\treturn bHandled = FALSE;\n\t}\n};\n\n#endif // _WTL_CE_NO_FULLSCREEN\n\n\n// --- WinCE zoom support ---\n\n#ifndef _WTL_CE_NO_ZOOMSCROLL\n\n///////////////////////////////////////////////////////////////////////////////\n// CZoomScrollImpl - WinCE zooming implementation on top of CScrollImpl\n\ntemplate <class T>\nclass  CZoomScrollImpl: public CScrollImpl< T >\n{\npublic:\n// Data members\n\t_WTYPES_NS::CSize m_sizeTrue;\n\tdouble\tm_fzoom;\n\n// Creation\n\tCZoomScrollImpl() : m_sizeTrue(0), m_fzoom(1.)\n\t{ }\n\n// Zoom operations and access\n\tvoid SetZoomScrollSize(_WTYPES_NS::CSize sizeTrue, double fzoom = 1., BOOL bRedraw = TRUE)\n\t{\n\t\tATLASSERT(fzoom > 0.);\n\t\tm_sizeTrue = sizeTrue;\n\t\tm_fzoom = fzoom;\n\n\t\tCScrollImpl< T >::SetScrollSize(sizeTrue / fzoom, bRedraw);\n\t}\n\n\tvoid SetZoomScrollSize(int cx, int cy, double fzoom=1., BOOL bRedraw = TRUE)\n\t{\n\t\tSetZoomScrollSize(_WTYPES_NS::CSize(cx, cy), fzoom, bRedraw);\n\t}\n\n\tvoid SetZoom(double fzoom, BOOL bRedraw = TRUE)\n\t{\n\t\t_WTYPES_NS::CPoint ptCenter = WndtoTrue(m_sizeClient / 2);\n\t\t_WTYPES_NS::CSize sizePage = GetScrollPage();\n\t\t_WTYPES_NS::CSize sizeLine = GetScrollLine();\n\n\t\tSetZoomScrollSize(GetScrollSize(), fzoom, bRedraw);\n\n\t\tSetScrollLine(sizeLine);\n\t\tSetScrollPage(sizePage);\n\t\t_WTYPES_NS::CPoint ptOffset = ptCenter - (m_sizeClient / 2) * fzoom;\n\t\tSetScrollOffset(ptOffset, bRedraw);\n\t}\n\n\tdouble GetZoom()\n\t{\n\t\treturn m_fzoom;\n\t}\n\n// CScrollImpl overrides\n\tvoid SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)\n\t{\n\t\tCScrollImpl< T >::SetScrollOffset((int)(x / m_fzoom), (int)(y / m_fzoom), bRedraw);\n\t}\n\n\tvoid SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)\n\t{\n\t\tSetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);\n\t}\n\n\tvoid GetScrollOffset(POINT& ptOffset)\n\t{\n\t\tptOffset.x = (LONG)(m_ptOffset.x * m_fzoom);\n\t\tptOffset.y = (LONG)(m_ptOffset.y * m_fzoom);\n\t}\n\n\tvoid SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE)\n\t{\n\t\tSetZoomScrollSize(cx, cy, GetZoom(), bRedraw);\n\t}\n\n\tvoid SetScrollSize(SIZE sizeTrue, BOOL bRedraw = TRUE)\n\t{\n\t\tSetZoomScrollSize(sizeTrue, GetZoom(), bRedraw);\n\t}\n\n\tvoid GetScrollSize(SIZE& sizeTrue) const\n\t{\n\t\tsizeTrue = m_sizeTrue;\n\t}\n\n\tvoid SetScrollPage(int cxPage, int cyPage)\n\t{\n\t\tSetScrollPage(_WTYPES_NS::CSize(cxPage, cyPage));\n\t}\n\n\tvoid SetScrollPage(SIZE sizePage)\n\t{\n\t\tCScrollImpl< T >::SetScrollPage(sizePage / m_fzoom);\n\t}\n\n\tvoid GetScrollPage(SIZE& sizePage) const\n\t{\n\t\tsizePage = m_sizePage * m_fzoom;\n\t}\n\n\tvoid SetScrollLine(int cxLine, int cyLine)\n\t{\n\t\tSetScrollLine(_WTYPES_NS::CSize(cxLine, cyLine));\n\t}\n\n\tvoid SetScrollLine(SIZE sizeLine)\n\t{\n\t\tCScrollImpl< T >::SetScrollLine(sizeLine / m_fzoom);\n\t}\n\n\tvoid GetScrollLine(SIZE& sizeLine) const\n\t{\n\t\tsizeLine = m_sizeLine * m_fzoom;\n\t}\n\n// Data access complements\n\t_WTYPES_NS::CSize GetScrollSize()\n\t{\n\t\treturn m_sizeTrue;\n\t}\n\n\t_WTYPES_NS::CSize GetScrollPage()\n\t{\n\t\treturn m_sizePage * m_fzoom;\n\t}\n\n\t_WTYPES_NS::CSize GetScrollLine()\n\t{\n\t\treturn m_sizeLine * m_fzoom;\n\t}\n\n\t_WTYPES_NS::CPoint GetScrollOffset()\n\t{\n\t\treturn (_WTYPES_NS::CSize)m_ptOffset * m_fzoom;\n\t}\n\n// Helper coordinate functions\n\t_WTYPES_NS::CPoint WndtoTrue(CPoint ptW)\n\t{\n\t\treturn (_WTYPES_NS::CSize)ptW * GetZoom() + GetScrollOffset();\n\t}\n\n\tvoid WndtoTrue(LPPOINT aptW, int nPts)   // in place coord transformation\n\t{\n\t\tfor (int i = 0 ; i < nPts ; i++)\n\t\t\taptW[i] = WndtoTrue(aptW[i]);\n\t}\n\n\tvoid WndtoTrue(LPRECT prectW)   // in place coord transformation\n\t{\n\t\tWndtoTrue((LPPOINT)prectW, 2);\n\t}\n\n\t_WTYPES_NS::CPoint TruetoWnd(CPoint ptT)\n\t{\n\t\treturn (ptT - GetScrollOffset()) / GetZoom();\n\t}\n\n\tvoid TruetoWnd(LPPOINT aptT, int nPts)   // in place coord transformation\n\t{\n\t\tfor (int i = 0 ; i < nPts ; i++)\n\t\t\taptT[i] = TruetoWnd(aptT[i]);\n\t}\n\n\tvoid TruetoWnd(LPRECT prectT)   // in place coord transformation\n\t{\n\t\tTruetoWnd((LPPOINT)prectT, 2);\n\t}\n\n// Drawing operations : assume adequate setting of data members\n\tBOOL Draw(HBITMAP hbm, HDC hdestDC, DWORD dwROP = SRCCOPY)\n\t{\n\t\tCDC memDC = CreateCompatibleDC(hdestDC);\n\t\tCBitmapHandle bmpOld = memDC.SelectBitmap(hbm);\n\t\tBOOL bRes = Draw(memDC, hdestDC, dwROP);\n\t\tmemDC.SelectBitmap(bmpOld);\n\t\treturn bRes;\n\t}\n\n\tBOOL Draw(HDC hsourceDC, HDC hdestDC, DWORD dwROP = SRCCOPY)\n\t{\n\t\tCDCHandle destDC = hdestDC;\n\t\tdestDC.SetViewportOrg(0,0);\n\t\t_WTYPES_NS::CPoint ptOffset = GetScrollOffset();\n\t\t_WTYPES_NS::CSize sizeZClient = m_sizeClient * GetZoom();\n\t\treturn destDC.StretchBlt(0, 0, m_sizeClient.cx, m_sizeClient.cy, hsourceDC, ptOffset.x, ptOffset.y, sizeZClient.cx, sizeZClient.cy, dwROP);\n\t}\n\n#ifdef _IMAGING_H\n\tBOOL Draw(IImage* pIImage, HDC hdestDC)\n\t{\n\t\tCDCHandle destDC = hdestDC;\n\t\tdestDC.SetViewportOrg(0,0);\n\t\treturn SUCCEEDED(pIImage->Draw(destDC, _WTYPES_NS::CRect(-_WTYPES_NS::CPoint(m_ptOffset), m_sizeAll), NULL));\n\t}\n#endif\n\n// Message map and handlers\n\tBEGIN_MSG_MAP(CZoomScrollImpl< T >)\n\t\tMESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)\n\t\tCHAIN_MSG_MAP(CScrollImpl< T >)\n\tEND_MSG_MAP()\n\t\n\tLRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)\n\t{\n\t\tT* pT = static_cast<T*>(this);\n\t\tATLASSERT(::IsWindow(pT->m_hWnd));\n\t\tif ((GetScrollExtendedStyle() & SCRL_ERASEBACKGROUND))\n\t\t{\n\t\t\t_WTYPES_NS::CRect rect;\n\t\t\tpT->GetClientRect(rect);\n\t\t\t_WTYPES_NS::CSize sizeClient=rect.Size();\n\n\t\t\tif (m_sizeAll.cx < sizeClient.cx || m_sizeAll.cy < sizeClient.cy)\n\t\t\t{\n\t\t\t\tCDCHandle hdc = (HDC)wParam;\n\t\t\t\tHBRUSH hbr = GetSysColorBrush((int)T::GetWndClassInfo().m_wc.hbrBackground - 1);\n\n\t\t\t\tif (m_sizeAll.cx < sizeClient.cx)\n\t\t\t\t{\n\t\t\t\t\t_WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(m_sizeAll.cx, 0), sizeClient);\n\t\t\t\t\thdc.FillRect(rectBG, hbr);\n\t\t\t\t}\n\n\t\t\t\tif (m_sizeAll.cy < sizeClient.cy)\n\t\t\t\t{\n\t\t\t\t\t_WTYPES_NS::CRect rectBG(_WTYPES_NS::CPoint(0, m_sizeAll.cy), sizeClient);\n\t\t\t\t\thdc.FillRect(rectBG, hbr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbHandled = FALSE;\n\t\t}\n\n\t\treturn 1;\n \t}\n};\n\n#endif // _WTL_CE_NO_ZOOMSCROLL\n\n#ifndef _WTL_CE_NO_CONTROLS\n\n// --- PPC bottom TabView control ---\n\n#if defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC)\n\n///////////////////////////////////////////////////////////////////////////////\n// CBottomTabViewImpl\n\ntemplate <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\nclass ATL_NO_VTABLE CBottomTabViewImpl : public CTabViewImpl<T, TBase, TWinTraits>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE)\n\n// Implementation overrideables\n\tbool CreateTabControl()\n\t{\n\t\tm_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | TCS_BOTTOM, 0, m_nTabID);\n\n\t\tATLASSERT(m_tab.m_hWnd != NULL);\n\t\tif(m_tab.m_hWnd == NULL)\n\t\t\treturn false;\n\n\t\tm_tab.SendMessage(CCM_SETVERSION, COMCTL32_VERSION);\n\t\tm_tab.SetItemExtra(sizeof(TABVIEWPAGE));\n\n\t\tT* pT = static_cast<T*>(this);\n\t\tm_cyTabHeight = pT->CalcTabHeight();\n\n\t\treturn true;\n\t}\n\n\tint CalcTabHeight()\n\t{\n\t\tint nCount = m_tab.GetItemCount();\n\t\tTCITEMEXTRA tcix = { 0 };\n\t\ttcix.tciheader.mask = TCIF_TEXT;\n\t\ttcix.tciheader.pszText = _T(\"NS\");\n\t\tint nIndex = m_tab.InsertItem(nCount, tcix);\n\n\t\tRECT rect = { 0 };\n\t\tSystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);\n\t\tRECT rcWnd = rect;\n\n\t\tm_tab.AdjustRect(FALSE, &rect);\n\t\trcWnd.top = rect.bottom;\n\t\t::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle());\n\t\tm_tab.DeleteItem(nIndex);\n\n\t\treturn rcWnd.bottom - rcWnd.top;\n\t}\n\n\tvoid UpdateLayout()\n\t{\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(&rect);\n\n\t\tif(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))\n\t\t\tm_tab.SetWindowPos(NULL, 0, rect.bottom - m_cyTabHeight, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER /*| SWP_SHOWWINDOW*/);\n\n\t\tif(m_nActivePage != -1)\n\t\t\t\t::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, 0, rect.right - rect.left, rect.bottom - m_cyTabHeight, SWP_NOZORDER);\n\t}\n\n};\n\nclass CBottomTabView : public CBottomTabViewImpl<CBottomTabView>\n{\npublic:\n\tDECLARE_WND_CLASS_EX(_T(\"WTL_BottomTabView\"), 0, COLOR_APPWORKSPACE)\n};\n\n#endif // defined(__ATLCTRLX_H__) && defined(WIN32_PLATFORM_PSPC)\n\n\n// --- PPC/SmartPhone controls ---\n\n////////////////////////////////////////////////////////////////////////////////\n// These are wrapper classes for the Pocket PC 2002/2003 and SmartPhone 2003 controls\n// To implement a window based on a control, use following:\n// Example: Implementing a window based on a Html control\n//\n// class CMyHtml : CWindowImpl<CMyHtml, CHtmlCtrl>\n// {\n// public:\n//      BEGIN_MSG_MAP(CMyHtml)\n//          // put your message handler entries here\n//      END_MSG_MAP()\n// };\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// CHtmlCtrl\n\ntemplate <class TBase>\nclass CHtmlCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCHtmlCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCHtmlCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call InitHTMLControl(hInstance) ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_HTML;\n\t}\n\n#if (_WIN32_WCE >= 400)\n\tvoid AddStyle(LPCWSTR pszStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ADDSTYLE, 0, (LPARAM)pszStyle);\n\t}\n#endif // (_WIN32_WCE >= 400)\n\n\tvoid AddText(BOOL bPlainText, LPCSTR pszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)bPlainText, (LPARAM)pszText);\n\t}\n\n\tvoid AddHTML(LPCSTR pszHTML)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ADDTEXT, (WPARAM)FALSE, (LPARAM)pszHTML);\n\t}\n\n\tvoid AddText(BOOL bPlainText, LPCWSTR pszText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)bPlainText, (LPARAM)pszText);\n\t}\n\n\tvoid AddHTML(LPCWSTR pszHTML)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ADDTEXTW, (WPARAM)FALSE, (LPARAM)pszHTML);\n\t}\n\n\tvoid Anchor(LPCSTR pszAnchor)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ANCHOR, 0, (LPARAM)pszAnchor);\n\t}\n\n\tvoid Anchor(LPCWSTR pszAnchor)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ANCHORW, 0, (LPARAM)pszAnchor);\n\t}\n\n#if (_WIN32_WCE >= 420)\n\tvoid GetBrowserDispatch(IDispatch** ppDispatch)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(ppDispatch);\n\t\tATLASSERT(*ppDispatch==NULL);\n\t\t::SendMessage(m_hWnd, DTM_BROWSERDISPATCH, 0, (LPARAM)ppDispatch);\n\t}\n\tvoid GetDocumentDispatch(IDispatch** ppDispatch)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(ppDispatch);\n\t\tATLASSERT(*ppDispatch==NULL);\n\t\t::SendMessage(m_hWnd, DTM_DOCUMENTDISPATCH , 0, (LPARAM)ppDispatch);\n\t}\n#endif // (_WIN32_WCE >= 420)\n\n\tvoid Clear()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_CLEAR, 0, 0L);\n\t}\n\n\tvoid EnableClearType(BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ENABLECLEARTYPE, 0, (LPARAM)bEnable);\n\t}\n\n\tvoid EnableContextMenu(BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ENABLECONTEXTMENU, 0, (LPARAM)bEnable);\n\t}\n\n\tvoid EnableScripting(BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ENABLESCRIPTING, 0, (LPARAM)bEnable);\n\t}\n\n\tvoid EnableShrink(BOOL bEnable = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ENABLESHRINK, 0, (LPARAM)bEnable);\n\t}\n\n\tvoid EndOfSource()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ENDOFSOURCE, 0, 0L);\n\t}\n\n\tvoid ImageFail(DWORD dwCookie)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_IMAGEFAIL, 0, (LPARAM)dwCookie);\n\t}\n\n\tint GetLayoutHeight() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DTM_LAYOUTHEIGHT, 0, 0L);\n\t}\n\n\tint GetLayoutWidth() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DTM_LAYOUTWIDTH, 0, 0L);\n\t}\n\n\tvoid Navigate(LPCTSTR pstrURL, UINT uFlags = 0)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrURL);\n\t\t::SendMessage(m_hWnd, DTM_NAVIGATE, (WPARAM)uFlags, (LPARAM)pstrURL);\n\t}\n\n\tvoid SelectAll()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_SELECTALL, 0, 0L);\n\t}\n\n\tvoid SetImage(INLINEIMAGEINFO* pImageInfo)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pImageInfo);\n\t\t::SendMessage(m_hWnd, DTM_SETIMAGE, 0, (LPARAM)pImageInfo);\n\t}\n\n\tvoid ZoomLevel(int iLevel)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_ZOOMLEVEL, 0, (LPARAM)iLevel);\n\t}\n\n#if (_WIN32_WCE >= 400)\n\tvoid Stop()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DTM_STOP, 0, 0L);\n\t}\n#endif // (_WIN32_WCE >= 400)\n\n\tvoid GetScriptDispatch(IDispatch** ppDispatch)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(ppDispatch);\n\t\tATLASSERT(*ppDispatch==NULL);\n\t\t::SendMessage(m_hWnd, DTM_SCRIPTDISPATCH, 0, (LPARAM)ppDispatch);\n\t}\n};\n\ntypedef CHtmlCtrlT<ATL::CWindow> CHtmlCtrl;\n\n\n#ifdef WIN32_PLATFORM_PSPC\n\n///////////////////////////////////////////////////////////////////////////////\n// CRichInkCtrl\n\ntemplate <class TBase>\nclass CRichInkCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCRichInkCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCRichInkCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call InitRichInkDLL() ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_RICHINK;\n\t}\n\n\tBOOL CanPaste(UINT uFormat = 0) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANPASTE, (WPARAM)uFormat, 0L);\n\t}\n\n\tBOOL CanRedo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANREDO, 0, 0L);\n\t}\n\n\tBOOL CanUndo() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_CANUNDO, 0, 0L);\n\t}\n\n\tvoid ClearAll(BOOL bRepaint = TRUE) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_CLEARALL, (WPARAM)bRepaint, 0L);\n\t}\n\n\tBOOL GetModify() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, EM_GETMODIFY, 0, 0L);\n\t}\n\n\tUINT GetPageStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETPAGESTYLE, 0, 0L);\n\t}\n\n\tUINT GetPenMode() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETPENMODE, 0, 0L);\n\t}\n\n\tUINT GetViewStyle() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETVIEW, 0, 0L);\n\t}\n\n\tUINT GetWrapMode() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETWRAPMODE, 0, 0L);\n\t}\n\n\tUINT GetZoomPercent() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_GETZOOMPERCENT, 0, 0L);\n\t}\n\n\tvoid InsertLinks(LPWSTR lpString, int cchLength = -1)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tif(cchLength == -1)\n\t\t\tcchLength = lstrlen(lpString);\n\t\t::SendMessage(m_hWnd, EM_INSERTLINKS, (WPARAM)cchLength, (LPARAM)lpString);\n\t}\n\n\tvoid RedoEvent()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_REDOEVENT, 0, 0L);\n\t}\n\n\tUINT SetInkLayer(UINT uLayer)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (UINT)::SendMessage(m_hWnd, EM_SETINKLAYER, (WPARAM)uLayer, 0L);\n\t}\n\n\tvoid SetPageStyle(UINT uStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETPAGESTYLE, (WPARAM)uStyle, 0L);\n\t}\n\n\tvoid SetPenMode(UINT uMode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETPENMODE, (WPARAM)uMode, 0L);\n\t}\n\n\tvoid SetViewStyle(UINT uStyle)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETVIEW, (WPARAM)uStyle, 0L);\n\t}\n\n\tvoid SetViewAttributes(VIEWATTRIBUTES* pAttribs)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pAttribs);\n\t\t::SendMessage(m_hWnd, EM_SETVIEWATTRIBUTES, 0, (LPARAM)pAttribs);\n\t}\n\n\tvoid SetWrapMode(UINT uMode)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETWRAPMODE, (WPARAM)uMode, 0L);\n\t}\n\n\tvoid SetZoomPercent(UINT uPercent)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETZOOMPERCENT, (WPARAM)uPercent, 0L);\n\t}\n\n\tLONG StreamIn(UINT uFormat, EDITSTREAM& es)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_STREAMIN, (WPARAM)uFormat, (LPARAM)&es);\n\t}\n\n\tLONG StreamOut(UINT uFormat, EDITSTREAM& es)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (LONG)::SendMessage(m_hWnd, EM_STREAMOUT, (WPARAM)uFormat, (LPARAM)&es);\n\t}\n\n\tvoid UndoEvent()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_UNDOEVENT, 0, 0L);\n\t}\n\n\tvoid Undo()\n\t{\n\t\tUndoEvent();\n\t}\n\n// Standard EM_xxx messages\n\tDWORD GetSel() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);\n\t\treturn (DWORD)::SendMessage(m_hWnd, EM_GETSEL, 0, 0L);\n\t}\n\n\tvoid GetSel(int& nStartChar, int& nEndChar) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);\n\t\t::SendMessage(m_hWnd, EM_GETSEL, (WPARAM)&nStartChar, (LPARAM)&nEndChar);\n\t}\n\n\tvoid SetSel(int nStartChar, int nEndChar)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);\n\t\t::SendMessage(m_hWnd, EM_SETSEL, nStartChar, nEndChar);\n\t}\n\n\tvoid ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(GetViewStyle() != VT_DRAWINGVIEW);\n\t\t::SendMessage(m_hWnd, EM_REPLACESEL, (WPARAM)bCanUndo, (LPARAM)lpszNewText);\n\t}\n\n\tvoid SetModify(BOOL bModified = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, EM_SETMODIFY, (WPARAM)bModified, 0L);\n\t}\n\n\tint GetTextLength() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, WM_GETTEXTLENGTH, 0, 0L);\n\t}\n\n// Clipboard operations\n\tvoid Clear()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CLEAR, 0, 0L);\n\t}\n\n\tvoid Copy()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_COPY, 0, 0L);\n\t}\n\n\tvoid Cut()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_CUT, 0, 0L);\n\t}\n\n\tvoid Paste()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, WM_PASTE, 0, 0L);\n\t}\n};\n\ntypedef CRichInkCtrlT<ATL::CWindow> CRichInkCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CInkXCtrl\n\ntemplate <class TBase>\nclass CInkXCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCInkXCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCInkXCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call InitInkX() ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_INKX;\n\t}\n\n\tstatic UINT GetHotRecordingMessage()\n\t{\n\t\treturn ::RegisterWindowMessage(szHotRecording);\n\t}\n\n\tvoid ClearAll()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IM_CLEARALL, 0, 0L);\n\t}\n\n\tint GetData(BYTE* lpBuffer, INT cbBuffer) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpBuffer);\n\t\treturn (int)::SendMessage(m_hWnd, IM_GETDATA, (WPARAM)cbBuffer, (LPARAM)lpBuffer);\n\t}\n\n\tint GetDataLen() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, IM_GETDATALEN, 0, 0L);\n\t}\n\n\tCRichInkCtrl GetRichInk() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HWND)::SendMessage(m_hWnd, IM_GETRICHINK, 0, 0L);\n\t}\n\n\tBOOL IsRecording() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, IM_RECORDING, 0, 0L);\n\t}\n\n\tvoid ReInit()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IM_REINIT, 0, 0L);\n\t}\n\n\tvoid SetData(const BYTE* lpInkData, INT cbInkData)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(lpInkData);\n\t\t::SendMessage(m_hWnd, IM_SETDATA, (WPARAM)cbInkData, (LPARAM)lpInkData);\n\t}\n\n\tvoid VoicePlay()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IM_VOICE_PLAY, 0, 0L);\n\t}\n\n\tBOOL IsVoicePlaying() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, IM_VOICE_PLAYING, 0, 0L);\n\t}\n\n\tBOOL VoiceRecord()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, IM_VOICE_RECORD, 0, 0L);\n\t}\n\n\tvoid VoiceStop()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IM_VOICE_STOP, 0, 0L);\n\t}\n\n\tvoid ShowVoiceBar(BOOL bShow = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, IM_VOICEBAR, (WPARAM)bShow, 0L);\n\t}\n};\n\ntypedef CInkXCtrlT<ATL::CWindow> CInkXCtrl;\n\n#endif // WIN32_PLATFORM_PSPC\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CVoiceRecorderCtrl\n\ntemplate <class TBase>\nclass CVoiceRecorderCtrlT : public TBase\n{\npublic:\n// Constructors\n\tCVoiceRecorderCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCVoiceRecorderCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, const POINT pt, LPTSTR pstrFileName, UINT nID, DWORD dwStyle = 0)\n\t{\n\t\tATLASSERT(pstrFileName != NULL);\n\t\tCM_VOICE_RECORDER cmvr = { 0 };\n\t\tcmvr.cb = sizeof(CM_VOICE_RECORDER);\n\t\tcmvr.dwStyle = dwStyle;\n\t\tcmvr.xPos = pt.x;\n\t\tcmvr.yPos = pt.y;\n\t\tcmvr.hwndParent = hWndParent;\n\t\tcmvr.id = nID;\n\t\tcmvr.lpszRecordFileName = pstrFileName;\n\t\tm_hWnd = VoiceRecorder_Create(&cmvr);\n\t\treturn m_hWnd;\n\t}\n\n\tHWND Create(LPCM_VOICE_RECORDER pAttribs)\n\t{\n\t\tATLASSERT(pAttribs);\n\t\tm_hWnd = VoiceRecorder_Create(pAttribs);\n\t\treturn m_hWnd;\n\t}\n\n// Attributes\n\tvoid Record()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, VRM_RECORD, 0, 0L);\n\t}\n\n\tvoid Play()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, VRM_PLAY, 0, 0L);\n\t}\n\n\tvoid Stop()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, VRM_STOP, 0, 0L);\n\t}\n\n\tvoid Cancel()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, VRM_CANCEL, 0, 0L);\n\t}\n\n\tvoid Done()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, VRM_OK, 0, 0L);\n\t}\n};\n\ntypedef CVoiceRecorderCtrlT<ATL::CWindow> CVoiceRecorderCtrl;\n\n\n#ifdef WIN32_PLATFORM_PSPC\n\n///////////////////////////////////////////////////////////////////////////////\n// CDocListCtrl\n\ntemplate <class TBase>\nclass CDocListCtrlT : public TBase\n{\npublic:\n// Attributes\n\tDOCLISTCREATE m_dlc;\n\tTCHAR m_szPath[MAX_PATH];\n\n// Constructors\n\tCDocListCtrlT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCDocListCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, WORD wId, LPCTSTR pszFolder = NULL, LPCTSTR pstrFilter = NULL,\n\t\t\tWORD wFilterIndex = 0, DWORD dwFlags = DLF_SHOWEXTENSION)\n\t{\n\t\tATLASSERT(pstrFilter != NULL);   // It seems to need a filter badly!!\n\t\t::ZeroMemory(&m_dlc, sizeof(DOCLISTCREATE));\n\t\t::ZeroMemory(m_szPath, sizeof(m_szPath));\n\t\tif(pszFolder != NULL)\n\t\t\tSecureHelper::strncpy_x(m_szPath, MAX_PATH, pszFolder, MAX_PATH - 1);\n\t\tm_dlc.dwStructSize = sizeof(DOCLISTCREATE);\n\t\tm_dlc.hwndParent = hWndParent;\n\t\tm_dlc.pszFolder = m_szPath;\n\t\tm_dlc.pstrFilter = pstrFilter;\n\t\tm_dlc.wFilterIndex = wFilterIndex;\n\t\tm_dlc.wId = wId;\n\t\tm_dlc.dwFlags = dwFlags;\n\t\tm_hWnd = DocList_Create(&m_dlc);\n\t\treturn m_hWnd;\n\t}\n\n\tHWND Create(DOCLISTCREATE* pDlc)\n\t{\n\t\tm_dlc = *pDlc;\n\t\tm_hWnd = DocList_Create(&m_dlc);\n\t\treturn m_hWnd;\n\t}\n\n// Attributes\n\tvoid DeleteSel()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_DELETESEL, 0, 0L);\n\t}\n\n\tvoid DisableUpdates()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_DISABLEUPDATES, 0, 0L);\n\t}\n\n\tvoid EnableUpdates()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_ENABLEUPDATES, 0, 0L);\n\t}\n\n\tint GetFilterIndex() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_GETFILTERINDEX, 0, 0L);\n\t}\n\n\tint GetItemCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_GETITEMCOUNT, 0, 0L);\n\t}\n\n\tint GetNextItem(int iIndex, DWORD dwRelation = LVNI_ALL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)iIndex, (LPARAM)dwRelation);\n\t}\n\n\tint GetFirstItem(DWORD dwRelation = LVNI_ALL) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_GETNEXTITEM, (WPARAM)-1, (LPARAM)dwRelation);\n\t}\n\n\tBOOL GetNextWave(int* pIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pIndex);\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_GETNEXTWAVE, 0, (LPARAM)pIndex);\n\t}\n\n\tBOOL GetPrevWave(int* pIndex) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pIndex);\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_GETPREVWAVE, 0, (LPARAM)pIndex);\n\t}\n\n\tint GetSelCount() const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_GETSELCOUNT, 0, 0L);\n\t}\n\n\tBOOL GetSelPathName(LPTSTR pstrPath, int cchMax) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrPath);\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_GETSELPATHNAME, (WPARAM)cchMax, (LPARAM)pstrPath);\n\t}\n\n\tvoid ReceiveIR(LPCTSTR pstrPath) const\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrPath);\n\t\t::SendMessage(m_hWnd, DLM_RECEIVEIR, 0, (LPARAM)pstrPath);\n\t}\n\n\tvoid Refresh()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_REFRESH, 0, 0L);\n\t}\n\n\tBOOL RenameMoveSelectedItems()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_RENAMEMOVE, 0, 0L);\n\t}\n\n\tint SelectAll()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (int)::SendMessage(m_hWnd, DLM_SELECTALL, 0, 0L);\n\t}\n\n\tHRESULT SelectItem(LPCTSTR pstrPath, BOOL bVisible = TRUE)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrPath);\n\t\treturn (HRESULT)::SendMessage(m_hWnd, DLM_SELECTITEM, (WPARAM)bVisible, (LPARAM)pstrPath);\n\t}\n\n\tvoid SendEMail(LPCTSTR pstrAttachment)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_SENDEMAIL, 0, (LPARAM)pstrAttachment);\n\t}\n\n\tvoid SendIR(LPCTSTR pstrPath)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_SENDIR, 0, (LPARAM)pstrPath);\n\t}\n\n\tHRESULT SetFilterIndex(int iIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, DLM_SETFILTERINDEX, (WPARAM)iIndex, 0L);\n\t}\n\n\tvoid SetFolder(LPCTSTR pstrPath)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrPath);\n\t\t::SendMessage(m_hWnd, DLM_SETFOLDER, 0, (LPARAM)pstrPath);\n\t}\n\n\tBOOL SetItemState(int iIndex, const LVITEM* pItem)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pItem);\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)pItem);\n\t}\n\n\tBOOL SetItemState(int iIndex, UINT uState, UINT uMask)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tLVITEM lvi = { 0 };\n\t\tlvi.stateMask = uMask;\n\t\tlvi.state = uState;\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_SETITEMSTATE, (WPARAM)iIndex, (LPARAM)&lvi);\n\t}\n\n\tvoid SetOneItem(int iIndex, LPCVOID pPA)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_SETONEITEM, (WPARAM)iIndex, (LPARAM)pPA);\n\t}\n\n\tvoid SetSelect(int iIndex)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\t::SendMessage(m_hWnd, DLM_SETSELECT, (WPARAM)iIndex, 0L);\n\t}\n\n\tvoid SetSelPathName(LPCTSTR pstrPath)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrPath);\n\t\t::SendMessage(m_hWnd, DLM_SETSELPATHNAME, 0, (LPARAM)pstrPath);\n\t}\n\n\tBOOL SetSortOrder()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_SETSORTORDER, 0, 0L);\n\t}\n\n\tHRESULT Update()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (HRESULT)::SendMessage(m_hWnd, DLM_UPDATE, 0, 0L);\n\t}\n\n\tBOOL ValidateFolder()\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn (BOOL)::SendMessage(m_hWnd, DLM_VALIDATEFOLDER, 0, 0L);\n\t}\n\n// Functions\n\tBOOL GetFirstSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn DocList_GetFirstSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath);\n\t}\n\n\tBOOL GetNextSelectedWaveFile(int* pIndex, LPTSTR szPath, const size_t cchPath)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\treturn DocList_GetNextSelectedWaveFile(m_hWnd, pIndex, szPath, cchPath);\n\t}\n};\n\ntypedef CDocListCtrlT<ATL::CWindow> CDocListCtrl;\n\n#endif // WIN32_PLATFORM_PSPC\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CCapEdit\n\ntemplate <class TBase>\nclass CCapEditT : public TBase\n{\npublic:\n// Constructors\n\tCCapEditT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCCapEditT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = /*TBase*/CWindow::Create(GetWndClassName(), hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call SHInitExtraControls() ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_CAPEDIT;\n\t}\n};\n\ntypedef CCapEditT<WTL::CEdit> CCapEdit;\n\n///////////////////////////////////////////////////////////////////////////////\n// CTTStatic\n\n#ifndef WIN32_PLATFORM_WFSP // Tooltips not supported on SmartPhone\n\ntemplate <class TBase>\nclass CTTStaticT : public TBase\n{\npublic:\n// Constructors\n\tCTTStaticT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCTTStaticT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call SHInitExtraControls() ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_TSTATIC;\n\t}\n\n// Operations\n\tBOOL SetToolTipText(LPCTSTR pstrTipText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrTipText);\n\t\tATLASSERT(lstrlen(pstrTipText) <= 253);\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tint cchLen = lstrlen(pstrTipText) + 3;\n\t\tLPTSTR pstr = buff.Allocate(cchLen);\n\t\tif(pstr == NULL)\n\t\t\treturn FALSE;\n\t\tSecureHelper::strcpy_x(pstr, cchLen, _T(\"~~\"));\n\t\tSecureHelper::strcat_x(pstr, cchLen, pstrTipText);\n\t\treturn SetWindowText(pstr);\n\t}\n};\n\ntypedef CTTStaticT<WTL::CStatic> CTTStatic;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CTTButton\n\ntemplate <class TBase>\nclass CTTButtonT : public TBase\n{\npublic:\n// Constructors\n\tCTTButtonT(HWND hWnd = NULL) : TBase(hWnd)\n\t{ }\n\n\tCTTButtonT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\t\tHWND hWnd = TBase::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);\n\t\tATLASSERT(hWnd != NULL);   // Did you remember to call SHInitExtraControls() ??\n\t\treturn hWnd;\n\t}\n\n// Attributes\n\tstatic LPCTSTR GetWndClassName()\n\t{\n\t\treturn WC_TBUTTON;\n\t}\n\n// Operations\n\tBOOL SetToolTipText(LPCTSTR pstrTipText)\n\t{\n\t\tATLASSERT(::IsWindow(m_hWnd));\n\t\tATLASSERT(pstrTipText);\n\t\tATLASSERT(lstrlen(pstrTipText) <= 253);\n\t\tCTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;\n\t\tint cchLen = lstrlen(pstrTipText) + 3;\n\t\tLPTSTR pstr = buff.Allocate(cchLen);\n\t\tif(pstr == NULL)\n\t\t\treturn FALSE;\n\t\tSecureHelper::strcpy_x(pstr, cchLen, _T(\"~~\"));\n\t\tSecureHelper::strcat_x(pstr, cchLen, pstrTipText);\n\t\treturn SetWindowText(pstr);\n\t}\n};\n\ntypedef CTTButtonT<WTL::CButton> CTTButton;\n\n#endif // !WIN32_PLATFORM_WFSP\n\n\n// --- SmartPhone specific controls ---\n\n#ifdef WIN32_PLATFORM_WFSP\n\n///////////////////////////////////////////////////////////////////////////////\n// CSpinCtrlT - CSpinCtrl : SmartPhone adapted UpDown control\n\ntemplate <class TBase>\nclass CSpinCtrlT : public CUpDownCtrlT< TBase >\n{\npublic:\n// Constructors\n\tCSpinCtrlT(HWND hWnd = NULL) : CUpDownCtrlT< TBase >(hWnd)\n\t{ }\n\n\tCSpinCtrlT< TBase >& operator =(HWND hWnd)\n\t{\n\t\tm_hWnd = hWnd;\n\t\treturn *this;\n\t}\n\n\tHWND Create(HWND hWndParent, HWND hBuddy, DWORD dwStyle, int nID, LPCTSTR szExpandedName = NULL)\n\t{\n\t\tATLASSERT(::IsWindow(hWndParent));\n\t\tCUpDownCtrlT< TBase >::Create(hWndParent, NULL, szExpandedName, dwStyle, 0, nID, NULL);\n\t\tATLASSERT(m_hWnd != NULL);   // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)?\n\t\tif (hBuddy != NULL)\n\t\t{\n\t\t\tATLASSERT(::IsWindow(hBuddy));\n\t\t\tSetBuddy(hBuddy);\n\t\t}\n\t\treturn m_hWnd;\n\t}\n};\n\ntypedef CSpinCtrlT<ATL::CWindow> CSpinCtrl;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CSpinned - SmartPhone association of control and Spin\n\ntemplate <class TBase, bool t_bExpandOnly>\nclass CSpinned : public TBase\n{\npublic:\n\tCSpinCtrl m_SpinCtrl;\n\tDWORD m_dwSpinnedStyle;\n\n// Constructors\n\tCSpinned(HWND hWnd = NULL) : TBase(hWnd)\n\t{\n\t\tm_dwSpinnedStyle = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE;\n\t\t\n\t\tif (t_bExpandOnly == true)\n\t\t\tm_dwSpinnedStyle |= UDS_NOSCROLL;\n\t\telse\n\t\t\tm_dwSpinnedStyle |= UDS_HORZ | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_WRAP;\n\n\t\tif (hWnd != NULL)\n\t\t\tAttachOrCreateSpinCtrl();\n\t}\n\n\tCSpinned<TBase, t_bExpandOnly>& operator =(HWND hWnd)\n\t{\n\t\tAttach(hWnd);\n\t\treturn *this;\n\t}\n\n\tvoid Attach(HWND hWnd)\n\t{\n\t\tATLASSERT(!IsWindow());\n\t\tTBase* pT = static_cast<TBase*>(this);\n\t\tpT->m_hWnd = hWnd;\n\t\tif (hWnd != NULL)\n\t\t\tAttachOrCreateSpinCtrl();\n\t}\n\n\tHWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szExpandedName = NULL,\n\t\t\tDWORD dwStyle = 0, DWORD dwExStyle = 0,\n\t\t\tATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)\n\t{\n\n\t\tTBase* pT = static_cast<TBase*>(this);\n\t\tTBase::Create(hWndParent, rect, NULL, dwStyle, dwExStyle, MenuOrID, lpCreateParam);\n\t\tATLASSERT(pT->m_hWnd != NULL);\n\n\t\tm_SpinCtrl.Create(hWndParent, pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + (int)MenuOrID.m_hMenu, szExpandedName);\n\n\t\tATLASSERT(m_SpinCtrl.m_hWnd != NULL);   // Did you remember to call AtlInitCommonControls(ICC_UPDOWN_CLASS)?\n\n\t\treturn pT->m_hWnd;\n\t}\n\n// Attributes\n\tCSpinCtrl& GetSpinCtrl()\n\t{\n\t\treturn m_SpinCtrl;\n\t}\n\n// Implementation\n\t// Attach our existing SpinCtrl or create one\n\tbool AttachOrCreateSpinCtrl()\n\t{\n\t\tTBase* pT = static_cast<TBase*>(this);\n\n\t\tHWND hSpin = ::GetDlgItem(pT->GetParent(), ATL_IDW_SPIN_ID + pT->GetDlgCtrlID());\n\n\t\tif (hSpin != NULL)\n\t\t{\n\t\t\tm_SpinCtrl.Attach(hSpin);\n#ifdef DEBUG\n\t\t\tTCHAR sClassName[16] = { 0 };\n\t\t\t::GetClassName(hSpin, sClassName, 16);\n\t\t\tATLASSERT(!_tcscmp(sClassName, UPDOWN_CLASS));\n\t\t\tATLASSERT(m_SpinCtrl.GetBuddy().m_hWnd == pT->m_hWnd);\n#endif // DEBUG\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_SpinCtrl.Create(pT->GetParent(), pT->m_hWnd, m_dwSpinnedStyle, ATL_IDW_SPIN_ID + pT->GetDlgCtrlID());\n\t\t}\n\n\t\treturn m_SpinCtrl.m_hWnd != NULL;\n\t}\n};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// CSpinListBox - SmartPhone spinned ListBox control\n// CExpandListBox - SmartPhone expandable ListBox control\n// CExpandEdit - SmartPhone expandable Edit control\n// CExpandCapEdit - SmartPhone expandable CapEdit control\n\ntypedef CSpinned<CListBox, false>   CSpinListBox;\ntypedef CSpinned<CListBox, true>    CExpandListBox;\ntypedef CSpinned<CEdit, true>\t\tCExpandEdit;\ntypedef CSpinned<CCapEdit, true>    CExpandCapEdit;\n\n#endif // WIN32_PLATFORM_WFSP\n\n#endif // _WTL_CE_NO_CONTROLS\n\n}; // namespace WTL\n\n#endif // __ATLWINCE_H__\n"
  },
  {
    "path": "WTL/atlwinx.h",
    "content": "// Windows Template Library - WTL version 9.10\n// Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.\n//\n// This file is a part of the Windows Template Library.\n// The use and distribution terms for this software are covered by the\n// Microsoft Public License (http://opensource.org/licenses/MS-PL)\n// which can be found in the file MS-PL.txt at the root folder.\n\n#ifndef __ATLWINX_H__\n#define __ATLWINX_H__\n\n#pragma once\n\n#ifndef __ATLAPP_H__\n\t#error atlwinx.h requires atlapp.h to be included first\n#endif\n\n#if (_ATL_VER >= 0x0700)\n  #include <atlwin.h>\n#endif // (_ATL_VER >= 0x0700)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Classes in this file:\n//\n// _U_RECT\n// _U_MENUorID\n// _U_STRINGorID\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Command Chaining Macros\n\n#define CHAIN_COMMANDS(theChainClass) \\\n\tif(uMsg == WM_COMMAND) \\\n\t\tCHAIN_MSG_MAP(theChainClass)\n\n#define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \\\n\tif(uMsg == WM_COMMAND) \\\n\t\tCHAIN_MSG_MAP_ALT(theChainClass, msgMapID)\n\n#define CHAIN_COMMANDS_MEMBER(theChainMember) \\\n\tif(uMsg == WM_COMMAND) \\\n\t\tCHAIN_MSG_MAP_MEMBER(theChainMember)\n\n#define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \\\n\tif(uMsg == WM_COMMAND) \\\n\t\tCHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Macros for parent message map to selectively reflect control messages\n\n// NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot\n//  (and overridden in 2 cases - CContainedWindowT and CAxHostWindow)\n//  Since we can't modify ATL, we'll provide the needed additions\n//  in a separate function (that is not a member of CWindowImplRoot)\n\nnamespace WTL\n{\n\ninline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled,\n                                               UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL)\n{\n\tif((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg))\n\t{\n\t\t// The notification message doesn't match the filter.\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tHWND hWndChild = NULL;\n\tUINT_PTR idFrom = 0;\n\n\tswitch(uMsg)\n\t{\n\tcase WM_COMMAND:\n\t\tif(lParam != NULL)\t// not from a menu\n\t\t{\n\t\t\thWndChild = (HWND)lParam;\n\t\t\tidFrom = (UINT_PTR)LOWORD(wParam);\n\t\t}\n\t\tbreak;\n\tcase WM_NOTIFY:\n\t\thWndChild = ((LPNMHDR)lParam)->hwndFrom;\n\t\tidFrom = ((LPNMHDR)lParam)->idFrom;\n\t\tbreak;\n#ifndef _WIN32_WCE\n\tcase WM_PARENTNOTIFY:\n\t\tswitch(LOWORD(wParam))\n\t\t{\n\t\tcase WM_CREATE:\n\t\tcase WM_DESTROY:\n\t\t\thWndChild = (HWND)lParam;\n\t\t\tidFrom = (UINT_PTR)HIWORD(wParam);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\thWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam));\n\t\t\tidFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n#endif // !_WIN32_WCE\n\tcase WM_DRAWITEM:\n\t\tif(wParam)\t// not from a menu\n\t\t{\n\t\t\thWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem;\n\t\t\tidFrom = (UINT_PTR)wParam;\n\t\t}\n\t\tbreak;\n\tcase WM_MEASUREITEM:\n\t\tif(wParam)\t// not from a menu\n\t\t{\n\t\t\thWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID);\n\t\t\tidFrom = (UINT_PTR)wParam;\n\t\t}\n\t\tbreak;\n\tcase WM_COMPAREITEM:\n\t\tif(wParam)\t// not from a menu\n\t\t{\n\t\t\thWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem;\n\t\t\tidFrom = (UINT_PTR)wParam;\n\t\t}\n\t\tbreak;\n\tcase WM_DELETEITEM:\n\t\tif(wParam)\t// not from a menu\n\t\t{\n\t\t\thWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem;\n\t\t\tidFrom = (UINT_PTR)wParam;\n\t\t}\n\t\tbreak;\n\tcase WM_VKEYTOITEM:\n\tcase WM_CHARTOITEM:\n\tcase WM_HSCROLL:\n\tcase WM_VSCROLL:\n\t\thWndChild = (HWND)lParam;\n\t\tidFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);\n\t\tbreak;\n\tcase WM_CTLCOLORBTN:\n\tcase WM_CTLCOLORDLG:\n\tcase WM_CTLCOLOREDIT:\n\tcase WM_CTLCOLORLISTBOX:\n\tcase WM_CTLCOLORMSGBOX:\n\tcase WM_CTLCOLORSCROLLBAR:\n\tcase WM_CTLCOLORSTATIC:\n\t\thWndChild = (HWND)lParam;\n\t\tidFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif((hWndChild == NULL) ||\n\t\t((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild)))\n\t{\n\t\t// Either hWndChild isn't valid, or\n\t\t// hWndChild doesn't match the filter.\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tif((idFromFilter != 0) && (idFromFilter != idFrom))\n\t{\n\t\t// The dialog control id doesn't match the filter.\n\t\tbHandled = FALSE;\n\t\treturn 1;\n\t}\n\n\tATLASSERT(::IsWindow(hWndChild));\n\tLRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);\n\tif((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC))\n\t{\n\t\t// Try to prevent problems with WM_CTLCOLOR* messages when\n\t\t// the message wasn't really handled\n\t\tbHandled = FALSE;\n\t}\n\n\treturn lResult;\n}\n\n}; // namespace WTL\n\n// Try to prevent problems with WM_CTLCOLOR* messages when\n// the message wasn't really handled\n#define REFLECT_NOTIFICATIONS_EX() \\\n{ \\\n\tbHandled = TRUE; \\\n\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\tif((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \\\n\t\tbHandled = FALSE; \\\n\tif(bHandled) \\\n\t\treturn TRUE; \\\n}\n\n#define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::WtlReflectNotificationsFiltered(m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_COMMAND(id, code) \\\n\tif(uMsg == WM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_COMMAND_ID(id) \\\n\tif(uMsg == WM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_COMMAND_CODE(code) \\\n\tif(uMsg == WM_COMMAND && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_COMMAND_RANGE(idFirst, idLast) \\\n\tif(uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \\\n\tif(uMsg == WM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFY(id, cd) \\\n\tif(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFY_ID(id) \\\n\tif(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFY_CODE(cd) \\\n\tif(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFY_RANGE(idFirst, idLast) \\\n\tif(uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \\\n\tif(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = ReflectNotifications(uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Reflected message handler macros for message maps (for ATL 3.0)\n\n#if (_ATL_VER < 0x0700)\n\n#define REFLECTED_COMMAND_HANDLER(id, code, func) \\\n\tif(uMsg == OCM_COMMAND && id == LOWORD(wParam) && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_COMMAND_ID_HANDLER(id, func) \\\n\tif(uMsg == OCM_COMMAND && id == LOWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_COMMAND_CODE_HANDLER(code, func) \\\n\tif(uMsg == OCM_COMMAND && code == HIWORD(wParam)) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_COMMAND_RANGE_HANDLER(idFirst, idLast, func) \\\n\tif(uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_COMMAND_RANGE_CODE_HANDLER(idFirst, idLast, code, func) \\\n\tif(uMsg == OCM_COMMAND && code == HIWORD(wParam) && LOWORD(wParam) >= idFirst  && LOWORD(wParam) <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_NOTIFY_HANDLER(id, cd, func) \\\n\tif(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_NOTIFY_ID_HANDLER(id, func) \\\n\tif(uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_NOTIFY_CODE_HANDLER(cd, func) \\\n\tif(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_NOTIFY_RANGE_HANDLER(idFirst, idLast, func) \\\n\tif(uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#define REFLECTED_NOTIFY_RANGE_CODE_HANDLER(idFirst, idLast, cd, func) \\\n\tif(uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && ((LPNMHDR)lParam)->idFrom >= idFirst && ((LPNMHDR)lParam)->idFrom <= idLast) \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\n#endif // (_ATL_VER < 0x0700)\n\n\n///////////////////////////////////////////////////////////////////////////////\n// Dual argument helper classes (for ATL 3.0)\n\n#if (_ATL_VER < 0x0700)\n\nnamespace ATL\n{\n\nclass _U_RECT\n{\npublic:\n\t_U_RECT(LPRECT lpRect) : m_lpRect(lpRect)\n\t{ }\n\t_U_RECT(RECT& rc) : m_lpRect(&rc)\n\t{ }\n\tLPRECT m_lpRect;\n};\n\nclass _U_MENUorID\n{\npublic:\n\t_U_MENUorID(HMENU hMenu) : m_hMenu(hMenu)\n\t{ }\n\t_U_MENUorID(UINT nID) : m_hMenu((HMENU)LongToHandle(nID))\n\t{ }\n\tHMENU m_hMenu;\n};\n\nclass _U_STRINGorID\n{\npublic:\n\t_U_STRINGorID(LPCTSTR lpString) : m_lpstr(lpString)\n\t{ }\n\t_U_STRINGorID(UINT nID) : m_lpstr(MAKEINTRESOURCE(nID))\n\t{ }\n\tLPCTSTR m_lpstr;\n};\n\n}; // namespace ATL\n\n#endif // (_ATL_VER < 0x0700)\n\n\nnamespace WTL\n{\n\n///////////////////////////////////////////////////////////////////////////////\n// Forward notifications support for message maps (for ATL 3.0)\n\n#if (_ATL_VER < 0x0700)\n\n// forward notifications support\n#define FORWARD_NOTIFICATIONS() \\\n\t{ \\\n\t\tbHandled = TRUE; \\\n\t\tlResult = WTL::Atl3ForwardNotifications(m_hWnd, uMsg, wParam, lParam, bHandled); \\\n\t\tif(bHandled) \\\n\t\t\treturn TRUE; \\\n\t}\n\nstatic LRESULT Atl3ForwardNotifications(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\n{\n\tLRESULT lResult = 0;\n\tswitch(uMsg)\n\t{\n\tcase WM_COMMAND:\n\tcase WM_NOTIFY:\n#ifndef _WIN32_WCE\n\tcase WM_PARENTNOTIFY:\n#endif // !_WIN32_WCE\n\tcase WM_DRAWITEM:\n\tcase WM_MEASUREITEM:\n\tcase WM_COMPAREITEM:\n\tcase WM_DELETEITEM:\n\tcase WM_VKEYTOITEM:\n\tcase WM_CHARTOITEM:\n\tcase WM_HSCROLL:\n\tcase WM_VSCROLL:\n\tcase WM_CTLCOLORBTN:\n\tcase WM_CTLCOLORDLG:\n\tcase WM_CTLCOLOREDIT:\n\tcase WM_CTLCOLORLISTBOX:\n\tcase WM_CTLCOLORMSGBOX:\n\tcase WM_CTLCOLORSCROLLBAR:\n\tcase WM_CTLCOLORSTATIC:\n\t\tlResult = ::SendMessage(::GetParent(hWnd), uMsg, wParam, lParam);\n\t\tbreak;\n\tdefault:\n\t\tbHandled = FALSE;\n\t\tbreak;\n\t}\n\treturn lResult;\n}\n\n#endif // (_ATL_VER < 0x0700)\n\n}; // namespace WTL\n\n#endif // __ATLWINX_H__\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/LICENSE",
    "content": "-----BEGIN PGP SIGNED MESSAGE-----\n\n\n                 ooooo     ooo ooooooooo.   ooooooo  ooooo\n                 `888'     `8' `888   `Y88.  `8888    d8'\n                  888       8   888   .d88'    Y888..8P\n                  888       8   888ooo88P'      `8888'\n                  888       8   888            .8PY888.\n                  `88.    .8'   888           d8'  `888b\n                    `YbodP'    o888o        o888o  o88888o\n\n\n                    The Ultimate Packer for eXecutables\n          Copyright (c) 1996-2000 Markus Oberhumer & Laszlo Molnar\n               http://wildsau.idv.uni-linz.ac.at/mfx/upx.html\n                          http://www.nexus.hu/upx\n                            http://upx.tsx.org\n\n\nPLEASE CAREFULLY READ THIS LICENSE AGREEMENT, ESPECIALLY IF YOU PLAN\nTO MODIFY THE UPX SOURCE CODE OR USE A MODIFIED UPX VERSION.\n\n\nABSTRACT\n========\n\n   UPX and UCL are copyrighted software distributed under the terms\n   of the GNU General Public License (hereinafter the \"GPL\").\n\n   The stub which is imbedded in each UPX compressed program is part\n   of UPX and UCL, and contains code that is under our copyright. The\n   terms of the GNU General Public License still apply as compressing\n   a program is a special form of linking with our stub.\n\n   As a special exception we grant the free usage of UPX for all\n   executables, including commercial programs.\n   See below for details and restrictions.\n\n\nCOPYRIGHT\n=========\n\n   UPX and UCL are copyrighted software. All rights remain with the authors.\n\n   UPX is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer\n   UPX is Copyright (C) 1996-2000 Laszlo Molnar\n\n   UCL is Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer\n\n\nGNU GENERAL PUBLIC LICENSE\n==========================\n\n   UPX and the UCL library are free software; you can redistribute them\n   and/or modify them under the terms of the GNU General Public License as\n   published by the Free Software Foundation; either version 2 of\n   the License, or (at your option) any later version.\n\n   UPX and UCL are distributed in the hope that they will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; see the file COPYING.\n\n\nSPECIAL EXCEPTION FOR COMPRESSED EXECUTABLES\n============================================\n\n   The stub which is imbedded in each UPX compressed program is part\n   of UPX and UCL, and contains code that is under our copyright. The\n   terms of the GNU General Public License still apply as compressing\n   a program is a special form of linking with our stub.\n\n   Hereby Markus F.X.J. Oberhumer and Laszlo Molnar grant you special\n   permission to freely use and distribute all UPX compressed programs\n   (including commercial ones), subject to the following restrictions:\n\n   1. You must compress your program with a completely unmodified UPX\n      version; either with our precompiled version, or (at your option)\n      with a self compiled version of the unmodified UPX sources as\n      distributed by us.\n   2. This also implies that the UPX stub must be completely unmodfied, i.e.\n      the stub imbedded in your compressed program must be byte-identical\n      to the stub that is produced by the official unmodified UPX version.\n   3. The decompressor and any other code from the stub must exclusively get\n      used by the unmodified UPX stub for decompressing your program at\n      program startup. No portion of the stub may get read, copied,\n      called or otherwise get used or accessed by your program.\n\n\nANNOTATIONS\n===========\n\n  - You can use a modified UPX version or modified UPX stub only for\n    programs that are compatible with the GNU General Public License.\n\n  - We grant you special permission to freely use and distribute all UPX\n    compressed programs. But any modification of the UPX stub (such as,\n    but not limited to, removing our copyright string or making your\n    program non-decompressible) will immediately revoke your right to\n    use and distribute a UPX compressed program.\n\n  - UPX is not a software protection tool; by requiring that you use\n    the unmodified UPX version for your proprietary programs we\n    make sure that any user can decompress your program. This protects\n    both you and your users as nobody can hide malicious code -\n    any program that cannot be decompressed is highly suspicious\n    by definition.\n\n  - You can integrate all or part of UPX and UCL into projects that\n    are compatible with the GNU GPL, but obviously you cannot grant\n    any special exceptions beyond the GPL for our code in your project.\n\n  - We want to actively support manufacturers of virus scanners and\n    similar security software. Please contact us if you would like to\n    incorporate parts of UPX or UCL into such a product.\n\n\n\nMarkus F.X.J. Oberhumer                   Laszlo Molnar\nmarkus.oberhumer@jk.uni-linz.ac.at        ml1050@cdata.tvnet.hu\n\nLinz, Austria, 25 Feb 2000\n\n\n\n-----BEGIN PGP SIGNATURE-----\nVersion: 2.6.3ia\nCharset: noconv\n\niQCVAwUBOLaLS210fyLu8beJAQFYVAP/ShzENWKLTvedLCjZbDcwaBEHfUVcrGMI\nwE7frMkbWT2zmkdv9hW90WmjMhOBu7yhUplvN8BKOtLiolEnZmLCYu8AGCwr5wBf\ndfLoClxnzfTtgQv5axF1awp4RwCUH3hf4cDrOVqmAsWXKPHtm4hx96jF6L4oHhjx\nOO03+ojZdO8=\n=CS52\n-----END PGP SIGNATURE-----\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/NEWS",
    "content": "==================================================================\nUser visible changes for UPX\n==================================================================\n\nChanges in 4.1.0 (08 Aug 2023):\n  * ELF: handle shared libraries with more than 2 PT_LOAD segments\n  * bug fixes - see https://github.com/upx/upx/milestone/11\n\nChanges in 4.0.2 (30 Jan 2023):\n  * bug fixes - see https://github.com/upx/upx/milestone/9\n\nChanges in 4.0.1 (16 Nov 2022):\n  * bug fixes - see https://github.com/upx/upx/milestone/8\n\nChanges in 4.0.0 (28 Oct 2022):\n  * Switch to semantic versioning\n  * SECURITY NOTES: emphasize the security context in the docs\n  * Support easy building from source code with CMake\n  * Support easy rebuilding the stubs from source with Podman/Docker\n  * Add integrated doctest C++ testing framework\n  * Add support for EFI files (PE x86; Kornel Pal)\n  * win32/pe and win64/pe: set correct SizeOfHeaders in the PE header\n  * bug fixes - see https://github.com/upx/upx/milestone/6\n  * bug fixes - see https://github.com/upx/upx/milestone/7\n\nChanges in 3.96 (23 Jan 2020):\n  * bug fixes - see https://github.com/upx/upx/milestone/5\n\nChanges in 3.95 (26 Aug 2018):\n  * Flag --android-shlib to work around bad design in Android\n  * Flag --force-pie when ET_DYN main program is not marked as DF_1_PIE\n  * Better compatibility with varying layout of address space on Linux\n  * Support for 4 PT_LOAD layout in ELF generated by binutils-2.31\n  * bug fixes, particularly better diagnosis of malformed input\n  * bug fixes - see https://github.com/upx/upx/milestone/4\n\nChanges in 3.94 (12 May 2017):\n  * Add support for arm64-linux (aka \"aarch64\").\n  * Add support for --lzma compression on 64-bit PowerPC (Thierry Fauck).\n  * For Mach, \"upx -d\" will unpack a prefix of the file (and warn).\n  * Various improvements to the ELF formats.\n  * bug fixes - see https://github.com/upx/upx/milestone/3\n\nChanges in 3.93 (29 Jan 2017):\n  * Fixed some win32/pe and win64/pe regressions introduced in 3.92\n  * bug fixes - see https://github.com/upx/upx/milestone/2\n\nChanges in 3.92 (11 Dec 2016):\n  * INFO: UPX has moved to GitHub - the new home page is https://upx.github.io\n  * IMPORTANT: all PE formats: internal changes: reunited the diverged source\n    files - please report all regressions into the bug tracker and try UPX 3.91\n    in case of problems.\n  * Support Apple MacOS 10.12 \"Sierra\", including more-robust de-compression.\n  * Explicitly diagnose Go-language bad PT_LOAD; recommend hemfix.c.\n    https://sourceforge.net/p/upx/bugs/195/   https://github.com/pwaller/goupx\n  * Fix CERT-FI Case 829767 UPX command line tools segfaults.\n    Received by UPX Team on 2015-May-08; originally reported\n    by Codenomicon to NCSC-FI on 2015-01-08.\n    The vulnerabilities were discovered by Joonas Kuorilehto and\n    Antti Häyrynen from Codenomicon.\n  * bug fixes - see https://github.com/upx/upx/milestone/1\n\nChanges in 3.91 (30 Sep 2013):\n  * Added experimental support for Windows 64-bit PE files, based on\n    work by Stefan Widmann. Please use for testing only!\n  * bug fixes\n\n==================================================================\n\nChanges in 3.09 (18 Feb 2013):\n  * New option --preserve-build-id for GNU ELF.\n  * Allow for code signing and LC_UUID on Mac OS X executables.\n  * Allow non-contiguous LC_SEGMENTs and 0==.vmsize for Mach-O.\n  * Allow zero-filled final page in PackUnix::canUnpack().\n  * bug fixes\n\nChanges in 3.08 (12 Dec 2011):\n  * Fix allocation in runtime stub for darwin.macho-entry (i386 and amd64).\n  * Compress shared library on ELF i386 only [ld.so threatens even this case].\n  * Attempt to support ELF on QNX 6.3.0 for armel (experimental).\n  * Better diagnostic when ELF -fPIC is needed.\n  * PT_NOTE improvements for BSD.\n  * Preserve more ELF .e_flags on ARM.\n  * Minor code improvements for ELF stubs.\n  * Defend against another flavor of corrupt PE header.\n  * bug fixes\n\nChanges in 3.07 (08 Sep 2010):\n  * win32/pe: fixed relocation handling for files with *no* TLS callbacks\n    [severe bug introduced in 3.06]\n\nChanges in 3.06 (04 Sep 2010):\n  * win32/pe: TLS callback support contributed by Stefan Widmann. Thanks!\n  * bug fixes\n\nChanges in 3.05 (27 Apr 2010):\n  * i386-linux and amd64-linux support shared libraries (DT_INIT must\n    exist, all info needed by runtime loader must be first in .text, etc.)\n  * Linux /proc/self/exe now is preserved by default, by leaving behind\n    one page.  New compress-time option --unmap-all-pages is available.\n  * Withdraw support for shared libraries on Darwin (Apple Mac OS X)\n    because upx does not understand enough about .dylib.\n  * bug fixes\n\nChanges in 3.04 (27 Sep 2009):\n  * new format Mach/AMD64 supports 64-bit programs on Apple Macintosh.\n  * new formats Dylib/i386 and Dylib/ppc32 support shared libraries\n    [such as browser plugins] on Darwin (Apple Macintosh).  An existing\n    -init function (LC_ROUTINES command) is required.\n  * new format vmlinuz/armel for Debian NSLU2 (etc.) linux kernel\n  * bvmlinuz boot protocol 2.08 for 386 Linux kernel\n  * Extended ABI version 4 for armel-eabi ARM Linux ELF\n  * bug fixes\n\nChanges in 3.03 (27 Apr 2008):\n  * implement cache flushing for PowerPC (esp. model 440)\n  * fix cache flushing on MIPS (>3 MiB compressed, or with holes)\n  * fix MIPS big-endian\n  * bug fixes\n\nChanges in 3.02 (16 Dec 2007):\n  * fix unmapping on arm-linux.elf\n  * fix error checking in mmap for i386-linux.elf [triggered by -fPIE]\n  * bug fixes\n\nChanges in 3.01 (31 Jul 2007):\n  * new options --no-mode, --no-owner and --no-time to disable preservation\n    of mode (file permissions), file ownership and timestamps.\n  * dos/exe: fixed an incorrect error message caused by a bug in\n    relocation handling\n  * new format linux/mipsel supports ELF on [32-bit] R3000\n  * fix argv[0] on PowerPC with --lzma\n  * bug fixes\n\nChanges in 3.00 (27 Apr 2007):\n  * watcom/le & tmt/adam: fixed a problem when using certain filters\n\nChanges in 2.93 beta (08 Mar 2007):\n  * new formats Mach/i386 and Mach/fat support Mac OS X i686 and\n    Universal binaries [i686 and PowerPC only]\n  * dos/exe: LZMA is now also supported for 16-bit dos/exe. Please note that\n    you have to explicitly use '--lzma' even for '--ultra-brute' here\n    because runtime decompression is about 30 times slower than NRV -\n    which is really noticeable on old machines.\n  * dos/exe: fixed a rarely occurring bug in relocation handling\n  * win32/pe & arm/pe: better icon compression handling\n\nChanges in 2.92 beta (23 Jan 2007):\n  * new option '--ultra-brute' which tries even more variants\n  * slightly improved compression ratio for some files when\n    using '--brute' or '--ultra-brute'\n  * bug fixes\n\nChanges in 2.91 beta (29 Nov 2006):\n  * assorted bug fixes\n  * wince/arm: fix \"missing\" icon & version info resource problem for WinCE 5\n  * win32/pe & arm/pe: added option --compress-icons=3 to compress all icons\n\nChanges in 2.90 beta (08 Oct 2006):\n  * LZMA algorithm support for most of the 32-bit and 64-bit file formats;\n    use new option '--lzma' to enable\n  * new format: BSD/elf386 supporting FreeBSD, NetBSD and OpenBSD\n    via auto-detection of PT_NOTE or EI_OSABI\n  * arm/pe: all the NRV compression methods are now supported\n    (only NRV2D is missing in thumb mode)\n  * linux/elf386, linux/ElfAMD: remember /proc/self/exe in environment\n  * major source code changes: the runtime decompression stubs are now\n    built from internal ELF objects\n\n==================================================================\n\nChanges in 2.03 (07 Nov 2006):\n  * bvmlinuz/386: fix for kernels not at 0x100000; also allow x86_64\n  * linux/elf386: work around Linux kernel bug (0-length .bss needs PF_W)\n\nChanges in 2.02 (13 Aug 2006):\n  * linux/386: work around Linux kernel bug (\".bss\" requires PF_W)\n  * linux/ppc32, mach/ppc32: compressed programs now work on a 405 CPU\n  * vmlinuz/386: fixed zlib uncompression problem on DOS\n\nChanges in 2.01 (06 Jun 2006):\n  * arm/pe: better DLL support\n  * dos/exe: device driver support added\n  * linux/386: Fix --force-execve for PaX, grSecurity, and strict SELinux.\n    /tmp must support execve(); therefore /tmp cannot be mounted 'noexec'.\n  * win32/pe & arm/pe: added new option '--keep-resource=' for\n    excluding selected resources from compression\n\nChanges in 2.00 (27 Apr 2006):\n  * linux/386: the stub now prints an error message if some strict\n    SELinux mode does prevent runtime decompression and execution\n    (for a fully SELinux-compatible but otherwise inferior compression\n    format you can use the '--force-execve' option)\n  * linux/386: worked around a problem where certain Linux kernels\n    clobber the %ebx register during a syscall\n  * win32/pe: disable filters for files with broken PE headers\n\nChanges in 1.96 beta (13 Apr 2006):\n  * arm/pe: added filter support\n  * win32/pe: removed an unnecessary check so that Delphi 2006 and\n    Digital Mars C++ programs finally are supported\n\nChanges in 1.95 beta (09 Apr 2006):\n  * arm/pe: added DLL support\n  * arm/pe: added thumb mode stub support\n  * arm/pe: added unpacking support\n  * win32/pe: really worked around R6002 runtime errors\n\nChanges in 1.94 beta (11 Mar 2006):\n  * new format: added support for wince/arm (ARM executables running on WinCE)\n  * new format: added support for linux elf/amd64\n  * new format: added support for linux elf/ppc32\n  * new format: added support for mach/ppc32 (Apple Mac OS X)\n  * win32/pe: hopefully working \"load config\" support\n  * win32/pe: R6002 runtime errors worked around\n  * win32/pe: the stub now clears the dirty stack\n\nChanges in 1.93 beta (07 Feb 2005):\n  * vmlinuz/386: fixes to support more kernels\n\nChanges in 1.92 beta (20 Jul 2004):\n  * win32/pe: added option '--strip-loadconf' to strip the SEH load\n    config section [NOTE: this option is obsolete since UPX 1.94]\n  * win32/pe: try to detect .NET (win32/net) files [not yet supported by UPX]\n  * vmlinux/386: new format that directly supports building Linux kernels\n  * source code: now compiles cleanly under Win64\n\nChanges in 1.91 beta (30 Jun 2004):\n  * djgpp2/coff: added support for recent binutils versions\n  * linux/elf386, linux/sh386: lots of improvements\n  * vmlinuz/386: added support for recent kernels\n  * watcom/le: don't crash on files without relocations\n  * win32/pe: stricter checks of some PE values\n  * option '--brute' now implies '--crp-ms=999999'.\n  * source code: much improved portability using ACC, the\n    Automatic Compiler Configuration\n  * source code: compile fixes for strict ISO C++ compilers\n  * source code: compile fixes for Win64\n  * re-synced with upx 1.25 branch\n\nChanges in 1.90 beta (11 Nov 2002):\n  * implemented several new options for finer compression control:\n    '--all-methods', '--all-filters' and '--brute'\n  * ps1/exe: new format - UPX now supports PlayStation One programs\n  * linux/386: added the option '--force-execve'\n  * vmlinuz/386: better kernel detection and sanity checks\n  * re-synced with upx 1.24 branch\n  * documentation updates\n\nChanges in 1.11 beta (20 Dec 2000):\n  * vmlinuz/386: new format - UPX now supports bootable linux kernels\n  * linux/elf386: added the new ELF direct-to-memory executable format - no\n    more temp files are needed for decompression!\n  * linux/sh386: added the new shell direct-to-memory executable format - no\n    more temp files are needed for decompression!\n  * reduced overall memory requirements during packing\n  * quite a number of internal source code rearrangements\n\n==================================================================\n\nChanges in 1.25 (29 Jun 2004)\n  * INFO: http://upx.sourceforge.net is the new UPX home page\n  * watcom/le: don't crash on files without relocations\n  * win32/pe: stricter checks of some PE values\n  * source code: much improved portability using ACC, the\n    Automatic Compiler Configuration\n  * source code: compile fixes for strict ISO C++ compilers\n  * source code: compile fixes for Win64\n\nChanges in 1.24 (07 Nov 2002)\n  * djgpp2/coff: stricter check of the COFF header to work around a\n    problem with certain binutils versions\n\nChanges in 1.23 (05 Sep 2002)\n  * atari/tos: fixed an unpacking problem where a buffer was too\n    small (introduced in 1.22)\n  * linux/386: don't give up too early if a single block turns out\n    to be incompressible\n  * documentation: added some quick tips how to achieve the best\n    compression ratio for the final release of your application\n  * fixed a rare situation where the exit code was not set correctly\n\nChanges in 1.22 (27 Jun 2002)\n  * atari/tos: the stub now flushes the CPU cache to avoid\n    problems on 68030+ machines\n  * source code: additional compiler support for Borland C++,\n    Digital Mars C++ and Watcom C++\n\nChanges in 1.21 (01 Jun 2002)\n  * New option '--crp-ms=' for slightly better compression at the cost\n    of higher memory requirements during compression.\n    Try 'upx --best --crp-ms=100000'. See the docs for more info.\n  * source code: portability fixes\n  * source code: compile fixes for g++ 3.0 and g++ 3.1\n\nChanges in 1.20 (23 May 2001)\n  * slightly faster compression\n  * work around a gcc problem in the latest djgpp2 distribution\n  * watcom/le: fixed detection of already compressed files\n  * win32/pe: do not compress RT_MANIFEST resource types\n  * win32/pe: improved the error message for empty resource sections\n  * [NOTE: the jump from 1.08 to 1.20 is to avoid confusion with\n           our unstable development releases 1.1x and 1.9x]\n\nChanges in 1.08 (30 Apr 2001)\n  * new native port to atari/tos\n  * win32/pe: shortened the identstring\n  * source code: portability fixes - UPX now builds cleanly under m68k CPUs\n\nChanges in 1.07 (20 Feb 2001)\n  * win32/pe: corrected the TLS callback check\n  * win32/pe: really fixed that rare bug in relocation handling\n  * win32/pe: experimental support for SizeOfHeaders > 0x1000\n  * win32/pe: check for superfluous data between sections\n  * win32/pe: compressing screensavers (.scr) should finally work\n\nChanges in 1.06 (27 Jan 2001)\n  * win32/pe: the check for TLS callbacks introduced in 1.05\n      was too strict - disabled for now\n  * dos/com: decreased the decompressor stack size a little bit\n\nChanges in 1.05 (24 Jan 2001)\n  * win32/pe: refuse to compress programs with TLS callbacks\n  * win32/pe: stub changes to avoid slowdowns with some virus monitors\n  * win32/pe: reverted the relocation handling changes in 1.04\n  * linux/386: dont try to compress Linux kernel images (have a look\n      at the unstable UPX 1.1x beta versions for that)\n\nChanges in 1.04 (19 Dec 2000)\n  * dos/exe: fixed an internal error when using '--no-reloc'\n  * win32/pe: fixed a rare bug in the relocation handling code\n  * some tunings for the default compression level\n\nChanges in 1.03 (30 Nov 2000)\n  * linked with a new version of the NRV compression library:\n      - improved compression ratio a little bit\n      - overall significantly faster compression\n      - much faster when using high compression levels like '-9' or '--best'\n      - much faster with large files\n  * atari/tos: added support for FreeMiNT\n  * the 32-bit DOS version now uses the new CWSDSTUB extender\n\nChanges in 1.02 (13 Sep 2000)\n  * watcom/le: fixed a problem with the Causeway extender\n  * win32/pe: don't automatically strip relocs if they seem needed\n  * support multiple backup generations when using '-k'\n  * updated the console screen driver\n\nChanges in 1.01 (09 Apr 2000)\n  * win32/pe: fixed an uncompression problem in DLLs with empty\n    fixup sections\n  * win32/pe: fixed another rare uncompression problem - a field in the\n    PE header was set incorrectly\n\nChanges in 1.00 (26 Mar 2000)\n  * documentation updates\n  * watcom/le: do not duplicate the non-resident name table\n  * win32/pe: fixed an import handling problem: sometimes too much data\n    could be deleted from a file -> the uncompressed file would not work\n    anymore\n\nChanges in 0.99.3 (07 Mar 2000)\n  * win32/pe: fixed a rare problem in the stub string handling part\n\nChanges in 0.99.2 (02 Mar 2000)\n  * dos/exe: fixed a typo causing an internal error (introduced in 0.99.1)\n\nChanges in 0.99.1 (29 Feb 2000)\n  * win32/pe: fixed some object alignments which were causing\n    problems when loading compressed DLLs under Windows NT/2000\n\nChanges in 0.99 (25 Feb 2000)\n  * FULL SOURCE CODE RELEASED UNDER THE TERMS OF THE GNU GPL\n  * win32/pe: changed default to '--strip-relocs=1'\n  * dos/com and dos/sys: fixed a bad decompressor problem\n  * linux/386: the counter for the progress indicator was off by one\n\n==================================================================\n\nChanges in 0.94 (06 Dec 1999)\n  * win32/pe: the stub now calls ExitProcess in case of import errors\n  * under DOS and Windows, the environment variable UPX now accepts\n    a '#' as replacement for '=' because of a COMMAND.COM limitation\n\nChanges in 0.93 (22 Nov 1999)\n  * win32/pe: fixed --strip-relocs problem with uncompression\n  * win32/pe: fixed a bug which could produce a broken decompressor stub\n  * linux/386: yet another FreeBSD compatibility fix\n\nChanges in 0.92 (14 Nov 1999)\n  * win32/pe: really fixed that one line (see below)\n\nChanges in 0.91 (13 Nov 1999)\n  * win32/pe: an important one-line fix for the newly introduced problems\n  * dos/com and dos/sys: fixed an internal error\n  * dos/exe: correctly restore cs when uncompressing\n\nChanges in 0.90 (10 Nov 1999)\n  * all formats: '--overlay=copy' now is the default overlay mode\n  * improved compression ratio for most files\n  * win32/pe: uncompression is finally supported\n  * win32/pe: never compress REGISTRY resources\n  * win32/pe: headersize was not set in PE header\n  * win32/pe: resource handling is rewritten\n  * win32/pe: the last :-) TLS problem is fixed\n  * win32/pe: somewhat less memory is required during compression\n  * linux/386: fixed compression of scripts which was broken since 0.71\n  * linux/386: more FreeBSD compatibility issues\n  * changed option: '-i' now prints some more details during compression\n    (not finished yet)\n\nChanges in 0.84 (04 Oct 1999)\n  * dos/exe: fixed a rare problem where the decompressor could crash\n  * some other minor fixes\n\nChanges in 0.83 (17 Sep 1999)\n  * dos/exe: fixed minimal memory requirement problem for some files\n  * win32/pe: fixed a bug which caused a crash in some compressed files\n  * linux/386: various improvements in the stub; also, for the sake\n    of FreeBSD users, the stub is now branded as Linux/ELF\n\nChanges in 0.82 (16 Aug 1999)\n  * dos/exe: fixed a decompressor bug which could cause crash on some files\n  * linux/386: section headers are now stripped from the stub so that\n    'strip' won't ruin a compressed file any longer\n  * wc/le: support for stack not in the last object disabled again\n  * win32/pe: removed some unneeded data\n\nChanges in 0.81 (04 Aug 1999)\n  * win32/pe: fixed an important bug in import handling\n  * dos/com: fixed an internal error that could happen with very small files\n\nChanges in 0.80 (03 Aug 1999)\n  * you can set some default options in the environment var 'UPX'\n  * dos/com: the decompressor stub now checks for enough free memory\n  * dos/exe: decompressor rewritten, some bugs are fixed\n  * dos/exe: new option '--no-reloc': no relocation data is put into\n    the DOS header\n  * tmt/adam: added support for more stubs, detect already packed files\n  * tmt/adam: new option '--copy-overlay'\n  * wc/le: reduced memory requirement during uncompression\n  * wc/le: support files which do not contain their stack in the last object\n  * wc/le: fixed a bug which could cause a crash, improved relocation\n    handling\n  * wc/le: new option '--copy-overlay'\n  * win32/pe: '--compress-icons=2' is now the default\n  * win32/pe: even better TLS support\n  * win32/pe: versioninfo works on NT\n  * win32/pe: import by ordinal from kernel32.dll works\n  * win32/pe: other import improvements: importing a nonexistent DLL\n    results in a usual Windows message, importing a nonexistent function\n    results in program exit (instead of crash ;-)\n  * win32/pe: new option: '--compress-resources=0'\n  * win32/pe: reduced memory requirement during uncompression, some\n    files might even require LESS memory when they're compressed\n  * win32/pe: TYPELIBs should work now\n  * win32/pe: improved relocation handling, 16-bit relocations should work\n  * win32/pe: new option '--strip-relocs' (only if you know what you are doing)\n  * win32/pe: new option '--copy-overlay'\n  * important internal changes: now the stubs are built at runtime\n\nChanges in 0.72 (12 May 1999)\n  * tmt/adam: fixed a serious problem in the decompressor stub; all\n    compressed tmt files should be recompressed\n  * win32/pe: fixed the 'shared sections not supported' warning:\n    read-only shared sections are fine\n  * win32/pe: never compress TYPELIB resources\n  * win32/pe: compressed files are hopefully less suspicious to heuristic\n    virus scanners now\n  * linux/386: minor decompressor stub updates, nicer progress bar\n\nChanges in 0.71 (19 Apr 1999)\n  * dos/exe: added option '--no-overlay'\n  * linux/386: various improvements in the stub, most notably the\n    overhead for an extra cleanup process has been removed\n  * win32/pe: added support for export forwarders\n  * win32/pe: added support for DLLs without entry point or imports\n  * win32/pe: yet another .bss fix\n  * win32/pe: new option '--compress-icons=2': compress all icons\n    which are not in the first icon directory\n  * win32/pe: rearranged stub to avoid false alerts from some virus scanners\n\nChanges in 0.70 (30 Mar 1999)\n  * added support for linux/386 executables\n  * improved compression ratio quite a bit\n  * added new compression level '--best' to squeeze out even some more bytes\n  * win32/pe: TLS support is much better now\n  * win32/pe: --compress-icons=0 should now work as well\n  * the usual minor fixes for win32/pe\n\nChanges in 0.62 (16 Mar 1999)\n  * win32/pe: --compress-icons and --compress-exports are on now by default\n  * win32/pe: --compress-icons should really work now\n  * win32/pe: fixed a problem with embedded .bss sections\n\nChanges in 0.61 (08 Mar 1999)\n  * atari/tos: fixed a problem where the bss segment could become too small\n\nChanges in 0.60 (06 Mar 1999)\n  * win32/pe: fixed file corruption when the size of the export data is invalid\n  * win32/pe: fixed a problem with empty resource data\n  * win32/pe: compressed file alignment set to minimum value\n  * win32/pe: made all compressed sections writable\n  * fixed some other win32/pe bugs\n  * fixed an address optimization problem for some not Watcom LE files\n  * fixed a bug which could make UPX hang when an exe header contained\n    an illegal value\n  * added some compression flags for the win32/pe format\n  * added support for Atari ST/TT executables (atari/tos)\n  * improved compression ratio\n  * improved compression speed\n\nChanges in 0.51 (14 Jan 1999)\n  * fixed a small bug in the PE header that would prevent some compressed\n    win32/pe executables from running under Windows NT and WINE\n\nChanges in 0.50 (03 Jan 1999)\n  * added support for PE format executables (win32/pe & rtm32/pe)\n  * added support for TMT executables (tmt/adam)\n  * fixed a dos/sys bug that affected OpenDOS\n\nChanges in 0.40 (05 Oct 1998)\n  * improved compression ratio\n  * fixed a small but fatal bug in dos/sys introduced in 0.30\n  * fixed a rare bug in dos/exe\n  * worked around a bug in djgpp's strip 2.8\n  * djgpp2/coff: Allegro packfile support should work now\n  * added dos/exeh compression method (works on 386+)\n\nChanges in 0.30 (27 Jul 1998)\n  * fixed a serious bug in the 32-bit compressors - please don't use\n    djgpp2/coff and watcom/le compressed files from previous versions,\n    some of them are possibly damaged !\n  * the 16-bit uncompressors are a little bit shorter & faster\n  * fixed progress indicator for VESA and SVGA text modes\n\nChanges in 0.20 (05 Jul 1998)\n  * second public beta release\n  * too many changes to list here\n\nChanges in 0.05 (26 May 1998)\n  * first public beta release\n  * based on experience gained from our previous packers DJP (djgpp2/coff, 1996),\n    lzop (1996) and mfxpak (atari/tos, 1990)\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/README",
    "content": "                 ooooo     ooo  ooooooooo.  ooooooo  ooooo\n                 `888'     `8'  `888   `Y88. `8888    d8'\n                  888       8    888   .d88'   Y888..8P\n                  888       8    888ooo88P'     `8888'\n                  888       8    888           .8PY888.\n                  `88.    .8'    888          d8'  `888b\n                    `YbodP'     o888o       o888o  o88888o\n\n\n                    The Ultimate Packer for eXecutables\n   Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser\n                           https://upx.github.io\n\n\n\nWELCOME\n=======\n\nWelcome to UPX !\n\nUPX is a free, secure, portable, extendable, high-performance\nexecutable packer for several executable formats.\n\n\nINTRODUCTION\n============\n\nUPX is an advanced executable file compressor. UPX will typically\nreduce the file size of programs and DLLs by around 50%-70%, thus\nreducing disk space, network load times, download times and\nother distribution and storage costs.\n\nPrograms and libraries compressed by UPX are completely self-contained\nand run exactly as before, with no runtime or memory penalty for most\nof the supported formats.\n\nUPX supports a number of different executable formats, including\nWindows programs and DLLs, macOS apps and Linux executables.\n\nUPX is free software distributed under the term of the GNU General\nPublic License. Full source code is available.\n\nUPX may be distributed and used freely, even with commercial applications.\nSee the UPX License Agreements for details.\n\n\nSECURITY CONTEXT\n================\n\nIMPORTANT NOTE: UPX inherits the security context of any files it handles.\n\nThis means that packing, unpacking, or even testing or listing a file requires\nthe same security considerations as actually executing the file.\n\nUse UPX on trusted files only!\n\n\nSHORT DOCUMENTATION\n===================\n\n'upx program.exe' will compress a program or DLL. For best compression\nresults try 'upx --best program.exe' or 'upx --brute program.exe'.\n\nPlease see the file UPX.DOC for the full documentation. The files\nNEWS and BUGS also contain various tidbits of information.\n\n\nTHE FUTURE\n==========\n\n  - Stay up-to-date with ongoing OS and executable format changes\n\n  - RISC-V 64 for Linux\n\n  - ARM64 for Windows (help wanted)\n\n  - We will *NOT* add any sort of protection and/or encryption.\n    This only gives people a false feeling of security because\n    all \"protectors\" can be broken by definition.\n\n  - Fix all remaining bugs - please report any issues\n    https://github.com/upx/upx/issues\n\n\nCOPYRIGHT\n=========\n\nCopyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\nCopyright (C) 1996-2023 Laszlo Molnar\nCopyright (C) 2000-2023 John F. Reiser\n\nUPX is distributed with full source code under the terms of the\nGNU General Public License v2+; either under the pure GPLv2+ (see\nthe file COPYING), or (at your option) under the GPLv+2 with special\nexceptions and restrictions granting the free usage for all binaries\nincluding commercial programs (see the file LICENSE).\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nYou should have received a copy of the UPX License Agreements along\nwith this program; see the files COPYING and LICENSE. If not,\nvisit the UPX home page.\n\n\nShare and enjoy,\nMarkus & Laszlo & John\n\n\n   Markus F.X.J. Oberhumer              Laszlo Molnar\n   <markus@oberhumer.com>               <ezerotven+github@gmail.com>\n\n   John F. Reiser\n   <jreiser@BitWagon.com>\n\n\n[ The term UPX is a shorthand for the Ultimate Packer for eXecutables\n  and holds no connection with potential owners of registered trademarks\n  or other rights. ]\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/THANKS.txt",
    "content": "                 ooooo     ooo  ooooooooo.  ooooooo  ooooo\n                 `888'     `8'  `888   `Y88. `8888    d8'\n                  888       8    888   .d88'   Y888..8P\n                  888       8    888ooo88P'     `8888'\n                  888       8    888           .8PY888.\n                  `88.    .8'    888          d8'  `888b\n                    `YbodP'     o888o       o888o  o88888o\n\n\n                    The Ultimate Packer for eXecutables\n   Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser\n                           https://upx.github.io\n\n\n.___..        .\n  |  |_  _.._ ;_/ __\n  |  [ )(_][ )| \\_)\n--------------------\n\nUPX would not be what it is today without the invaluable help of\neverybody who was kind enough to spend time testing it, using it\nin applications and reporting bugs.\n\nThe following people made especially gracious contributions of their\ntime and energy in helping to track down bugs, add new features, and\ngenerally assist in the UPX maintainership process:\n\nAdam Ierymenko <api@one.net>\n  for severals ideas for the Linux version\nAndi Kleen <ak@muc.de> and Jamie Lokier <nospam@cern.ch>\n  for the /proc/self/fd/X and other Linux suggestions\nAndreas Muegge <andreas.muegge@gmx.de>\n  for the Win32 GUI\nAtli Mar Gudmundsson <agudmundsson@symantec.com>\n  for several comments on the win32/pe stub\nCharles W. Sandmann <sandmann@clio.rice.edu>\n  for the idea with the stubless decompressor in djgpp2/coff\nIce\n  for debugging the PE headersize problem down\nJoergen Ibsen <jibz@hotmail.com> and d'b\n  for the relocation & address optimization ideas\nJohn S. Fine <johnfine@erols.com>\n  for the new version of the dos/exe decompressor\nKornel Pal\n  for the EFI support\nLukundoo <Lukundoo@softhome.net>\n  for beta testing\nMichael Devore\n  for initial dos/exe device driver support\nOleg V. Volkov <rover@lglobus.ru>\n  for various FreeBSD specific information\nThe Owl & G-RoM\n  for the --compress-icons fix\nRalph Roth <RalphRoth@gmx.net>\n  for reporting several bugs\nSalvador Eduardo Tropea\n  for beta testing\nStefan Widmann\n  for the win32/pe TLS callback support\nThe WINE project (https://www.winehq.com/)\n  for lots of useful information found in their PE loader sources\nNatascha\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/upx-doc.html",
    "content": "<?xml version=\"1.0\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>upx - compress or expand executable files</title>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n<link rev=\"made\" href=\"mailto:root@localhost\" />\n</head>\n\n<body>\n\n\n\n<h1 id=\"NAME\">NAME</h1>\n\n<p>upx - compress or expand executable files</p>\n\n<h1 id=\"SYNOPSIS\">SYNOPSIS</h1>\n\n<p><b>upx</b> <span style=\"white-space: nowrap;\">[ <i>command</i> ]</span> <span style=\"white-space: nowrap;\">[ <i>options</i> ]</span> <i>filename</i>...</p>\n\n<h1 id=\"ABSTRACT\">ABSTRACT</h1>\n\n<pre><code>                 The Ultimate Packer for eXecutables\nCopyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar &amp; John Reiser\n                        https://upx.github.io</code></pre>\n\n<p><b>UPX</b> is a portable, extendable, high-performance executable packer for several different executable formats. It achieves an excellent compression ratio and offers <i>*very*</i> fast decompression. Your executables suffer no memory overhead or other drawbacks for most of the formats supported, because of in-place decompression.</p>\n\n<h1 id=\"DISCLAIMER\">DISCLAIMER</h1>\n\n<p><b>UPX</b> comes with ABSOLUTELY NO WARRANTY; for details see the file COPYING.</p>\n\n<p>Please report all problems or suggestions to the authors. Thanks.</p>\n\n<h1 id=\"SECURITY-CONTEXT\">SECURITY CONTEXT</h1>\n\n<p>IMPORTANT NOTE: <b>UPX</b> inherits the security context of any files it handles.</p>\n\n<p>This means that packing, unpacking, or even testing or listing a file requires the same security considerations as actually executing the file.</p>\n\n<p>Use <b>UPX</b> on trusted files only!</p>\n\n<h1 id=\"DESCRIPTION\">DESCRIPTION</h1>\n\n<p><b>UPX</b> is a versatile executable packer with the following features:</p>\n\n<pre><code>- secure: as UPX is documented Open Source since many years any relevant\n    Security/Antivirus software is able to peek inside UPX compressed\n    apps to verify them\n\n- excellent compression ratio: typically compresses better than Zip,\n    use UPX to decrease the size of your distribution !\n\n- very fast decompression: more than 500 MB/sec on any reasonably modern\n    machine\n\n- no memory overhead for your compressed executables for most of the\n    supported formats because of in-place decompression\n\n- safe: you can list, test and unpack your executables.\n    Also, a checksum of both the compressed and uncompressed file is\n    maintained internally.\n\n- universal: UPX can pack a number of executable formats, including\n    Windows programs and DLLs, macOS apps and Linux executables\n\n- portable: UPX is written in portable endian-neutral C++\n\n- extendable: because of the class layout it&#39;s very easy to support\n    new executable formats or add new compression algorithms\n\n- free: UPX is distributed with full source code under the GNU General\n    Public License v2+, with special exceptions granting the free usage\n    for commercial programs</code></pre>\n\n<p>You probably understand now why we call <b>UPX</b> the &quot;<i>ultimate</i>&quot; executable packer.</p>\n\n<h1 id=\"COMMANDS\">COMMANDS</h1>\n\n<h2 id=\"Compress\">Compress</h2>\n\n<p>This is the default operation, eg. <b>upx yourfile.exe</b> will compress the file specified on the command line.</p>\n\n<h2 id=\"Decompress\">Decompress</h2>\n\n<p>All <b>UPX</b> supported file formats can be unpacked using the <b>-d</b> switch, eg. <b>upx -d yourfile.exe</b> will uncompress the file you&#39;ve just compressed.</p>\n\n<h2 id=\"Test\">Test</h2>\n\n<p>The <b>-t</b> command tests the integrity of the compressed and uncompressed data, eg. <b>upx -t yourfile.exe</b> check whether your file can be safely decompressed. Note, that this command doesn&#39;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.</p>\n\n<h2 id=\"List\">List</h2>\n\n<p>The <b>-l</b> command prints out some information about the compressed files specified on the command line as parameters, eg <b>upx -l yourfile.exe</b> shows the compressed / uncompressed size and the compression ratio of <i>yourfile.exe</i>.</p>\n\n<h1 id=\"OPTIONS\">OPTIONS</h1>\n\n<p><b>-q</b>: be quiet, suppress warnings</p>\n\n<p><b>-q -q</b> (or <b>-qq</b>): be very quiet, suppress errors</p>\n\n<p><b>-q -q -q</b> (or <b>-qqq</b>): produce no output at all</p>\n\n<p><b>--help</b>: prints the help</p>\n\n<p><b>--version</b>: print the version of <b>UPX</b></p>\n\n<p><b>--exact</b>: when compressing, require to be able to get a byte-identical file after decompression with option <b>-d</b>. [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.]</p>\n\n<p><b>-k</b>: keep backup files</p>\n\n<p><b>-o file</b>: write output to file</p>\n\n<p>[ ...more docs need to be written... - type `<b>upx --help</b>&#39; for now ]</p>\n\n<h1 id=\"COMPRESSION-LEVELS-TUNING\">COMPRESSION LEVELS &amp; TUNING</h1>\n\n<p><b>UPX</b> offers ten different compression levels from <b>-1</b> to <b>-9</b>, and <b>--best</b>. The default compression level is <b>-8</b> for files smaller than 512 KiB, and <b>-7</b> otherwise.</p>\n\n<ul>\n\n<li><p>Compression levels 1, 2 and 3 are pretty fast.</p>\n\n</li>\n<li><p>Compression levels 4, 5 and 6 achieve a good time/ratio performance.</p>\n\n</li>\n<li><p>Compression levels 7, 8 and 9 favor compression ratio over speed.</p>\n\n</li>\n<li><p>Compression level <b>--best</b> may take a long time.</p>\n\n</li>\n</ul>\n\n<p>Note that compression level <b>--best</b> can be somewhat slow for large files, but you definitely should use it when releasing a final version of your program.</p>\n\n<p>Quick info for achieving the best compression ratio:</p>\n\n<ul>\n\n<li><p>Try <b>upx --brute --no-lzma myfile.exe</b> or even <b>upx --ultra-brute --no-lzma myfile.exe</b>.</p>\n\n</li>\n<li><p>The option <b>--lzma</b> enables LZMA compression, which compresses better but is *significantly slower* at decompression. You probably do not want to use it for large files.</p>\n\n<p>(Note that <b>--lzma</b> is automatically enabled by <b>--all-methods</b> and <b>--brute</b>, use <b>--no-lzma</b> to override.)</p>\n\n</li>\n<li><p>Try if <b>--overlay=strip</b> works.</p>\n\n</li>\n<li><p>For win32/pe programs there&#39;s <b>--strip-relocs=0</b>. See notes below.</p>\n\n</li>\n</ul>\n\n<h1 id=\"OVERLAY-HANDLING-OPTIONS\">OVERLAY HANDLING OPTIONS</h1>\n\n<p>Info: An &quot;overlay&quot; 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).</p>\n\n<p><b>UPX</b> handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn&#39;t work with others, depending on how an application actually accesses this overlaid data.</p>\n\n<pre><code>--overlay=copy    Copy any extra data attached to the file. [DEFAULT]\n\n--overlay=strip   Strip any overlay from the program instead of\n                  copying it. Be warned, this may make the compressed\n                  program crash or otherwise unusable.\n\n--overlay=skip    Refuse to compress any program which has an overlay.</code></pre>\n\n<h1 id=\"ENVIRONMENT-VARIABLE\">ENVIRONMENT VARIABLE</h1>\n\n<p>The environment variable <b>UPX</b> can hold a set of default options for <b>UPX</b>. These options are interpreted first and can be overwritten by explicit command line parameters. For example:</p>\n\n<pre><code>for DOS/Windows:   set UPX=-9 --compress-icons#0\nfor sh/ksh/zsh:    UPX=&quot;-9 --compress-icons=0&quot;; export UPX\nfor csh/tcsh:      setenv UPX &quot;-9 --compress-icons=0&quot;</code></pre>\n\n<p>Under DOS/Windows you must use &#39;#&#39; instead of &#39;=&#39; when setting the environment variable because of a COMMAND.COM limitation.</p>\n\n<p>Not all of the options are valid in the environment variable - <b>UPX</b> will tell you.</p>\n\n<p>You can explicitly use the <b>--no-env</b> option to ignore the environment variable.</p>\n\n<h1 id=\"NOTES-FOR-THE-SUPPORTED-EXECUTABLE-FORMATS\">NOTES FOR THE SUPPORTED EXECUTABLE FORMATS</h1>\n\n<h2 id=\"NOTES-FOR-ATARI-TOS\">NOTES FOR ATARI/TOS</h2>\n\n<p>This is the executable format used by the Atari ST/TT, a Motorola 68000 based personal computer which was popular in the late &#39;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.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression. All debug information will be stripped, though.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-BVMLINUZ-I386\">NOTES FOR BVMLINUZ/I386</h2>\n\n<p>Same as vmlinuz/i386.</p>\n\n<h2 id=\"NOTES-FOR-DOS-COM\">NOTES FOR DOS/COM</h2>\n\n<p>Obviously <b>UPX</b> won&#39;t work with executables that want to read data from themselves (like some commandline utilities that ship with Win95/98/ME).</p>\n\n<p>Compressed programs only work on a 286+.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression.</p>\n\n<p>Maximum uncompressed size: ~65100 bytes.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--8086              Create an executable that works on any 8086 CPU.\n\n--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--all-filters       Compress the program several times, using all\n                    available preprocessing filters. This may improve\n                    the compression ratio in some cases, but usually\n                    the default filter gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-DOS-EXE\">NOTES FOR DOS/EXE</h2>\n\n<p>dos/exe stands for all &quot;normal&quot; 16-bit DOS executables.</p>\n\n<p>Obviously <b>UPX</b> won&#39;t work with executables that want to read data from themselves (like some command line utilities that ship with Win95/98/ME).</p>\n\n<p>Compressed programs only work on a 286+.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--8086              Create an executable that works on any 8086 CPU.\n\n--no-reloc          Use no relocation records in the exe header.\n\n--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-DOS-SYS\">NOTES FOR DOS/SYS</h2>\n\n<p>Compressed programs only work on a 286+.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression.</p>\n\n<p>Maximum uncompressed size: ~65350 bytes.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--8086              Create an executable that works on any 8086 CPU.\n\n--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--all-filters       Compress the program several times, using all\n                    available preprocessing filters. This may improve\n                    the compression ratio in some cases, but usually\n                    the default filter gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-DJGPP2-COFF\">NOTES FOR DJGPP2/COFF</h2>\n\n<p>First of all, it is recommended to use <b>UPX</b> *instead* of <b>strip</b>. strip has the very bad habit of replacing your stub with its own (outdated) version. Additionally <b>UPX</b> corrects a bug/feature in strip v2.8.x: it will fix the 4 KiB alignment of the stub.</p>\n\n<p><b>UPX</b> includes the full functionality of stubify. This means it will automatically stubify your COFF files. Use the option <b>--coff</b> to disable this functionality (see below).</p>\n\n<p><b>UPX</b> automatically handles Allegro packfiles.</p>\n\n<p>The DLM format (a rather exotic shared library extension) is not supported.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression. All debug information and trailing garbage will be stripped, though.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--coff              Produce COFF output instead of EXE. By default\n                    UPX keeps your current stub.\n\n--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--all-filters       Compress the program several times, using all\n                    available preprocessing filters. This may improve\n                    the compression ratio in some cases, but usually\n                    the default filter gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-LINUX-general\">NOTES FOR LINUX [general]</h2>\n\n<p>Introduction</p>\n\n<pre><code>Linux/386 support in UPX consists of 3 different executable formats,\none optimized for ELF executables (&quot;linux/elf386&quot;), one optimized\nfor shell scripts (&quot;linux/sh386&quot;), and one generic format\n(&quot;linux/386&quot;).\n\nWe will start with a general discussion first, but please\nalso read the relevant docs for each of the individual formats.\n\nAlso, there is special support for bootable kernels - see the\ndescription of the vmlinuz/386 format.</code></pre>\n\n<p>General user&#39;s overview</p>\n\n<pre><code>Running a compressed executable program trades less space on a\n``permanent&#39;&#39; storage medium (such as a hard disk, floppy disk,\nCD-ROM, flash memory, EPROM, etc.) for more space in one or more\n``temporary&#39;&#39; storage media (such as RAM, swap space, /tmp, etc.).\nRunning a compressed executable also requires some additional CPU\ncycles to generate the compressed executable in the first place,\nand to decompress it at each invocation.\n\nHow much space is traded?  It depends on the executable, but many\nprograms save 30% to 50% of permanent disk space.  How much CPU\noverhead is there?  Again, it depends on the executable, but\ndecompression speed generally is at least many megabytes per second,\nand frequently is limited by the speed of the underlying disk\nor network I/O.\n\nDepending on the statistics of usage and access, and the relative\nspeeds of CPU, RAM, swap space, /tmp, and file system storage, then\ninvoking and running a compressed executable can be faster than\ndirectly running the corresponding uncompressed program.\nThe operating system might perform fewer expensive I/O operations\nto invoke the compressed program.  Paging to or from swap space\nor /tmp might be faster than paging from the general file system.\n``Medium-sized&#39;&#39; programs which access about 1/3 to 1/2 of their\nstored program bytes can do particularly well with compression.\nSmall programs tend not to benefit as much because the absolute\nsavings is less.  Big programs tend not to benefit proportionally\nbecause each invocation may use only a small fraction of the program,\nyet UPX decompresses the entire program before invoking it.\nBut in environments where disk or flash memory storage is limited,\nthen compression may win anyway.\n\nCurrently, executables compressed by UPX do not share RAM at runtime\nin the way that executables mapped from a file system do.  As a\nresult, if the same program is run simultaneously by more than one\nprocess, then using the compressed version will require more RAM and/or\nswap space.  So, shell programs (bash, csh, etc.)  and ``make&#39;&#39;\nmight not be good candidates for compression.\n\nUPX recognizes three executable formats for Linux: Linux/elf386,\nLinux/sh386, and Linux/386.  Linux/386 is the most generic format;\nit accommodates any file that can be executed.  At runtime, the UPX\ndecompression stub re-creates in /tmp a copy of the original file,\nand then the copy is (re-)executed with the same arguments.\nELF binary executables prefer the Linux/elf386 format by default,\nbecause UPX decompresses them directly into RAM, uses only one\nexec, does not use space in /tmp, and does not use /proc.\nShell scripts where the underlying shell accepts a ``-c&#39;&#39; argument\ncan use the Linux/sh386 format.  UPX decompresses the shell script\ninto low memory, then maps the shell and passes the entire text of the\nscript as an argument with a leading ``-c&#39;&#39;.</code></pre>\n\n<p>General benefits:</p>\n\n<pre><code>- UPX can compress all executables, be it AOUT, ELF, libc4, libc5,\n  libc6, Shell/Perl/Python/... scripts, standalone Java .class\n  binaries, or whatever...\n  All scripts and programs will work just as before.\n\n- Compressed programs are completely self-contained. No need for\n  any external program.\n\n- UPX keeps your original program untouched. This means that\n  after decompression you will have a byte-identical version,\n  and you can use UPX as a file compressor just like gzip.\n  [ Note that UPX maintains a checksum of the file internally,\n    so it is indeed a reliable alternative. ]\n\n- As the stub only uses syscalls and isn&#39;t linked against libc it\n  should run under any Linux configuration that can run ELF\n  binaries.\n\n- For the same reason compressed executables should run under\n  FreeBSD and other systems which can run Linux binaries.\n  [ Please send feedback on this topic ]</code></pre>\n\n<p>General drawbacks:</p>\n\n<pre><code>- It is not advisable to compress programs which usually have many\n  instances running (like `sh&#39; or `make&#39;) because the common segments of\n  compressed programs won&#39;t be shared any longer between different\n  processes.\n\n- `ldd&#39; and `size&#39; won&#39;t show anything useful because all they\n  see is the statically linked stub.  Since version 0.82 the section\n  headers are stripped from the UPX stub and `size&#39; doesn&#39;t even\n  recognize the file format.  The file patches/patch-elfcode.h has a\n  patch to fix this bug in `size&#39; and other programs which use GNU BFD.</code></pre>\n\n<p>General notes:</p>\n\n<pre><code>- As UPX leaves your original program untouched it is advantageous\n  to strip it before compression.\n\n- If you compress a script you will lose platform independence -\n  this could be a problem if you are using NFS mounted disks.\n\n- Compression of suid, guid and sticky-bit programs is rejected\n  because of possible security implications.\n\n- For the same reason there is no sense in making any compressed\n  program suid.\n\n- Obviously UPX won&#39;t work with executables that want to read data\n  from themselves. E.g., this might be a problem for Perl scripts\n  which access their __DATA__ lines.\n\n- In case of internal errors the stub will abort with exitcode 127.\n  Typical reasons for this to happen are that the program has somehow\n  been modified after compression.\n  Running `strace -o strace.log compressed_file&#39; will tell you more.</code></pre>\n\n<h2 id=\"NOTES-FOR-LINUX-ELF386\">NOTES FOR LINUX/ELF386</h2>\n\n<p>Please read the general Linux description first.</p>\n\n<p>The linux/elf386 format decompresses directly into RAM, uses only one exec, does not use space in /tmp, and does not use /proc.</p>\n\n<p>Linux/elf386 is automatically selected for Linux ELF executables.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression.</p>\n\n<p>How it works:</p>\n\n<pre><code>For ELF executables, UPX decompresses directly to memory, simulating\nthe mapping that the operating system kernel uses during exec(),\nincluding the PT_INTERP program interpreter (if any).\nThe brk() is set by a special PT_LOAD segment in the compressed\nexecutable itself.  UPX then wipes the stack clean except for\narguments, environment variables, and Elf_auxv entries (this is\nrequired by bugs in the startup code of /lib/ld-linux.so as of\nMay 2000), and transfers control to the program interpreter or\nthe e_entry address of the original executable.\n\nThe UPX stub is about 1700 bytes long, partly written in assembler\nand only uses kernel syscalls. It is not linked against any libc.</code></pre>\n\n<p>Specific drawbacks:</p>\n\n<pre><code>- For linux/elf386 and linux/sh386 formats, you will be relying on\n  RAM and swap space to hold all of the decompressed program during\n  the lifetime of the process.  If you already use most of your swap\n  space, then you may run out.  A system that is &quot;out of memory&quot;\n  can become fragile.  Many programs do not react gracefully when\n  malloc() returns 0.  With newer Linux kernels, the kernel\n  may decide to kill some processes to regain memory, and you\n  may not like the kernel&#39;s choice of which to kill.  Running\n  /usr/bin/top is one way to check on the usage of swap space.</code></pre>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>(none)</code></pre>\n\n<h2 id=\"NOTES-FOR-LINUX-SH386\">NOTES FOR LINUX/SH386</h2>\n\n<p>Please read the general Linux description first.</p>\n\n<p>Shell scripts where the underling shell accepts a ``-c&#39;&#39; argument can use the Linux/sh386 format. <b>UPX</b> 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&#39;&#39;. It does not use space in /tmp, and does not use /proc.</p>\n\n<p>Linux/sh386 is automatically selected for shell scripts that use a known shell.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression.</p>\n\n<p>How it works:</p>\n\n<pre><code>For shell script executables (files beginning with &quot;#!/&quot; or &quot;#! /&quot;)\nwhere the shell is known to accept &quot;-c &lt;command&gt;&quot;, UPX decompresses\nthe file into low memory, then maps the shell (and its PT_INTERP),\nand passes control to the shell with the entire decompressed file\nas the argument after &quot;-c&quot;.  Known shells are sh, ash, bash, bsh, csh,\nksh, tcsh, pdksh.  Restriction: UPX cannot use this method\nfor shell scripts which use the one optional string argument after\nthe shell name in the script (example: &quot;#! /bin/sh option3\\n&quot;.)\n\nThe UPX stub is about 1700 bytes long, partly written in assembler\nand only uses kernel syscalls. It is not linked against any libc.</code></pre>\n\n<p>Specific drawbacks:</p>\n\n<pre><code>- For linux/elf386 and linux/sh386 formats, you will be relying on\n  RAM and swap space to hold all of the decompressed program during\n  the lifetime of the process.  If you already use most of your swap\n  space, then you may run out.  A system that is &quot;out of memory&quot;\n  can become fragile.  Many programs do not react gracefully when\n  malloc() returns 0.  With newer Linux kernels, the kernel\n  may decide to kill some processes to regain memory, and you\n  may not like the kernel&#39;s choice of which to kill.  Running\n  /usr/bin/top is one way to check on the usage of swap space.</code></pre>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>(none)</code></pre>\n\n<h2 id=\"NOTES-FOR-LINUX-386\">NOTES FOR LINUX/386</h2>\n\n<p>Please read the general Linux description first.</p>\n\n<p>The generic linux/386 format decompresses to /tmp and needs /proc file system support. It starts the decompressed program via the execve() syscall.</p>\n\n<p>Linux/386 is only selected if the specialized linux/elf386 and linux/sh386 won&#39;t recognize a file.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression.</p>\n\n<p>How it works:</p>\n\n<pre><code>For files which are not ELF and not a script for a known &quot;-c&quot; shell,\nUPX uses kernel execve(), which first requires decompressing to a\ntemporary file in the file system.  Interestingly -\nbecause of the good memory management of the Linux kernel - this\noften does not introduce a noticeable delay, and in fact there\nwill be no disk access at all if you have enough free memory as\nthe entire process takes places within the file system buffers.\n\nA compressed executable consists of the UPX stub and an overlay\nwhich contains the original program in a compressed form.\n\nThe UPX stub is a statically linked ELF executable and does\nthe following at program startup:\n\n  1) decompress the overlay to a temporary location in /tmp\n  2) open the temporary file for reading\n  3) try to delete the temporary file and start (execve)\n     the uncompressed program in /tmp using /proc/&lt;pid&gt;/fd/X as\n     attained by step 2)\n  4) if that fails, fork off a subprocess to clean up and\n     start the program in /tmp in the meantime\n\nThe UPX stub is about 1700 bytes long, partly written in assembler\nand only uses kernel syscalls. It is not linked against any libc.</code></pre>\n\n<p>Specific drawbacks:</p>\n\n<pre><code>- You need additional free disk space for the uncompressed program\n  in your /tmp directory. This program is deleted immediately after\n  decompression, but you still need it for the full execution time\n  of the program.\n\n- You must have /proc file system support as the stub wants to open\n  /proc/&lt;pid&gt;/exe and needs /proc/&lt;pid&gt;/fd/X. This also means that you\n  cannot compress programs that are used during the boot sequence\n  before /proc is mounted.\n\n- Utilities like `top&#39; will display numerical values in the process\n  name field. This is because Linux computes the process name from\n  the first argument of the last execve syscall (which is typically\n  something like /proc/&lt;pid&gt;/fd/3).\n\n- Because of temporary decompression to disk the decompression speed\n  is not as fast as with the other executable formats. Still, I can see\n  no noticeable delay when starting programs like my ~3 MiB emacs (which\n  is less than 1 MiB when compressed :-).</code></pre>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--force-execve      Force the use of the generic linux/386 &quot;execve&quot;\n                    format, i.e. do not try the linux/elf386 and\n                    linux/sh386 formats.</code></pre>\n\n<h2 id=\"NOTES-FOR-PS1-EXE\">NOTES FOR PS1/EXE</h2>\n\n<p>This is the executable format used by the Sony PlayStation (PSone), a MIPS R3000 based gaming console which is popular since the late &#39;90s. Support of this format is very similar to the Atari one, because of nostalgic feelings of one of the authors.</p>\n\n<p>Packed programs will be byte-identical to the original after uncompression, until further notice.</p>\n\n<p>Maximum uncompressed size: ~1.89 / ~7.60 MiB.</p>\n\n<p>Notes:</p>\n\n<pre><code>- UPX creates as default a suitable executable for CD-Mastering\n  and console transfer. For a CD-Master main executable you could also try\n  the special option &quot;--boot-only&quot; as described below.\n  It has been reported that upx packed executables are fully compatible with\n  the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in\n  Sony PlayStation (PSone) emulation mode.\n\n- Normally the packed files use the same memory areas like the uncompressed\n  versions, so they will not override other memory areas while unpacking.\n  If this isn&#39;t possible UPX will abort showing a &#39;packed data overlap&#39;\n  error. With the &quot;--force&quot; option UPX will relocate the loading address\n  for the packed file, but this isn&#39;t a real problem if it is a single or\n  the main executable.</code></pre>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--8-bit             Uses 8 bit size compression [default: 32 bit]\n\n--8mib-ram          PSone has 8 MiB ram available [default: 2 MiB]\n\n--boot-only         This format is for main exes and CD-Mastering only !\n                    It may slightly improve the compression ratio,\n                    decompression routines are faster than default ones.\n                    But it cannot be used for console transfer !\n\n--no-align          This option disables CD mode 2 data sector format\n                    alignment. May slightly improves the compression ratio,\n                    but the compressed executable will not boot from a CD.\n                    Use it for console transfer only !</code></pre>\n\n<h2 id=\"NOTES-FOR-RTM32-PE-and-ARM-PE\">NOTES FOR RTM32/PE and ARM/PE</h2>\n\n<p>Same as win32/pe.</p>\n\n<h2 id=\"NOTES-FOR-TMT-ADAM\">NOTES FOR TMT/ADAM</h2>\n\n<p>This format is used by the TMT Pascal compiler - see http://www.tmt.com/ .</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--all-filters       Compress the program several times, using all\n                    available preprocessing filters. This may improve\n                    the compression ratio in some cases, but usually\n                    the default filter gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-VMLINUZ-386\">NOTES FOR VMLINUZ/386</h2>\n\n<p>The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed bootable Linux kernel image (&quot;vmlinuz&quot;, &quot;zImage&quot;, &quot;bzImage&quot;), gzip-decompress it and re-compress it with the <b>UPX</b> compression method.</p>\n\n<p>vmlinuz/386 is completely unrelated to the other Linux executable formats, and it does not share any of their drawbacks.</p>\n\n<p>Notes:</p>\n\n<pre><code>- Be sure that &quot;vmlinuz/386&quot; or &quot;bvmlinuz/386&quot; is displayed\nduring compression - otherwise a wrong executable format\nmay have been used, and the kernel won&#39;t boot.</code></pre>\n\n<p>Benefits:</p>\n\n<pre><code>- Better compression (but note that the kernel was already compressed,\nso the improvement is not as large as with other formats).\nStill, the bytes saved may be essential for special needs like\nboot disks.\n\n   For example, this is what I get for my 2.2.16 kernel:\n      1589708  vmlinux\n       641073  bzImage        [original]\n       560755  bzImage.upx    [compressed by &quot;upx -9&quot;]\n\n- Much faster decompression at kernel boot time (but kernel\n  decompression speed is not really an issue these days).</code></pre>\n\n<p>Drawbacks:</p>\n\n<pre><code>(none)</code></pre>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--all-methods       Compress the program several times, using all\n                    available compression methods. This may improve\n                    the compression ratio in some cases, but usually\n                    the default method gives the best results anyway.\n\n--all-filters       Compress the program several times, using all\n                    available preprocessing filters. This may improve\n                    the compression ratio in some cases, but usually\n                    the default filter gives the best results anyway.</code></pre>\n\n<h2 id=\"NOTES-FOR-WATCOM-LE\">NOTES FOR WATCOM/LE</h2>\n\n<p><b>UPX</b> 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).</p>\n\n<p>DLLs and the LX format are not supported.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--le                Produce an unbound LE output instead of\n                    keeping the current stub.</code></pre>\n\n<h2 id=\"NOTES-FOR-WIN32-PE\">NOTES FOR WIN32/PE</h2>\n\n<p>The PE support in <b>UPX</b> is quite stable now, but probably there are still some incompatibilities with some files.</p>\n\n<p>Because of the way <b>UPX</b> (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&#39;re wasting memory because the common segments of the program won&#39;t get shared across the instances. On the other hand if you&#39;re compressing only smaller programs, or running only one instance of larger programs, then this penalty is smaller, but it&#39;s still there.</p>\n\n<p>If you&#39;re running executables from network, then compressed programs will load faster, and require less bandwidth during execution.</p>\n\n<p>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.</p>\n\n<p>Screensavers are supported, with the restriction that the filename must end with &quot;.scr&quot; (as screensavers are handled slightly different than normal exe files).</p>\n\n<p>UPX compressed PE files have some minor memory overhead (usually in the 10 - 30 KiB range) which can be seen by specifying the &quot;-i&quot; command line switch during compression.</p>\n\n<p>Extra options available for this executable format:</p>\n\n<pre><code>--compress-exports=0 Don&#39;t compress the export section.\n                     Use this if you plan to run the compressed\n                     program under Wine.\n--compress-exports=1 Compress the export section. [DEFAULT]\n                     Compression of the export section can improve the\n                     compression ratio quite a bit but may not work\n                     with all programs (like winword.exe).\n                     UPX never compresses the export section of a DLL\n                     regardless of this option.\n\n --compress-icons=0  Don&#39;t compress any icons.\n --compress-icons=1  Compress all but the first icon.\n --compress-icons=2  Compress all icons which are not in the\n                     first icon directory. [DEFAULT]\n --compress-icons=3  Compress all icons.\n\n --compress-resources=0  Don&#39;t compress any resources at all.\n\n --keep-resource=list Don&#39;t compress resources specified by the list.\n                     The members of the list are separated by commas.\n                     A list member has the following format: I&lt;type[/name]&gt;.\n                     I&lt;Type&gt; is the type of the resource. Standard types\n                     must be specified as decimal numbers, user types can be\n                     specified by decimal IDs or strings. I&lt;Name&gt; is the\n                     identifier of the resource. It can be a decimal number\n                     or a string. For example:\n\n                     --keep-resource=2/MYBITMAP,5,6/12345\n\n                     UPX won&#39;t compress the named bitmap resource &quot;MYBITMAP&quot;,\n                     it leaves every dialog (5) resource uncompressed, and\n                     it won&#39;t touch the string table resource with identifier\n                     12345.\n\n --force             Force compression even when there is an\n                     unexpected value in a header field.\n                     Use with care.\n\n --strip-relocs=0    Don&#39;t strip relocation records.\n --strip-relocs=1    Strip relocation records. [DEFAULT]\n                     This option only works on executables with base\n                     address greater or equal to 0x400000. Usually the\n                     compressed files becomes smaller, but some files\n                     may become larger. Note that the resulting file will\n                     not work under Windows 3.x (Win32s).\n                     UPX never strips relocations from a DLL\n                     regardless of this option.\n\n --all-methods       Compress the program several times, using all\n                     available compression methods. This may improve\n                     the compression ratio in some cases, but usually\n                     the default method gives the best results anyway.\n\n --all-filters       Compress the program several times, using all\n                     available preprocessing filters. This may improve\n                     the compression ratio in some cases, but usually\n                     the default filter gives the best results anyway.</code></pre>\n\n<h1 id=\"DIAGNOSTICS\">DIAGNOSTICS</h1>\n\n<p>Exit status is normally 0; if an error occurs, exit status is 1. If a warning occurs, exit status is 2.</p>\n\n<p><b>UPX</b>&#39;s diagnostics are intended to be self-explanatory.</p>\n\n<h1 id=\"BUGS\">BUGS</h1>\n\n<p>Please report all bugs immediately to the authors.</p>\n\n<h1 id=\"AUTHORS\">AUTHORS</h1>\n\n<pre><code>Markus F.X.J. Oberhumer &lt;markus@oberhumer.com&gt;\nhttp://www.oberhumer.com\n\nLaszlo Molnar &lt;ezerotven+github@gmail.com&gt;\n\nJohn F. Reiser &lt;jreiser@BitWagon.com&gt;\n\nJens Medoch &lt;jssg@users.sourceforge.net&gt;</code></pre>\n\n<h1 id=\"COPYRIGHT\">COPYRIGHT</h1>\n\n<p>Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer</p>\n\n<p>Copyright (C) 1996-2023 Laszlo Molnar</p>\n\n<p>Copyright (C) 2000-2023 John F. Reiser</p>\n\n<p>Copyright (C) 2002-2023 Jens Medoch</p>\n\n<p><b>UPX</b> 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).</p>\n\n<p>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.</p>\n\n<p>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.</p>\n\n\n</body>\n\n</html>\n\n\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/upx-doc.txt",
    "content": "NAME\n    upx - compress or expand executable files\n\nSYNOPSIS\n    upx [ *command* ] [ *options* ] *filename*...\n\nABSTRACT\n                        The Ultimate Packer for eXecutables\n       Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser\n                               https://upx.github.io\n\n    UPX is a portable, extendable, high-performance executable packer for\n    several different executable formats. It achieves an excellent\n    compression ratio and offers **very** fast decompression. Your\n    executables suffer no memory overhead or other drawbacks for most of the\n    formats supported, because of in-place decompression.\n\nDISCLAIMER\n    UPX comes with ABSOLUTELY NO WARRANTY; for details see the file COPYING.\n\n    Please report all problems or suggestions to the authors. Thanks.\n\nSECURITY CONTEXT\n    IMPORTANT NOTE: UPX inherits the security context of any files it\n    handles.\n\n    This means that packing, unpacking, or even testing or listing a file\n    requires the same security considerations as actually executing the\n    file.\n\n    Use UPX on trusted files only!\n\nDESCRIPTION\n    UPX is a versatile executable packer with the following features:\n\n      - secure: as UPX is documented Open Source since many years any relevant\n          Security/Antivirus software is able to peek inside UPX compressed\n          apps to verify them\n\n      - excellent compression ratio: typically compresses better than Zip,\n          use UPX to decrease the size of your distribution !\n\n      - very fast decompression: more than 500 MB/sec on any reasonably modern\n          machine\n\n      - no memory overhead for your compressed executables for most of the\n          supported formats because of in-place decompression\n\n      - safe: you can list, test and unpack your executables.\n          Also, a checksum of both the compressed and uncompressed file is\n          maintained internally.\n\n      - universal: UPX can pack a number of executable formats, including\n          Windows programs and DLLs, macOS apps and Linux executables\n\n      - portable: UPX is written in portable endian-neutral C++\n\n      - extendable: because of the class layout it's very easy to support\n          new executable formats or add new compression algorithms\n\n      - free: UPX is distributed with full source code under the GNU General\n          Public License v2+, with special exceptions granting the free usage\n          for commercial programs\n\n    You probably understand now why we call UPX the \"*ultimate*\" executable\n    packer.\n\nCOMMANDS\n  Compress\n    This is the default operation, eg. upx yourfile.exe will compress the\n    file specified on the command line.\n\n  Decompress\n    All UPX supported file formats can be unpacked using the -d switch, eg.\n    upx -d yourfile.exe will uncompress the file you've just compressed.\n\n  Test\n    The -t command tests the integrity of the compressed and uncompressed\n    data, eg. upx -t yourfile.exe check whether your file can be safely\n    decompressed. Note, that this command doesn't check the whole file, only\n    the part that will be uncompressed during program execution. This means\n    that you should not use this command instead of a virus checker.\n\n  List\n    The -l command prints out some information about the compressed files\n    specified on the command line as parameters, eg upx -l yourfile.exe\n    shows the compressed / uncompressed size and the compression ratio of\n    *yourfile.exe*.\n\nOPTIONS\n    -q: be quiet, suppress warnings\n\n    -q -q (or -qq): be very quiet, suppress errors\n\n    -q -q -q (or -qqq): produce no output at all\n\n    --help: prints the help\n\n    --version: print the version of UPX\n\n    --exact: when compressing, require to be able to get a byte-identical\n    file after decompression with option -d. [NOTE: this is work in progress\n    and is not supported for all formats yet. If you do care, as a\n    workaround you can compress and then decompress your program a first\n    time - any further compress-decompress steps should then yield\n    byte-identical results as compared to the first decompressed version.]\n\n    -k: keep backup files\n\n    -o file: write output to file\n\n    [ ...more docs need to be written... - type `upx --help' for now ]\n\nCOMPRESSION LEVELS & TUNING\n    UPX offers ten different compression levels from -1 to -9, and --best.\n    The default compression level is -8 for files smaller than 512 KiB, and\n    -7 otherwise.\n\n    *   Compression levels 1, 2 and 3 are pretty fast.\n\n    *   Compression levels 4, 5 and 6 achieve a good time/ratio performance.\n\n    *   Compression levels 7, 8 and 9 favor compression ratio over speed.\n\n    *   Compression level --best may take a long time.\n\n    Note that compression level --best can be somewhat slow for large files,\n    but you definitely should use it when releasing a final version of your\n    program.\n\n    Quick info for achieving the best compression ratio:\n\n    *   Try upx --brute --no-lzma myfile.exe or even upx --ultra-brute\n        --no-lzma myfile.exe.\n\n    *   The option --lzma enables LZMA compression, which compresses better\n        but is *significantly slower* at decompression. You probably do not\n        want to use it for large files.\n\n        (Note that --lzma is automatically enabled by --all-methods and\n        --brute, use --no-lzma to override.)\n\n    *   Try if --overlay=strip works.\n\n    *   For win32/pe programs there's --strip-relocs=0. See notes below.\n\nOVERLAY HANDLING OPTIONS\n    Info: An \"overlay\" means auxiliary data attached after the logical end\n    of an executable, and it often contains application specific data (this\n    is a common practice to avoid an extra data file, though it would be\n    better to use resource sections).\n\n    UPX handles overlays like many other executable packers do: it simply\n    copies the overlay after the compressed image. This works with some\n    files, but doesn't work with others, depending on how an application\n    actually accesses this overlaid data.\n\n      --overlay=copy    Copy any extra data attached to the file. [DEFAULT]\n\n      --overlay=strip   Strip any overlay from the program instead of\n                        copying it. Be warned, this may make the compressed\n                        program crash or otherwise unusable.\n\n      --overlay=skip    Refuse to compress any program which has an overlay.\n\nENVIRONMENT VARIABLE\n    The environment variable UPX can hold a set of default options for UPX.\n    These options are interpreted first and can be overwritten by explicit\n    command line parameters. For example:\n\n        for DOS/Windows:   set UPX=-9 --compress-icons#0\n        for sh/ksh/zsh:    UPX=\"-9 --compress-icons=0\"; export UPX\n        for csh/tcsh:      setenv UPX \"-9 --compress-icons=0\"\n\n    Under DOS/Windows you must use '#' instead of '=' when setting the\n    environment variable because of a COMMAND.COM limitation.\n\n    Not all of the options are valid in the environment variable - UPX will\n    tell you.\n\n    You can explicitly use the --no-env option to ignore the environment\n    variable.\n\nNOTES FOR THE SUPPORTED EXECUTABLE FORMATS\n  NOTES FOR ATARI/TOS\n    This is the executable format used by the Atari ST/TT, a Motorola 68000\n    based personal computer which was popular in the late '80s. Support of\n    this format is only because of nostalgic feelings of one of the authors\n    and serves no practical purpose :-). See https://freemint.github.io for\n    more info.\n\n    Packed programs will be byte-identical to the original after\n    uncompression. All debug information will be stripped, though.\n\n    Extra options available for this executable format:\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n  NOTES FOR BVMLINUZ/I386\n    Same as vmlinuz/i386.\n\n  NOTES FOR DOS/COM\n    Obviously UPX won't work with executables that want to read data from\n    themselves (like some commandline utilities that ship with Win95/98/ME).\n\n    Compressed programs only work on a 286+.\n\n    Packed programs will be byte-identical to the original after\n    uncompression.\n\n    Maximum uncompressed size: ~65100 bytes.\n\n    Extra options available for this executable format:\n\n      --8086              Create an executable that works on any 8086 CPU.\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\n  NOTES FOR DOS/EXE\n    dos/exe stands for all \"normal\" 16-bit DOS executables.\n\n    Obviously UPX won't work with executables that want to read data from\n    themselves (like some command line utilities that ship with\n    Win95/98/ME).\n\n    Compressed programs only work on a 286+.\n\n    Extra options available for this executable format:\n\n      --8086              Create an executable that works on any 8086 CPU.\n\n      --no-reloc          Use no relocation records in the exe header.\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n  NOTES FOR DOS/SYS\n    Compressed programs only work on a 286+.\n\n    Packed programs will be byte-identical to the original after\n    uncompression.\n\n    Maximum uncompressed size: ~65350 bytes.\n\n    Extra options available for this executable format:\n\n      --8086              Create an executable that works on any 8086 CPU.\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\n  NOTES FOR DJGPP2/COFF\n    First of all, it is recommended to use UPX *instead* of strip. strip has\n    the very bad habit of replacing your stub with its own (outdated)\n    version. Additionally UPX corrects a bug/feature in strip v2.8.x: it\n    will fix the 4 KiB alignment of the stub.\n\n    UPX includes the full functionality of stubify. This means it will\n    automatically stubify your COFF files. Use the option --coff to disable\n    this functionality (see below).\n\n    UPX automatically handles Allegro packfiles.\n\n    The DLM format (a rather exotic shared library extension) is not\n    supported.\n\n    Packed programs will be byte-identical to the original after\n    uncompression. All debug information and trailing garbage will be\n    stripped, though.\n\n    Extra options available for this executable format:\n\n      --coff              Produce COFF output instead of EXE. By default\n                          UPX keeps your current stub.\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\n  NOTES FOR LINUX [general]\n    Introduction\n\n      Linux/386 support in UPX consists of 3 different executable formats,\n      one optimized for ELF executables (\"linux/elf386\"), one optimized\n      for shell scripts (\"linux/sh386\"), and one generic format\n      (\"linux/386\").\n\n      We will start with a general discussion first, but please\n      also read the relevant docs for each of the individual formats.\n\n      Also, there is special support for bootable kernels - see the\n      description of the vmlinuz/386 format.\n\n    General user's overview\n\n      Running a compressed executable program trades less space on a\n      ``permanent'' storage medium (such as a hard disk, floppy disk,\n      CD-ROM, flash memory, EPROM, etc.) for more space in one or more\n      ``temporary'' storage media (such as RAM, swap space, /tmp, etc.).\n      Running a compressed executable also requires some additional CPU\n      cycles to generate the compressed executable in the first place,\n      and to decompress it at each invocation.\n\n      How much space is traded?  It depends on the executable, but many\n      programs save 30% to 50% of permanent disk space.  How much CPU\n      overhead is there?  Again, it depends on the executable, but\n      decompression speed generally is at least many megabytes per second,\n      and frequently is limited by the speed of the underlying disk\n      or network I/O.\n\n      Depending on the statistics of usage and access, and the relative\n      speeds of CPU, RAM, swap space, /tmp, and file system storage, then\n      invoking and running a compressed executable can be faster than\n      directly running the corresponding uncompressed program.\n      The operating system might perform fewer expensive I/O operations\n      to invoke the compressed program.  Paging to or from swap space\n      or /tmp might be faster than paging from the general file system.\n      ``Medium-sized'' programs which access about 1/3 to 1/2 of their\n      stored program bytes can do particularly well with compression.\n      Small programs tend not to benefit as much because the absolute\n      savings is less.  Big programs tend not to benefit proportionally\n      because each invocation may use only a small fraction of the program,\n      yet UPX decompresses the entire program before invoking it.\n      But in environments where disk or flash memory storage is limited,\n      then compression may win anyway.\n\n      Currently, executables compressed by UPX do not share RAM at runtime\n      in the way that executables mapped from a file system do.  As a\n      result, if the same program is run simultaneously by more than one\n      process, then using the compressed version will require more RAM and/or\n      swap space.  So, shell programs (bash, csh, etc.)  and ``make''\n      might not be good candidates for compression.\n\n      UPX recognizes three executable formats for Linux: Linux/elf386,\n      Linux/sh386, and Linux/386.  Linux/386 is the most generic format;\n      it accommodates any file that can be executed.  At runtime, the UPX\n      decompression stub re-creates in /tmp a copy of the original file,\n      and then the copy is (re-)executed with the same arguments.\n      ELF binary executables prefer the Linux/elf386 format by default,\n      because UPX decompresses them directly into RAM, uses only one\n      exec, does not use space in /tmp, and does not use /proc.\n      Shell scripts where the underlying shell accepts a ``-c'' argument\n      can use the Linux/sh386 format.  UPX decompresses the shell script\n      into low memory, then maps the shell and passes the entire text of the\n      script as an argument with a leading ``-c''.\n\n    General benefits:\n\n      - UPX can compress all executables, be it AOUT, ELF, libc4, libc5,\n        libc6, Shell/Perl/Python/... scripts, standalone Java .class\n        binaries, or whatever...\n        All scripts and programs will work just as before.\n\n      - Compressed programs are completely self-contained. No need for\n        any external program.\n\n      - UPX keeps your original program untouched. This means that\n        after decompression you will have a byte-identical version,\n        and you can use UPX as a file compressor just like gzip.\n        [ Note that UPX maintains a checksum of the file internally,\n          so it is indeed a reliable alternative. ]\n\n      - As the stub only uses syscalls and isn't linked against libc it\n        should run under any Linux configuration that can run ELF\n        binaries.\n\n      - For the same reason compressed executables should run under\n        FreeBSD and other systems which can run Linux binaries.\n        [ Please send feedback on this topic ]\n\n    General drawbacks:\n\n      - It is not advisable to compress programs which usually have many\n        instances running (like `sh' or `make') because the common segments of\n        compressed programs won't be shared any longer between different\n        processes.\n\n      - `ldd' and `size' won't show anything useful because all they\n        see is the statically linked stub.  Since version 0.82 the section\n        headers are stripped from the UPX stub and `size' doesn't even\n        recognize the file format.  The file patches/patch-elfcode.h has a\n        patch to fix this bug in `size' and other programs which use GNU BFD.\n\n    General notes:\n\n      - As UPX leaves your original program untouched it is advantageous\n        to strip it before compression.\n\n      - If you compress a script you will lose platform independence -\n        this could be a problem if you are using NFS mounted disks.\n\n      - Compression of suid, guid and sticky-bit programs is rejected\n        because of possible security implications.\n\n      - For the same reason there is no sense in making any compressed\n        program suid.\n\n      - Obviously UPX won't work with executables that want to read data\n        from themselves. E.g., this might be a problem for Perl scripts\n        which access their __DATA__ lines.\n\n      - In case of internal errors the stub will abort with exitcode 127.\n        Typical reasons for this to happen are that the program has somehow\n        been modified after compression.\n        Running `strace -o strace.log compressed_file' will tell you more.\n\n  NOTES FOR LINUX/ELF386\n    Please read the general Linux description first.\n\n    The linux/elf386 format decompresses directly into RAM, uses only one\n    exec, does not use space in /tmp, and does not use /proc.\n\n    Linux/elf386 is automatically selected for Linux ELF executables.\n\n    Packed programs will be byte-identical to the original after\n    uncompression.\n\n    How it works:\n\n      For ELF executables, UPX decompresses directly to memory, simulating\n      the mapping that the operating system kernel uses during exec(),\n      including the PT_INTERP program interpreter (if any).\n      The brk() is set by a special PT_LOAD segment in the compressed\n      executable itself.  UPX then wipes the stack clean except for\n      arguments, environment variables, and Elf_auxv entries (this is\n      required by bugs in the startup code of /lib/ld-linux.so as of\n      May 2000), and transfers control to the program interpreter or\n      the e_entry address of the original executable.\n\n      The UPX stub is about 1700 bytes long, partly written in assembler\n      and only uses kernel syscalls. It is not linked against any libc.\n\n    Specific drawbacks:\n\n      - For linux/elf386 and linux/sh386 formats, you will be relying on\n        RAM and swap space to hold all of the decompressed program during\n        the lifetime of the process.  If you already use most of your swap\n        space, then you may run out.  A system that is \"out of memory\"\n        can become fragile.  Many programs do not react gracefully when\n        malloc() returns 0.  With newer Linux kernels, the kernel\n        may decide to kill some processes to regain memory, and you\n        may not like the kernel's choice of which to kill.  Running\n        /usr/bin/top is one way to check on the usage of swap space.\n\n    Extra options available for this executable format:\n\n      (none)\n\n  NOTES FOR LINUX/SH386\n    Please read the general Linux description first.\n\n    Shell scripts where the underling shell accepts a ``-c'' argument can\n    use the Linux/sh386 format. UPX decompresses the shell script into low\n    memory, then maps the shell and passes the entire text of the script as\n    an argument with a leading ``-c''. It does not use space in /tmp, and\n    does not use /proc.\n\n    Linux/sh386 is automatically selected for shell scripts that use a known\n    shell.\n\n    Packed programs will be byte-identical to the original after\n    uncompression.\n\n    How it works:\n\n      For shell script executables (files beginning with \"#!/\" or \"#! /\")\n      where the shell is known to accept \"-c <command>\", UPX decompresses\n      the file into low memory, then maps the shell (and its PT_INTERP),\n      and passes control to the shell with the entire decompressed file\n      as the argument after \"-c\".  Known shells are sh, ash, bash, bsh, csh,\n      ksh, tcsh, pdksh.  Restriction: UPX cannot use this method\n      for shell scripts which use the one optional string argument after\n      the shell name in the script (example: \"#! /bin/sh option3\\n\".)\n\n      The UPX stub is about 1700 bytes long, partly written in assembler\n      and only uses kernel syscalls. It is not linked against any libc.\n\n    Specific drawbacks:\n\n      - For linux/elf386 and linux/sh386 formats, you will be relying on\n        RAM and swap space to hold all of the decompressed program during\n        the lifetime of the process.  If you already use most of your swap\n        space, then you may run out.  A system that is \"out of memory\"\n        can become fragile.  Many programs do not react gracefully when\n        malloc() returns 0.  With newer Linux kernels, the kernel\n        may decide to kill some processes to regain memory, and you\n        may not like the kernel's choice of which to kill.  Running\n        /usr/bin/top is one way to check on the usage of swap space.\n\n    Extra options available for this executable format:\n\n      (none)\n\n  NOTES FOR LINUX/386\n    Please read the general Linux description first.\n\n    The generic linux/386 format decompresses to /tmp and needs /proc file\n    system support. It starts the decompressed program via the execve()\n    syscall.\n\n    Linux/386 is only selected if the specialized linux/elf386 and\n    linux/sh386 won't recognize a file.\n\n    Packed programs will be byte-identical to the original after\n    uncompression.\n\n    How it works:\n\n      For files which are not ELF and not a script for a known \"-c\" shell,\n      UPX uses kernel execve(), which first requires decompressing to a\n      temporary file in the file system.  Interestingly -\n      because of the good memory management of the Linux kernel - this\n      often does not introduce a noticeable delay, and in fact there\n      will be no disk access at all if you have enough free memory as\n      the entire process takes places within the file system buffers.\n\n      A compressed executable consists of the UPX stub and an overlay\n      which contains the original program in a compressed form.\n\n      The UPX stub is a statically linked ELF executable and does\n      the following at program startup:\n\n        1) decompress the overlay to a temporary location in /tmp\n        2) open the temporary file for reading\n        3) try to delete the temporary file and start (execve)\n           the uncompressed program in /tmp using /proc/<pid>/fd/X as\n           attained by step 2)\n        4) if that fails, fork off a subprocess to clean up and\n           start the program in /tmp in the meantime\n\n      The UPX stub is about 1700 bytes long, partly written in assembler\n      and only uses kernel syscalls. It is not linked against any libc.\n\n    Specific drawbacks:\n\n      - You need additional free disk space for the uncompressed program\n        in your /tmp directory. This program is deleted immediately after\n        decompression, but you still need it for the full execution time\n        of the program.\n\n      - You must have /proc file system support as the stub wants to open\n        /proc/<pid>/exe and needs /proc/<pid>/fd/X. This also means that you\n        cannot compress programs that are used during the boot sequence\n        before /proc is mounted.\n\n      - Utilities like `top' will display numerical values in the process\n        name field. This is because Linux computes the process name from\n        the first argument of the last execve syscall (which is typically\n        something like /proc/<pid>/fd/3).\n\n      - Because of temporary decompression to disk the decompression speed\n        is not as fast as with the other executable formats. Still, I can see\n        no noticeable delay when starting programs like my ~3 MiB emacs (which\n        is less than 1 MiB when compressed :-).\n\n    Extra options available for this executable format:\n\n      --force-execve      Force the use of the generic linux/386 \"execve\"\n                          format, i.e. do not try the linux/elf386 and\n                          linux/sh386 formats.\n\n  NOTES FOR PS1/EXE\n    This is the executable format used by the Sony PlayStation (PSone), a\n    MIPS R3000 based gaming console which is popular since the late '90s.\n    Support of this format is very similar to the Atari one, because of\n    nostalgic feelings of one of the authors.\n\n    Packed programs will be byte-identical to the original after\n    uncompression, until further notice.\n\n    Maximum uncompressed size: ~1.89 / ~7.60 MiB.\n\n    Notes:\n\n      - UPX creates as default a suitable executable for CD-Mastering\n        and console transfer. For a CD-Master main executable you could also try\n        the special option \"--boot-only\" as described below.\n        It has been reported that upx packed executables are fully compatible with\n        the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in\n        Sony PlayStation (PSone) emulation mode.\n\n      - Normally the packed files use the same memory areas like the uncompressed\n        versions, so they will not override other memory areas while unpacking.\n        If this isn't possible UPX will abort showing a 'packed data overlap'\n        error. With the \"--force\" option UPX will relocate the loading address\n        for the packed file, but this isn't a real problem if it is a single or\n        the main executable.\n\n    Extra options available for this executable format:\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --8-bit             Uses 8 bit size compression [default: 32 bit]\n\n      --8mib-ram          PSone has 8 MiB ram available [default: 2 MiB]\n\n      --boot-only         This format is for main exes and CD-Mastering only !\n                          It may slightly improve the compression ratio,\n                          decompression routines are faster than default ones.\n                          But it cannot be used for console transfer !\n\n      --no-align          This option disables CD mode 2 data sector format\n                          alignment. May slightly improves the compression ratio,\n                          but the compressed executable will not boot from a CD.\n                          Use it for console transfer only !\n\n  NOTES FOR RTM32/PE and ARM/PE\n    Same as win32/pe.\n\n  NOTES FOR TMT/ADAM\n    This format is used by the TMT Pascal compiler - see http://www.tmt.com/\n    .\n\n    Extra options available for this executable format:\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\n  NOTES FOR VMLINUZ/386\n    The vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed bootable\n    Linux kernel image (\"vmlinuz\", \"zImage\", \"bzImage\"), gzip-decompress it\n    and re-compress it with the UPX compression method.\n\n    vmlinuz/386 is completely unrelated to the other Linux executable\n    formats, and it does not share any of their drawbacks.\n\n    Notes:\n\n      - Be sure that \"vmlinuz/386\" or \"bvmlinuz/386\" is displayed\n      during compression - otherwise a wrong executable format\n      may have been used, and the kernel won't boot.\n\n    Benefits:\n\n      - Better compression (but note that the kernel was already compressed,\n      so the improvement is not as large as with other formats).\n      Still, the bytes saved may be essential for special needs like\n      boot disks.\n\n         For example, this is what I get for my 2.2.16 kernel:\n            1589708  vmlinux\n             641073  bzImage        [original]\n             560755  bzImage.upx    [compressed by \"upx -9\"]\n\n      - Much faster decompression at kernel boot time (but kernel\n        decompression speed is not really an issue these days).\n\n    Drawbacks:\n\n      (none)\n\n    Extra options available for this executable format:\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\n  NOTES FOR WATCOM/LE\n    UPX has been successfully tested with the following extenders: DOS4G,\n    DOS4GW, PMODE/W, DOS32a, CauseWay. The WDOS/X extender is partly\n    supported (for details see the file bugs BUGS).\n\n    DLLs and the LX format are not supported.\n\n    Extra options available for this executable format:\n\n      --le                Produce an unbound LE output instead of\n                          keeping the current stub.\n\n  NOTES FOR WIN32/PE\n    The PE support in UPX is quite stable now, but probably there are still\n    some incompatibilities with some files.\n\n    Because of the way UPX (and other packers for this format) works, you\n    can see increased memory usage of your compressed files because the\n    whole program is loaded into memory at startup. If you start several\n    instances of huge compressed programs you're wasting memory because the\n    common segments of the program won't get shared across the instances. On\n    the other hand if you're compressing only smaller programs, or running\n    only one instance of larger programs, then this penalty is smaller, but\n    it's still there.\n\n    If you're running executables from network, then compressed programs\n    will load faster, and require less bandwidth during execution.\n\n    DLLs are supported. But UPX compressed DLLs can not share common data\n    and code when they got used by multiple applications. So compressing\n    msvcrt.dll is a waste of memory, but compressing the dll plugins of a\n    particular application may be a better idea.\n\n    Screensavers are supported, with the restriction that the filename must\n    end with \".scr\" (as screensavers are handled slightly different than\n    normal exe files).\n\n    UPX compressed PE files have some minor memory overhead (usually in the\n    10 - 30 KiB range) which can be seen by specifying the \"-i\" command line\n    switch during compression.\n\n    Extra options available for this executable format:\n\n     --compress-exports=0 Don't compress the export section.\n                          Use this if you plan to run the compressed\n                          program under Wine.\n     --compress-exports=1 Compress the export section. [DEFAULT]\n                          Compression of the export section can improve the\n                          compression ratio quite a bit but may not work\n                          with all programs (like winword.exe).\n                          UPX never compresses the export section of a DLL\n                          regardless of this option.\n\n      --compress-icons=0  Don't compress any icons.\n      --compress-icons=1  Compress all but the first icon.\n      --compress-icons=2  Compress all icons which are not in the\n                          first icon directory. [DEFAULT]\n      --compress-icons=3  Compress all icons.\n\n      --compress-resources=0  Don't compress any resources at all.\n\n      --keep-resource=list Don't compress resources specified by the list.\n                          The members of the list are separated by commas.\n                          A list member has the following format: I<type[/name]>.\n                          I<Type> is the type of the resource. Standard types\n                          must be specified as decimal numbers, user types can be\n                          specified by decimal IDs or strings. I<Name> is the\n                          identifier of the resource. It can be a decimal number\n                          or a string. For example:\n\n                          --keep-resource=2/MYBITMAP,5,6/12345\n\n                          UPX won't compress the named bitmap resource \"MYBITMAP\",\n                          it leaves every dialog (5) resource uncompressed, and\n                          it won't touch the string table resource with identifier\n                          12345.\n\n      --force             Force compression even when there is an\n                          unexpected value in a header field.\n                          Use with care.\n\n      --strip-relocs=0    Don't strip relocation records.\n      --strip-relocs=1    Strip relocation records. [DEFAULT]\n                          This option only works on executables with base\n                          address greater or equal to 0x400000. Usually the\n                          compressed files becomes smaller, but some files\n                          may become larger. Note that the resulting file will\n                          not work under Windows 3.x (Win32s).\n                          UPX never strips relocations from a DLL\n                          regardless of this option.\n\n      --all-methods       Compress the program several times, using all\n                          available compression methods. This may improve\n                          the compression ratio in some cases, but usually\n                          the default method gives the best results anyway.\n\n      --all-filters       Compress the program several times, using all\n                          available preprocessing filters. This may improve\n                          the compression ratio in some cases, but usually\n                          the default filter gives the best results anyway.\n\nDIAGNOSTICS\n    Exit status is normally 0; if an error occurs, exit status is 1. If a\n    warning occurs, exit status is 2.\n\n    UPX's diagnostics are intended to be self-explanatory.\n\nBUGS\n    Please report all bugs immediately to the authors.\n\nAUTHORS\n     Markus F.X.J. Oberhumer <markus@oberhumer.com>\n     http://www.oberhumer.com\n\n     Laszlo Molnar <ezerotven+github@gmail.com>\n\n     John F. Reiser <jreiser@BitWagon.com>\n\n     Jens Medoch <jssg@users.sourceforge.net>\n\nCOPYRIGHT\n    Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\n\n    Copyright (C) 1996-2023 Laszlo Molnar\n\n    Copyright (C) 2000-2023 John F. Reiser\n\n    Copyright (C) 2002-2023 Jens Medoch\n\n    UPX is distributed with full source code under the terms of the GNU\n    General Public License v2+; either under the pure GPLv2+ (see the file\n    COPYING), or (at your option) under the GPLv+2 with special exceptions\n    and restrictions granting the free usage for all binaries including\n    commercial programs (see the file LICENSE).\n\n    This program is distributed in the hope that it will be useful, but\n    WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n    You should have received a copy of the UPX License Agreements along with\n    this program; see the files COPYING and LICENSE. If not, visit the UPX\n    home page.\n\n"
  },
  {
    "path": "bin/upx-4.1.0-win32/upx.1",
    "content": ".\\\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42)\n.\\\"\n.\\\" Standard preamble:\n.\\\" ========================================================================\n.de Sp \\\" Vertical space (when we can't use .PP)\n.if t .sp .5v\n.if n .sp\n..\n.de Vb \\\" Begin verbatim text\n.ft CW\n.nf\n.ne \\\\$1\n..\n.de Ve \\\" End verbatim text\n.ft R\n.fi\n..\n.\\\" Set up some character translations and predefined strings.  \\*(-- will\n.\\\" give an unbreakable dash, \\*(PI will give pi, \\*(L\" will give a left\n.\\\" double quote, and \\*(R\" will give a right double quote.  \\*(C+ will\n.\\\" give a nicer C++.  Capital omega is used to do unbreakable dashes and\n.\\\" therefore won't be available.  \\*(C` and \\*(C' expand to `' in nroff,\n.\\\" nothing in troff, for use with C<>.\n.tr \\(*W-\n.ds C+ C\\v'-.1v'\\h'-1p'\\s-2+\\h'-1p'+\\s0\\v'.1v'\\h'-1p'\n.ie n \\{\\\n.    ds -- \\(*W-\n.    ds PI pi\n.    if (\\n(.H=4u)&(1m=24u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-12u'-\\\" diablo 10 pitch\n.    if (\\n(.H=4u)&(1m=20u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-8u'-\\\"  diablo 12 pitch\n.    ds L\" \"\"\n.    ds R\" \"\"\n.    ds C` \"\"\n.    ds C' \"\"\n'br\\}\n.el\\{\\\n.    ds -- \\|\\(em\\|\n.    ds PI \\(*p\n.    ds L\" ``\n.    ds R\" ''\n.    ds C`\n.    ds C'\n'br\\}\n.\\\"\n.\\\" Escape single quotes in literal strings from groff's Unicode transform.\n.ie \\n(.g .ds Aq \\(aq\n.el       .ds Aq '\n.\\\"\n.\\\" If the F register is >0, we'll generate index entries on stderr for\n.\\\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index\n.\\\" entries marked with X<> in POD.  Of course, you'll have to process the\n.\\\" output yourself in some meaningful fashion.\n.\\\"\n.\\\" Avoid warning from groff about undefined register 'F'.\n.de IX\n..\n.nr rF 0\n.if \\n(.g .if rF .nr rF 1\n.if (\\n(rF:(\\n(.g==0)) \\{\\\n.    if \\nF \\{\\\n.        de IX\n.        tm Index:\\\\$1\\t\\\\n%\\t\"\\\\$2\"\n..\n.        if !\\nF==2 \\{\\\n.            nr % 0\n.            nr F 2\n.        \\}\n.    \\}\n.\\}\n.rr rF\n.\\\"\n.\\\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).\n.\\\" Fear.  Run.  Save yourself.  No user-serviceable parts.\n.    \\\" fudge factors for nroff and troff\n.if n \\{\\\n.    ds #H 0\n.    ds #V .8m\n.    ds #F .3m\n.    ds #[ \\f1\n.    ds #] \\fP\n.\\}\n.if t \\{\\\n.    ds #H ((1u-(\\\\\\\\n(.fu%2u))*.13m)\n.    ds #V .6m\n.    ds #F 0\n.    ds #[ \\&\n.    ds #] \\&\n.\\}\n.    \\\" simple accents for nroff and troff\n.if n \\{\\\n.    ds ' \\&\n.    ds ` \\&\n.    ds ^ \\&\n.    ds , \\&\n.    ds ~ ~\n.    ds /\n.\\}\n.if t \\{\\\n.    ds ' \\\\k:\\h'-(\\\\n(.wu*8/10-\\*(#H)'\\'\\h\"|\\\\n:u\"\n.    ds ` \\\\k:\\h'-(\\\\n(.wu*8/10-\\*(#H)'\\`\\h'|\\\\n:u'\n.    ds ^ \\\\k:\\h'-(\\\\n(.wu*10/11-\\*(#H)'^\\h'|\\\\n:u'\n.    ds , \\\\k:\\h'-(\\\\n(.wu*8/10)',\\h'|\\\\n:u'\n.    ds ~ \\\\k:\\h'-(\\\\n(.wu-\\*(#H-.1m)'~\\h'|\\\\n:u'\n.    ds / \\\\k:\\h'-(\\\\n(.wu*8/10-\\*(#H)'\\z\\(sl\\h'|\\\\n:u'\n.\\}\n.    \\\" troff and (daisy-wheel) nroff accents\n.ds : \\\\k:\\h'-(\\\\n(.wu*8/10-\\*(#H+.1m+\\*(#F)'\\v'-\\*(#V'\\z.\\h'.2m+\\*(#F'.\\h'|\\\\n:u'\\v'\\*(#V'\n.ds 8 \\h'\\*(#H'\\(*b\\h'-\\*(#H'\n.ds o \\\\k:\\h'-(\\\\n(.wu+\\w'\\(de'u-\\*(#H)/2u'\\v'-.3n'\\*(#[\\z\\(de\\v'.3n'\\h'|\\\\n:u'\\*(#]\n.ds d- \\h'\\*(#H'\\(pd\\h'-\\w'~'u'\\v'-.25m'\\f2\\(hy\\fP\\v'.25m'\\h'-\\*(#H'\n.ds D- D\\\\k:\\h'-\\w'D'u'\\v'-.11m'\\z\\(hy\\v'.11m'\\h'|\\\\n:u'\n.ds th \\*(#[\\v'.3m'\\s+1I\\s-1\\v'-.3m'\\h'-(\\w'I'u*2/3)'\\s-1o\\s+1\\*(#]\n.ds Th \\*(#[\\s+2I\\s-2\\h'-\\w'I'u*3/5'\\v'-.3m'o\\v'.3m'\\*(#]\n.ds ae a\\h'-(\\w'a'u*4/10)'e\n.ds Ae A\\h'-(\\w'A'u*4/10)'E\n.    \\\" corrections for vroff\n.if v .ds ~ \\\\k:\\h'-(\\\\n(.wu*9/10-\\*(#H)'\\s-2\\u~\\d\\s+2\\h'|\\\\n:u'\n.if v .ds ^ \\\\k:\\h'-(\\\\n(.wu*10/11-\\*(#H)'\\v'-.4m'^\\v'.4m'\\h'|\\\\n:u'\n.    \\\" for low resolution devices (crt and lpr)\n.if \\n(.H>23 .if \\n(.V>19 \\\n\\{\\\n.    ds : e\n.    ds 8 ss\n.    ds o a\n.    ds d- d\\h'-1'\\(ga\n.    ds D- D\\h'-1'\\(hy\n.    ds th \\o'bp'\n.    ds Th \\o'LP'\n.    ds ae ae\n.    ds Ae AE\n.\\}\n.rm #[ #] #H #V #F C\n.\\\" ========================================================================\n.\\\"\n.IX Title \"UPX 1\"\n.TH UPX 1 \"2023-08-08\" \"upx 4.1.0\" \" \"\n.\\\" For nroff, turn off justification.  Always turn off hyphenation; it makes\n.\\\" way too many mistakes in technical documents.\n.if n .ad l\n.nh\n.SH \"NAME\"\nupx \\- compress or expand executable files\n.SH \"SYNOPSIS\"\n.IX Header \"SYNOPSIS\"\n\\&\\fBupx\\fR [\\ \\fIcommand\\fR\\ ] [\\ \\fIoptions\\fR\\ ] \\fIfilename\\fR...\n.SH \"ABSTRACT\"\n.IX Header \"ABSTRACT\"\n.Vb 3\n\\&                    The Ultimate Packer for eXecutables\n\\&   Copyright (c) 1996\\-2023 Markus Oberhumer, Laszlo Molnar & John Reiser\n\\&                           https://upx.github.io\n.Ve\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR is a portable, extendable, high-performance executable packer for\nseveral different executable formats. It achieves an excellent compression\nratio and offers \\fI*very*\\fR fast decompression. Your executables suffer\nno memory overhead or other drawbacks for most of the formats supported,\nbecause of in-place decompression.\n.SH \"DISCLAIMER\"\n.IX Header \"DISCLAIMER\"\n\\&\\fB\\s-1UPX\\s0\\fR comes with \\s-1ABSOLUTELY NO WARRANTY\\s0; for details see the file \\s-1COPYING.\\s0\n.PP\nPlease report all problems or suggestions to the authors. Thanks.\n.SH \"SECURITY CONTEXT\"\n.IX Header \"SECURITY CONTEXT\"\n\\&\\s-1IMPORTANT NOTE:\\s0 \\fB\\s-1UPX\\s0\\fR inherits the security context of any files it handles.\n.PP\nThis means that packing, unpacking, or even testing or listing a file requires\nthe same security considerations as actually executing the file.\n.PP\nUse \\fB\\s-1UPX\\s0\\fR on trusted files only!\n.SH \"DESCRIPTION\"\n.IX Header \"DESCRIPTION\"\n\\&\\fB\\s-1UPX\\s0\\fR is a versatile executable packer with the following features:\n.PP\n.Vb 3\n\\&  \\- secure: as UPX is documented Open Source since many years any relevant\n\\&      Security/Antivirus software is able to peek inside UPX compressed\n\\&      apps to verify them\n\\&\n\\&  \\- excellent compression ratio: typically compresses better than Zip,\n\\&      use UPX to decrease the size of your distribution !\n\\&\n\\&  \\- very fast decompression: more than 500 MB/sec on any reasonably modern\n\\&      machine\n\\&\n\\&  \\- no memory overhead for your compressed executables for most of the\n\\&      supported formats because of in\\-place decompression\n\\&\n\\&  \\- safe: you can list, test and unpack your executables.\n\\&      Also, a checksum of both the compressed and uncompressed file is\n\\&      maintained internally.\n\\&\n\\&  \\- universal: UPX can pack a number of executable formats, including\n\\&      Windows programs and DLLs, macOS apps and Linux executables\n\\&\n\\&  \\- portable: UPX is written in portable endian\\-neutral C++\n\\&\n\\&  \\- extendable: because of the class layout it\\*(Aqs very easy to support\n\\&      new executable formats or add new compression algorithms\n\\&\n\\&  \\- free: UPX is distributed with full source code under the GNU General\n\\&      Public License v2+, with special exceptions granting the free usage\n\\&      for commercial programs\n.Ve\n.PP\nYou probably understand now why we call \\fB\\s-1UPX\\s0\\fR the \"\\fIultimate\\fR\"\nexecutable packer.\n.SH \"COMMANDS\"\n.IX Header \"COMMANDS\"\n.SS \"Compress\"\n.IX Subsection \"Compress\"\nThis is the default operation, eg. \\fBupx yourfile.exe\\fR will compress the file\nspecified on the command line.\n.SS \"Decompress\"\n.IX Subsection \"Decompress\"\nAll \\fB\\s-1UPX\\s0\\fR supported file formats can be unpacked using the \\fB\\-d\\fR switch, eg.\n\\&\\fBupx \\-d yourfile.exe\\fR will uncompress the file you've just compressed.\n.SS \"Test\"\n.IX Subsection \"Test\"\nThe \\fB\\-t\\fR command tests the integrity of the compressed and uncompressed\ndata, eg. \\fBupx \\-t yourfile.exe\\fR check whether your file can be safely\ndecompressed. Note, that this command doesn't check the whole file, only\nthe part that will be uncompressed during program execution. This means\nthat you should not use this command instead of a virus checker.\n.SS \"List\"\n.IX Subsection \"List\"\nThe \\fB\\-l\\fR command prints out some information about the compressed files\nspecified on the command line as parameters, eg \\fBupx \\-l yourfile.exe\\fR\nshows the compressed / uncompressed size and the compression ratio of\n\\&\\fIyourfile.exe\\fR.\n.SH \"OPTIONS\"\n.IX Header \"OPTIONS\"\n\\&\\fB\\-q\\fR: be quiet, suppress warnings\n.PP\n\\&\\fB\\-q \\-q\\fR (or \\fB\\-qq\\fR): be very quiet, suppress errors\n.PP\n\\&\\fB\\-q \\-q \\-q\\fR (or \\fB\\-qqq\\fR): produce no output at all\n.PP\n\\&\\fB\\-\\-help\\fR: prints the help\n.PP\n\\&\\fB\\-\\-version\\fR: print the version of \\fB\\s-1UPX\\s0\\fR\n.PP\n\\&\\fB\\-\\-exact\\fR: when compressing, require to be able to get a byte-identical file\nafter decompression with option \\fB\\-d\\fR. [\\s-1NOTE:\\s0 this is work in progress and is\nnot supported for all formats yet. If you do care, as a workaround you can\ncompress and then decompress your program a first time \\- any further\ncompress-decompress steps should then yield byte-identical results\nas compared to the first decompressed version.]\n.PP\n\\&\\fB\\-k\\fR: keep backup files\n.PP\n\\&\\fB\\-o file\\fR: write output to file\n.PP\n[ ...more docs need to be written... \\- type `\\fBupx \\-\\-help\\fR' for now ]\n.SH \"COMPRESSION LEVELS & TUNING\"\n.IX Header \"COMPRESSION LEVELS & TUNING\"\n\\&\\fB\\s-1UPX\\s0\\fR offers ten different compression levels from \\fB\\-1\\fR to \\fB\\-9\\fR,\nand \\fB\\-\\-best\\fR.  The default compression level is \\fB\\-8\\fR for files\nsmaller than 512 KiB, and \\fB\\-7\\fR otherwise.\n.IP \"\\(bu\" 4\nCompression levels 1, 2 and 3 are pretty fast.\n.IP \"\\(bu\" 4\nCompression levels 4, 5 and 6 achieve a good time/ratio performance.\n.IP \"\\(bu\" 4\nCompression levels 7, 8 and 9 favor compression ratio over speed.\n.IP \"\\(bu\" 4\nCompression level \\fB\\-\\-best\\fR may take a long time.\n.PP\nNote that compression level \\fB\\-\\-best\\fR can be somewhat slow for large\nfiles, but you definitely should use it when releasing a final version\nof your program.\n.PP\nQuick info for achieving the best compression ratio:\n.IP \"\\(bu\" 4\nTry \\fBupx \\-\\-brute \\-\\-no\\-lzma myfile.exe\\fR or even\n\\&\\fBupx \\-\\-ultra\\-brute \\-\\-no\\-lzma myfile.exe\\fR.\n.IP \"\\(bu\" 4\nThe option \\fB\\-\\-lzma\\fR enables \\s-1LZMA\\s0 compression, which compresses better but\nis *significantly slower* at decompression. You probably do not want\nto use it for large files.\n.Sp\n(Note that \\fB\\-\\-lzma\\fR is automatically enabled by \\fB\\-\\-all\\-methods\\fR and\n\\&\\fB\\-\\-brute\\fR, use \\fB\\-\\-no\\-lzma\\fR to override.)\n.IP \"\\(bu\" 4\nTry if \\fB\\-\\-overlay=strip\\fR works.\n.IP \"\\(bu\" 4\nFor win32/pe programs there's \\fB\\-\\-strip\\-relocs=0\\fR. See notes below.\n.SH \"OVERLAY HANDLING OPTIONS\"\n.IX Header \"OVERLAY HANDLING OPTIONS\"\nInfo: An \\*(L\"overlay\\*(R\" means auxiliary data attached after the logical end of\nan executable, and it often contains application specific data\n(this is a common practice to avoid an extra data file, though\nit would be better to use resource sections).\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR handles overlays like many other executable packers do: it simply\ncopies the overlay after the compressed image. This works with some\nfiles, but doesn't work with others, depending on how an application\nactually accesses this overlaid data.\n.PP\n.Vb 1\n\\&  \\-\\-overlay=copy    Copy any extra data attached to the file. [DEFAULT]\n\\&\n\\&  \\-\\-overlay=strip   Strip any overlay from the program instead of\n\\&                    copying it. Be warned, this may make the compressed\n\\&                    program crash or otherwise unusable.\n\\&\n\\&  \\-\\-overlay=skip    Refuse to compress any program which has an overlay.\n.Ve\n.SH \"ENVIRONMENT VARIABLE\"\n.IX Header \"ENVIRONMENT VARIABLE\"\nThe environment variable \\fB\\s-1UPX\\s0\\fR can hold a set of default\noptions for \\fB\\s-1UPX\\s0\\fR. These options are interpreted first and\ncan be overwritten by explicit command line parameters.\nFor example:\n.PP\n.Vb 3\n\\&    for DOS/Windows:   set UPX=\\-9 \\-\\-compress\\-icons#0\n\\&    for sh/ksh/zsh:    UPX=\"\\-9 \\-\\-compress\\-icons=0\"; export UPX\n\\&    for csh/tcsh:      setenv UPX \"\\-9 \\-\\-compress\\-icons=0\"\n.Ve\n.PP\nUnder DOS/Windows you must use '#' instead of '=' when setting the\nenvironment variable because of a \\s-1COMMAND.COM\\s0 limitation.\n.PP\nNot all of the options are valid in the environment variable \\-\n\\&\\fB\\s-1UPX\\s0\\fR will tell you.\n.PP\nYou can explicitly use the \\fB\\-\\-no\\-env\\fR option to ignore the\nenvironment variable.\n.SH \"NOTES FOR THE SUPPORTED EXECUTABLE FORMATS\"\n.IX Header \"NOTES FOR THE SUPPORTED EXECUTABLE FORMATS\"\n.SS \"\\s-1NOTES FOR ATARI/TOS\\s0\"\n.IX Subsection \"NOTES FOR ATARI/TOS\"\nThis is the executable format used by the Atari \\s-1ST/TT,\\s0 a Motorola 68000\nbased personal computer which was popular in the late '80s. Support\nof this format is only because of nostalgic feelings of one of\nthe authors and serves no practical purpose :\\-).\nSee https://freemint.github.io for more info.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\nAll debug information will be stripped, though.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 4\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR BVMLINUZ/I386\\s0\"\n.IX Subsection \"NOTES FOR BVMLINUZ/I386\"\nSame as vmlinuz/i386.\n.SS \"\\s-1NOTES FOR DOS/COM\\s0\"\n.IX Subsection \"NOTES FOR DOS/COM\"\nObviously \\fB\\s-1UPX\\s0\\fR won't work with executables that want to read data from\nthemselves (like some commandline utilities that ship with Win95/98/ME).\n.PP\nCompressed programs only work on a 286+.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\n.PP\nMaximum uncompressed size: ~65100 bytes.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 1\n\\&  \\-\\-8086              Create an executable that works on any 8086 CPU.\n\\&\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR DOS/EXE\\s0\"\n.IX Subsection \"NOTES FOR DOS/EXE\"\ndos/exe stands for all \\*(L\"normal\\*(R\" 16\\-bit \\s-1DOS\\s0 executables.\n.PP\nObviously \\fB\\s-1UPX\\s0\\fR won't work with executables that want to read data from\nthemselves (like some command line utilities that ship with Win95/98/ME).\n.PP\nCompressed programs only work on a 286+.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 1\n\\&  \\-\\-8086              Create an executable that works on any 8086 CPU.\n\\&\n\\&  \\-\\-no\\-reloc          Use no relocation records in the exe header.\n\\&\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR DOS/SYS\\s0\"\n.IX Subsection \"NOTES FOR DOS/SYS\"\nCompressed programs only work on a 286+.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\n.PP\nMaximum uncompressed size: ~65350 bytes.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 1\n\\&  \\-\\-8086              Create an executable that works on any 8086 CPU.\n\\&\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR DJGPP2/COFF\\s0\"\n.IX Subsection \"NOTES FOR DJGPP2/COFF\"\nFirst of all, it is recommended to use \\fB\\s-1UPX\\s0\\fR *instead* of \\fBstrip\\fR. strip has\nthe very bad habit of replacing your stub with its own (outdated) version.\nAdditionally \\fB\\s-1UPX\\s0\\fR corrects a bug/feature in strip v2.8.x: it\nwill fix the 4 KiB alignment of the stub.\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR includes the full functionality of stubify. This means it will\nautomatically stubify your \\s-1COFF\\s0 files. Use the option \\fB\\-\\-coff\\fR to\ndisable this functionality (see below).\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR automatically handles Allegro packfiles.\n.PP\nThe \\s-1DLM\\s0 format (a rather exotic shared library extension) is not supported.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\nAll debug information and trailing garbage will be stripped, though.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 2\n\\&  \\-\\-coff              Produce COFF output instead of EXE. By default\n\\&                      UPX keeps your current stub.\n\\&\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR LINUX\\s0 [general]\"\n.IX Subsection \"NOTES FOR LINUX [general]\"\nIntroduction\n.PP\n.Vb 4\n\\&  Linux/386 support in UPX consists of 3 different executable formats,\n\\&  one optimized for ELF executables (\"linux/elf386\"), one optimized\n\\&  for shell scripts (\"linux/sh386\"), and one generic format\n\\&  (\"linux/386\").\n\\&\n\\&  We will start with a general discussion first, but please\n\\&  also read the relevant docs for each of the individual formats.\n\\&\n\\&  Also, there is special support for bootable kernels \\- see the\n\\&  description of the vmlinuz/386 format.\n.Ve\n.PP\nGeneral user's overview\n.PP\n.Vb 7\n\\&  Running a compressed executable program trades less space on a\n\\&  \\`\\`permanent\\*(Aq\\*(Aq storage medium (such as a hard disk, floppy disk,\n\\&  CD\\-ROM, flash memory, EPROM, etc.) for more space in one or more\n\\&  \\`\\`temporary\\*(Aq\\*(Aq storage media (such as RAM, swap space, /tmp, etc.).\n\\&  Running a compressed executable also requires some additional CPU\n\\&  cycles to generate the compressed executable in the first place,\n\\&  and to decompress it at each invocation.\n\\&\n\\&  How much space is traded?  It depends on the executable, but many\n\\&  programs save 30% to 50% of permanent disk space.  How much CPU\n\\&  overhead is there?  Again, it depends on the executable, but\n\\&  decompression speed generally is at least many megabytes per second,\n\\&  and frequently is limited by the speed of the underlying disk\n\\&  or network I/O.\n\\&\n\\&  Depending on the statistics of usage and access, and the relative\n\\&  speeds of CPU, RAM, swap space, /tmp, and file system storage, then\n\\&  invoking and running a compressed executable can be faster than\n\\&  directly running the corresponding uncompressed program.\n\\&  The operating system might perform fewer expensive I/O operations\n\\&  to invoke the compressed program.  Paging to or from swap space\n\\&  or /tmp might be faster than paging from the general file system.\n\\&  \\`\\`Medium\\-sized\\*(Aq\\*(Aq programs which access about 1/3 to 1/2 of their\n\\&  stored program bytes can do particularly well with compression.\n\\&  Small programs tend not to benefit as much because the absolute\n\\&  savings is less.  Big programs tend not to benefit proportionally\n\\&  because each invocation may use only a small fraction of the program,\n\\&  yet UPX decompresses the entire program before invoking it.\n\\&  But in environments where disk or flash memory storage is limited,\n\\&  then compression may win anyway.\n\\&\n\\&  Currently, executables compressed by UPX do not share RAM at runtime\n\\&  in the way that executables mapped from a file system do.  As a\n\\&  result, if the same program is run simultaneously by more than one\n\\&  process, then using the compressed version will require more RAM and/or\n\\&  swap space.  So, shell programs (bash, csh, etc.)  and \\`\\`make\\*(Aq\\*(Aq\n\\&  might not be good candidates for compression.\n\\&\n\\&  UPX recognizes three executable formats for Linux: Linux/elf386,\n\\&  Linux/sh386, and Linux/386.  Linux/386 is the most generic format;\n\\&  it accommodates any file that can be executed.  At runtime, the UPX\n\\&  decompression stub re\\-creates in /tmp a copy of the original file,\n\\&  and then the copy is (re\\-)executed with the same arguments.\n\\&  ELF binary executables prefer the Linux/elf386 format by default,\n\\&  because UPX decompresses them directly into RAM, uses only one\n\\&  exec, does not use space in /tmp, and does not use /proc.\n\\&  Shell scripts where the underlying shell accepts a \\`\\`\\-c\\*(Aq\\*(Aq argument\n\\&  can use the Linux/sh386 format.  UPX decompresses the shell script\n\\&  into low memory, then maps the shell and passes the entire text of the\n\\&  script as an argument with a leading \\`\\`\\-c\\*(Aq\\*(Aq.\n.Ve\n.PP\nGeneral benefits:\n.PP\n.Vb 4\n\\&  \\- UPX can compress all executables, be it AOUT, ELF, libc4, libc5,\n\\&    libc6, Shell/Perl/Python/... scripts, standalone Java .class\n\\&    binaries, or whatever...\n\\&    All scripts and programs will work just as before.\n\\&\n\\&  \\- Compressed programs are completely self\\-contained. No need for\n\\&    any external program.\n\\&\n\\&  \\- UPX keeps your original program untouched. This means that\n\\&    after decompression you will have a byte\\-identical version,\n\\&    and you can use UPX as a file compressor just like gzip.\n\\&    [ Note that UPX maintains a checksum of the file internally,\n\\&      so it is indeed a reliable alternative. ]\n\\&\n\\&  \\- As the stub only uses syscalls and isn\\*(Aqt linked against libc it\n\\&    should run under any Linux configuration that can run ELF\n\\&    binaries.\n\\&\n\\&  \\- For the same reason compressed executables should run under\n\\&    FreeBSD and other systems which can run Linux binaries.\n\\&    [ Please send feedback on this topic ]\n.Ve\n.PP\nGeneral drawbacks:\n.PP\n.Vb 4\n\\&  \\- It is not advisable to compress programs which usually have many\n\\&    instances running (like \\`sh\\*(Aq or \\`make\\*(Aq) because the common segments of\n\\&    compressed programs won\\*(Aqt be shared any longer between different\n\\&    processes.\n\\&\n\\&  \\- \\`ldd\\*(Aq and \\`size\\*(Aq won\\*(Aqt show anything useful because all they\n\\&    see is the statically linked stub.  Since version 0.82 the section\n\\&    headers are stripped from the UPX stub and \\`size\\*(Aq doesn\\*(Aqt even\n\\&    recognize the file format.  The file patches/patch\\-elfcode.h has a\n\\&    patch to fix this bug in \\`size\\*(Aq and other programs which use GNU BFD.\n.Ve\n.PP\nGeneral notes:\n.PP\n.Vb 2\n\\&  \\- As UPX leaves your original program untouched it is advantageous\n\\&    to strip it before compression.\n\\&\n\\&  \\- If you compress a script you will lose platform independence \\-\n\\&    this could be a problem if you are using NFS mounted disks.\n\\&\n\\&  \\- Compression of suid, guid and sticky\\-bit programs is rejected\n\\&    because of possible security implications.\n\\&\n\\&  \\- For the same reason there is no sense in making any compressed\n\\&    program suid.\n\\&\n\\&  \\- Obviously UPX won\\*(Aqt work with executables that want to read data\n\\&    from themselves. E.g., this might be a problem for Perl scripts\n\\&    which access their _\\|_DATA_\\|_ lines.\n\\&\n\\&  \\- In case of internal errors the stub will abort with exitcode 127.\n\\&    Typical reasons for this to happen are that the program has somehow\n\\&    been modified after compression.\n\\&    Running \\`strace \\-o strace.log compressed_file\\*(Aq will tell you more.\n.Ve\n.SS \"\\s-1NOTES FOR LINUX/ELF386\\s0\"\n.IX Subsection \"NOTES FOR LINUX/ELF386\"\nPlease read the general Linux description first.\n.PP\nThe linux/elf386 format decompresses directly into \\s-1RAM,\\s0\nuses only one exec, does not use space in /tmp,\nand does not use /proc.\n.PP\nLinux/elf386 is automatically selected for Linux \\s-1ELF\\s0 executables.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\n.PP\nHow it works:\n.PP\n.Vb 9\n\\&  For ELF executables, UPX decompresses directly to memory, simulating\n\\&  the mapping that the operating system kernel uses during exec(),\n\\&  including the PT_INTERP program interpreter (if any).\n\\&  The brk() is set by a special PT_LOAD segment in the compressed\n\\&  executable itself.  UPX then wipes the stack clean except for\n\\&  arguments, environment variables, and Elf_auxv entries (this is\n\\&  required by bugs in the startup code of /lib/ld\\-linux.so as of\n\\&  May 2000), and transfers control to the program interpreter or\n\\&  the e_entry address of the original executable.\n\\&\n\\&  The UPX stub is about 1700 bytes long, partly written in assembler\n\\&  and only uses kernel syscalls. It is not linked against any libc.\n.Ve\n.PP\nSpecific drawbacks:\n.PP\n.Vb 9\n\\&  \\- For linux/elf386 and linux/sh386 formats, you will be relying on\n\\&    RAM and swap space to hold all of the decompressed program during\n\\&    the lifetime of the process.  If you already use most of your swap\n\\&    space, then you may run out.  A system that is \"out of memory\"\n\\&    can become fragile.  Many programs do not react gracefully when\n\\&    malloc() returns 0.  With newer Linux kernels, the kernel\n\\&    may decide to kill some processes to regain memory, and you\n\\&    may not like the kernel\\*(Aqs choice of which to kill.  Running\n\\&    /usr/bin/top is one way to check on the usage of swap space.\n.Ve\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 1\n\\&  (none)\n.Ve\n.SS \"\\s-1NOTES FOR LINUX/SH386\\s0\"\n.IX Subsection \"NOTES FOR LINUX/SH386\"\nPlease read the general Linux description first.\n.PP\nShell scripts where the underling shell accepts a ``\\-c'' argument\ncan use the Linux/sh386 format.  \\fB\\s-1UPX\\s0\\fR decompresses the shell script\ninto low memory, then maps the shell and passes the entire text of the\nscript as an argument with a leading ``\\-c''.\nIt does not use space in /tmp, and does not use /proc.\n.PP\nLinux/sh386 is automatically selected for shell scripts that\nuse a known shell.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\n.PP\nHow it works:\n.PP\n.Vb 8\n\\&  For shell script executables (files beginning with \"#!/\" or \"#! /\")\n\\&  where the shell is known to accept \"\\-c <command>\", UPX decompresses\n\\&  the file into low memory, then maps the shell (and its PT_INTERP),\n\\&  and passes control to the shell with the entire decompressed file\n\\&  as the argument after \"\\-c\".  Known shells are sh, ash, bash, bsh, csh,\n\\&  ksh, tcsh, pdksh.  Restriction: UPX cannot use this method\n\\&  for shell scripts which use the one optional string argument after\n\\&  the shell name in the script (example: \"#! /bin/sh option3\\en\".)\n\\&\n\\&  The UPX stub is about 1700 bytes long, partly written in assembler\n\\&  and only uses kernel syscalls. It is not linked against any libc.\n.Ve\n.PP\nSpecific drawbacks:\n.PP\n.Vb 9\n\\&  \\- For linux/elf386 and linux/sh386 formats, you will be relying on\n\\&    RAM and swap space to hold all of the decompressed program during\n\\&    the lifetime of the process.  If you already use most of your swap\n\\&    space, then you may run out.  A system that is \"out of memory\"\n\\&    can become fragile.  Many programs do not react gracefully when\n\\&    malloc() returns 0.  With newer Linux kernels, the kernel\n\\&    may decide to kill some processes to regain memory, and you\n\\&    may not like the kernel\\*(Aqs choice of which to kill.  Running\n\\&    /usr/bin/top is one way to check on the usage of swap space.\n.Ve\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 1\n\\&  (none)\n.Ve\n.SS \"\\s-1NOTES FOR LINUX/386\\s0\"\n.IX Subsection \"NOTES FOR LINUX/386\"\nPlease read the general Linux description first.\n.PP\nThe generic linux/386 format decompresses to /tmp and needs\n/proc file system support. It starts the decompressed program\nvia the \\fBexecve()\\fR syscall.\n.PP\nLinux/386 is only selected if the specialized linux/elf386\nand linux/sh386 won't recognize a file.\n.PP\nPacked programs will be byte-identical to the original after uncompression.\n.PP\nHow it works:\n.PP\n.Vb 7\n\\&  For files which are not ELF and not a script for a known \"\\-c\" shell,\n\\&  UPX uses kernel execve(), which first requires decompressing to a\n\\&  temporary file in the file system.  Interestingly \\-\n\\&  because of the good memory management of the Linux kernel \\- this\n\\&  often does not introduce a noticeable delay, and in fact there\n\\&  will be no disk access at all if you have enough free memory as\n\\&  the entire process takes places within the file system buffers.\n\\&\n\\&  A compressed executable consists of the UPX stub and an overlay\n\\&  which contains the original program in a compressed form.\n\\&\n\\&  The UPX stub is a statically linked ELF executable and does\n\\&  the following at program startup:\n\\&\n\\&    1) decompress the overlay to a temporary location in /tmp\n\\&    2) open the temporary file for reading\n\\&    3) try to delete the temporary file and start (execve)\n\\&       the uncompressed program in /tmp using /proc/<pid>/fd/X as\n\\&       attained by step 2)\n\\&    4) if that fails, fork off a subprocess to clean up and\n\\&       start the program in /tmp in the meantime\n\\&\n\\&  The UPX stub is about 1700 bytes long, partly written in assembler\n\\&  and only uses kernel syscalls. It is not linked against any libc.\n.Ve\n.PP\nSpecific drawbacks:\n.PP\n.Vb 4\n\\&  \\- You need additional free disk space for the uncompressed program\n\\&    in your /tmp directory. This program is deleted immediately after\n\\&    decompression, but you still need it for the full execution time\n\\&    of the program.\n\\&\n\\&  \\- You must have /proc file system support as the stub wants to open\n\\&    /proc/<pid>/exe and needs /proc/<pid>/fd/X. This also means that you\n\\&    cannot compress programs that are used during the boot sequence\n\\&    before /proc is mounted.\n\\&\n\\&  \\- Utilities like \\`top\\*(Aq will display numerical values in the process\n\\&    name field. This is because Linux computes the process name from\n\\&    the first argument of the last execve syscall (which is typically\n\\&    something like /proc/<pid>/fd/3).\n\\&\n\\&  \\- Because of temporary decompression to disk the decompression speed\n\\&    is not as fast as with the other executable formats. Still, I can see\n\\&    no noticeable delay when starting programs like my ~3 MiB emacs (which\n\\&    is less than 1 MiB when compressed :\\-).\n.Ve\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 3\n\\&  \\-\\-force\\-execve      Force the use of the generic linux/386 \"execve\"\n\\&                      format, i.e. do not try the linux/elf386 and\n\\&                      linux/sh386 formats.\n.Ve\n.SS \"\\s-1NOTES FOR PS1/EXE\\s0\"\n.IX Subsection \"NOTES FOR PS1/EXE\"\nThis is the executable format used by the Sony PlayStation (PSone),\na \\s-1MIPS R3000\\s0 based gaming console which is popular since the late '90s.\nSupport of this format is very similar to the Atari one, because of\nnostalgic feelings of one of the authors.\n.PP\nPacked programs will be byte-identical to the original after uncompression,\nuntil further notice.\n.PP\nMaximum uncompressed size: ~1.89 / ~7.60 MiB.\n.PP\nNotes:\n.PP\n.Vb 6\n\\&  \\- UPX creates as default a suitable executable for CD\\-Mastering\n\\&    and console transfer. For a CD\\-Master main executable you could also try\n\\&    the special option \"\\-\\-boot\\-only\" as described below.\n\\&    It has been reported that upx packed executables are fully compatible with\n\\&    the Sony PlayStation 2 (PS2, PStwo) and Sony PlayStation Portable (PSP) in\n\\&    Sony PlayStation (PSone) emulation mode.\n\\&\n\\&  \\- Normally the packed files use the same memory areas like the uncompressed\n\\&    versions, so they will not override other memory areas while unpacking.\n\\&    If this isn\\*(Aqt possible UPX will abort showing a \\*(Aqpacked data overlap\\*(Aq\n\\&    error. With the \"\\-\\-force\" option UPX will relocate the loading address\n\\&    for the packed file, but this isn\\*(Aqt a real problem if it is a single or\n\\&    the main executable.\n.Ve\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 4\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-8\\-bit             Uses 8 bit size compression [default: 32 bit]\n\\&\n\\&  \\-\\-8mib\\-ram          PSone has 8 MiB ram available [default: 2 MiB]\n\\&\n\\&  \\-\\-boot\\-only         This format is for main exes and CD\\-Mastering only !\n\\&                      It may slightly improve the compression ratio,\n\\&                      decompression routines are faster than default ones.\n\\&                      But it cannot be used for console transfer !\n\\&\n\\&  \\-\\-no\\-align          This option disables CD mode 2 data sector format\n\\&                      alignment. May slightly improves the compression ratio,\n\\&                      but the compressed executable will not boot from a CD.\n\\&                      Use it for console transfer only !\n.Ve\n.SS \"\\s-1NOTES FOR RTM32/PE\\s0 and \\s-1ARM/PE\\s0\"\n.IX Subsection \"NOTES FOR RTM32/PE and ARM/PE\"\nSame as win32/pe.\n.SS \"\\s-1NOTES FOR TMT/ADAM\\s0\"\n.IX Subsection \"NOTES FOR TMT/ADAM\"\nThis format is used by the \\s-1TMT\\s0 Pascal compiler \\- see http://www.tmt.com/ .\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 4\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR VMLINUZ/386\\s0\"\n.IX Subsection \"NOTES FOR VMLINUZ/386\"\nThe vmlinuz/386 and bvmlinuz/386 formats take a gzip-compressed\nbootable Linux kernel image (\\*(L\"vmlinuz\\*(R\", \\*(L\"zImage\\*(R\", \\*(L\"bzImage\\*(R\"),\ngzip-decompress it and re-compress it with the \\fB\\s-1UPX\\s0\\fR compression method.\n.PP\nvmlinuz/386 is completely unrelated to the other Linux executable\nformats, and it does not share any of their drawbacks.\n.PP\nNotes:\n.PP\n.Vb 3\n\\&  \\- Be sure that \"vmlinuz/386\" or \"bvmlinuz/386\" is displayed\n\\&  during compression \\- otherwise a wrong executable format\n\\&  may have been used, and the kernel won\\*(Aqt boot.\n.Ve\n.PP\nBenefits:\n.PP\n.Vb 4\n\\&  \\- Better compression (but note that the kernel was already compressed,\n\\&  so the improvement is not as large as with other formats).\n\\&  Still, the bytes saved may be essential for special needs like\n\\&  boot disks.\n\\&\n\\&     For example, this is what I get for my 2.2.16 kernel:\n\\&        1589708  vmlinux\n\\&         641073  bzImage        [original]\n\\&         560755  bzImage.upx    [compressed by \"upx \\-9\"]\n\\&\n\\&  \\- Much faster decompression at kernel boot time (but kernel\n\\&    decompression speed is not really an issue these days).\n.Ve\n.PP\nDrawbacks:\n.PP\n.Vb 1\n\\&  (none)\n.Ve\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 4\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SS \"\\s-1NOTES FOR WATCOM/LE\\s0\"\n.IX Subsection \"NOTES FOR WATCOM/LE\"\n\\&\\fB\\s-1UPX\\s0\\fR has been successfully tested with the following extenders:\n  \\s-1DOS4G, DOS4GW, PMODE/W,\\s0 DOS32a, CauseWay.\n  The \\s-1WDOS/X\\s0 extender is partly supported (for details\n  see the file bugs \\s-1BUGS\\s0).\n.PP\nDLLs and the \\s-1LX\\s0 format are not supported.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 2\n\\&  \\-\\-le                Produce an unbound LE output instead of\n\\&                      keeping the current stub.\n.Ve\n.SS \"\\s-1NOTES FOR WIN32/PE\\s0\"\n.IX Subsection \"NOTES FOR WIN32/PE\"\nThe \\s-1PE\\s0 support in \\fB\\s-1UPX\\s0\\fR is quite stable now, but probably there are\nstill some incompatibilities with some files.\n.PP\nBecause of the way \\fB\\s-1UPX\\s0\\fR (and other packers for this format) works, you\ncan see increased memory usage of your compressed files because the whole\nprogram is loaded into memory at startup.\nIf you start several instances of huge compressed programs you're\nwasting memory because the common segments of the program won't\nget shared across the instances.\nOn the other hand if you're compressing only smaller programs, or\nrunning only one instance of larger programs, then this penalty is\nsmaller, but it's still there.\n.PP\nIf you're running executables from network, then compressed programs\nwill load faster, and require less bandwidth during execution.\n.PP\nDLLs are supported. But \\s-1UPX\\s0 compressed DLLs can not share common data and\ncode when they got used by multiple applications. So compressing msvcrt.dll\nis a waste of memory, but compressing the dll plugins of a particular\napplication may be a better idea.\n.PP\nScreensavers are supported, with the restriction that the filename\nmust end with \\*(L\".scr\\*(R\" (as screensavers are handled slightly different\nthan normal exe files).\n.PP\n\\&\\s-1UPX\\s0 compressed \\s-1PE\\s0 files have some minor memory overhead (usually in the\n10 \\- 30 KiB range) which can be seen by specifying the \\*(L\"\\-i\\*(R\" command\nline switch during compression.\n.PP\nExtra options available for this executable format:\n.PP\n.Vb 9\n\\& \\-\\-compress\\-exports=0 Don\\*(Aqt compress the export section.\n\\&                      Use this if you plan to run the compressed\n\\&                      program under Wine.\n\\& \\-\\-compress\\-exports=1 Compress the export section. [DEFAULT]\n\\&                      Compression of the export section can improve the\n\\&                      compression ratio quite a bit but may not work\n\\&                      with all programs (like winword.exe).\n\\&                      UPX never compresses the export section of a DLL\n\\&                      regardless of this option.\n\\&\n\\&  \\-\\-compress\\-icons=0  Don\\*(Aqt compress any icons.\n\\&  \\-\\-compress\\-icons=1  Compress all but the first icon.\n\\&  \\-\\-compress\\-icons=2  Compress all icons which are not in the\n\\&                      first icon directory. [DEFAULT]\n\\&  \\-\\-compress\\-icons=3  Compress all icons.\n\\&\n\\&  \\-\\-compress\\-resources=0  Don\\*(Aqt compress any resources at all.\n\\&\n\\&  \\-\\-keep\\-resource=list Don\\*(Aqt compress resources specified by the list.\n\\&                      The members of the list are separated by commas.\n\\&                      A list member has the following format: I<type[/name]>.\n\\&                      I<Type> is the type of the resource. Standard types\n\\&                      must be specified as decimal numbers, user types can be\n\\&                      specified by decimal IDs or strings. I<Name> is the\n\\&                      identifier of the resource. It can be a decimal number\n\\&                      or a string. For example:\n\\&\n\\&                      \\-\\-keep\\-resource=2/MYBITMAP,5,6/12345\n\\&\n\\&                      UPX won\\*(Aqt compress the named bitmap resource \"MYBITMAP\",\n\\&                      it leaves every dialog (5) resource uncompressed, and\n\\&                      it won\\*(Aqt touch the string table resource with identifier\n\\&                      12345.\n\\&\n\\&  \\-\\-force             Force compression even when there is an\n\\&                      unexpected value in a header field.\n\\&                      Use with care.\n\\&\n\\&  \\-\\-strip\\-relocs=0    Don\\*(Aqt strip relocation records.\n\\&  \\-\\-strip\\-relocs=1    Strip relocation records. [DEFAULT]\n\\&                      This option only works on executables with base\n\\&                      address greater or equal to 0x400000. Usually the\n\\&                      compressed files becomes smaller, but some files\n\\&                      may become larger. Note that the resulting file will\n\\&                      not work under Windows 3.x (Win32s).\n\\&                      UPX never strips relocations from a DLL\n\\&                      regardless of this option.\n\\&\n\\&  \\-\\-all\\-methods       Compress the program several times, using all\n\\&                      available compression methods. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default method gives the best results anyway.\n\\&\n\\&  \\-\\-all\\-filters       Compress the program several times, using all\n\\&                      available preprocessing filters. This may improve\n\\&                      the compression ratio in some cases, but usually\n\\&                      the default filter gives the best results anyway.\n.Ve\n.SH \"DIAGNOSTICS\"\n.IX Header \"DIAGNOSTICS\"\nExit status is normally 0; if an error occurs, exit status\nis 1. If a warning occurs, exit status is 2.\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR's diagnostics are intended to be self-explanatory.\n.SH \"BUGS\"\n.IX Header \"BUGS\"\nPlease report all bugs immediately to the authors.\n.SH \"AUTHORS\"\n.IX Header \"AUTHORS\"\n.Vb 2\n\\& Markus F.X.J. Oberhumer <markus@oberhumer.com>\n\\& http://www.oberhumer.com\n\\&\n\\& Laszlo Molnar <ezerotven+github@gmail.com>\n\\&\n\\& John F. Reiser <jreiser@BitWagon.com>\n\\&\n\\& Jens Medoch <jssg@users.sourceforge.net>\n.Ve\n.SH \"COPYRIGHT\"\n.IX Header \"COPYRIGHT\"\nCopyright (C) 1996\\-2023 Markus Franz Xaver Johannes Oberhumer\n.PP\nCopyright (C) 1996\\-2023 Laszlo Molnar\n.PP\nCopyright (C) 2000\\-2023 John F. Reiser\n.PP\nCopyright (C) 2002\\-2023 Jens Medoch\n.PP\n\\&\\fB\\s-1UPX\\s0\\fR is distributed with full source code under the terms of the\n\\&\\s-1GNU\\s0 General Public License v2+; either under the pure GPLv2+ (see\nthe file \\s-1COPYING\\s0), or (at your option) under the GPLv+2 with special\nexceptions and restrictions granting the free usage for all binaries\nincluding commercial programs (see the file \\s-1LICENSE\\s0).\n.PP\nThis program is distributed in the hope that it will be useful,\nbut \\s-1WITHOUT ANY WARRANTY\\s0; without even the implied warranty of\n\\&\\s-1MERCHANTABILITY\\s0 or \\s-1FITNESS FOR A PARTICULAR PURPOSE.\\s0\n.PP\nYou should have received a copy of the \\s-1UPX\\s0 License Agreements along\nwith this program; see the files \\s-1COPYING\\s0 and \\s-1LICENSE.\\s0 If not,\nvisit the \\s-1UPX\\s0 home page.\n"
  },
  {
    "path": "common/jsoncpp/json/autolink.h",
    "content": "#ifndef JSON_AUTOLINK_H_INCLUDED\n# define JSON_AUTOLINK_H_INCLUDED\n\n# include \"config.h\"\n\n# ifdef JSON_IN_CPPTL\n#  include <cpptl/cpptl_autolink.h>\n# endif\n\n# if !defined(JSON_NO_AUTOLINK)  &&  !defined(JSON_DLL_BUILD)  &&  !defined(JSON_IN_CPPTL)\n#  define CPPTL_AUTOLINK_NAME \"json\"\n#  undef CPPTL_AUTOLINK_DLL\n#  ifdef JSON_DLL\n#   define CPPTL_AUTOLINK_DLL\n#  endif\n#  include \"autolink.h\"\n# endif\n\n#endif // JSON_AUTOLINK_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/config.h",
    "content": "#ifndef JSON_CONFIG_H_INCLUDED\n# define JSON_CONFIG_H_INCLUDED\n\n/// If defined, indicates that json library is embedded in CppTL library.\n//# define JSON_IN_CPPTL 1\n\n/// If defined, indicates that json may leverage CppTL library\n//#  define JSON_USE_CPPTL 1\n/// If defined, indicates that cpptl vector based map should be used instead of std::map\n/// as Value container.\n//#  define JSON_USE_CPPTL_SMALLMAP 1\n/// If defined, indicates that Json specific container should be used\n/// (hash table & simple deque container with customizable allocator).\n/// THIS FEATURE IS STILL EXPERIMENTAL!\n//#  define JSON_VALUE_USE_INTERNAL_MAP 1\n/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.\n/// The memory pools allocator used optimization (initializing Value and ValueInternalLink\n/// as if it was a POD) that may cause some validation tool to report errors.\n/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.\n//#  define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1\n\n/// If defined, indicates that Json use exception to report invalid type manipulation\n/// instead of C assert macro.\n# define JSON_USE_EXCEPTION 1\n\n# ifdef JSON_IN_CPPTL\n#  include <cpptl/config.h>\n#  ifndef JSON_USE_CPPTL\n#   define JSON_USE_CPPTL 1\n#  endif\n# endif\n\n# ifdef JSON_IN_CPPTL\n#  define JSON_API CPPTL_API\n# elif defined(JSON_DLL_BUILD)\n#  define JSON_API __declspec(dllexport)\n# elif defined(JSON_DLL)\n#  define JSON_API __declspec(dllimport)\n# else\n#  define JSON_API\n# endif\n\n#endif // JSON_CONFIG_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/features.h",
    "content": "#ifndef CPPTL_JSON_FEATURES_H_INCLUDED\n# define CPPTL_JSON_FEATURES_H_INCLUDED\n\n# include \"forwards.h\"\n\nnamespace Json {\n\n   /** \\brief Configuration passed to reader and writer.\n    * This configuration object can be used to force the Reader or Writer\n    * to behave in a standard conforming way.\n    */\n   class JSON_API Features\n   {\n   public:\n      /** \\brief A configuration that allows all features and assumes all strings are UTF-8.\n       * - C & C++ comments are allowed\n       * - Root object can be any JSON value\n       * - Assumes Value strings are encoded in UTF-8\n       */\n      static Features all();\n\n      /** \\brief A configuration that is strictly compatible with the JSON specification.\n       * - Comments are forbidden.\n       * - Root object must be either an array or an object value.\n       * - Assumes Value strings are encoded in UTF-8\n       */\n      static Features strictMode();\n\n      /** \\brief Initialize the configuration like JsonConfig::allFeatures;\n       */\n      Features();\n\n      /// \\c true if comments are allowed. Default: \\c true.\n      bool allowComments_;\n\n      /// \\c true if root must be either an array or an object value. Default: \\c false.\n      bool strictRoot_;\n   };\n\n} // namespace Json\n\n#endif // CPPTL_JSON_FEATURES_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/forwards.h",
    "content": "#ifndef JSON_FORWARDS_H_INCLUDED\n# define JSON_FORWARDS_H_INCLUDED\n\n# include \"config.h\"\n\nnamespace Json {\n\n   // writer.h\n   class FastWriter;\n   class StyledWriter;\n\n   // reader.h\n   class Reader;\n\n   // features.h\n   class Features;\n\n   // value.h\n   typedef int Int;\n   typedef unsigned int UInt;\n   class StaticString;\n   class Path;\n   class PathArgument;\n   class Value;\n   class ValueIteratorBase;\n   class ValueIterator;\n   class ValueConstIterator;\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   class ValueAllocator;\n   class ValueMapAllocator;\n   class ValueInternalLink;\n   class ValueInternalArray;\n   class ValueInternalMap;\n#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n} // namespace Json\n\n\n#endif // JSON_FORWARDS_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/json.h",
    "content": "#ifndef JSON_JSON_H_INCLUDED\n# define JSON_JSON_H_INCLUDED\n\n# include \"autolink.h\"\n# include \"value.h\"\n# include \"reader.h\"\n# include \"writer.h\"\n# include \"features.h\"\n\n#endif // JSON_JSON_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/reader.h",
    "content": "#ifndef CPPTL_JSON_READER_H_INCLUDED\n# define CPPTL_JSON_READER_H_INCLUDED\n\n# include \"features.h\"\n# include \"value.h\"\n# include <deque>\n# include <stack>\n# include <string>\n# include <iostream>\n\nnamespace Json {\n\n   /** \\brief Unserialize a <a HREF=\"http://www.json.org\">JSON</a> document into a Value.\n    *\n    */\n   class JSON_API Reader\n   {\n   public:\n      typedef char Char;\n      typedef const Char *Location;\n\n      /** \\brief Constructs a Reader allowing all features\n       * for parsing.\n       */\n      Reader();\n\n      /** \\brief Constructs a Reader allowing the specified feature set\n       * for parsing.\n       */\n      Reader( const Features &features );\n\n      /** \\brief Read a Value from a <a HREF=\"http://www.json.org\">JSON</a> document.\n       * \\param document UTF-8 encoded string containing the document to read.\n       * \\param root [out] Contains the root value of the document if it was\n       *             successfully parsed.\n       * \\param collectComments \\c true to collect comment and allow writing them back during\n       *                        serialization, \\c false to discard comments.\n       *                        This parameter is ignored if Features::allowComments_\n       *                        is \\c false.\n       * \\return \\c true if the document was successfully parsed, \\c false if an error occurred.\n       */\n      bool parse( const std::string &document, \n                  Value &root,\n                  bool collectComments = true );\n\n      /** \\brief Read a Value from a <a HREF=\"http://www.json.org\">JSON</a> document.\n       * \\param document UTF-8 encoded string containing the document to read.\n       * \\param root [out] Contains the root value of the document if it was\n       *             successfully parsed.\n       * \\param collectComments \\c true to collect comment and allow writing them back during\n       *                        serialization, \\c false to discard comments.\n       *                        This parameter is ignored if Features::allowComments_\n       *                        is \\c false.\n       * \\return \\c true if the document was successfully parsed, \\c false if an error occurred.\n       */\n      bool parse( const char *beginDoc, const char *endDoc, \n                  Value &root,\n                  bool collectComments = true );\n\n      /// \\brief Parse from input stream.\n      /// \\see Json::operator>>(std::istream&, Json::Value&).\n      bool parse( std::istream &is,\n                  Value &root,\n                  bool collectComments = true );\n\n      /** \\brief Returns a user friendly string that list errors in the parsed document.\n       * \\return Formatted error message with the list of errors with their location in \n       *         the parsed document. An empty string is returned if no error occurred\n       *         during parsing.\n       */\n      std::string getFormatedErrorMessages() const;\n\n   private:\n      enum TokenType\n      {\n         tokenEndOfStream = 0,\n         tokenObjectBegin,\n         tokenObjectEnd,\n         tokenArrayBegin,\n         tokenArrayEnd,\n         tokenString,\n         tokenNumber,\n         tokenTrue,\n         tokenFalse,\n         tokenNull,\n         tokenArraySeparator,\n         tokenMemberSeparator,\n         tokenComment,\n         tokenError\n      };\n\n      class Token\n      {\n      public:\n         TokenType type_;\n         Location start_;\n         Location end_;\n      };\n\n      class ErrorInfo\n      {\n      public:\n         Token token_;\n         std::string message_;\n         Location extra_;\n      };\n\n      typedef std::deque<ErrorInfo> Errors;\n\n      bool expectToken( TokenType type, Token &token, const char *message );\n      bool readToken( Token &token );\n      void skipSpaces();\n      bool match( Location pattern, \n                  int patternLength );\n      bool readComment();\n      bool readCStyleComment();\n      bool readCppStyleComment();\n      bool readString();\n      void readNumber();\n      bool readValue();\n      bool readObject( Token &token );\n      bool readArray( Token &token );\n      bool decodeNumber( Token &token );\n      bool decodeString( Token &token );\n      bool decodeString( Token &token, std::string &decoded );\n      bool decodeDouble( Token &token );\n      bool decodeUnicodeCodePoint( Token &token, \n                                   Location &current, \n                                   Location end, \n                                   unsigned int &unicode );\n      bool decodeUnicodeEscapeSequence( Token &token, \n                                        Location &current, \n                                        Location end, \n                                        unsigned int &unicode );\n      bool addError( const std::string &message, \n                     Token &token,\n                     Location extra = 0 );\n      bool recoverFromError( TokenType skipUntilToken );\n      bool addErrorAndRecover( const std::string &message, \n                               Token &token,\n                               TokenType skipUntilToken );\n      void skipUntilSpace();\n      Value &currentValue();\n      Char getNextChar();\n      void getLocationLineAndColumn( Location location,\n                                     int &line,\n                                     int &column ) const;\n      std::string getLocationLineAndColumn( Location location ) const;\n      void addComment( Location begin, \n                       Location end, \n                       CommentPlacement placement );\n      void skipCommentTokens( Token &token );\n   \n      typedef std::stack<Value *> Nodes;\n      Nodes nodes_;\n      Errors errors_;\n      std::string document_;\n      Location begin_;\n      Location end_;\n      Location current_;\n      Location lastValueEnd_;\n      Value *lastValue_;\n      std::string commentsBefore_;\n      Features features_;\n      bool collectComments_;\n   };\n\n   /** \\brief Read from 'sin' into 'root'.\n\n    Always keep comments from the input JSON.\n\n    This can be used to read a file into a particular sub-object.\n    For example:\n    \\code\n    Json::Value root;\n    cin >> root[\"dir\"][\"file\"];\n    cout << root;\n    \\endcode\n    Result:\n    \\verbatim\n    {\n\t\"dir\": {\n\t    \"file\": {\n\t\t// The input stream JSON would be nested here.\n\t    }\n\t}\n    }\n    \\endverbatim\n    \\throw std::exception on parse error.\n    \\see Json::operator<<()\n   */\n   std::istream& operator>>( std::istream&, Value& );\n\n} // namespace Json\n\n#endif // CPPTL_JSON_READER_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/value.h",
    "content": "#ifndef CPPTL_JSON_H_INCLUDED\n# define CPPTL_JSON_H_INCLUDED\n\n# include \"forwards.h\"\n# include <string>\n# include <vector>\n\n# ifndef JSON_USE_CPPTL_SMALLMAP\n#  include <map>\n# else\n#  include <cpptl/smallmap.h>\n# endif\n# ifdef JSON_USE_CPPTL\n#  include <cpptl/forwards.h>\n# endif\n\n/** \\brief JSON (JavaScript Object Notation).\n */\nnamespace Json {\n\n   /** \\brief Type of the value held by a Value object.\n    */\n   enum ValueType\n   {\n      nullValue = 0, ///< 'null' value\n      intValue,      ///< signed integer value\n      uintValue,     ///< unsigned integer value\n      realValue,     ///< double value\n      stringValue,   ///< UTF-8 string value\n      booleanValue,  ///< bool value\n      arrayValue,    ///< array value (ordered list)\n      objectValue    ///< object value (collection of name/value pairs).\n   };\n\n   enum CommentPlacement\n   {\n      commentBefore = 0,        ///< a comment placed on the line before a value\n      commentAfterOnSameLine,   ///< a comment just after a value on the same line\n      commentAfter,             ///< a comment on the line after a value (only make sense for root value)\n      numberOfCommentPlacement\n   };\n\n//# ifdef JSON_USE_CPPTL\n//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;\n//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;\n//# endif\n\n   /** \\brief Lightweight wrapper to tag static string.\n    *\n    * Value constructor and objectValue member assignement takes advantage of the\n    * StaticString and avoid the cost of string duplication when storing the\n    * string or the member name.\n    *\n    * Example of usage:\n    * \\code\n    * Json::Value aValue( StaticString(\"some text\") );\n    * Json::Value object;\n    * static const StaticString code(\"code\");\n    * object[code] = 1234;\n    * \\endcode\n    */\n   class JSON_API StaticString\n   {\n   public:\n      explicit StaticString( const char *czstring )\n         : str_( czstring )\n      {\n      }\n\n      operator const char *() const\n      {\n         return str_;\n      }\n\n      const char *c_str() const\n      {\n         return str_;\n      }\n\n   private:\n      const char *str_;\n   };\n\n   /** \\brief Represents a <a HREF=\"http://www.json.org\">JSON</a> value.\n    *\n    * This class is a discriminated union wrapper that can represents a:\n    * - signed integer [range: Value::minInt - Value::maxInt]\n    * - unsigned integer (range: 0 - Value::maxUInt)\n    * - double\n    * - UTF-8 string\n    * - boolean\n    * - 'null'\n    * - an ordered list of Value\n    * - collection of name/value pairs (javascript object)\n    *\n    * The type of the held value is represented by a #ValueType and \n    * can be obtained using type().\n    *\n    * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. \n    * Non const methods will automatically create the a #nullValue element \n    * if it does not exist. \n    * The sequence of an #arrayValue will be automatically resize and initialized \n    * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.\n    *\n    * The get() methods can be used to obtanis default value in the case the required element\n    * does not exist.\n    *\n    * It is possible to iterate over the list of a #objectValue values using \n    * the getMemberNames() method.\n    */\n   class JSON_API Value \n   {\n      friend class ValueIteratorBase;\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      friend class ValueInternalLink;\n      friend class ValueInternalMap;\n# endif\n   public:\n      typedef std::vector<std::string> Members;\n      typedef ValueIterator iterator;\n      typedef ValueConstIterator const_iterator;\n      typedef Json::UInt UInt;\n      typedef Json::Int Int;\n      typedef UInt ArrayIndex;\n\n      static const Value null;\n      static const Int minInt;\n      static const Int maxInt;\n      static const UInt maxUInt;\n\n   private:\n#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n# ifndef JSON_VALUE_USE_INTERNAL_MAP\n      class CZString \n      {\n      public:\n         enum DuplicationPolicy \n         {\n            noDuplication = 0,\n            duplicate,\n            duplicateOnCopy\n         };\n         CZString( int index );\n         CZString( const char *cstr, DuplicationPolicy allocate );\n         CZString( const CZString &other );\n         ~CZString();\n         CZString &operator =( const CZString &other );\n         bool operator<( const CZString &other ) const;\n         bool operator==( const CZString &other ) const;\n         int index() const;\n         const char *c_str() const;\n         bool isStaticString() const;\n      private:\n         void swap( CZString &other );\n         const char *cstr_;\n         int index_;\n      };\n\n   public:\n#  ifndef JSON_USE_CPPTL_SMALLMAP\n      typedef std::map<CZString, Value> ObjectValues;\n#  else\n      typedef CppTL::SmallMap<CZString, Value> ObjectValues;\n#  endif // ifndef JSON_USE_CPPTL_SMALLMAP\n# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP\n#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n   public:\n      /** \\brief Create a default Value of the given type.\n\n        This is a very useful constructor.\n        To create an empty array, pass arrayValue.\n        To create an empty object, pass objectValue.\n        Another Value can then be set to this one by assignment.\n\tThis is useful since clear() and resize() will not alter types.\n\n        Examples:\n\t\\code\n\tJson::Value null_value; // null\n\tJson::Value arr_value(Json::arrayValue); // []\n\tJson::Value obj_value(Json::objectValue); // {}\n\t\\endcode\n      */\n      Value( ValueType type = nullValue );\n      Value( Int value );\n      Value( UInt value );\n      Value( double value );\n      Value( const char *value );\n      Value( const char *beginValue, const char *endValue );\n      /** \\brief Constructs a value from a static string.\n\n       * Like other value string constructor but do not duplicate the string for\n       * internal storage. The given string must remain alive after the call to this\n       * constructor.\n       * Example of usage:\n       * \\code\n       * Json::Value aValue( StaticString(\"some text\") );\n       * \\endcode\n       */\n      Value( const StaticString &value );\n      Value( const std::string &value );\n# ifdef JSON_USE_CPPTL\n      Value( const CppTL::ConstString &value );\n# endif\n      Value( bool value );\n      Value( const Value &other );\n      ~Value();\n\n      Value &operator=( const Value &other );\n      /// Swap values.\n      /// \\note Currently, comments are intentionally not swapped, for\n      /// both logic and efficiency.\n      void swap( Value &other );\n\n      ValueType type() const;\n\n      bool operator <( const Value &other ) const;\n      bool operator <=( const Value &other ) const;\n      bool operator >=( const Value &other ) const;\n      bool operator >( const Value &other ) const;\n\n      bool operator ==( const Value &other ) const;\n      bool operator !=( const Value &other ) const;\n\n      int compare( const Value &other );\n\n      const char *asCString() const;\n      std::string asString() const;\n# ifdef JSON_USE_CPPTL\n      CppTL::ConstString asConstString() const;\n# endif\n      Int asInt() const;\n      UInt asUInt() const;\n      double asDouble() const;\n      bool asBool() const;\n\n      bool isNull() const;\n      bool isBool() const;\n      bool isInt() const;\n      bool isUInt() const;\n      bool isIntegral() const;\n      bool isDouble() const;\n      bool isNumeric() const;\n      bool isString() const;\n      bool isArray() const;\n      bool isObject() const;\n\n      bool isConvertibleTo( ValueType other ) const;\n\n      /// Number of values in array or object\n      UInt size() const;\n\n      /// \\brief Return true if empty array, empty object, or null;\n      /// otherwise, false.\n      bool empty() const;\n\n      /// Return isNull()\n      bool operator!() const;\n\n      /// Remove all object members and array elements.\n      /// \\pre type() is arrayValue, objectValue, or nullValue\n      /// \\post type() is unchanged\n      void clear();\n\n      /// Resize the array to size elements. \n      /// New elements are initialized to null.\n      /// May only be called on nullValue or arrayValue.\n      /// \\pre type() is arrayValue or nullValue\n      /// \\post type() is arrayValue\n      void resize( UInt size );\n\n      /// Access an array element (zero based index ).\n      /// If the array contains less than index element, then null value are inserted\n      /// in the array so that its size is index+1.\n      /// (You may need to say 'value[0u]' to get your compiler to distinguish\n      ///  this from the operator[] which takes a string.)\n      Value &operator[]( UInt index );\n      /// Access an array element (zero based index )\n      /// (You may need to say 'value[0u]' to get your compiler to distinguish\n      ///  this from the operator[] which takes a string.)\n      const Value &operator[]( UInt index ) const;\n      /// If the array contains at least index+1 elements, returns the element value, \n      /// otherwise returns defaultValue.\n      Value get( UInt index, \n                 const Value &defaultValue ) const;\n      /// Return true if index < size().\n      bool isValidIndex( UInt index ) const;\n      /// \\brief Append value to array at the end.\n      ///\n      /// Equivalent to jsonvalue[jsonvalue.size()] = value;\n      Value &append( const Value &value );\n\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const char *key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const char *key ) const;\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const std::string &key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const std::string &key ) const;\n      /** \\brief Access an object value by name, create a null member if it does not exist.\n\n       * If the object as no entry for that name, then the member name used to store\n       * the new entry is not duplicated.\n       * Example of use:\n       * \\code\n       * Json::Value object;\n       * static const StaticString code(\"code\");\n       * object[code] = 1234;\n       * \\endcode\n       */\n      Value &operator[]( const StaticString &key );\n# ifdef JSON_USE_CPPTL\n      /// Access an object value by name, create a null member if it does not exist.\n      Value &operator[]( const CppTL::ConstString &key );\n      /// Access an object value by name, returns null if there is no member with that name.\n      const Value &operator[]( const CppTL::ConstString &key ) const;\n# endif\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const char *key, \n                 const Value &defaultValue ) const;\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const std::string &key,\n                 const Value &defaultValue ) const;\n# ifdef JSON_USE_CPPTL\n      /// Return the member named key if it exist, defaultValue otherwise.\n      Value get( const CppTL::ConstString &key,\n                 const Value &defaultValue ) const;\n# endif\n      /// \\brief Remove and return the named member.  \n      ///\n      /// Do nothing if it did not exist.\n      /// \\return the removed Value, or null.\n      /// \\pre type() is objectValue or nullValue\n      /// \\post type() is unchanged\n      Value removeMember( const char* key );\n      /// Same as removeMember(const char*)\n      Value removeMember( const std::string &key );\n\n      /// Return true if the object has a member named key.\n      bool isMember( const char *key ) const;\n      /// Return true if the object has a member named key.\n      bool isMember( const std::string &key ) const;\n# ifdef JSON_USE_CPPTL\n      /// Return true if the object has a member named key.\n      bool isMember( const CppTL::ConstString &key ) const;\n# endif\n\n      /// \\brief Return a list of the member names.\n      ///\n      /// If null, return an empty list.\n      /// \\pre type() is objectValue or nullValue\n      /// \\post if type() was nullValue, it remains nullValue\n      Members getMemberNames() const;\n\n//# ifdef JSON_USE_CPPTL\n//      EnumMemberNames enumMemberNames() const;\n//      EnumValues enumValues() const;\n//# endif\n\n      /// Comments must be //... or /* ... */\n      void setComment( const char *comment,\n                       CommentPlacement placement );\n      /// Comments must be //... or /* ... */\n      void setComment( const std::string &comment,\n                       CommentPlacement placement );\n      bool hasComment( CommentPlacement placement ) const;\n      /// Include delimiters and embedded newlines.\n      std::string getComment( CommentPlacement placement ) const;\n\n      std::string toStyledString() const;\n\n      const_iterator begin() const;\n      const_iterator end() const;\n\n      iterator begin();\n      iterator end();\n\n\t  void SetSrcString(const std::string &strSrc)\n\t  {\n\t\t  strSrc_ = strSrc;\n\t  }\n\t  std::string GetSrcString()\n\t  {\n\t\t  return strSrc_;\n\t  }\n   private:\n      Value &resolveReference( const char *key, \n                               bool isStatic );\n\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      inline bool isItemAvailable() const\n      {\n         return itemIsUsed_ == 0;\n      }\n\n      inline void setItemUsed( bool isUsed = true )\n      {\n         itemIsUsed_ = isUsed ? 1 : 0;\n      }\n\n      inline bool isMemberNameStatic() const\n      {\n         return memberNameIsStatic_ == 0;\n      }\n\n      inline void setMemberNameIsStatic( bool isStatic )\n      {\n         memberNameIsStatic_ = isStatic ? 1 : 0;\n      }\n# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n   private:\n      struct CommentInfo\n      {\n         CommentInfo();\n         ~CommentInfo();\n\n         void setComment( const char *text );\n\n         char *comment_;\n      };\n\n      //struct MemberNamesTransform\n      //{\n      //   typedef const char *result_type;\n      //   const char *operator()( const CZString &name ) const\n      //   {\n      //      return name.c_str();\n      //   }\n      //};\n\n      union ValueHolder\n      {\n         Int int_;\n         UInt uint_;\n         double real_;\n         bool bool_;\n         char *string_;\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n         ValueInternalArray *array_;\n         ValueInternalMap *map_;\n#else\n         ObjectValues *map_;\n# endif\n      } value_;\n      ValueType type_ : 8;\n      int allocated_ : 1;     // Notes: if declared as bool, bitfield is useless.\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n      unsigned int itemIsUsed_ : 1;      // used by the ValueInternalMap container.\n      int memberNameIsStatic_ : 1;       // used by the ValueInternalMap container.\n# endif\n      CommentInfo *comments_;\n\t  std::string strSrc_;\n   };\n\n\n   /** \\brief Experimental and untested: represents an element of the \"path\" to access a node.\n    */\n   class PathArgument\n   {\n   public:\n      friend class Path;\n\n      PathArgument();\n      PathArgument( UInt index );\n      PathArgument( const char *key );\n      PathArgument( const std::string &key );\n\n   private:\n      enum Kind\n      {\n         kindNone = 0,\n         kindIndex,\n         kindKey\n      };\n      std::string key_;\n      UInt index_;\n      Kind kind_;\n   };\n\n   /** \\brief Experimental and untested: represents a \"path\" to access a node.\n    *\n    * Syntax:\n    * - \".\" => root node\n    * - \".[n]\" => elements at index 'n' of root node (an array value)\n    * - \".name\" => member named 'name' of root node (an object value)\n    * - \".name1.name2.name3\"\n    * - \".[0][1][2].name1[3]\"\n    * - \".%\" => member name is provided as parameter\n    * - \".[%]\" => index is provied as parameter\n    */\n   class Path\n   {\n   public:\n      Path( const std::string &path,\n            const PathArgument &a1 = PathArgument(),\n            const PathArgument &a2 = PathArgument(),\n            const PathArgument &a3 = PathArgument(),\n            const PathArgument &a4 = PathArgument(),\n            const PathArgument &a5 = PathArgument() );\n\n      const Value &resolve( const Value &root ) const;\n      Value resolve( const Value &root, \n                     const Value &defaultValue ) const;\n      /// Creates the \"path\" to access the specified node and returns a reference on the node.\n      Value &make( Value &root ) const;\n\n   private:\n      typedef std::vector<const PathArgument *> InArgs;\n      typedef std::vector<PathArgument> Args;\n\n      void makePath( const std::string &path,\n                     const InArgs &in );\n      void addPathInArg( const std::string &path, \n                         const InArgs &in, \n                         InArgs::const_iterator &itInArg, \n                         PathArgument::Kind kind );\n      void invalidPath( const std::string &path, \n                        int location );\n\n      Args args_;\n   };\n\n   /** \\brief Experimental do not use: Allocator to customize member name and string value memory management done by Value.\n    *\n    * - makeMemberName() and releaseMemberName() are called to respectively duplicate and\n    *   free an Json::objectValue member name.\n    * - duplicateStringValue() and releaseStringValue() are called similarly to\n    *   duplicate and free a Json::stringValue value.\n    */\n   class ValueAllocator\n   {\n   public:\n      enum { unknown = (unsigned)-1 };\n\n      virtual ~ValueAllocator();\n\n      virtual char *makeMemberName( const char *memberName ) = 0;\n      virtual void releaseMemberName( char *memberName ) = 0;\n      virtual char *duplicateStringValue( const char *value, \n                                          unsigned int length = unknown ) = 0;\n      virtual void releaseStringValue( char *value ) = 0;\n   };\n\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   /** \\brief Allocator to customize Value internal map.\n    * Below is an example of a simple implementation (default implementation actually\n    * use memory pool for speed).\n    * \\code\n      class DefaultValueMapAllocator : public ValueMapAllocator\n      {\n      public: // overridden from ValueMapAllocator\n         virtual ValueInternalMap *newMap()\n         {\n            return new ValueInternalMap();\n         }\n\n         virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )\n         {\n            return new ValueInternalMap( other );\n         }\n\n         virtual void destructMap( ValueInternalMap *map )\n         {\n            delete map;\n         }\n\n         virtual ValueInternalLink *allocateMapBuckets( unsigned int size )\n         {\n            return new ValueInternalLink[size];\n         }\n\n         virtual void releaseMapBuckets( ValueInternalLink *links )\n         {\n            delete [] links;\n         }\n\n         virtual ValueInternalLink *allocateMapLink()\n         {\n            return new ValueInternalLink();\n         }\n\n         virtual void releaseMapLink( ValueInternalLink *link )\n         {\n            delete link;\n         }\n      };\n    * \\endcode\n    */ \n   class JSON_API ValueMapAllocator\n   {\n   public:\n      virtual ~ValueMapAllocator();\n      virtual ValueInternalMap *newMap() = 0;\n      virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;\n      virtual void destructMap( ValueInternalMap *map ) = 0;\n      virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;\n      virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;\n      virtual ValueInternalLink *allocateMapLink() = 0;\n      virtual void releaseMapLink( ValueInternalLink *link ) = 0;\n   };\n\n   /** \\brief ValueInternalMap hash-map bucket chain link (for internal use only).\n    * \\internal previous_ & next_ allows for bidirectional traversal.\n    */\n   class JSON_API ValueInternalLink\n   {\n   public:\n      enum { itemPerLink = 6 };  // sizeof(ValueInternalLink) = 128 on 32 bits architecture.\n      enum InternalFlags { \n         flagAvailable = 0,\n         flagUsed = 1\n      };\n\n      ValueInternalLink();\n\n      ~ValueInternalLink();\n\n      Value items_[itemPerLink];\n      char *keys_[itemPerLink];\n      ValueInternalLink *previous_;\n      ValueInternalLink *next_;\n   };\n\n\n   /** \\brief A linked page based hash-table implementation used internally by Value.\n    * \\internal ValueInternalMap is a tradional bucket based hash-table, with a linked\n    * list in each bucket to handle collision. There is an addional twist in that\n    * each node of the collision linked list is a page containing a fixed amount of\n    * value. This provides a better compromise between memory usage and speed.\n    * \n    * Each bucket is made up of a chained list of ValueInternalLink. The last\n    * link of a given bucket can be found in the 'previous_' field of the following bucket.\n    * The last link of the last bucket is stored in tailLink_ as it has no following bucket.\n    * Only the last link of a bucket may contains 'available' item. The last link always\n    * contains at least one element unless is it the bucket one very first link.\n    */\n   class JSON_API ValueInternalMap\n   {\n      friend class ValueIteratorBase;\n      friend class Value;\n   public:\n      typedef unsigned int HashKey;\n      typedef unsigned int BucketIndex;\n\n# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n      struct IteratorState\n      {\n         IteratorState() \n            : map_(0)\n            , link_(0)\n            , itemIndex_(0)\n            , bucketIndex_(0) \n         {\n         }\n         ValueInternalMap *map_;\n         ValueInternalLink *link_;\n         BucketIndex itemIndex_;\n         BucketIndex bucketIndex_;\n      };\n# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n      ValueInternalMap();\n      ValueInternalMap( const ValueInternalMap &other );\n      ValueInternalMap &operator =( const ValueInternalMap &other );\n      ~ValueInternalMap();\n\n      void swap( ValueInternalMap &other );\n\n      BucketIndex size() const;\n\n      void clear();\n\n      bool reserveDelta( BucketIndex growth );\n\n      bool reserve( BucketIndex newItemCount );\n\n      const Value *find( const char *key ) const;\n\n      Value *find( const char *key );\n\n      Value &resolveReference( const char *key, \n                               bool isStatic );\n\n      void remove( const char *key );\n\n      void doActualRemove( ValueInternalLink *link, \n                           BucketIndex index,\n                           BucketIndex bucketIndex );\n\n      ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );\n\n      Value &setNewItem( const char *key, \n                         bool isStatic, \n                         ValueInternalLink *link, \n                         BucketIndex index );\n\n      Value &unsafeAdd( const char *key, \n                        bool isStatic, \n                        HashKey hashedKey );\n\n      HashKey hash( const char *key ) const;\n\n      int compare( const ValueInternalMap &other ) const;\n\n   private:\n      void makeBeginIterator( IteratorState &it ) const;\n      void makeEndIterator( IteratorState &it ) const;\n      static bool equals( const IteratorState &x, const IteratorState &other );\n      static void increment( IteratorState &iterator );\n      static void incrementBucket( IteratorState &iterator );\n      static void decrement( IteratorState &iterator );\n      static const char *key( const IteratorState &iterator );\n      static const char *key( const IteratorState &iterator, bool &isStatic );\n      static Value &value( const IteratorState &iterator );\n      static int distance( const IteratorState &x, const IteratorState &y );\n\n   private:\n      ValueInternalLink *buckets_;\n      ValueInternalLink *tailLink_;\n      BucketIndex bucketsSize_;\n      BucketIndex itemCount_;\n   };\n\n   /** \\brief A simplified deque implementation used internally by Value.\n   * \\internal\n   * It is based on a list of fixed \"page\", each page contains a fixed number of items.\n   * Instead of using a linked-list, a array of pointer is used for fast item look-up.\n   * Look-up for an element is as follow:\n   * - compute page index: pageIndex = itemIndex / itemsPerPage\n   * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]\n   *\n   * Insertion is amortized constant time (only the array containing the index of pointers\n   * need to be reallocated when items are appended).\n   */\n   class JSON_API ValueInternalArray\n   {\n      friend class Value;\n      friend class ValueIteratorBase;\n   public:\n      enum { itemsPerPage = 8 };    // should be a power of 2 for fast divide and modulo.\n      typedef Value::ArrayIndex ArrayIndex;\n      typedef unsigned int PageIndex;\n\n# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n      struct IteratorState // Must be a POD\n      {\n         IteratorState() \n            : array_(0)\n            , currentPageIndex_(0)\n            , currentItemIndex_(0) \n         {\n         }\n         ValueInternalArray *array_;\n         Value **currentPageIndex_;\n         unsigned int currentItemIndex_;\n      };\n# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\n      ValueInternalArray();\n      ValueInternalArray( const ValueInternalArray &other );\n      ValueInternalArray &operator =( const ValueInternalArray &other );\n      ~ValueInternalArray();\n      void swap( ValueInternalArray &other );\n\n      void clear();\n      void resize( ArrayIndex newSize );\n\n      Value &resolveReference( ArrayIndex index );\n\n      Value *find( ArrayIndex index ) const;\n\n      ArrayIndex size() const;\n\n      int compare( const ValueInternalArray &other ) const;\n\n   private:\n      static bool equals( const IteratorState &x, const IteratorState &other );\n      static void increment( IteratorState &iterator );\n      static void decrement( IteratorState &iterator );\n      static Value &dereference( const IteratorState &iterator );\n      static Value &unsafeDereference( const IteratorState &iterator );\n      static int distance( const IteratorState &x, const IteratorState &y );\n      static ArrayIndex indexOf( const IteratorState &iterator );\n      void makeBeginIterator( IteratorState &it ) const;\n      void makeEndIterator( IteratorState &it ) const;\n      void makeIterator( IteratorState &it, ArrayIndex index ) const;\n\n      void makeIndexValid( ArrayIndex index );\n\n      Value **pages_;\n      ArrayIndex size_;\n      PageIndex pageCount_;\n   };\n\n   /** \\brief Experimental: do not use. Allocator to customize Value internal array.\n    * Below is an example of a simple implementation (actual implementation use\n    * memory pool).\n      \\code\nclass DefaultValueArrayAllocator : public ValueArrayAllocator\n{\npublic: // overridden from ValueArrayAllocator\n   virtual ~DefaultValueArrayAllocator()\n   {\n   }\n\n   virtual ValueInternalArray *newArray()\n   {\n      return new ValueInternalArray();\n   }\n\n   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )\n   {\n      return new ValueInternalArray( other );\n   }\n\n   virtual void destruct( ValueInternalArray *array )\n   {\n      delete array;\n   }\n\n   virtual void reallocateArrayPageIndex( Value **&indexes, \n                                          ValueInternalArray::PageIndex &indexCount,\n                                          ValueInternalArray::PageIndex minNewIndexCount )\n   {\n      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;\n      if ( minNewIndexCount > newIndexCount )\n         newIndexCount = minNewIndexCount;\n      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );\n      if ( !newIndexes )\n         throw std::bad_alloc();\n      indexCount = newIndexCount;\n      indexes = static_cast<Value **>( newIndexes );\n   }\n   virtual void releaseArrayPageIndex( Value **indexes, \n                                       ValueInternalArray::PageIndex indexCount )\n   {\n      if ( indexes )\n         free( indexes );\n   }\n\n   virtual Value *allocateArrayPage()\n   {\n      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );\n   }\n\n   virtual void releaseArrayPage( Value *value )\n   {\n      if ( value )\n         free( value );\n   }\n};\n      \\endcode\n    */ \n   class JSON_API ValueArrayAllocator\n   {\n   public:\n      virtual ~ValueArrayAllocator();\n      virtual ValueInternalArray *newArray() = 0;\n      virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;\n      virtual void destructArray( ValueInternalArray *array ) = 0;\n      /** \\brief Reallocate array page index.\n       * Reallocates an array of pointer on each page.\n       * \\param indexes [input] pointer on the current index. May be \\c NULL.\n       *                [output] pointer on the new index of at least \n       *                         \\a minNewIndexCount pages. \n       * \\param indexCount [input] current number of pages in the index.\n       *                   [output] number of page the reallocated index can handle.\n       *                            \\b MUST be >= \\a minNewIndexCount.\n       * \\param minNewIndexCount Minimum number of page the new index must be able to\n       *                         handle.\n       */\n      virtual void reallocateArrayPageIndex( Value **&indexes, \n                                             ValueInternalArray::PageIndex &indexCount,\n                                             ValueInternalArray::PageIndex minNewIndexCount ) = 0;\n      virtual void releaseArrayPageIndex( Value **indexes, \n                                          ValueInternalArray::PageIndex indexCount ) = 0;\n      virtual Value *allocateArrayPage() = 0;\n      virtual void releaseArrayPage( Value *value ) = 0;\n   };\n#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP\n\n\n   /** \\brief base class for Value iterators.\n    *\n    */\n   class ValueIteratorBase\n   {\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef ValueIteratorBase SelfType;\n\n      ValueIteratorBase();\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueIteratorBase( const Value::ObjectValues::iterator &current );\n#else\n      ValueIteratorBase( const ValueInternalArray::IteratorState &state );\n      ValueIteratorBase( const ValueInternalMap::IteratorState &state );\n#endif\n\n      bool operator ==( const SelfType &other ) const\n      {\n         return isEqual( other );\n      }\n\n      bool operator !=( const SelfType &other ) const\n      {\n         return !isEqual( other );\n      }\n\n      difference_type operator -( const SelfType &other ) const\n      {\n         return computeDistance( other );\n      }\n\n      /// Return either the index or the member name of the referenced value as a Value.\n      Value key() const;\n\n      /// Return the index of the referenced Value. -1 if it is not an arrayValue.\n      UInt index() const;\n\n      /// Return the member name of the referenced Value. \"\" if it is not an objectValue.\n      const char *memberName() const;\n\n   protected:\n      Value &deref() const;\n\n      void increment();\n\n      void decrement();\n\n      difference_type computeDistance( const SelfType &other ) const;\n\n      bool isEqual( const SelfType &other ) const;\n\n      void copy( const SelfType &other );\n\n   private:\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      Value::ObjectValues::iterator current_;\n      // Indicates that iterator is for a null value.\n      bool isNull_;\n#else\n      union\n      {\n         ValueInternalArray::IteratorState array_;\n         ValueInternalMap::IteratorState map_;\n      } iterator_;\n      bool isArray_;\n#endif\n   };\n\n   /** \\brief const iterator for object and array value.\n    *\n    */\n   class ValueConstIterator : public ValueIteratorBase\n   {\n      friend class Value;\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef const Value &reference;\n      typedef const Value *pointer;\n      typedef ValueConstIterator SelfType;\n\n      ValueConstIterator();\n   private:\n      /*! \\internal Use by Value to create an iterator.\n       */\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueConstIterator( const Value::ObjectValues::iterator &current );\n#else\n      ValueConstIterator( const ValueInternalArray::IteratorState &state );\n      ValueConstIterator( const ValueInternalMap::IteratorState &state );\n#endif\n   public:\n      SelfType &operator =( const ValueIteratorBase &other );\n\n      SelfType operator++( int )\n      {\n         SelfType temp( *this );\n         ++*this;\n         return temp;\n      }\n\n      SelfType operator--( int )\n      {\n         SelfType temp( *this );\n         --*this;\n         return temp;\n      }\n\n      SelfType &operator--()\n      {\n         decrement();\n         return *this;\n      }\n\n      SelfType &operator++()\n      {\n         increment();\n         return *this;\n      }\n\n      reference operator *() const\n      {\n         return deref();\n      }\n   };\n\n\n   /** \\brief Iterator for object and array value.\n    */\n   class ValueIterator : public ValueIteratorBase\n   {\n      friend class Value;\n   public:\n      typedef unsigned int size_t;\n      typedef int difference_type;\n      typedef Value &reference;\n      typedef Value *pointer;\n      typedef ValueIterator SelfType;\n\n      ValueIterator();\n      ValueIterator( const ValueConstIterator &other );\n      ValueIterator( const ValueIterator &other );\n   private:\n      /*! \\internal Use by Value to create an iterator.\n       */\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n      explicit ValueIterator( const Value::ObjectValues::iterator &current );\n#else\n      ValueIterator( const ValueInternalArray::IteratorState &state );\n      ValueIterator( const ValueInternalMap::IteratorState &state );\n#endif\n   public:\n\n      SelfType &operator =( const SelfType &other );\n\n      SelfType operator++( int )\n      {\n         SelfType temp( *this );\n         ++*this;\n         return temp;\n      }\n\n      SelfType operator--( int )\n      {\n         SelfType temp( *this );\n         --*this;\n         return temp;\n      }\n\n      SelfType &operator--()\n      {\n         decrement();\n         return *this;\n      }\n\n      SelfType &operator++()\n      {\n         increment();\n         return *this;\n      }\n\n      reference operator *() const\n      {\n         return deref();\n      }\n   };\n\n\n} // namespace Json\n\n\n#endif // CPPTL_JSON_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json/writer.h",
    "content": "#ifndef JSON_WRITER_H_INCLUDED\n# define JSON_WRITER_H_INCLUDED\n\n# include \"value.h\"\n# include <vector>\n# include <string>\n# include <iostream>\n\nnamespace Json {\n\n   class Value;\n\n   /** \\brief Abstract class for writers.\n    */\n   class JSON_API Writer\n   {\n   public:\n      virtual ~Writer();\n\n      virtual std::string write( const Value &root ) = 0;\n   };\n\n   /** \\brief Outputs a Value in <a HREF=\"http://www.json.org\">JSON</a> format without formatting (not human friendly).\n    *\n    * The JSON document is written in a single line. It is not intended for 'human' consumption,\n    * but may be usefull to support feature such as RPC where bandwith is limited.\n    * \\sa Reader, Value\n    */\n   class JSON_API FastWriter : public Writer\n   {\n   public:\n      FastWriter();\n      virtual ~FastWriter(){}\n\n      void enableYAMLCompatibility();\n\n   public: // overridden from Writer\n      virtual std::string write( const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n\n      std::string document_;\n      bool yamlCompatiblityEnabled_;\n   };\n\n   /** \\brief Writes a Value in <a HREF=\"http://www.json.org\">JSON</a> format in a human friendly way.\n    *\n    * The rules for line break and indent are as follow:\n    * - Object value:\n    *     - if empty then print {} without indent and line break\n    *     - if not empty the print '{', line break & indent, print one value per line\n    *       and then unindent and line break and print '}'.\n    * - Array value:\n    *     - if empty then print [] without indent and line break\n    *     - if the array contains no object value, empty array or some other value types,\n    *       and all the values fit on one lines, then print the array on a single line.\n    *     - otherwise, it the values do not fit on one line, or the array contains\n    *       object or non empty array, then print one value per line.\n    *\n    * If the Value have comments then they are outputed according to their #CommentPlacement.\n    *\n    * \\sa Reader, Value, Value::setComment()\n    */\n   class JSON_API StyledWriter: public Writer\n   {\n   public:\n      StyledWriter();\n      virtual ~StyledWriter(){}\n\n   public: // overridden from Writer\n      /** \\brief Serialize a Value in <a HREF=\"http://www.json.org\">JSON</a> format.\n       * \\param root Value to serialize.\n       * \\return String containing the JSON document that represents the root value.\n       */\n      virtual std::string write( const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n      void writeArrayValue( const Value &value );\n      bool isMultineArray( const Value &value );\n      void pushValue( const std::string &value );\n      void writeIndent();\n      void writeWithIndent( const std::string &value );\n      void indent();\n      void unindent();\n      void writeCommentBeforeValue( const Value &root );\n      void writeCommentAfterValueOnSameLine( const Value &root );\n      bool hasCommentForValue( const Value &value );\n      static std::string normalizeEOL( const std::string &text );\n\n      typedef std::vector<std::string> ChildValues;\n\n      ChildValues childValues_;\n      std::string document_;\n      std::string indentString_;\n      int rightMargin_;\n      int indentSize_;\n      bool addChildValues_;\n   };\n\n   /** \\brief Writes a Value in <a HREF=\"http://www.json.org\">JSON</a> format in a human friendly way,\n        to a stream rather than to a string.\n    *\n    * The rules for line break and indent are as follow:\n    * - Object value:\n    *     - if empty then print {} without indent and line break\n    *     - if not empty the print '{', line break & indent, print one value per line\n    *       and then unindent and line break and print '}'.\n    * - Array value:\n    *     - if empty then print [] without indent and line break\n    *     - if the array contains no object value, empty array or some other value types,\n    *       and all the values fit on one lines, then print the array on a single line.\n    *     - otherwise, it the values do not fit on one line, or the array contains\n    *       object or non empty array, then print one value per line.\n    *\n    * If the Value have comments then they are outputed according to their #CommentPlacement.\n    *\n    * \\param indentation Each level will be indented by this amount extra.\n    * \\sa Reader, Value, Value::setComment()\n    */\n   class JSON_API StyledStreamWriter\n   {\n   public:\n      StyledStreamWriter( std::string indentation=\"\\t\" );\n      ~StyledStreamWriter(){}\n\n   public:\n      /** \\brief Serialize a Value in <a HREF=\"http://www.json.org\">JSON</a> format.\n       * \\param out Stream to write to. (Can be ostringstream, e.g.)\n       * \\param root Value to serialize.\n       * \\note There is no point in deriving from Writer, since write() should not return a value.\n       */\n      void write( std::ostream &out, const Value &root );\n\n   private:\n      void writeValue( const Value &value );\n      void writeArrayValue( const Value &value );\n      bool isMultineArray( const Value &value );\n      void pushValue( const std::string &value );\n      void writeIndent();\n      void writeWithIndent( const std::string &value );\n      void indent();\n      void unindent();\n      void writeCommentBeforeValue( const Value &root );\n      void writeCommentAfterValueOnSameLine( const Value &root );\n      bool hasCommentForValue( const Value &value );\n      static std::string normalizeEOL( const std::string &text );\n\n      typedef std::vector<std::string> ChildValues;\n\n      ChildValues childValues_;\n      std::ostream* document_;\n      std::string indentString_;\n      int rightMargin_;\n      std::string indentation_;\n      bool addChildValues_;\n   };\n\n   std::string JSON_API valueToString( Int value );\n   std::string JSON_API valueToString( UInt value );\n   std::string JSON_API valueToString( double value );\n   std::string JSON_API valueToString( bool value );\n   std::string JSON_API valueToQuotedString( const char *value );\n\n   /// \\brief Output using the StyledStreamWriter.\n   /// \\see Json::operator>>()\n   std::ostream& operator<<( std::ostream&, const Value &root );\n\n} // namespace Json\n\n\n\n#endif // JSON_WRITER_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json_batchallocator.h",
    "content": "#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED\n#define JSONCPP_BATCHALLOCATOR_H_INCLUDED\n\n#include <stdlib.h>\n#include <assert.h>\n\n#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION\n\nnamespace Json {\n\n/* Fast memory allocator.\n *\n * This memory allocator allocates memory for a batch of object (specified by\n * the page size, the number of object in each page).\n *\n * It does not allow the destruction of a single object. All the allocated objects\n * can be destroyed at once. The memory can be either released or reused for future\n * allocation.\n * \n * The in-place new operator must be used to construct the object using the pointer\n * returned by allocate.\n */\ntemplate<typename AllocatedType\n        ,const unsigned int objectPerAllocation>\nclass BatchAllocator\n{\npublic:\n   typedef AllocatedType Type;\n\n   BatchAllocator( unsigned int objectsPerPage = 255 )\n      : freeHead_( 0 )\n      , objectsPerPage_( objectsPerPage )\n   {\n//      printf( \"Size: %d => %s\\n\", sizeof(AllocatedType), typeid(AllocatedType).name() );\n      assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.\n      assert( objectsPerPage >= 16 );\n      batches_ = allocateBatch( 0 );   // allocated a dummy page\n      currentBatch_ = batches_;\n   }\n\n   ~BatchAllocator()\n   {\n      for ( BatchInfo *batch = batches_; batch;  )\n      {\n         BatchInfo *nextBatch = batch->next_;\n         free( batch );\n         batch = nextBatch;\n      }\n   }\n\n   /// allocate space for an array of objectPerAllocation object.\n   /// @warning it is the responsability of the caller to call objects constructors.\n   AllocatedType *allocate()\n   {\n      if ( freeHead_ ) // returns node from free list.\n      {\n         AllocatedType *object = freeHead_;\n         freeHead_ = *(AllocatedType **)object;\n         return object;\n      }\n      if ( currentBatch_->used_ == currentBatch_->end_ )\n      {\n         currentBatch_ = currentBatch_->next_;\n         while ( currentBatch_  &&  currentBatch_->used_ == currentBatch_->end_ )\n            currentBatch_ = currentBatch_->next_;\n\n         if ( !currentBatch_  ) // no free batch found, allocate a new one\n         { \n            currentBatch_ = allocateBatch( objectsPerPage_ );\n            currentBatch_->next_ = batches_; // insert at the head of the list\n            batches_ = currentBatch_;\n         }\n      }\n      AllocatedType *allocated = currentBatch_->used_;\n      currentBatch_->used_ += objectPerAllocation;\n      return allocated;\n   }\n\n   /// Release the object.\n   /// @warning it is the responsability of the caller to actually destruct the object.\n   void release( AllocatedType *object )\n   {\n      assert( object != 0 );\n      *(AllocatedType **)object = freeHead_;\n      freeHead_ = object;\n   }\n\nprivate:\n   struct BatchInfo\n   {\n      BatchInfo *next_;\n      AllocatedType *used_;\n      AllocatedType *end_;\n      AllocatedType buffer_[objectPerAllocation];\n   };\n\n   // disabled copy constructor and assignement operator.\n   BatchAllocator( const BatchAllocator & );\n   void operator =( const BatchAllocator &);\n\n   static BatchInfo *allocateBatch( unsigned int objectsPerPage )\n   {\n      const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation\n                                + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;\n      BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );\n      batch->next_ = 0;\n      batch->used_ = batch->buffer_;\n      batch->end_ = batch->buffer_ + objectsPerPage;\n      return batch;\n   }\n\n   BatchInfo *batches_;\n   BatchInfo *currentBatch_;\n   /// Head of a single linked list within the allocated space of freeed object\n   AllocatedType *freeHead_;\n   unsigned int objectsPerPage_;\n};\n\n\n} // namespace Json\n\n#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION\n\n#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED\n"
  },
  {
    "path": "common/jsoncpp/json_valueiterator.inl",
    "content": "// included by json_value.cpp\n// everything is within Json namespace\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueIteratorBase\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueIteratorBase::ValueIteratorBase()\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   : current_()\n   , isNull_( true )\n{\n}\n#else\n   : isArray_( true )\n   , isNull_( true )\n{\n   iterator_.array_ = ValueInternalArray::IteratorState();\n}\n#endif\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )\n   : current_( current )\n   , isNull_( false )\n{\n}\n#else\nValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )\n   : isArray_( true )\n{\n   iterator_.array_ = state;\n}\n\n\nValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )\n   : isArray_( false )\n{\n   iterator_.map_ = state;\n}\n#endif\n\nValue &\nValueIteratorBase::deref() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   return current_->second;\n#else\n   if ( isArray_ )\n      return ValueInternalArray::dereference( iterator_.array_ );\n   return ValueInternalMap::value( iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::increment()\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   ++current_;\n#else\n   if ( isArray_ )\n      ValueInternalArray::increment( iterator_.array_ );\n   ValueInternalMap::increment( iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::decrement()\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   --current_;\n#else\n   if ( isArray_ )\n      ValueInternalArray::decrement( iterator_.array_ );\n   ValueInternalMap::decrement( iterator_.map_ );\n#endif\n}\n\n\nValueIteratorBase::difference_type \nValueIteratorBase::computeDistance( const SelfType &other ) const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n# ifdef JSON_USE_CPPTL_SMALLMAP\n   return current_ - other.current_;\n# else\n   // Iterator for null value are initialized using the default\n   // constructor, which initialize current_ to the default\n   // std::map::iterator. As begin() and end() are two instance \n   // of the default std::map::iterator, they can not be compared.\n   // To allow this, we handle this comparison specifically.\n   if ( isNull_  &&  other.isNull_ )\n   {\n      return 0;\n   }\n\n\n   // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,\n   // which is the one used by default).\n   // Using a portable hand-made version for non random iterator instead:\n   //   return difference_type( std::distance( current_, other.current_ ) );\n   difference_type myDistance = 0;\n   for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )\n   {\n      ++myDistance;\n   }\n   return myDistance;\n# endif\n#else\n   if ( isArray_ )\n      return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );\n   return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );\n#endif\n}\n\n\nbool \nValueIteratorBase::isEqual( const SelfType &other ) const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   if ( isNull_ )\n   {\n      return other.isNull_;\n   }\n   return current_ == other.current_;\n#else\n   if ( isArray_ )\n      return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );\n   return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );\n#endif\n}\n\n\nvoid \nValueIteratorBase::copy( const SelfType &other )\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   current_ = other.current_;\n#else\n   if ( isArray_ )\n      iterator_.array_ = other.iterator_.array_;\n   iterator_.map_ = other.iterator_.map_;\n#endif\n}\n\n\nValue \nValueIteratorBase::key() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const Value::CZString czstring = (*current_).first;\n   if ( czstring.c_str() )\n   {\n      if ( czstring.isStaticString() )\n         return Value( StaticString( czstring.c_str() ) );\n      return Value( czstring.c_str() );\n   }\n   return Value( czstring.index() );\n#else\n   if ( isArray_ )\n      return Value( ValueInternalArray::indexOf( iterator_.array_ ) );\n   bool isStatic;\n   const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );\n   if ( isStatic )\n      return Value( StaticString( memberName ) );\n   return Value( memberName );\n#endif\n}\n\n\nUInt \nValueIteratorBase::index() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const Value::CZString czstring = (*current_).first;\n   if ( !czstring.c_str() )\n      return czstring.index();\n   return Value::UInt( -1 );\n#else\n   if ( isArray_ )\n      return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );\n   return Value::UInt( -1 );\n#endif\n}\n\n\nconst char *\nValueIteratorBase::memberName() const\n{\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   const char *name = (*current_).first.c_str();\n   return name ? name : \"\";\n#else\n   if ( !isArray_ )\n      return ValueInternalMap::key( iterator_.map_ );\n   return \"\";\n#endif\n}\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueConstIterator\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueConstIterator::ValueConstIterator()\n{\n}\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )\n   : ValueIteratorBase( current )\n{\n}\n#else\nValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n\nValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n#endif\n\nValueConstIterator &\nValueConstIterator::operator =( const ValueIteratorBase &other )\n{\n   copy( other );\n   return *this;\n}\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class ValueIterator\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\nValueIterator::ValueIterator()\n{\n}\n\n\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\nValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )\n   : ValueIteratorBase( current )\n{\n}\n#else\nValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n\nValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )\n   : ValueIteratorBase( state )\n{\n}\n#endif\n\nValueIterator::ValueIterator( const ValueConstIterator &other )\n   : ValueIteratorBase( other )\n{\n}\n\nValueIterator::ValueIterator( const ValueIterator &other )\n   : ValueIteratorBase( other )\n{\n}\n\nValueIterator &\nValueIterator::operator =( const SelfType &other )\n{\n   copy( other );\n   return *this;\n}\n"
  },
  {
    "path": "common/jsoncpp/reader.cpp",
    "content": "#include <utility>\n#include <cstdio>\n#include <cassert>\n#include <cstring>\n#include <iostream>\n#include <stdexcept>\n#include \"json/value.h\"\n#include \"json/reader.h\"\n\n#if _MSC_VER >= 1400 // VC++ 8.0\n#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.\n#endif\n\nnamespace Json {\n\n// Implementation of class Features\n// ////////////////////////////////\n\nFeatures::Features()\n   : allowComments_( true )\n   , strictRoot_( false )\n{\n}\n\n\nFeatures \nFeatures::all()\n{\n   return Features();\n}\n\n\nFeatures \nFeatures::strictMode()\n{\n   Features features;\n   features.allowComments_ = false;\n   features.strictRoot_ = true;\n   return features;\n}\n\n// Implementation of class Reader\n// ////////////////////////////////\n\n\nstatic inline bool \nin( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )\n{\n   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;\n}\n\nstatic inline bool \nin( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )\n{\n   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;\n}\n\n\nstatic bool \ncontainsNewLine( Reader::Location begin, \n                 Reader::Location end )\n{\n   for ( ;begin < end; ++begin )\n      if ( *begin == '\\n'  ||  *begin == '\\r' )\n         return true;\n   return false;\n}\n\nstatic std::string codePointToUTF8(unsigned int cp)\n{\n   std::string result;\n   \n   // based on description from http://en.wikipedia.org/wiki/UTF-8\n\n   if (cp <= 0x7f) \n   {\n      result.resize(1);\n      result[0] = static_cast<char>(cp);\n   } \n   else if (cp <= 0x7FF) \n   {\n      result.resize(2);\n      result[1] = static_cast<char>(0x80 | (0x3f & cp));\n      result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));\n   } \n   else if (cp <= 0xFFFF) \n   {\n      result.resize(3);\n      result[2] = static_cast<char>(0x80 | (0x3f & cp));\n      result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));\n      result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));\n   }\n   else if (cp <= 0x10FFFF) \n   {\n      result.resize(4);\n      result[3] = static_cast<char>(0x80 | (0x3f & cp));\n      result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));\n      result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));\n      result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));\n   }\n\n   return result;\n}\n\n\n// Class Reader\n// //////////////////////////////////////////////////////////////////\n\nReader::Reader()\n   : features_( Features::all() )\n{\n}\n\n\nReader::Reader( const Features &features )\n   : features_( features )\n{\n}\n\n\nbool\nReader::parse( const std::string &document, \n               Value &root,\n               bool collectComments )\n{\n   document_ = document;\n   const char *begin = document_.c_str();\n   const char *end = begin + document_.length();\n   return parse( begin, end, root, collectComments );\n}\n\n\nbool\nReader::parse( std::istream& sin,\n               Value &root,\n               bool collectComments )\n{\n   //std::istream_iterator<char> begin(sin);\n   //std::istream_iterator<char> end;\n   // Those would allow streamed input from a file, if parse() were a\n   // template function.\n\n   // Since std::string is reference-counted, this at least does not\n   // create an extra copy.\n   std::string doc;\n   std::getline(sin, doc, (char)EOF);\n   return parse( doc, root, collectComments );\n}\n\nbool \nReader::parse( const char *beginDoc, const char *endDoc, \n               Value &root,\n               bool collectComments )\n{\n   if ( !features_.allowComments_ )\n   {\n      collectComments = false;\n   }\n\n   begin_ = beginDoc;\n   end_ = endDoc;\n   collectComments_ = collectComments;\n   current_ = begin_;\n   lastValueEnd_ = 0;\n   lastValue_ = 0;\n   commentsBefore_ = \"\";\n   errors_.clear();\n   while ( !nodes_.empty() )\n      nodes_.pop();\n   nodes_.push( &root );\n   \n   bool successful = readValue();\n   Token token;\n   skipCommentTokens( token );\n   if ( collectComments_  &&  !commentsBefore_.empty() )\n      root.setComment( commentsBefore_, commentAfter );\n   if ( features_.strictRoot_ )\n   {\n      if ( !root.isArray()  &&  !root.isObject() )\n      {\n         // Set error location to start of doc, ideally should be first token found in doc\n         token.type_ = tokenError;\n         token.start_ = beginDoc;\n         token.end_ = endDoc;\n         addError( \"A valid JSON document must be either an array or an object value.\",\n                   token );\n         return false;\n      }\n   }\n   return successful;\n}\n\n\nbool\nReader::readValue()\n{\n   Token token;\n   skipCommentTokens( token );\n   bool successful = true;\n\n   if ( collectComments_  &&  !commentsBefore_.empty() )\n   {\n      currentValue().setComment( commentsBefore_, commentBefore );\n      commentsBefore_ = \"\";\n   }\n\n\n   switch ( token.type_ )\n   {\n   case tokenObjectBegin:\n      successful = readObject( token );\n      break;\n   case tokenArrayBegin:\n      successful = readArray( token );\n      break;\n   case tokenNumber:\n      successful = decodeNumber( token );\n      break;\n   case tokenString:\n      successful = decodeString( token );\n      break;\n   case tokenTrue:\n      currentValue() = true;\n      break;\n   case tokenFalse:\n      currentValue() = false;\n      break;\n   case tokenNull:\n      currentValue() = Value();\n      break;\n   default:\n      return addError( \"Syntax error: value, object or array expected.\", token );\n   }\n\n   if ( collectComments_ )\n   {\n      lastValueEnd_ = current_;\n      lastValue_ = &currentValue();\n   }\n\n   return successful;\n}\n\n\nvoid \nReader::skipCommentTokens( Token &token )\n{\n   if ( features_.allowComments_ )\n   {\n      do\n      {\n         readToken( token );\n      }\n      while ( token.type_ == tokenComment );\n   }\n   else\n   {\n      readToken( token );\n   }\n}\n\n\nbool \nReader::expectToken( TokenType type, Token &token, const char *message )\n{\n   readToken( token );\n   if ( token.type_ != type )\n      return addError( message, token );\n   return true;\n}\n\n\nbool \nReader::readToken( Token &token )\n{\n   skipSpaces();\n   token.start_ = current_;\n   Char c = getNextChar();\n   bool ok = true;\n   switch ( c )\n   {\n   case '{':\n      token.type_ = tokenObjectBegin;\n      break;\n   case '}':\n      token.type_ = tokenObjectEnd;\n      break;\n   case '[':\n      token.type_ = tokenArrayBegin;\n      break;\n   case ']':\n      token.type_ = tokenArrayEnd;\n      break;\n   case '\"':\n      token.type_ = tokenString;\n      ok = readString();\n      break;\n   case '/':\n      token.type_ = tokenComment;\n      ok = readComment();\n      break;\n   case '0':\n   case '1':\n   case '2':\n   case '3':\n   case '4':\n   case '5':\n   case '6':\n   case '7':\n   case '8':\n   case '9':\n   case '-':\n      token.type_ = tokenNumber;\n      readNumber();\n      break;\n   case 't':\n      token.type_ = tokenTrue;\n      ok = match( \"rue\", 3 );\n      break;\n   case 'f':\n      token.type_ = tokenFalse;\n      ok = match( \"alse\", 4 );\n      break;\n   case 'n':\n      token.type_ = tokenNull;\n      ok = match( \"ull\", 3 );\n      break;\n   case ',':\n      token.type_ = tokenArraySeparator;\n      break;\n   case ':':\n      token.type_ = tokenMemberSeparator;\n      break;\n   case 0:\n      token.type_ = tokenEndOfStream;\n      break;\n   default:\n      ok = false;\n      break;\n   }\n   if ( !ok )\n      token.type_ = tokenError;\n   token.end_ = current_;\n   return true;\n}\n\n\nvoid \nReader::skipSpaces()\n{\n   while ( current_ != end_ )\n   {\n      Char c = *current_;\n      if ( c == ' '  ||  c == '\\t'  ||  c == '\\r'  ||  c == '\\n' )\n         ++current_;\n      else\n         break;\n   }\n}\n\n\nbool \nReader::match( Location pattern, \n               int patternLength )\n{\n   if ( end_ - current_ < patternLength )\n      return false;\n   int index = patternLength;\n   while ( index-- )\n      if ( current_[index] != pattern[index] )\n         return false;\n   current_ += patternLength;\n   return true;\n}\n\n\nbool\nReader::readComment()\n{\n   Location commentBegin = current_ - 1;\n   Char c = getNextChar();\n   bool successful = false;\n   if ( c == '*' )\n      successful = readCStyleComment();\n   else if ( c == '/' )\n      successful = readCppStyleComment();\n   if ( !successful )\n      return false;\n\n   if ( collectComments_ )\n   {\n      CommentPlacement placement = commentBefore;\n      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )\n      {\n         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )\n            placement = commentAfterOnSameLine;\n      }\n\n      addComment( commentBegin, current_, placement );\n   }\n   return true;\n}\n\n\nvoid \nReader::addComment( Location begin, \n                    Location end, \n                    CommentPlacement placement )\n{\n   assert( collectComments_ );\n   if ( placement == commentAfterOnSameLine )\n   {\n      assert( lastValue_ != 0 );\n      lastValue_->setComment( std::string( begin, end ), placement );\n   }\n   else\n   {\n      if ( !commentsBefore_.empty() )\n         commentsBefore_ += \"\\n\";\n      commentsBefore_ += std::string( begin, end );\n   }\n}\n\n\nbool \nReader::readCStyleComment()\n{\n   while ( current_ != end_ )\n   {\n      Char c = getNextChar();\n      if ( c == '*'  &&  *current_ == '/' )\n         break;\n   }\n   return getNextChar() == '/';\n}\n\n\nbool \nReader::readCppStyleComment()\n{\n   while ( current_ != end_ )\n   {\n      Char c = getNextChar();\n      if (  c == '\\r'  ||  c == '\\n' )\n         break;\n   }\n   return true;\n}\n\n\nvoid \nReader::readNumber()\n{\n   while ( current_ != end_ )\n   {\n      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&\n           !in( *current_, '.', 'e', 'E', '+', '-' ) )\n         break;\n      ++current_;\n   }\n}\n\nbool\nReader::readString()\n{\n   Char c = 0;\n   while ( current_ != end_ )\n   {\n      c = getNextChar();\n      if ( c == '\\\\' )\n         getNextChar();\n      else if ( c == '\"' )\n         break;\n   }\n   return c == '\"';\n}\n\n\nbool \nReader::readObject( Token &tokenStart )\n{\n   Token tokenName;\n   std::string name;\n   currentValue() = Value( objectValue );\n   while ( readToken( tokenName ) )\n   {\n      bool initialTokenOk = true;\n      while ( tokenName.type_ == tokenComment  &&  initialTokenOk )\n         initialTokenOk = readToken( tokenName );\n      if  ( !initialTokenOk )\n         break;\n      if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object\n         return true;\n      if ( tokenName.type_ != tokenString )\n         break;\n      \n      name = \"\";\n      if ( !decodeString( tokenName, name ) )\n         return recoverFromError( tokenObjectEnd );\n\n      Token colon;\n      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )\n      {\n         return addErrorAndRecover( \"Missing ':' after object member name\", \n                                    colon, \n                                    tokenObjectEnd );\n      }\n      Value &value = currentValue()[ name ];\n      nodes_.push( &value );\n      bool ok = readValue();\n      nodes_.pop();\n      if ( !ok ) // error already set\n         return recoverFromError( tokenObjectEnd );\n\n      Token comma;\n      if ( !readToken( comma )\n            ||  ( comma.type_ != tokenObjectEnd  &&  \n                  comma.type_ != tokenArraySeparator &&\n\t\t  comma.type_ != tokenComment ) )\n      {\n         return addErrorAndRecover( \"Missing ',' or '}' in object declaration\", \n                                    comma, \n                                    tokenObjectEnd );\n      }\n      bool finalizeTokenOk = true;\n      while ( comma.type_ == tokenComment &&\n              finalizeTokenOk )\n         finalizeTokenOk = readToken( comma );\n      if ( comma.type_ == tokenObjectEnd )\n         return true;\n   }\n   return addErrorAndRecover( \"Missing '}' or object member name\", \n                              tokenName, \n                              tokenObjectEnd );\n}\n\n\nbool \nReader::readArray( Token &tokenStart )\n{\n   currentValue() = Value( arrayValue );\n\n   skipSpaces();\n   if ( *current_ == ']' ) // empty array\n   {\n      Token endArray;\n      readToken( endArray );\n      return true;\n   }\n\n   Value &arrValue = currentValue();\n   Location locStart = current_;\n\n   int index = 0;\n   while ( true )\n   {\n      Value &value = currentValue()[ index++ ];\n      nodes_.push( &value );\n      bool ok = readValue();\n      nodes_.pop();\n      if ( !ok ) // error already set\n         return recoverFromError( tokenArrayEnd );\n\n      Token token;\n      // Accept Comment after last item in the array.\n      ok = readToken( token );\n      while ( token.type_ == tokenComment  &&  ok )\n      {\n         ok = readToken( token );\n      }\n      bool badTokenType = ( token.type_ == tokenArraySeparator  &&  \n                            token.type_ == tokenArrayEnd );\n      if ( !ok  ||  badTokenType )\n      {\n         return addErrorAndRecover( \"Missing ',' or ']' in array declaration\", \n                                    token, \n                                    tokenArrayEnd );\n      }\n      if ( token.type_ == tokenArrayEnd )\n         break;\n   }\n   \n   Location locEnd = current_;\n   std::string strSrc(locStart,locEnd - locStart);\n   strSrc = \"[\"+strSrc;\n   arrValue.SetSrcString(strSrc);\n   return true;\n}\n\n\nbool \nReader::decodeNumber( Token &token )\n{\n   bool isDouble = false;\n   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )\n   {\n      isDouble = isDouble  \n                 ||  in( *inspect, '.', 'e', 'E', '+' )  \n                 ||  ( *inspect == '-'  &&  inspect != token.start_ );\n   }\n   if ( isDouble )\n      return decodeDouble( token );\n   Location current = token.start_;\n   bool isNegative = *current == '-';\n   if ( isNegative )\n      ++current;\n   Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) \n                                       : Value::maxUInt) / 10;\n   Value::UInt value = 0;\n   while ( current < token.end_ )\n   {\n      Char c = *current++;\n      if ( c < '0'  ||  c > '9' )\n         return addError( \"'\" + std::string( token.start_, token.end_ ) + \"' is not a number.\", token );\n      if ( value >= threshold )\n         return decodeDouble( token );\n      value = value * 10 + Value::UInt(c - '0');\n   }\n   if ( isNegative )\n      currentValue() = -Value::Int( value );\n   else if ( value <= Value::UInt(Value::maxInt) )\n      currentValue() = Value::Int( value );\n   else\n      currentValue() = value;\n   return true;\n}\n\n\nbool \nReader::decodeDouble( Token &token )\n{\n   double value = 0;\n   const int bufferSize = 32;\n   int count;\n   int length = int(token.end_ - token.start_);\n   if ( length <= bufferSize )\n   {\n      Char buffer[bufferSize];\n      memcpy( buffer, token.start_, length );\n      buffer[length] = 0;\n      count = sscanf( buffer, \"%lf\", &value );\n   }\n   else\n   {\n      std::string buffer( token.start_, token.end_ );\n      count = sscanf( buffer.c_str(), \"%lf\", &value );\n   }\n\n   if ( count != 1 )\n      return addError( \"'\" + std::string( token.start_, token.end_ ) + \"' is not a number.\", token );\n   currentValue() = value;\n   return true;\n}\n\n\nbool \nReader::decodeString( Token &token )\n{\n   std::string decoded;\n   if ( !decodeString( token, decoded ) )\n      return false;\n   currentValue() = decoded;\n   return true;\n}\n\n\nbool \nReader::decodeString( Token &token, std::string &decoded )\n{\n   decoded.reserve( token.end_ - token.start_ - 2 );\n   Location current = token.start_ + 1; // skip '\"'\n   Location end = token.end_ - 1;      // do not include '\"'\n   while ( current != end )\n   {\n      Char c = *current++;\n      if ( c == '\"' )\n         break;\n      else if ( c == '\\\\' )\n      {\n         if ( current == end )\n            return addError( \"Empty escape sequence in string\", token, current );\n         Char escape = *current++;\n         switch ( escape )\n         {\n         case '\"': decoded += '\"'; break;\n         case '/': decoded += '/'; break;\n         case '\\\\': decoded += '\\\\'; break;\n         case 'b': decoded += '\\b'; break;\n         case 'f': decoded += '\\f'; break;\n         case 'n': decoded += '\\n'; break;\n         case 'r': decoded += '\\r'; break;\n         case 't': decoded += '\\t'; break;\n         case 'u':\n            {\n               unsigned int unicode;\n               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )\n                  return false;\n               decoded += codePointToUTF8(unicode);\n            }\n            break;\n         default:\n            return addError( \"Bad escape sequence in string\", token, current );\n         }\n      }\n      else\n      {\n         decoded += c;\n      }\n   }\n   return true;\n}\n\nbool\nReader::decodeUnicodeCodePoint( Token &token, \n                                     Location &current, \n                                     Location end, \n                                     unsigned int &unicode )\n{\n\n   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )\n      return false;\n   if (unicode >= 0xD800 && unicode <= 0xDBFF)\n   {\n      // surrogate pairs\n      if (end - current < 6)\n         return addError( \"additional six characters expected to parse unicode surrogate pair.\", token, current );\n      unsigned int surrogatePair;\n      if (*(current++) == '\\\\' && *(current++)== 'u')\n      {\n         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))\n         {\n            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);\n         } \n         else\n            return false;\n      } \n      else\n         return addError( \"expecting another \\\\u token to begin the second half of a unicode surrogate pair\", token, current );\n   }\n   return true;\n}\n\nbool \nReader::decodeUnicodeEscapeSequence( Token &token, \n                                     Location &current, \n                                     Location end, \n                                     unsigned int &unicode )\n{\n   if ( end - current < 4 )\n      return addError( \"Bad unicode escape sequence in string: four digits expected.\", token, current );\n   unicode = 0;\n   for ( int index =0; index < 4; ++index )\n   {\n      Char c = *current++;\n      unicode *= 16;\n      if ( c >= '0'  &&  c <= '9' )\n         unicode += c - '0';\n      else if ( c >= 'a'  &&  c <= 'f' )\n         unicode += c - 'a' + 10;\n      else if ( c >= 'A'  &&  c <= 'F' )\n         unicode += c - 'A' + 10;\n      else\n         return addError( \"Bad unicode escape sequence in string: hexadecimal digit expected.\", token, current );\n   }\n   return true;\n}\n\n\nbool \nReader::addError( const std::string &message, \n                  Token &token,\n                  Location extra )\n{\n   ErrorInfo info;\n   info.token_ = token;\n   info.message_ = message;\n   info.extra_ = extra;\n   errors_.push_back( info );\n   return false;\n}\n\n\nbool \nReader::recoverFromError( TokenType skipUntilToken )\n{\n   int errorCount = int(errors_.size());\n   Token skip;\n   while ( true )\n   {\n      if ( !readToken(skip) )\n         errors_.resize( errorCount ); // discard errors caused by recovery\n      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )\n         break;\n   }\n   errors_.resize( errorCount );\n   return false;\n}\n\n\nbool \nReader::addErrorAndRecover( const std::string &message, \n                            Token &token,\n                            TokenType skipUntilToken )\n{\n   addError( message, token );\n   return recoverFromError( skipUntilToken );\n}\n\n\nValue &\nReader::currentValue()\n{\n   return *(nodes_.top());\n}\n\n\nReader::Char \nReader::getNextChar()\n{\n   if ( current_ == end_ )\n      return 0;\n   return *current_++;\n}\n\n\nvoid \nReader::getLocationLineAndColumn( Location location,\n                                  int &line,\n                                  int &column ) const\n{\n   Location current = begin_;\n   Location lastLineStart = current;\n   line = 0;\n   while ( current < location  &&  current != end_ )\n   {\n      Char c = *current++;\n      if ( c == '\\r' )\n      {\n         if ( *current == '\\n' )\n            ++current;\n         lastLineStart = current;\n         ++line;\n      }\n      else if ( c == '\\n' )\n      {\n         lastLineStart = current;\n         ++line;\n      }\n   }\n   // column & line start at 1\n   column = int(location - lastLineStart) + 1;\n   ++line;\n}\n\n\nstd::string\nReader::getLocationLineAndColumn( Location location ) const\n{\n   int line, column;\n   getLocationLineAndColumn( location, line, column );\n   char buffer[18+16+16+1];\n   sprintf( buffer, \"Line %d, Column %d\", line, column );\n   return buffer;\n}\n\n\nstd::string \nReader::getFormatedErrorMessages() const\n{\n   std::string formattedMessage;\n   for ( Errors::const_iterator itError = errors_.begin();\n         itError != errors_.end();\n         ++itError )\n   {\n      const ErrorInfo &error = *itError;\n      formattedMessage += \"* \" + getLocationLineAndColumn( error.token_.start_ ) + \"\\n\";\n      formattedMessage += \"  \" + error.message_ + \"\\n\";\n      if ( error.extra_ )\n         formattedMessage += \"See \" + getLocationLineAndColumn( error.extra_ ) + \" for detail.\\n\";\n   }\n   return formattedMessage;\n}\n\n\nstd::istream& operator>>( std::istream &sin, Value &root )\n{\n    Json::Reader reader;\n    bool ok = reader.parse(sin, root, true);\n    //JSON_ASSERT( ok );\n    if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());\n    return sin;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "common/jsoncpp/value.cpp",
    "content": "#include <iostream>\n#include <utility>\n#include <stdexcept>\n#include <cstring>\n#include <cassert>\n#ifdef JSON_USE_CPPTL\n# include <cpptl/conststring.h>\n#endif\n#include <cstddef>    // size_t\n#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n# include \"json_batchallocator.h\"\n#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR\n#include \"json/value.h\"\n#include \"json/writer.h\"\n\n#define JSON_ASSERT_UNREACHABLE assert( false )\n#define JSON_ASSERT( condition ) assert( condition );  // @todo <= change this into an exception throw\n#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );\n\nnamespace Json {\n\nconst Value Value::null;\nconst Int Value::minInt = Int( ~(UInt(-1)/2) );\nconst Int Value::maxInt = Int( UInt(-1)/2 );\nconst UInt Value::maxUInt = UInt(-1);\n\n\nValueAllocator::~ValueAllocator()\n{\n}\n\nclass DefaultValueAllocator : public ValueAllocator\n{\npublic:\n   virtual ~DefaultValueAllocator()\n   {\n   }\n\n   virtual char *makeMemberName( const char *memberName )\n   {\n      return duplicateStringValue( memberName );\n   }\n\n   virtual void releaseMemberName( char *memberName )\n   {\n      releaseStringValue( memberName );\n   }\n\n   virtual char *duplicateStringValue( const char *value, \n                                       unsigned int length = unknown )\n   {\n\n      if ( length == unknown )\n         length = (unsigned int)strlen(value);\n      char *newString = static_cast<char *>( malloc( length + 1 ) );\n      memcpy( newString, value, length );\n      newString[length] = 0;\n      return newString;\n   }\n\n   virtual void releaseStringValue( char *value )\n   {\n      if ( value )\n         free( value );\n   }\n};\n\nstatic ValueAllocator *&valueAllocator()\n{\n   static DefaultValueAllocator defaultAllocator;\n   static ValueAllocator *valueAllocator = &defaultAllocator;\n   return valueAllocator;\n}\n\nstatic struct DummyValueAllocatorInitializer {\n   DummyValueAllocatorInitializer() \n   {\n      valueAllocator();      // ensure valueAllocator() statics are initialized before main().\n   }\n} dummyValueAllocatorInitializer;\n\n\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n# include \"json_internalarray.inl\"\n# include \"json_internalmap.inl\"\n#endif // JSON_VALUE_USE_INTERNAL_MAP\n\n# include \"json_valueiterator.inl\"\n\n\nValue::CommentInfo::CommentInfo()\n   : comment_( 0 )\n{\n}\n\nValue::CommentInfo::~CommentInfo()\n{\n   if ( comment_ )\n      valueAllocator()->releaseStringValue( comment_ );\n}\n\n\nvoid \nValue::CommentInfo::setComment( const char *text )\n{\n   if ( comment_ )\n      valueAllocator()->releaseStringValue( comment_ );\n   JSON_ASSERT( text );\n   JSON_ASSERT_MESSAGE( text[0]=='\\0' || text[0]=='/', \"Comments must start with /\");\n   // It seems that /**/ style comments are acceptable as well.\n   comment_ = valueAllocator()->duplicateStringValue( text );\n}\n\n# ifndef JSON_VALUE_USE_INTERNAL_MAP\n\n// Notes: index_ indicates if the string was allocated when\n// a string is stored.\n\nValue::CZString::CZString( int index )\n   : cstr_( 0 )\n   , index_( index )\n{\n}\n\nValue::CZString::CZString( const char *cstr, DuplicationPolicy allocate )\n   : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) \n                                  : cstr )\n   , index_( allocate )\n{\n}\n\nValue::CZString::CZString( const CZString &other )\n: cstr_( other.index_ != noDuplication &&  other.cstr_ != 0\n                ?  valueAllocator()->makeMemberName( other.cstr_ )\n                : other.cstr_ )\n   , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)\n                         : other.index_ )\n{\n}\n\nValue::CZString::~CZString()\n{\n   if ( cstr_  &&  index_ == duplicate )\n      valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) );\n}\n\nvoid \nValue::CZString::swap( CZString &other )\n{\n   std::swap( cstr_, other.cstr_ );\n   std::swap( index_, other.index_ );\n}\n\nValue::CZString &\nValue::CZString::operator =( const CZString &other )\n{\n   CZString temp( other );\n   swap( temp );\n   return *this;\n}\n\nbool \nValue::CZString::operator<( const CZString &other ) const \n{\n   if ( cstr_ )\n      return strcmp( cstr_, other.cstr_ ) < 0;\n   return index_ < other.index_;\n}\n\nbool \nValue::CZString::operator==( const CZString &other ) const \n{\n   if ( cstr_ )\n      return strcmp( cstr_, other.cstr_ ) == 0;\n   return index_ == other.index_;\n}\n\n\nint \nValue::CZString::index() const\n{\n   return index_;\n}\n\n\nconst char *\nValue::CZString::c_str() const\n{\n   return cstr_;\n}\n\nbool \nValue::CZString::isStaticString() const\n{\n   return index_ == noDuplication;\n}\n\n#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP\n\n\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// class Value::Value\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n// //////////////////////////////////////////////////////////////////\n\n/*! \\internal Default constructor initialization must be equivalent to:\n * memset( this, 0, sizeof(Value) )\n * This optimization is used in ValueInternalMap fast allocator.\n */\nValue::Value( ValueType type )\n   : type_( type )\n   , allocated_( 0 )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   switch ( type )\n   {\n   case nullValue:\n      break;\n   case intValue:\n   case uintValue:\n      value_.int_ = 0;\n      break;\n   case realValue:\n      value_.real_ = 0.0;\n      break;\n   case stringValue:\n      value_.string_ = 0;\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      value_.map_ = new ObjectValues();\n      break;\n#else\n   case arrayValue:\n      value_.array_ = arrayAllocator()->newArray();\n      break;\n   case objectValue:\n      value_.map_ = mapAllocator()->newMap();\n      break;\n#endif\n   case booleanValue:\n      value_.bool_ = false;\n      break;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n}\n\n\nValue::Value( Int value )\n   : type_( intValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.int_ = value;\n}\n\n\nValue::Value( UInt value )\n   : type_( uintValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.uint_ = value;\n}\n\nValue::Value( double value )\n   : type_( realValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.real_ = value;\n}\n\nValue::Value( const char *value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value );\n}\n\n\nValue::Value( const char *beginValue, \n              const char *endValue )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( beginValue, \n                                                            UInt(endValue - beginValue) );\n}\n\n\nValue::Value( const std::string &value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), \n                                                            (unsigned int)value.length() );\n\n}\n\nValue::Value( const StaticString &value )\n   : type_( stringValue )\n   , allocated_( false )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = const_cast<char *>( value.c_str() );\n}\n\n\n# ifdef JSON_USE_CPPTL\nValue::Value( const CppTL::ConstString &value )\n   : type_( stringValue )\n   , allocated_( true )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );\n}\n# endif\n\nValue::Value( bool value )\n   : type_( booleanValue )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   value_.bool_ = value;\n}\n\n\nValue::Value( const Value &other )\n   : type_( other.type_ )\n   , comments_( 0 )\n# ifdef JSON_VALUE_USE_INTERNAL_MAP\n   , itemIsUsed_( 0 )\n#endif\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      value_ = other.value_;\n      break;\n   case stringValue:\n      if ( other.value_.string_ )\n      {\n         value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );\n         allocated_ = true;\n      }\n      else\n         value_.string_ = 0;\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n\t   strSrc_ = other.strSrc_;\n   case objectValue:\n      value_.map_ = new ObjectValues( *other.value_.map_ );\n      break;\n#else\n   case arrayValue:\n      value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );\n      break;\n   case objectValue:\n      value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );\n      break;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   if ( other.comments_ )\n   {\n      comments_ = new CommentInfo[numberOfCommentPlacement];\n      for ( int comment =0; comment < numberOfCommentPlacement; ++comment )\n      {\n         const CommentInfo &otherComment = other.comments_[comment];\n         if ( otherComment.comment_ )\n            comments_[comment].setComment( otherComment.comment_ );\n      }\n   }\n}\n\n\nValue::~Value()\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      break;\n   case stringValue:\n      if ( allocated_ )\n         valueAllocator()->releaseStringValue( value_.string_ );\n      break;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      delete value_.map_;\n      break;\n#else\n   case arrayValue:\n      arrayAllocator()->destructArray( value_.array_ );\n      break;\n   case objectValue:\n      mapAllocator()->destructMap( value_.map_ );\n      break;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n\n   if ( comments_ )\n      delete[] comments_;\n}\n\nValue &\nValue::operator=( const Value &other )\n{\n   Value temp( other );\n   swap( temp );\n   return *this;\n}\n\nvoid \nValue::swap( Value &other )\n{\n   ValueType temp = type_;\n   type_ = other.type_;\n   other.type_ = temp;\n   std::swap( value_, other.value_ );\n   int temp2 = allocated_;\n   allocated_ = other.allocated_;\n   other.allocated_ = temp2;\n   std::string strTemp = strSrc_;\n   strSrc_ = other.strSrc_;\n   other.strSrc_ = strTemp;\n   \n}\n\nValueType \nValue::type() const\n{\n   return type_;\n}\n\n\nint \nValue::compare( const Value &other )\n{\n   /*\n   int typeDelta = other.type_ - type_;\n   switch ( type_ )\n   {\n   case nullValue:\n\n      return other.type_ == type_;\n   case intValue:\n      if ( other.type_.isNumeric()\n   case uintValue:\n   case realValue:\n   case booleanValue:\n      break;\n   case stringValue,\n      break;\n   case arrayValue:\n      delete value_.array_;\n      break;\n   case objectValue:\n      delete value_.map_;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   */\n   return 0;  // unreachable\n}\n\nbool \nValue::operator <( const Value &other ) const\n{\n   int typeDelta = type_ - other.type_;\n   if ( typeDelta )\n      return typeDelta < 0 ? true : false;\n   switch ( type_ )\n   {\n   case nullValue:\n      return false;\n   case intValue:\n      return value_.int_ < other.value_.int_;\n   case uintValue:\n      return value_.uint_ < other.value_.uint_;\n   case realValue:\n      return value_.real_ < other.value_.real_;\n   case booleanValue:\n      return value_.bool_ < other.value_.bool_;\n   case stringValue:\n      return ( value_.string_ == 0  &&  other.value_.string_ )\n             || ( other.value_.string_  \n                  &&  value_.string_  \n                  && strcmp( value_.string_, other.value_.string_ ) < 0 );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      {\n         int delta = int( value_.map_->size() - other.value_.map_->size() );\n         if ( delta )\n            return delta < 0;\n         return (*value_.map_) < (*other.value_.map_);\n      }\n#else\n   case arrayValue:\n      return value_.array_->compare( *(other.value_.array_) ) < 0;\n   case objectValue:\n      return value_.map_->compare( *(other.value_.map_) ) < 0;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0;  // unreachable\n}\n\nbool \nValue::operator <=( const Value &other ) const\n{\n   return !(other > *this);\n}\n\nbool \nValue::operator >=( const Value &other ) const\n{\n   return !(*this < other);\n}\n\nbool \nValue::operator >( const Value &other ) const\n{\n   return other < *this;\n}\n\nbool \nValue::operator ==( const Value &other ) const\n{\n   //if ( type_ != other.type_ )\n   // GCC 2.95.3 says:\n   // attempt to take address of bit-field structure member `Json::Value::type_'\n   // Beats me, but a temp solves the problem.\n   int temp = other.type_;\n   if ( type_ != temp )\n      return false;\n   switch ( type_ )\n   {\n   case nullValue:\n      return true;\n   case intValue:\n      return value_.int_ == other.value_.int_;\n   case uintValue:\n      return value_.uint_ == other.value_.uint_;\n   case realValue:\n      return value_.real_ == other.value_.real_;\n   case booleanValue:\n      return value_.bool_ == other.value_.bool_;\n   case stringValue:\n      return ( value_.string_ == other.value_.string_ )\n             || ( other.value_.string_  \n                  &&  value_.string_  \n                  && strcmp( value_.string_, other.value_.string_ ) == 0 );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      return value_.map_->size() == other.value_.map_->size()\n             && (*value_.map_) == (*other.value_.map_);\n#else\n   case arrayValue:\n      return value_.array_->compare( *(other.value_.array_) ) == 0;\n   case objectValue:\n      return value_.map_->compare( *(other.value_.map_) ) == 0;\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0;  // unreachable\n}\n\nbool \nValue::operator !=( const Value &other ) const\n{\n   return !( *this == other );\n}\n\nconst char *\nValue::asCString() const\n{\n   JSON_ASSERT( type_ == stringValue );\n   return value_.string_;\n}\n\n\nstd::string \nValue::asString() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return \"\";\n   case stringValue:\n      return value_.string_ ? value_.string_ : \"\";\n   case booleanValue:\n      return value_.bool_ ? \"true\" : \"false\";\n   case intValue:\n   case uintValue:\n   case realValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to string\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return \"\"; // unreachable\n}\n\n# ifdef JSON_USE_CPPTL\nCppTL::ConstString \nValue::asConstString() const\n{\n   return CppTL::ConstString( asString().c_str() );\n}\n# endif\n\nValue::Int \nValue::asInt() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0;\n   case intValue:\n      return value_.int_;\n   case uintValue:\n      JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, \"integer out of signed integer range\" );\n      return value_.uint_;\n   case realValue:\n      JSON_ASSERT_MESSAGE( value_.real_ >= minInt  &&  value_.real_ <= maxInt, \"Real out of signed integer range\" );\n      return Int( value_.real_ );\n   case booleanValue:\n      return value_.bool_ ? 1 : 0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to int\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\nValue::UInt \nValue::asUInt() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0;\n   case intValue:\n      JSON_ASSERT_MESSAGE( value_.int_ >= 0, \"Negative integer can not be converted to unsigned integer\" );\n      return value_.int_;\n   case uintValue:\n      return value_.uint_;\n   case realValue:\n      JSON_ASSERT_MESSAGE( value_.real_ >= 0  &&  value_.real_ <= maxUInt,  \"Real out of unsigned integer range\" );\n      return UInt( value_.real_ );\n   case booleanValue:\n      return value_.bool_ ? 1 : 0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to uint\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\ndouble \nValue::asDouble() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return 0.0;\n   case intValue:\n      return value_.int_;\n   case uintValue:\n      return value_.uint_;\n   case realValue:\n      return value_.real_;\n   case booleanValue:\n      return value_.bool_ ? 1.0 : 0.0;\n   case stringValue:\n   case arrayValue:\n   case objectValue:\n      JSON_ASSERT_MESSAGE( false, \"Type is not convertible to double\" );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\nbool \nValue::asBool() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return false;\n   case intValue:\n   case uintValue:\n      return value_.int_ != 0;\n   case realValue:\n      return value_.real_ != 0.0;\n   case booleanValue:\n      return value_.bool_;\n   case stringValue:\n      return value_.string_  &&  value_.string_[0] != 0;\n   case arrayValue:\n   case objectValue:\n      return value_.map_->size() != 0;\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return false; // unreachable;\n}\n\n\nbool \nValue::isConvertibleTo( ValueType other ) const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n      return true;\n   case intValue:\n      return ( other == nullValue  &&  value_.int_ == 0 )\n             || other == intValue\n             || ( other == uintValue  && value_.int_ >= 0 )\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case uintValue:\n      return ( other == nullValue  &&  value_.uint_ == 0 )\n             || ( other == intValue  && value_.uint_ <= (unsigned)maxInt )\n             || other == uintValue\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case realValue:\n      return ( other == nullValue  &&  value_.real_ == 0.0 )\n             || ( other == intValue  &&  value_.real_ >= minInt  &&  value_.real_ <= maxInt )\n             || ( other == uintValue  &&  value_.real_ >= 0  &&  value_.real_ <= maxUInt )\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case booleanValue:\n      return ( other == nullValue  &&  value_.bool_ == false )\n             || other == intValue\n             || other == uintValue\n             || other == realValue\n             || other == stringValue\n             || other == booleanValue;\n   case stringValue:\n      return other == stringValue\n             || ( other == nullValue  &&  (!value_.string_  ||  value_.string_[0] == 0) );\n   case arrayValue:\n      return other == arrayValue\n             ||  ( other == nullValue  &&  value_.map_->size() == 0 );\n   case objectValue:\n      return other == objectValue\n             ||  ( other == nullValue  &&  value_.map_->size() == 0 );\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return false; // unreachable;\n}\n\n\n/// Number of values in array or object\nValue::UInt \nValue::size() const\n{\n   switch ( type_ )\n   {\n   case nullValue:\n   case intValue:\n   case uintValue:\n   case realValue:\n   case booleanValue:\n   case stringValue:\n      return 0;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:  // size of the array is highest index + 1\n      if ( !value_.map_->empty() )\n      {\n         ObjectValues::const_iterator itLast = value_.map_->end();\n         --itLast;\n         return (*itLast).first.index()+1;\n      }\n      return 0;\n   case objectValue:\n      return Int( value_.map_->size() );\n#else\n   case arrayValue:\n      return Int( value_.array_->size() );\n   case objectValue:\n      return Int( value_.map_->size() );\n#endif\n   default:\n      JSON_ASSERT_UNREACHABLE;\n   }\n   return 0; // unreachable;\n}\n\n\nbool \nValue::empty() const\n{\n   if ( isNull() || isArray() || isObject() )\n      return size() == 0u;\n   else\n      return false;\n}\n\n\nbool\nValue::operator!() const\n{\n   return isNull();\n}\n\n\nvoid \nValue::clear()\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue  || type_ == objectValue );\n\n   switch ( type_ )\n   {\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n   case objectValue:\n      value_.map_->clear();\n      break;\n#else\n   case arrayValue:\n      value_.array_->clear();\n      break;\n   case objectValue:\n      value_.map_->clear();\n      break;\n#endif\n   default:\n      break;\n   }\n}\n\nvoid \nValue::resize( UInt newSize )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      *this = Value( arrayValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   UInt oldSize = size();\n   if ( newSize == 0 )\n      clear();\n   else if ( newSize > oldSize )\n      (*this)[ newSize - 1 ];\n   else\n   {\n      for ( UInt index = newSize; index < oldSize; ++index )\n         value_.map_->erase( index );\n      assert( size() == newSize );\n   }\n#else\n   value_.array_->resize( newSize );\n#endif\n}\n\n\nValue &\nValue::operator[]( UInt index )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      *this = Value( arrayValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString key( index );\n   ObjectValues::iterator it = value_.map_->lower_bound( key );\n   if ( it != value_.map_->end()  &&  (*it).first == key )\n      return (*it).second;\n\n   ObjectValues::value_type defaultValue( key, null );\n   it = value_.map_->insert( it, defaultValue );\n   return (*it).second;\n#else\n   return value_.array_->resolveReference( index );\n#endif\n}\n\n\nconst Value &\nValue::operator[]( UInt index ) const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString key( index );\n   ObjectValues::const_iterator it = value_.map_->find( key );\n   if ( it == value_.map_->end() )\n      return null;\n   return (*it).second;\n#else\n   Value *value = value_.array_->find( index );\n   return value ? *value : null;\n#endif\n}\n\n\nValue &\nValue::operator[]( const char *key )\n{\n   return resolveReference( key, false );\n}\n\n\nValue &\nValue::resolveReference( const char *key, \n                         bool isStatic )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      *this = Value( objectValue );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, isStatic ? CZString::noDuplication \n                                     : CZString::duplicateOnCopy );\n   ObjectValues::iterator it = value_.map_->lower_bound( actualKey );\n   if ( it != value_.map_->end()  &&  (*it).first == actualKey )\n      return (*it).second;\n\n   ObjectValues::value_type defaultValue( actualKey, null );\n   it = value_.map_->insert( it, defaultValue );\n   Value &value = (*it).second;\n   return value;\n#else\n   return value_.map_->resolveReference( key, isStatic );\n#endif\n}\n\n\nValue \nValue::get( UInt index, \n            const Value &defaultValue ) const\n{\n   const Value *value = &((*this)[index]);\n   return value == &null ? defaultValue : *value;\n}\n\n\nbool \nValue::isValidIndex( UInt index ) const\n{\n   return index < size();\n}\n\n\n\nconst Value &\nValue::operator[]( const char *key ) const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, CZString::noDuplication );\n   ObjectValues::const_iterator it = value_.map_->find( actualKey );\n   if ( it == value_.map_->end() )\n      return null;\n   return (*it).second;\n#else\n   const Value *value = value_.map_->find( key );\n   return value ? *value : null;\n#endif\n}\n\n\nValue &\nValue::operator[]( const std::string &key )\n{\n   return (*this)[ key.c_str() ];\n}\n\n\nconst Value &\nValue::operator[]( const std::string &key ) const\n{\n   return (*this)[ key.c_str() ];\n}\n\nValue &\nValue::operator[]( const StaticString &key )\n{\n   return resolveReference( key, true );\n}\n\n\n# ifdef JSON_USE_CPPTL\nValue &\nValue::operator[]( const CppTL::ConstString &key )\n{\n   return (*this)[ key.c_str() ];\n}\n\n\nconst Value &\nValue::operator[]( const CppTL::ConstString &key ) const\n{\n   return (*this)[ key.c_str() ];\n}\n# endif\n\n\nValue &\nValue::append( const Value &value )\n{\n   return (*this)[size()] = value;\n}\n\n\nValue \nValue::get( const char *key, \n            const Value &defaultValue ) const\n{\n   const Value *value = &((*this)[key]);\n   return value == &null ? defaultValue : *value;\n}\n\n\nValue \nValue::get( const std::string &key,\n            const Value &defaultValue ) const\n{\n   return get( key.c_str(), defaultValue );\n}\n\nValue\nValue::removeMember( const char* key )\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n      return null;\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   CZString actualKey( key, CZString::noDuplication );\n   ObjectValues::iterator it = value_.map_->find( actualKey );\n   if ( it == value_.map_->end() )\n      return null;\n   Value old(it->second);\n   value_.map_->erase(it);\n   return old;\n#else\n   Value *value = value_.map_->find( key );\n   if (value){\n      Value old(*value);\n      value_.map_.remove( key );\n      return old;\n   } else {\n      return null;\n   }\n#endif\n}\n\nValue\nValue::removeMember( const std::string &key )\n{\n   return removeMember( key.c_str() );\n}\n\n# ifdef JSON_USE_CPPTL\nValue \nValue::get( const CppTL::ConstString &key,\n            const Value &defaultValue ) const\n{\n   return get( key.c_str(), defaultValue );\n}\n# endif\n\nbool \nValue::isMember( const char *key ) const\n{\n   const Value *value = &((*this)[key]);\n   return value != &null;\n}\n\n\nbool \nValue::isMember( const std::string &key ) const\n{\n   return isMember( key.c_str() );\n}\n\n\n# ifdef JSON_USE_CPPTL\nbool \nValue::isMember( const CppTL::ConstString &key ) const\n{\n   return isMember( key.c_str() );\n}\n#endif\n\nValue::Members \nValue::getMemberNames() const\n{\n   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );\n   if ( type_ == nullValue )\n       return Value::Members();\n   Members members;\n   members.reserve( value_.map_->size() );\n#ifndef JSON_VALUE_USE_INTERNAL_MAP\n   ObjectValues::const_iterator it = value_.map_->begin();\n   ObjectValues::const_iterator itEnd = value_.map_->end();\n   for ( ; it != itEnd; ++it )\n      members.push_back( std::string( (*it).first.c_str() ) );\n#else\n   ValueInternalMap::IteratorState it;\n   ValueInternalMap::IteratorState itEnd;\n   value_.map_->makeBeginIterator( it );\n   value_.map_->makeEndIterator( itEnd );\n   for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )\n      members.push_back( std::string( ValueInternalMap::key( it ) ) );\n#endif\n   return members;\n}\n//\n//# ifdef JSON_USE_CPPTL\n//EnumMemberNames\n//Value::enumMemberNames() const\n//{\n//   if ( type_ == objectValue )\n//   {\n//      return CppTL::Enum::any(  CppTL::Enum::transform(\n//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),\n//         MemberNamesTransform() ) );\n//   }\n//   return EnumMemberNames();\n//}\n//\n//\n//EnumValues \n//Value::enumValues() const\n//{\n//   if ( type_ == objectValue  ||  type_ == arrayValue )\n//      return CppTL::Enum::anyValues( *(value_.map_), \n//                                     CppTL::Type<const Value &>() );\n//   return EnumValues();\n//}\n//\n//# endif\n\n\nbool\nValue::isNull() const\n{\n   return type_ == nullValue;\n}\n\n\nbool \nValue::isBool() const\n{\n   return type_ == booleanValue;\n}\n\n\nbool \nValue::isInt() const\n{\n   return type_ == intValue;\n}\n\n\nbool \nValue::isUInt() const\n{\n   return type_ == uintValue;\n}\n\n\nbool \nValue::isIntegral() const\n{\n   return type_ == intValue  \n          ||  type_ == uintValue  \n          ||  type_ == booleanValue;\n}\n\n\nbool \nValue::isDouble() const\n{\n   return type_ == realValue;\n}\n\n\nbool \nValue::isNumeric() const\n{\n   return isIntegral() || isDouble();\n}\n\n\nbool \nValue::isString() const\n{\n   return type_ == stringValue;\n}\n\n\nbool \nValue::isArray() const\n{\n   return type_ == nullValue  ||  type_ == arrayValue;\n}\n\n\nbool \nValue::isObject() const\n{\n   return type_ == nullValue  ||  type_ == objectValue;\n}\n\n\nvoid \nValue::setComment( const char *comment,\n                   CommentPlacement placement )\n{\n   if ( !comments_ )\n      comments_ = new CommentInfo[numberOfCommentPlacement];\n   comments_[placement].setComment( comment );\n}\n\n\nvoid \nValue::setComment( const std::string &comment,\n                   CommentPlacement placement )\n{\n   setComment( comment.c_str(), placement );\n}\n\n\nbool \nValue::hasComment( CommentPlacement placement ) const\n{\n   return comments_ != 0  &&  comments_[placement].comment_ != 0;\n}\n\nstd::string \nValue::getComment( CommentPlacement placement ) const\n{\n   if ( hasComment(placement) )\n      return comments_[placement].comment_;\n   return \"\";\n}\n\n\nstd::string \nValue::toStyledString() const\n{\n   StyledWriter writer;\n   return writer.write( *this );\n}\n\n\nValue::const_iterator \nValue::begin() const\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeBeginIterator( it );\n         return const_iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeBeginIterator( it );\n         return const_iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return const_iterator( value_.map_->begin() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return const_iterator();\n}\n\nValue::const_iterator \nValue::end() const\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeEndIterator( it );\n         return const_iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeEndIterator( it );\n         return const_iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return const_iterator( value_.map_->end() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return const_iterator();\n}\n\n\nValue::iterator \nValue::begin()\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeBeginIterator( it );\n         return iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeBeginIterator( it );\n         return iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return iterator( value_.map_->begin() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return iterator();\n}\n\nValue::iterator \nValue::end()\n{\n   switch ( type_ )\n   {\n#ifdef JSON_VALUE_USE_INTERNAL_MAP\n   case arrayValue:\n      if ( value_.array_ )\n      {\n         ValueInternalArray::IteratorState it;\n         value_.array_->makeEndIterator( it );\n         return iterator( it );\n      }\n      break;\n   case objectValue:\n      if ( value_.map_ )\n      {\n         ValueInternalMap::IteratorState it;\n         value_.map_->makeEndIterator( it );\n         return iterator( it );\n      }\n      break;\n#else\n   case arrayValue:\n   case objectValue:\n      if ( value_.map_ )\n         return iterator( value_.map_->end() );\n      break;\n#endif\n   default:\n      break;\n   }\n   return iterator();\n}\n\n\n// class PathArgument\n// //////////////////////////////////////////////////////////////////\n\nPathArgument::PathArgument()\n   : kind_( kindNone )\n{\n}\n\n\nPathArgument::PathArgument( Value::UInt index )\n   : index_( index )\n   , kind_( kindIndex )\n{\n}\n\n\nPathArgument::PathArgument( const char *key )\n   : key_( key )\n   , kind_( kindKey )\n{\n}\n\n\nPathArgument::PathArgument( const std::string &key )\n   : key_( key.c_str() )\n   , kind_( kindKey )\n{\n}\n\n// class Path\n// //////////////////////////////////////////////////////////////////\n\nPath::Path( const std::string &path,\n            const PathArgument &a1,\n            const PathArgument &a2,\n            const PathArgument &a3,\n            const PathArgument &a4,\n            const PathArgument &a5 )\n{\n   InArgs in;\n   in.push_back( &a1 );\n   in.push_back( &a2 );\n   in.push_back( &a3 );\n   in.push_back( &a4 );\n   in.push_back( &a5 );\n   makePath( path, in );\n}\n\n\nvoid \nPath::makePath( const std::string &path,\n                const InArgs &in )\n{\n   const char *current = path.c_str();\n   const char *end = current + path.length();\n   InArgs::const_iterator itInArg = in.begin();\n   while ( current != end )\n   {\n      if ( *current == '[' )\n      {\n         ++current;\n         if ( *current == '%' )\n            addPathInArg( path, in, itInArg, PathArgument::kindIndex );\n         else\n         {\n            Value::UInt index = 0;\n            for ( ; current != end && *current >= '0'  &&  *current <= '9'; ++current )\n               index = index * 10 + Value::UInt(*current - '0');\n            args_.push_back( index );\n         }\n         if ( current == end  ||  *current++ != ']' )\n            invalidPath( path, int(current - path.c_str()) );\n      }\n      else if ( *current == '%' )\n      {\n         addPathInArg( path, in, itInArg, PathArgument::kindKey );\n         ++current;\n      }\n      else if ( *current == '.' )\n      {\n         ++current;\n      }\n      else\n      {\n         const char *beginName = current;\n         while ( current != end  &&  !strchr( \"[.\", *current ) )\n            ++current;\n         args_.push_back( std::string( beginName, current ) );\n      }\n   }\n}\n\n\nvoid \nPath::addPathInArg( const std::string &path, \n                    const InArgs &in, \n                    InArgs::const_iterator &itInArg, \n                    PathArgument::Kind kind )\n{\n   if ( itInArg == in.end() )\n   {\n      // Error: missing argument %d\n   }\n   else if ( (*itInArg)->kind_ != kind )\n   {\n      // Error: bad argument type\n   }\n   else\n   {\n      args_.push_back( **itInArg );\n   }\n}\n\n\nvoid \nPath::invalidPath( const std::string &path, \n                   int location )\n{\n   // Error: invalid path.\n}\n\n\nconst Value &\nPath::resolve( const Value &root ) const\n{\n   const Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )\n         {\n            // Error: unable to resolve path (array value expected at position...\n         }\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n         {\n            // Error: unable to resolve path (object value expected at position...)\n         }\n         node = &((*node)[arg.key_]);\n         if ( node == &Value::null )\n         {\n            // Error: unable to resolve path (object has no member named '' at position...)\n         }\n      }\n   }\n   return *node;\n}\n\n\nValue \nPath::resolve( const Value &root, \n               const Value &defaultValue ) const\n{\n   const Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray()  ||  node->isValidIndex( arg.index_ ) )\n            return defaultValue;\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n            return defaultValue;\n         node = &((*node)[arg.key_]);\n         if ( node == &Value::null )\n            return defaultValue;\n      }\n   }\n   return *node;\n}\n\n\nValue &\nPath::make( Value &root ) const\n{\n   Value *node = &root;\n   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )\n   {\n      const PathArgument &arg = *it;\n      if ( arg.kind_ == PathArgument::kindIndex )\n      {\n         if ( !node->isArray() )\n         {\n            // Error: node is not an array at position ...\n         }\n         node = &((*node)[arg.index_]);\n      }\n      else if ( arg.kind_ == PathArgument::kindKey )\n      {\n         if ( !node->isObject() )\n         {\n            // Error: node is not an object at position...\n         }\n         node = &((*node)[arg.key_]);\n      }\n   }\n   return *node;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "common/jsoncpp/writer.cpp",
    "content": "#include <utility>\n#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n#include <iostream>\n#include <sstream>\n#include <iomanip>\n#include \"json/writer.h\"\n\n#if _MSC_VER >= 1400 // VC++ 8.0\n#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.\n#endif\n\nnamespace Json {\n\nstatic bool isControlCharacter(char ch)\n{\n   return ch > 0 && ch <= 0x1F;\n}\n\nstatic bool containsControlCharacter( const char* str )\n{\n   while ( *str ) \n   {\n      if ( isControlCharacter( *(str++) ) )\n         return true;\n   }\n   return false;\n}\nstatic void uintToString( unsigned int value, \n                          char *&current )\n{\n   *--current = 0;\n   do\n   {\n      *--current = (value % 10) + '0';\n      value /= 10;\n   }\n   while ( value != 0 );\n}\n\nstd::string valueToString( Int value )\n{\n   char buffer[32];\n   char *current = buffer + sizeof(buffer);\n   bool isNegative = value < 0;\n   if ( isNegative )\n      value = -value;\n   uintToString( UInt(value), current );\n   if ( isNegative )\n      *--current = '-';\n   assert( current >= buffer );\n   return current;\n}\n\n\nstd::string valueToString( UInt value )\n{\n   char buffer[32];\n   char *current = buffer + sizeof(buffer);\n   uintToString( value, current );\n   assert( current >= buffer );\n   return current;\n}\n\nstd::string valueToString( double value )\n{\n   char buffer[32];\n#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. \n   sprintf_s(buffer, sizeof(buffer), \"%#.16g\", value); \n#else\t\n   sprintf(buffer, \"%#.16g\", value); \n#endif\n   char* ch = buffer + strlen(buffer) - 1;\n   if (*ch != '0') return buffer; // nothing to truncate, so save time\n   while(ch > buffer && *ch == '0'){\n     --ch;\n   }\n   char* last_nonzero = ch;\n   while(ch >= buffer){\n     switch(*ch){\n     case '0':\n     case '1':\n     case '2':\n     case '3':\n     case '4':\n     case '5':\n     case '6':\n     case '7':\n     case '8':\n     case '9':\n       --ch;\n       continue;\n     case '.':\n       // Truncate zeroes to save bytes in output, but keep one.\n       *(last_nonzero+2) = '\\0';\n       return buffer;\n     default:\n       return buffer;\n     }\n   }\n   return buffer;\n}\n\n\nstd::string valueToString( bool value )\n{\n   return value ? \"true\" : \"false\";\n}\n\nstd::string valueToQuotedString( const char *value )\n{\n   // Not sure how to handle unicode...\n   if (strpbrk(value, \"\\\"\\\\\\b\\f\\n\\r\\t\") == NULL && !containsControlCharacter( value ))\n      return std::string(\"\\\"\") + value + \"\\\"\";\n   // We have to walk value and escape any special characters.\n   // Appending to std::string is not efficient, but this should be rare.\n   // (Note: forward slashes are *not* rare, but I am not escaping them.)\n   unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL\n   std::string result;\n   result.reserve(maxsize); // to avoid lots of mallocs\n   result += \"\\\"\";\n   for (const char* c=value; *c != 0; ++c)\n   {\n      switch(*c)\n      {\n         case '\\\"':\n            result += \"\\\\\\\"\";\n            break;\n         case '\\\\':\n            result += \"\\\\\\\\\";\n            break;\n         case '\\b':\n            result += \"\\\\b\";\n            break;\n         case '\\f':\n            result += \"\\\\f\";\n            break;\n         case '\\n':\n            result += \"\\\\n\";\n            break;\n         case '\\r':\n            result += \"\\\\r\";\n            break;\n         case '\\t':\n            result += \"\\\\t\";\n            break;\n         //case '/':\n            // Even though \\/ is considered a legal escape in JSON, a bare\n            // slash is also legal, so I see no reason to escape it.\n            // (I hope I am not misunderstanding something.\n            // blep notes: actually escaping \\/ may be useful in javascript to avoid </ \n            // sequence.\n            // Should add a flag to allow this compatibility mode and prevent this \n            // sequence from occurring.\n         default:\n            if ( isControlCharacter( *c ) )\n            {\n               std::ostringstream oss;\n               oss << \"\\\\u\" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);\n               result += oss.str();\n            }\n            else\n            {\n               result += *c;\n            }\n            break;\n      }\n   }\n   result += \"\\\"\";\n   return result;\n}\n\n// Class Writer\n// //////////////////////////////////////////////////////////////////\nWriter::~Writer()\n{\n}\n\n\n// Class FastWriter\n// //////////////////////////////////////////////////////////////////\n\nFastWriter::FastWriter()\n   : yamlCompatiblityEnabled_( false )\n{\n}\n\n\nvoid \nFastWriter::enableYAMLCompatibility()\n{\n   yamlCompatiblityEnabled_ = true;\n}\n\n\nstd::string \nFastWriter::write( const Value &root )\n{\n   document_ = \"\";\n   writeValue( root );\n   document_ += \"\\n\";\n   return document_;\n}\n\n\nvoid \nFastWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      document_ += \"null\";\n      break;\n   case intValue:\n      document_ += valueToString( value.asInt() );\n      break;\n   case uintValue:\n      document_ += valueToString( value.asUInt() );\n      break;\n   case realValue:\n      document_ += valueToString( value.asDouble() );\n      break;\n   case stringValue:\n      document_ += valueToQuotedString( value.asCString() );\n      break;\n   case booleanValue:\n      document_ += valueToString( value.asBool() );\n      break;\n   case arrayValue:\n      {\n         document_ += \"[\";\n         int size = value.size();\n         for ( int index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               document_ += \",\";\n            writeValue( value[index] );\n         }\n         document_ += \"]\";\n      }\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         document_ += \"{\";\n         for ( Value::Members::iterator it = members.begin(); \n               it != members.end(); \n               ++it )\n         {\n            const std::string &name = *it;\n            if ( it != members.begin() )\n               document_ += \",\";\n            document_ += valueToQuotedString( name.c_str() );\n            document_ += yamlCompatiblityEnabled_ ? \": \" \n                                                  : \":\";\n            writeValue( value[name] );\n         }\n         document_ += \"}\";\n      }\n      break;\n   }\n}\n\n\n// Class StyledWriter\n// //////////////////////////////////////////////////////////////////\n\nStyledWriter::StyledWriter()\n   : rightMargin_( 74 )\n   , indentSize_( 3 )\n{\n}\n\n\nstd::string \nStyledWriter::write( const Value &root )\n{\n   document_ = \"\";\n   addChildValues_ = false;\n   indentString_ = \"\";\n   writeCommentBeforeValue( root );\n   writeValue( root );\n   writeCommentAfterValueOnSameLine( root );\n   document_ += \"\\n\";\n   return document_;\n}\n\n\nvoid \nStyledWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      pushValue( \"null\" );\n      break;\n   case intValue:\n      pushValue( valueToString( value.asInt() ) );\n      break;\n   case uintValue:\n      pushValue( valueToString( value.asUInt() ) );\n      break;\n   case realValue:\n      pushValue( valueToString( value.asDouble() ) );\n      break;\n   case stringValue:\n      pushValue( valueToQuotedString( value.asCString() ) );\n      break;\n   case booleanValue:\n      pushValue( valueToString( value.asBool() ) );\n      break;\n   case arrayValue:\n      writeArrayValue( value);\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         if ( members.empty() )\n            pushValue( \"{}\" );\n         else\n         {\n            writeWithIndent( \"{\" );\n            indent();\n            Value::Members::iterator it = members.begin();\n            while ( true )\n            {\n               const std::string &name = *it;\n               const Value &childValue = value[name];\n               writeCommentBeforeValue( childValue );\n               writeWithIndent( valueToQuotedString( name.c_str() ) );\n               document_ += \" : \";\n               writeValue( childValue );\n               if ( ++it == members.end() )\n               {\n                  writeCommentAfterValueOnSameLine( childValue );\n                  break;\n               }\n               document_ += \",\";\n               writeCommentAfterValueOnSameLine( childValue );\n            }\n            unindent();\n            writeWithIndent( \"}\" );\n         }\n      }\n      break;\n   }\n}\n\n\nvoid \nStyledWriter::writeArrayValue( const Value &value )\n{\n   unsigned size = value.size();\n   if ( size == 0 )\n      pushValue( \"[]\" );\n   else\n   {\n      bool isArrayMultiLine = isMultineArray( value );\n      if ( isArrayMultiLine )\n      {\n         writeWithIndent( \"[\" );\n         indent();\n         bool hasChildValue = !childValues_.empty();\n         unsigned index =0;\n         while ( true )\n         {\n            const Value &childValue = value[index];\n            writeCommentBeforeValue( childValue );\n            if ( hasChildValue )\n               writeWithIndent( childValues_[index] );\n            else\n            {\n               writeIndent();\n               writeValue( childValue );\n            }\n            if ( ++index == size )\n            {\n               writeCommentAfterValueOnSameLine( childValue );\n               break;\n            }\n            document_ += \",\";\n            writeCommentAfterValueOnSameLine( childValue );\n         }\n         unindent();\n         writeWithIndent( \"]\" );\n      }\n      else // output on a single line\n      {\n         assert( childValues_.size() == size );\n         document_ += \"[ \";\n         for ( unsigned index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               document_ += \", \";\n            document_ += childValues_[index];\n         }\n         document_ += \" ]\";\n      }\n   }\n}\n\n\nbool \nStyledWriter::isMultineArray( const Value &value )\n{\n   int size = value.size();\n   bool isMultiLine = size*3 >= rightMargin_ ;\n   childValues_.clear();\n   for ( int index =0; index < size  &&  !isMultiLine; ++index )\n   {\n      const Value &childValue = value[index];\n      isMultiLine = isMultiLine  ||\n                     ( (childValue.isArray()  ||  childValue.isObject())  &&  \n                        childValue.size() > 0 );\n   }\n   if ( !isMultiLine ) // check if line length > max line length\n   {\n      childValues_.reserve( size );\n      addChildValues_ = true;\n      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'\n      for ( int index =0; index < size  &&  !isMultiLine; ++index )\n      {\n         writeValue( value[index] );\n         lineLength += int( childValues_[index].length() );\n         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );\n      }\n      addChildValues_ = false;\n      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;\n   }\n   return isMultiLine;\n}\n\n\nvoid \nStyledWriter::pushValue( const std::string &value )\n{\n   if ( addChildValues_ )\n      childValues_.push_back( value );\n   else\n      document_ += value;\n}\n\n\nvoid \nStyledWriter::writeIndent()\n{\n   if ( !document_.empty() )\n   {\n      char last = document_[document_.length()-1];\n      if ( last == ' ' )     // already indented\n         return;\n      if ( last != '\\n' )    // Comments may add new-line\n         document_ += '\\n';\n   }\n   document_ += indentString_;\n}\n\n\nvoid \nStyledWriter::writeWithIndent( const std::string &value )\n{\n   writeIndent();\n   document_ += value;\n}\n\n\nvoid \nStyledWriter::indent()\n{\n   indentString_ += std::string( indentSize_, ' ' );\n}\n\n\nvoid \nStyledWriter::unindent()\n{\n   assert( int(indentString_.size()) >= indentSize_ );\n   indentString_.resize( indentString_.size() - indentSize_ );\n}\n\n\nvoid \nStyledWriter::writeCommentBeforeValue( const Value &root )\n{\n   if ( !root.hasComment( commentBefore ) )\n      return;\n   document_ += normalizeEOL( root.getComment( commentBefore ) );\n   document_ += \"\\n\";\n}\n\n\nvoid \nStyledWriter::writeCommentAfterValueOnSameLine( const Value &root )\n{\n   if ( root.hasComment( commentAfterOnSameLine ) )\n      document_ += \" \" + normalizeEOL( root.getComment( commentAfterOnSameLine ) );\n\n   if ( root.hasComment( commentAfter ) )\n   {\n      document_ += \"\\n\";\n      document_ += normalizeEOL( root.getComment( commentAfter ) );\n      document_ += \"\\n\";\n   }\n}\n\n\nbool \nStyledWriter::hasCommentForValue( const Value &value )\n{\n   return value.hasComment( commentBefore )\n          ||  value.hasComment( commentAfterOnSameLine )\n          ||  value.hasComment( commentAfter );\n}\n\n\nstd::string \nStyledWriter::normalizeEOL( const std::string &text )\n{\n   std::string normalized;\n   normalized.reserve( text.length() );\n   const char *begin = text.c_str();\n   const char *end = begin + text.length();\n   const char *current = begin;\n   while ( current != end )\n   {\n      char c = *current++;\n      if ( c == '\\r' ) // mac or dos EOL\n      {\n         if ( *current == '\\n' ) // convert dos EOL\n            ++current;\n         normalized += '\\n';\n      }\n      else // handle unix EOL & other char\n         normalized += c;\n   }\n   return normalized;\n}\n\n\n// Class StyledStreamWriter\n// //////////////////////////////////////////////////////////////////\n\nStyledStreamWriter::StyledStreamWriter( std::string indentation )\n   : document_(NULL)\n   , rightMargin_( 74 )\n   , indentation_( indentation )\n{\n}\n\n\nvoid\nStyledStreamWriter::write( std::ostream &out, const Value &root )\n{\n   document_ = &out;\n   addChildValues_ = false;\n   indentString_ = \"\";\n   writeCommentBeforeValue( root );\n   writeValue( root );\n   writeCommentAfterValueOnSameLine( root );\n   *document_ << \"\\n\";\n   document_ = NULL; // Forget the stream, for safety.\n}\n\n\nvoid \nStyledStreamWriter::writeValue( const Value &value )\n{\n   switch ( value.type() )\n   {\n   case nullValue:\n      pushValue( \"null\" );\n      break;\n   case intValue:\n      pushValue( valueToString( value.asInt() ) );\n      break;\n   case uintValue:\n      pushValue( valueToString( value.asUInt() ) );\n      break;\n   case realValue:\n      pushValue( valueToString( value.asDouble() ) );\n      break;\n   case stringValue:\n      pushValue( valueToQuotedString( value.asCString() ) );\n      break;\n   case booleanValue:\n      pushValue( valueToString( value.asBool() ) );\n      break;\n   case arrayValue:\n      writeArrayValue( value);\n      break;\n   case objectValue:\n      {\n         Value::Members members( value.getMemberNames() );\n         if ( members.empty() )\n            pushValue( \"{}\" );\n         else\n         {\n            writeWithIndent( \"{\" );\n            indent();\n            Value::Members::iterator it = members.begin();\n            while ( true )\n            {\n               const std::string &name = *it;\n               const Value &childValue = value[name];\n               writeCommentBeforeValue( childValue );\n               writeWithIndent( valueToQuotedString( name.c_str() ) );\n               *document_ << \" : \";\n               writeValue( childValue );\n               if ( ++it == members.end() )\n               {\n                  writeCommentAfterValueOnSameLine( childValue );\n                  break;\n               }\n               *document_ << \",\";\n               writeCommentAfterValueOnSameLine( childValue );\n            }\n            unindent();\n            writeWithIndent( \"}\" );\n         }\n      }\n      break;\n   }\n}\n\n\nvoid \nStyledStreamWriter::writeArrayValue( const Value &value )\n{\n   unsigned size = value.size();\n   if ( size == 0 )\n      pushValue( \"[]\" );\n   else\n   {\n      bool isArrayMultiLine = isMultineArray( value );\n      if ( isArrayMultiLine )\n      {\n         writeWithIndent( \"[\" );\n         indent();\n         bool hasChildValue = !childValues_.empty();\n         unsigned index =0;\n         while ( true )\n         {\n            const Value &childValue = value[index];\n            writeCommentBeforeValue( childValue );\n            if ( hasChildValue )\n               writeWithIndent( childValues_[index] );\n            else\n            {\n\t       writeIndent();\n               writeValue( childValue );\n            }\n            if ( ++index == size )\n            {\n               writeCommentAfterValueOnSameLine( childValue );\n               break;\n            }\n            *document_ << \",\";\n            writeCommentAfterValueOnSameLine( childValue );\n         }\n         unindent();\n         writeWithIndent( \"]\" );\n      }\n      else // output on a single line\n      {\n         assert( childValues_.size() == size );\n         *document_ << \"[ \";\n         for ( unsigned index =0; index < size; ++index )\n         {\n            if ( index > 0 )\n               *document_ << \", \";\n            *document_ << childValues_[index];\n         }\n         *document_ << \" ]\";\n      }\n   }\n}\n\n\nbool \nStyledStreamWriter::isMultineArray( const Value &value )\n{\n   int size = value.size();\n   bool isMultiLine = size*3 >= rightMargin_ ;\n   childValues_.clear();\n   for ( int index =0; index < size  &&  !isMultiLine; ++index )\n   {\n      const Value &childValue = value[index];\n      isMultiLine = isMultiLine  ||\n                     ( (childValue.isArray()  ||  childValue.isObject())  &&  \n                        childValue.size() > 0 );\n   }\n   if ( !isMultiLine ) // check if line length > max line length\n   {\n      childValues_.reserve( size );\n      addChildValues_ = true;\n      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'\n      for ( int index =0; index < size  &&  !isMultiLine; ++index )\n      {\n         writeValue( value[index] );\n         lineLength += int( childValues_[index].length() );\n         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );\n      }\n      addChildValues_ = false;\n      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;\n   }\n   return isMultiLine;\n}\n\n\nvoid \nStyledStreamWriter::pushValue( const std::string &value )\n{\n   if ( addChildValues_ )\n      childValues_.push_back( value );\n   else\n      *document_ << value;\n}\n\n\nvoid \nStyledStreamWriter::writeIndent()\n{\n  /*\n    Some comments in this method would have been nice. ;-)\n\n   if ( !document_.empty() )\n   {\n      char last = document_[document_.length()-1];\n      if ( last == ' ' )     // already indented\n         return;\n      if ( last != '\\n' )    // Comments may add new-line\n         *document_ << '\\n';\n   }\n  */\n   *document_ << '\\n' << indentString_;\n}\n\n\nvoid \nStyledStreamWriter::writeWithIndent( const std::string &value )\n{\n   writeIndent();\n   *document_ << value;\n}\n\n\nvoid \nStyledStreamWriter::indent()\n{\n   indentString_ += indentation_;\n}\n\n\nvoid \nStyledStreamWriter::unindent()\n{\n   assert( indentString_.size() >= indentation_.size() );\n   indentString_.resize( indentString_.size() - indentation_.size() );\n}\n\n\nvoid \nStyledStreamWriter::writeCommentBeforeValue( const Value &root )\n{\n   if ( !root.hasComment( commentBefore ) )\n      return;\n   *document_ << normalizeEOL( root.getComment( commentBefore ) );\n   *document_ << \"\\n\";\n}\n\n\nvoid \nStyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )\n{\n   if ( root.hasComment( commentAfterOnSameLine ) )\n      *document_ << \" \" + normalizeEOL( root.getComment( commentAfterOnSameLine ) );\n\n   if ( root.hasComment( commentAfter ) )\n   {\n      *document_ << \"\\n\";\n      *document_ << normalizeEOL( root.getComment( commentAfter ) );\n      *document_ << \"\\n\";\n   }\n}\n\n\nbool \nStyledStreamWriter::hasCommentForValue( const Value &value )\n{\n   return value.hasComment( commentBefore )\n          ||  value.hasComment( commentAfterOnSameLine )\n          ||  value.hasComment( commentAfter );\n}\n\n\nstd::string \nStyledStreamWriter::normalizeEOL( const std::string &text )\n{\n   std::string normalized;\n   normalized.reserve( text.length() );\n   const char *begin = text.c_str();\n   const char *end = begin + text.length();\n   const char *current = begin;\n   while ( current != end )\n   {\n      char c = *current++;\n      if ( c == '\\r' ) // mac or dos EOL\n      {\n         if ( *current == '\\n' ) // convert dos EOL\n            ++current;\n         normalized += '\\n';\n      }\n      else // handle unix EOL & other char\n         normalized += c;\n   }\n   return normalized;\n}\n\n\nstd::ostream& operator<<( std::ostream &sout, const Value &root )\n{\n   Json::StyledStreamWriter writer;\n   writer.write(sout, root);\n   return sout;\n}\n\n\n} // namespace Json\n"
  },
  {
    "path": "common/util/base.cpp",
    "content": "#include \"stdafx.h\"\n#include <io.h>\n#include \"Base.h\"\n\nnamespace Util {\nnamespace Base {\nint GetAccurateOSVersion() {\n  static int lCurrentVersion = -1;\n  if (-1 ==  lCurrentVersion) {\n    lCurrentVersion = WINDOWS_OLDEST;\n    OSVERSIONINFOW os = {sizeof(OSVERSIONINFOW)};\n    if (::GetVersionExW(&os) && os.dwPlatformId == VER_PLATFORM_WIN32_NT) {\n      if (os.dwMajorVersion == 5) {\n        if (os.dwMinorVersion == 0)\n          lCurrentVersion = WINDOWS_2000;\n        else if (os.dwMinorVersion == 1) {\n          if (_wcsnicmp(L\"Service Pack 1\", os.szCSDVersion, 127) == 0)\n            lCurrentVersion = WINDOWS_XP_SP_1;\n          else if (_wcsnicmp(L\"Service Pack 2\", os.szCSDVersion, 127) == 0)\n            lCurrentVersion = WINDOWS_XP_SP_2;\n          else if (_wcsnicmp(L\"Service Pack 3\", os.szCSDVersion, 127) == 0)\n            lCurrentVersion = WINDOWS_XP_SP_3;\n          else\n            lCurrentVersion = WINDOWS_XP_NO_SP;\n        } else if (os.dwMinorVersion == 2)\n          lCurrentVersion = WINDOWS_2003;\n      } else if (os.dwMajorVersion == 6) {\n        if (os.dwMinorVersion == 0) {\n          if (_wcsnicmp(L\"Service Pack 1\", os.szCSDVersion, 127) == 0)\n            lCurrentVersion = WINDOWS_VISTA_SP_1;\n          else if (_wcsnicmp(L\"Service Pack 2\", os.szCSDVersion, 127) == 0)\n            lCurrentVersion = WINDOWS_VISTA_SP_2;\n          else\n            lCurrentVersion = WINDOWS_VISTA_NO_SP;\n        } else if (os.dwMinorVersion == 1)\n          lCurrentVersion = WINDOWS_7;\n        else if (os.dwMinorVersion == 2)\n          lCurrentVersion = WINDOWS_8;\n        else if (os.dwMinorVersion == 3)\n          lCurrentVersion = WINDOWS_8_SP1;\n      } else if (os.dwMajorVersion == 10) {\n        lCurrentVersion = WINDOWS_11;\n      } else {\n        lCurrentVersion = WINDOWS_LATEST;\n      }\n    }\n  }\n  return lCurrentVersion;\n}\n\nstd::string GetOSVersion() {\n  long version = GetAccurateOSVersion();\n  std::string version_str = \"unknown\";\n  switch (version) {\n  case WINDOWS_2000: {\n    version_str = \"Windows2000\";\n  } break;\n  case WINDOWS_XP_NO_SP:\n  case WINDOWS_XP_SP_1:\n  case WINDOWS_XP_SP_2:\n  case WINDOWS_XP_SP_3: {\n    version_str = \"WindowsXP\";\n  } break;\n  case WINDOWS_2003: {\n    version_str = \"WindowsServer2003\";\n  } break;\n  case WINDOWS_VISTA_NO_SP:\n  case WINDOWS_VISTA_SP_1: {\n    version_str = \"WindowsVista\";\n  } break;\n  case WINDOWS_7: {\n    version_str = \"Windows7\";\n  } break;\n  case WINDOWS_8: {\n    version_str = \"Windows8\";\n  } break;\n  case WINDOWS_8_SP1: {\n    version_str = \"Windows8.1\";\n  } break;\n  case WINDOWS_11: {\n    version_str = \"Windows11\";\n  } break;\n  default:\n    break;\n  }\n  return version_str;\n}\n\nstd::string longtochar(long l) {\n  char s[50] = {0};\n  _snprintf_s(s, 50, _TRUNCATE, \"%ld\", l);\n  std::string s_s = s;\n  return s_s;\n}\n\nstd::wstring longtocharw(long l) {\n  WCHAR s[50] = {0};\n  _snwprintf_s(s, 50, _TRUNCATE, L\"%ld\", l);\n  std::wstring s_s = s;\n  return s_s;\n}\n\nstd::wstring UTF8DecodeW(LPCSTR lpszUtf8Src) {\n  std::wstring strUnicode(L\"\");\n  if (!lpszUtf8Src)\n    return strUnicode;\n\n  int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src,\n    strlen(lpszUtf8Src), NULL, 0);\n\n  wchar_t* wszString = new wchar_t[wcsLen + 1];\n  if (wszString) {\n    ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src),\n      wszString, wcsLen);\n    wszString[wcsLen] = L'\\0';\n    strUnicode = wszString;\n    delete[] wszString;\n  }\n  return strUnicode;\n}\n\nstd::string UTF8DecodeA(LPCSTR lpszUtf8Src) {\n  std::string strAnsi(\"\");\n  if (!lpszUtf8Src)\n    return strAnsi;\n\n  int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src,\n    strlen(lpszUtf8Src), NULL, 0);\n\n  wchar_t* wszString = new wchar_t[wcsLen + 1];\n  if (wszString) {\n    ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8Src, strlen(lpszUtf8Src),\n      wszString, wcsLen);\n    wszString[wcsLen] = L'\\0';\n\n    int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString,\n      wcslen(wszString), NULL, 0, NULL, NULL);\n    char* szAnsi = new char[ansiLen + 1];\n    if (szAnsi) {\n      ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), szAnsi,\n        ansiLen, NULL, NULL);\n      szAnsi[ansiLen] = '\\0';\n      strAnsi = szAnsi;\n      delete[] szAnsi;\n    }\n    delete[] wszString;\n  }\n\n  return strAnsi;\n}\n\nstd::string WChar2Ansi(LPCWSTR pwszSrc) {\n  int nLen = WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, NULL, 0, NULL, NULL);\n  if (nLen <= 0)\n    return std::string(\"\");\n  char* pszDst = new char[nLen];\n  if (NULL == pszDst)\n    return std::string(\"\");\n  WideCharToMultiByte(CP_ACP, 0, pwszSrc, -1, pszDst, nLen, NULL, NULL);\n  pszDst[nLen - 1] = 0;\n  std::string strTemp(pszDst);\n  delete[] pszDst;\n  return strTemp;\n}\n\nstd::wstring Ansi2WChar(LPCSTR pszSrc, int nLen) {\n  int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, 0, 0);\n  if (nSize <= 0)\n    return std::wstring(L\"\");\n  WCHAR* pwszDst = new WCHAR[nSize + 1];\n  if (NULL == pwszDst)\n    return std::wstring(L\"\");\n  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszSrc, nLen, pwszDst, nSize);\n  pwszDst[nSize] = 0;\n  if (pwszDst[0] == 0xFEFF)\n    for (int i = 0; i < nSize; i++)\n      pwszDst[i] = pwszDst[i + 1];\n  std::wstring wcharString(pwszDst);\n  delete pwszDst;\n  return wcharString;\n}\n\nstd::string ws2s(std::wstring& inputws) { return WChar2Ansi(inputws.c_str()); }\n\nstd::wstring s2ws(const std::string& s) {\n  return Ansi2WChar(s.c_str(), s.size());\n}\n\nstd::string UnicodeToUTF8(LPCWSTR lpszUnicode) {\n  std::string utf8(\"\");\n  if (!lpszUnicode)\n    return utf8;\n\n  int u8Len = ::WideCharToMultiByte(CP_UTF8, NULL, lpszUnicode,\n                                    wcslen(lpszUnicode), NULL, 0, NULL, NULL);\n\n  char *szU8 = new char[u8Len + 1];\n  if (szU8) {\n    ::WideCharToMultiByte(CP_UTF8, NULL, lpszUnicode, wcslen(lpszUnicode), szU8,\n                          u8Len, NULL, NULL);\n    szU8[u8Len] = '\\0';\n    utf8 = szU8;\n    delete[] szU8;\n  }\n  return utf8;\n}\n\nstd::wstring UTF8ToUnicode(LPCSTR lpszUtf8) {\n  std::wstring strUnicode(L\"\");\n  if (!lpszUtf8)\n    return strUnicode;\n\n  int wcsLen =\n    ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8, strlen(lpszUtf8), NULL, 0);\n\n  wchar_t *wszString = new wchar_t[wcsLen + 1];\n  if (wszString) {\n    ::MultiByteToWideChar(CP_UTF8, NULL, lpszUtf8, strlen(lpszUtf8), wszString,\n      wcsLen);\n    wszString[wcsLen] = L'\\0';\n    strUnicode = wszString;\n    delete[] wszString;\n  }\n  return strUnicode;\n}\n\nstd::wstring dwtos(const DWORD dw) {\n  WCHAR ws[50] = { 0 };\n  _sntprintf_s(ws, 50, _TRUNCATE, _T(\"%u\"), dw);\n  return std::wstring(ws);\n}\n\nstd::string dwtoss(const DWORD dw) {\n  char ss[50] = { 0 };\n  _snprintf(ss, 50, \"%u\", dw);\n  return std::string(ss);\n}\n\nDWORD stodw(std::string& strNum) {\n  DWORD dw = strtoul(strNum.c_str(), NULL, 10);\n  return dw;\n}\n\nstd::string f2ss(const double f) {\n  char ss[50] = { 0 };\n  _snprintf(ss, 50, \"%f\", f);\n  return std::string(ss);\n}\n\nstd::wstring f2ws(const double f) {\n  WCHAR ws[50] = { 0 };\n  _sntprintf_s(ws, 50, _TRUNCATE, _T(\"%f\"), f);\n  return std::wstring(ws);\n}\n\n\n\n} // namespace Base\n\n} // namespace Util\n"
  },
  {
    "path": "common/util/base.h",
    "content": "#pragma once\r\n\r\nconstexpr int WINDOWS_OLDEST = -1000;\r\nconstexpr int WINDOWS_2000 = 1;\r\nconstexpr int WINDOWS_XP_NO_SP = 2;\r\nconstexpr int WINDOWS_XP_SP_1 = 3;\r\nconstexpr int WINDOWS_XP_SP_2 = 4;\r\nconstexpr int WINDOWS_XP_SP_3 = 5;\r\nconstexpr int WINDOWS_2003 = 6;\r\nconstexpr int WINDOWS_VISTA_NO_SP = 7;\r\nconstexpr int WINDOWS_VISTA_SP_1 = 8;\r\nconstexpr int WINDOWS_VISTA_SP_2 = 8;\r\nconstexpr int WINDOWS_7 = 9;\r\nconstexpr int WINDOWS_8 = 10;\r\nconstexpr int WINDOWS_8_SP1 = 11;\r\nconstexpr int WINDOWS_11 = 12;\r\nconstexpr int WINDOWS_LATEST = 1000;\r\n\r\nnamespace Util {\r\nnamespace Base {\r\nint GetAccurateOSVersion();\r\n\r\nstd::string GetOSVersion();\r\n\r\nstd::string longtochar(long l);\r\n\r\nstd::wstring longtocharw(long l);\r\n\r\nstd::wstring UTF8DecodeW(LPCSTR lpszUtf8Src);\r\n\r\nstd::string UTF8DecodeA(LPCSTR lpszUtf8Src);\r\n\r\nstd::string WChar2Ansi(LPCWSTR pwszSrc);\r\n\r\nstd::wstring Ansi2WChar(LPCSTR pszSrc, int nLen);\r\n\r\nstd::string ws2s(std::wstring& inputws);\r\n\r\nstd::wstring s2ws(const std::string& s);\r\n\r\nstd::string UnicodeToUTF8(LPCWSTR lpszUnicodeSrc);\r\n\r\nstd::wstring UTF8ToUnicode(LPCSTR lpszUtf8Src);\r\n\r\nstd::wstring dwtos(const DWORD dw);\r\n\r\nstd::string dwtoss(const DWORD dw);\r\n\r\nDWORD stodw(std::string& strNum);\r\n\r\nstd::string f2ss(const double f);\r\n\r\nstd::wstring f2ws(const double f);\r\n\r\n} // namespace Base\r\n\r\n} // namespace Util\r\n"
  },
  {
    "path": "common/util/def.h",
    "content": "#pragma once\n\n#define WM_DEL_GDI_OBJ WM_USER + 0x10E0C\n#define WM_IS_EXIST WM_USER + 0x10E0D\n\nnamespace app {\nenum NotificationType {\n  NOTIFICATION_APP_START = 0,\n  NOTIFICATION_APP_DOWNLOAD_CANCAL,\n};\n\n}\n\nextern UINT WM_TASKBARBUTTONCREATED;\n"
  },
  {
    "path": "common/util/md5.cpp",
    "content": "#include \"md5.h\"\n\nusing namespace std;\n\n/* Constants for MD5Transform routine. */\n#define S11 7\n#define S12 12\n#define S13 17\n#define S14 22\n#define S21 5\n#define S22 9\n#define S23 14\n#define S24 20\n#define S31 4\n#define S32 11\n#define S33 16\n#define S34 23\n#define S41 6\n#define S42 10\n#define S43 15\n#define S44 21\n\n/* F, G, H and I are basic MD5 functions.\n */\n#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\n#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define I(x, y, z) ((y) ^ ((x) | (~z)))\n\n/* ROTATE_LEFT rotates x left n bits.\n */\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\n\n/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.\nRotation is separate from addition to prevent recomputation.\n*/\n#define FF(a, b, c, d, x, s, ac)                                               \\\n  {                                                                            \\\n    (a) += F((b), (c), (d)) + (x) + ac;                                        \\\n    (a) = ROTATE_LEFT((a), (s));                                               \\\n    (a) += (b);                                                                \\\n  }\n#define GG(a, b, c, d, x, s, ac)                                               \\\n  {                                                                            \\\n    (a) += G((b), (c), (d)) + (x) + ac;                                        \\\n    (a) = ROTATE_LEFT((a), (s));                                               \\\n    (a) += (b);                                                                \\\n  }\n#define HH(a, b, c, d, x, s, ac)                                               \\\n  {                                                                            \\\n    (a) += H((b), (c), (d)) + (x) + ac;                                        \\\n    (a) = ROTATE_LEFT((a), (s));                                               \\\n    (a) += (b);                                                                \\\n  }\n#define II(a, b, c, d, x, s, ac)                                               \\\n  {                                                                            \\\n    (a) += I((b), (c), (d)) + (x) + ac;                                        \\\n    (a) = ROTATE_LEFT((a), (s));                                               \\\n    (a) += (b);                                                                \\\n  }\n\nconst byte MD5::PADDING[64] = {0x80};\nconst char MD5::HEX[16] = {'0', '1', '2', '3', '4', '5', '6', '7',\n                           '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n\nconst unsigned int MD5::BUFFER_SIZE = 1024;\n/* Default construct. */\nMD5::MD5() { reset(); }\n\n/* Construct a MD5 object with a input buffer. */\nMD5::MD5(const void *input, size_t length) {\n  reset();\n  update(input, length);\n}\n\n/* Construct a MD5 object with a string. */\nMD5::MD5(const string &str) {\n  reset();\n  update(str);\n}\n\n/* Construct a MD5 object with a file. */\nMD5::MD5(ifstream &in) {\n  reset();\n  update(in);\n}\n\n/* Return the message-digest */\nconst byte *MD5::digest() {\n  if (!_finished) {\n    _finished = true;\n    final();\n  }\n  return _digest;\n}\n\n/* Reset the calculate state */\nvoid MD5::reset() {\n\n  _finished = false;\n  /* reset number of bits. */\n  _count[0] = _count[1] = 0;\n  /* Load magic initialization constants. */\n  _state[0] = 0x67452301;\n  _state[1] = 0xefcdab89;\n  _state[2] = 0x98badcfe;\n  _state[3] = 0x10325476;\n}\n\n/* Updating the context with a input buffer. */\nvoid MD5::update(const void *input, size_t length) {\n  update((const byte *)input, length);\n}\n\n/* Updating the context with a string. */\nvoid MD5::update(const string &str) {\n  update((const byte *)str.c_str(), str.length());\n}\n\n/* Updating the context with a file. */\nvoid MD5::update(ifstream &in) {\n\n  if (!in)\n    return;\n\n  size_t length;\n  char buffer[BUFFER_SIZE];\n  while (!in.eof()) {\n    in.read(buffer, BUFFER_SIZE);\n    length = static_cast<size_t>(in.gcount());\n    if (length > 0)\n      update(buffer, length);\n  }\n  in.close();\n}\n\n/* MD5 block update operation. Continues an MD5 message-digest\noperation, processing another message block, and updating the\ncontext.\n*/\nvoid MD5::update(const byte *input, size_t length) {\n\n  uint32 i, index, partLen;\n\n  _finished = false;\n\n  /* Compute number of bytes mod 64 */\n  index = (uint32)((_count[0] >> 3) & 0x3f);\n\n  /* update number of bits */\n  if ((_count[0] += ((uint32)length << 3)) < ((uint32)length << 3))\n    _count[1]++;\n  _count[1] += ((uint32)length >> 29);\n\n  partLen = 64 - index;\n\n  /* transform as many times as possible. */\n  if (length >= partLen) {\n\n    memcpy(&_buffer[index], input, partLen);\n    transform(_buffer);\n\n    for (i = partLen; i + 63 < length; i += 64)\n      transform(&input[i]);\n    index = 0;\n\n  } else {\n    i = 0;\n  }\n\n  /* Buffer remaining input */\n  memcpy(&_buffer[index], &input[i], length - i);\n}\n\n/* MD5 finalization. Ends an MD5 message-_digest operation, writing the\nthe message _digest and zeroizing the context.\n*/\nvoid MD5::final() {\n\n  byte bits[8];\n  uint32 oldState[4];\n  uint32 oldCount[2];\n  uint32 index, padLen;\n\n  /* Save current state and count. */\n  memcpy(oldState, _state, 16);\n  memcpy(oldCount, _count, 8);\n\n  /* Save number of bits */\n  encode(_count, bits, 8);\n\n  /* Pad out to 56 mod 64. */\n  index = (uint32)((_count[0] >> 3) & 0x3f);\n  padLen = (index < 56) ? (56 - index) : (120 - index);\n  update(PADDING, padLen);\n\n  /* Append length (before padding) */\n  update(bits, 8);\n\n  /* Store state in digest */\n  encode(_state, _digest, 16);\n\n  /* Restore current state and count. */\n  memcpy(_state, oldState, 16);\n  memcpy(_count, oldCount, 8);\n}\n\n/* MD5 basic transformation. Transforms _state based on block. */\nvoid MD5::transform(const byte block[64]) {\n\n  uint32 a = _state[0], b = _state[1], c = _state[2], d = _state[3], x[16];\n\n  decode(block, x, 64);\n\n  /* Round 1 */\n  FF(a, b, c, d, x[0], S11, 0xd76aa478);  /* 1 */\n  FF(d, a, b, c, x[1], S12, 0xe8c7b756);  /* 2 */\n  FF(c, d, a, b, x[2], S13, 0x242070db);  /* 3 */\n  FF(b, c, d, a, x[3], S14, 0xc1bdceee);  /* 4 */\n  FF(a, b, c, d, x[4], S11, 0xf57c0faf);  /* 5 */\n  FF(d, a, b, c, x[5], S12, 0x4787c62a);  /* 6 */\n  FF(c, d, a, b, x[6], S13, 0xa8304613);  /* 7 */\n  FF(b, c, d, a, x[7], S14, 0xfd469501);  /* 8 */\n  FF(a, b, c, d, x[8], S11, 0x698098d8);  /* 9 */\n  FF(d, a, b, c, x[9], S12, 0x8b44f7af);  /* 10 */\n  FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */\n  FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */\n  FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */\n  FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */\n  FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */\n  FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */\n\n  /* Round 2 */\n  GG(a, b, c, d, x[1], S21, 0xf61e2562);  /* 17 */\n  GG(d, a, b, c, x[6], S22, 0xc040b340);  /* 18 */\n  GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */\n  GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);  /* 20 */\n  GG(a, b, c, d, x[5], S21, 0xd62f105d);  /* 21 */\n  GG(d, a, b, c, x[10], S22, 0x2441453);  /* 22 */\n  GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */\n  GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);  /* 24 */\n  GG(a, b, c, d, x[9], S21, 0x21e1cde6);  /* 25 */\n  GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */\n  GG(c, d, a, b, x[3], S23, 0xf4d50d87);  /* 27 */\n  GG(b, c, d, a, x[8], S24, 0x455a14ed);  /* 28 */\n  GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */\n  GG(d, a, b, c, x[2], S22, 0xfcefa3f8);  /* 30 */\n  GG(c, d, a, b, x[7], S23, 0x676f02d9);  /* 31 */\n  GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */\n\n  /* Round 3 */\n  HH(a, b, c, d, x[5], S31, 0xfffa3942);  /* 33 */\n  HH(d, a, b, c, x[8], S32, 0x8771f681);  /* 34 */\n  HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */\n  HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */\n  HH(a, b, c, d, x[1], S31, 0xa4beea44);  /* 37 */\n  HH(d, a, b, c, x[4], S32, 0x4bdecfa9);  /* 38 */\n  HH(c, d, a, b, x[7], S33, 0xf6bb4b60);  /* 39 */\n  HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */\n  HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */\n  HH(d, a, b, c, x[0], S32, 0xeaa127fa);  /* 42 */\n  HH(c, d, a, b, x[3], S33, 0xd4ef3085);  /* 43 */\n  HH(b, c, d, a, x[6], S34, 0x4881d05);   /* 44 */\n  HH(a, b, c, d, x[9], S31, 0xd9d4d039);  /* 45 */\n  HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */\n  HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */\n  HH(b, c, d, a, x[2], S34, 0xc4ac5665);  /* 48 */\n\n  /* Round 4 */\n  II(a, b, c, d, x[0], S41, 0xf4292244);  /* 49 */\n  II(d, a, b, c, x[7], S42, 0x432aff97);  /* 50 */\n  II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */\n  II(b, c, d, a, x[5], S44, 0xfc93a039);  /* 52 */\n  II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */\n  II(d, a, b, c, x[3], S42, 0x8f0ccc92);  /* 54 */\n  II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */\n  II(b, c, d, a, x[1], S44, 0x85845dd1);  /* 56 */\n  II(a, b, c, d, x[8], S41, 0x6fa87e4f);  /* 57 */\n  II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */\n  II(c, d, a, b, x[6], S43, 0xa3014314);  /* 59 */\n  II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */\n  II(a, b, c, d, x[4], S41, 0xf7537e82);  /* 61 */\n  II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */\n  II(c, d, a, b, x[2], S43, 0x2ad7d2bb);  /* 63 */\n  II(b, c, d, a, x[9], S44, 0xeb86d391);  /* 64 */\n\n  _state[0] += a;\n  _state[1] += b;\n  _state[2] += c;\n  _state[3] += d;\n}\n\n/* Encodes input (ulong) into output (byte). Assumes length is\na multiple of 4.\n*/\nvoid MD5::encode(const uint32 *input, byte *output, size_t length) {\n\n  for (size_t i = 0, j = 0; j < length; i++, j += 4) {\n    output[j] = (byte)(input[i] & 0xff);\n    output[j + 1] = (byte)((input[i] >> 8) & 0xff);\n    output[j + 2] = (byte)((input[i] >> 16) & 0xff);\n    output[j + 3] = (byte)((input[i] >> 24) & 0xff);\n  }\n}\n\n/* Decodes input (byte) into output (ulong). Assumes length is\na multiple of 4.\n*/\nvoid MD5::decode(const byte *input, uint32 *output, size_t length) {\n\n  for (size_t i = 0, j = 0; j < length; i++, j += 4) {\n    output[i] = ((uint32)input[j]) | (((uint32)input[j + 1]) << 8) |\n                (((uint32)input[j + 2]) << 16) | (((uint32)input[j + 3]) << 24);\n  }\n}\n\n/* Convert byte array to hex string. */\nstring MD5::bytesToHexString(const byte *input, size_t length) {\n  string str;\n  str.reserve(length << 1);\n  for (size_t i = 0; i < length; i++) {\n    int t = input[i];\n    int a = t / 16;\n    int b = t % 16;\n    str.append(1, HEX[a]);\n    str.append(1, HEX[b]);\n  }\n  return str;\n}\n\n/* Convert digest to string value */\nstring MD5::toString() { return bytesToHexString(digest(), 16); }\n"
  },
  {
    "path": "common/util/md5.h",
    "content": "#pragma once\n\n#include <fstream>\n#include <string>\n\n/* Type define */\ntypedef unsigned char byte;\ntypedef unsigned int uint32;\n\nusing std::ifstream;\nusing std::string;\n\n/* MD5 declaration. */\nclass MD5 {\npublic:\n  MD5();\n  MD5(const void *input, size_t length);\n  MD5(const string &str);\n  MD5(ifstream &in);\n  void update(const void *input, size_t length);\n  void update(const string &str);\n  void update(ifstream &in);\n  const byte *digest();\n  string toString();\n  void reset();\n\nprivate:\n  void update(const byte *input, size_t length);\n  void final();\n  void transform(const byte block[64]);\n  void encode(const uint32 *input, byte *output, size_t length);\n  void decode(const byte *input, uint32 *output, size_t length);\n  string bytesToHexString(const byte *input, size_t length);\n\n  /* class uncopyable */\n  MD5(const MD5 &);\n\nprivate:\n  uint32 _state[4]; /* state (ABCD) */\n  uint32 _count[2]; /* number of bits, modulo 2^64 (low-order word first) */\n  byte _buffer[64]; /* input buffer */\n  byte _digest[16]; /* message digest */\n  bool _finished;   /* calculate finished ? */\n\n  static const byte PADDING[64]; /* padding for calculate */\n  static const char HEX[16];\n  static const unsigned int BUFFER_SIZE;\n};\n"
  },
  {
    "path": "common/util/system.cpp",
    "content": "﻿#include \"StdAfx.h\"\r\n#include <io.h>\r\n#include <Tlhelp32.h>\r\n#include <Nb30.h>\r\n#include <winioctl.h>\r\n#include \"xzip/XUnzip.h\"\r\n#include \"system.h\"\r\n\r\n#pragma comment(lib, \"Version\")\r\n#pragma comment(lib, \"Wininet\")\r\n#pragma comment(lib, \"Netapi32.lib\")\r\n\r\nnamespace SystemCommon {\r\nnamespace FilePathHelper {\r\nBOOL ForceCreateDir(LPCTSTR pszFullPathFileName) {\r\n  if (!pszFullPathFileName || !pszFullPathFileName[0])\r\n    return FALSE;\r\n\r\n  if (PathIsRoot(pszFullPathFileName))\r\n    return TRUE;\r\n\r\n  TCHAR Dir[MAX_PATH + 1] = {};\r\n  int nNeed;\r\n  LPCTSTR p, pLast;\r\n  BOOL Result;\r\n\r\n  Result = FALSE;\r\n  pLast = pszFullPathFileName;\r\n  if (_tcslen(pLast) > _MAX_PATH) {\r\n    return FALSE;\r\n  }\r\n  while (NULL != *pLast) {\r\n    p = _tcsstr(pLast, _T(\"\\\\\"));\r\n    if (NULL == p) {\r\n      p = _tcsstr(pLast, _T(\"/\"));\r\n      if (NULL == p) {\r\n        return Result;\r\n      }\r\n    }\r\n    nNeed = p - pszFullPathFileName;\r\n    if (nNeed > 0) {\r\n      memset(Dir, 0, sizeof(Dir));\r\n      _tcsncpy_s(Dir, pszFullPathFileName, p - pszFullPathFileName);\r\n      Result = CreateMyDir(Dir);\r\n    }\r\n    p++;\r\n    pLast = p;\r\n  }\r\n  return Result;\r\n}\r\n\r\nBOOL CreateDir(LPCTSTR lpszPath) {\r\n  tstring strFile = lpszPath;\r\n  tstring strPath = GetPath(strFile);\r\n  strFile = strPath.substr(0, strPath.size() - 1);\r\n  while (!PathIsDirectory(strFile.c_str())) {\r\n    if (PathFileExists(strFile.c_str())) {\r\n      SetFileAttributes(strFile.c_str(), FILE_ATTRIBUTE_NORMAL);\r\n      DeleteFile(strFile.c_str());\r\n    }\r\n\r\n    TCHAR wszPath[1024] = {};\r\n    _tcsncpy_s(wszPath, strFile.c_str(), _TRUNCATE);\r\n    if ((_T('\\\\') == strFile[strFile.size() - 1]) ||\r\n        (_T('/') == strFile[strFile.size() - 1])) {\r\n      PathRemoveFileSpec(wszPath);\r\n    }\r\n    PathRemoveFileSpec(wszPath);\r\n\r\n    strFile = wszPath;\r\n  }\r\n\r\n  return ForceCreateDir(strPath.c_str());\r\n}\r\n\r\nBOOL CreateMyDir(LPCTSTR pszDir) {\r\n  assert(pszDir);\r\n\r\n  if (!pszDir || !pszDir[0])\r\n    return FALSE;\r\n\r\n  BOOL bRet;\r\n  bRet = ::CreateDirectory(pszDir, NULL);\r\n  if (FALSE == bRet) {\r\n    if (ERROR_ALREADY_EXISTS == GetLastError())\r\n      return TRUE;\r\n  }\r\n  return bRet;\r\n}\r\n\r\nBOOL GetAppPath(HINSTANCE hInst, LPTSTR lpPath, DWORD dMaxLen, LPCTSTR pAddon) {\r\n  if (!lpPath || dMaxLen <= 0)\r\n    return FALSE;\r\n\r\n  TCHAR FileName[MAX_PATH] = {};\r\n  TCHAR szFullPath[MAX_PATH] = {};\r\n  int nStrLen, i;\r\n\r\n  if (!GetModuleFileName(hInst, szFullPath, MAX_PATH))\r\n    return FALSE;\r\n\r\n  GetLongPathName(szFullPath, FileName, MAX_PATH);\r\n\r\n  nStrLen = (int)_tcslen(FileName);\r\n\r\n  for (i = nStrLen - 1; i > 0; i--) {\r\n    if (FileName[i] == _T('\\\\') && i >= 2) {\r\n      FileName[i + 1] = _T('\\0');\r\n      break;\r\n    }\r\n  }\r\n\r\n  if (NULL == pAddon)\r\n    _sntprintf_s(lpPath, dMaxLen, _TRUNCATE, _T(\"%s\"), FileName);\r\n  else\r\n    _sntprintf_s(lpPath, dMaxLen, _TRUNCATE, _T(\"%s%s\"), FileName, pAddon);\r\n  lpPath[dMaxLen - 1] = _T('\\0');\r\n  return TRUE;\r\n}\r\n\r\ntstring GetAssignPath(DWORD assing, BOOL forecCreate) {\r\n  TCHAR szAppPath[MAX_PATH + 1] = {0};\r\n  SHGetSpecialFolderPath(NULL, szAppPath, assing, forecCreate);\r\n  return szAppPath;\r\n}\r\n\r\ntstring GetFileName(tstring pathname) {\r\n  int i;\r\n  for (i = pathname.length() - 1; i >= 0; --i) {\r\n    if (pathname[i] == _T('\\\\') || pathname[i] == _T('/'))\r\n      break;\r\n  }\r\n  return pathname.substr(i + 1);\r\n}\r\n\r\ntstring GetPath(tstring pathname) {\r\n  int i;\r\n  for (i = pathname.length() - 1; i >= 0; --i) {\r\n    if (pathname[i] == _T('\\\\') || pathname[i] == _T('/'))\r\n      break;\r\n  }\r\n  return pathname.substr(0, i + 1);\r\n}\r\n\r\nBOOL DeepDeleteFile(const tstring &strFile) {\r\n  int nR = _taccess(strFile.c_str(), 0);\r\n\r\n  if (nR != 0 || PathIsDirectory(strFile.c_str())) {\r\n    return TRUE;\r\n  }\r\n\r\n  if (!PathFileExists(strFile.c_str()))\r\n    return TRUE;\r\n\r\n  SetFileAttributes(strFile.c_str(), FILE_ATTRIBUTE_NORMAL);\r\n\r\n  BOOL bRet = ::DeleteFile(strFile.c_str());\r\n  if (!bRet) {\r\n    tstring strDstTmp = strFile + _T(\".tmp\");\r\n    MoveFileEx(strFile.c_str(), strDstTmp.c_str(), MOVEFILE_REPLACE_EXISTING);\r\n    if (!DeleteFile(strDstTmp.c_str())) {\r\n      MoveFileEx(strDstTmp.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);\r\n    }\r\n  }\r\n  return bRet;\r\n}\r\n\r\nBOOL DeleteAllFiles(tstring strPath) {\r\n  if (strPath.empty()) {\r\n    return TRUE;\r\n  }\r\n  DeleteFile(strPath.c_str());\r\n\r\n  SHFILEOPSTRUCT fo;\r\n  tstring strFrom = strPath;\r\n\r\n  if (strPath[strPath.length() - 1] != _T('\\\\')) {\r\n    strFrom = strFrom + _T(\"\\\\\");\r\n  }\r\n  strFrom = strFrom + _T(\"*.*\") + _T('\\0');\r\n  memset(&fo, 0, sizeof(fo));\r\n\r\n  fo.hwnd = NULL;\r\n  fo.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;\r\n  fo.wFunc = FO_DELETE;\r\n  fo.pFrom = strFrom.c_str();\r\n\r\n  SHFileOperation(&fo);\r\n  RemoveDirectory(strPath.c_str());\r\n\r\n  return TRUE;\r\n}\r\n\r\nBOOL GetBackslashDir(tstring &strPath) {\r\n\r\n  TCHAR szPath[MAX_PATH] = {};\r\n  int len = strPath.length();\r\n  _tcsncpy_s(szPath, strPath.c_str(), _TRUNCATE);\r\n\r\n  if (len >= 1 &&\r\n      (_T('\\\\') != szPath[len - 1] || (_T('/') != szPath[len - 1]))) {\r\n    PathAddBackslash(szPath);\r\n  }\r\n  strPath = szPath;\r\n  return TRUE;\r\n}\r\n\r\nBOOL CopyFolder(const tstring &strSrc, const tstring &strDst, BOOL bForce) {\r\n  tstring tmpFrom(strSrc);\r\n  tstring tmpTo(strDst);\r\n  BOOL bRet = FALSE;\r\n\r\n  if (!PathFileExists(tmpTo.c_str())) {\r\n    ForceCreateDir(tmpTo.c_str());\r\n  }\r\n  if (PathFileExists(tmpFrom.c_str())) {\r\n    WIN32_FIND_DATA FindFileData;\r\n    tstring tmpFind(tmpFrom);\r\n    tmpFind += _T(\"\\\\*.*\");\r\n\r\n    HANDLE hFind = ::FindFirstFile(tmpFind.c_str(), &FindFileData);\r\n    if (INVALID_HANDLE_VALUE == hFind)\r\n      return bRet;\r\n\r\n    while (TRUE) {\r\n      tstring tmpFile(tmpTo);\r\n      tmpFile += _T(\"\\\\\");\r\n      tmpFile += FindFileData.cFileName;\r\n\r\n      if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {\r\n        if (FindFileData.cFileName[0] != '.') {\r\n          if (!PathFileExists(tmpFile.c_str())) {\r\n            GetBackslashDir(tmpFile);\r\n            ForceCreateDir(tmpFile.c_str());\r\n          }\r\n          bRet = CopyFolder(tmpFrom + _T(\"\\\\\") + FindFileData.cFileName,\r\n                            tmpFile, bForce);\r\n        }\r\n      } else {\r\n        if (bForce) {\r\n          bRet = DeepCopyFile(\r\n              (tmpFrom + _T(\"\\\\\") + FindFileData.cFileName).c_str(),\r\n              tmpFile.c_str());\r\n        } else if (!PathFileExists(tmpFile.c_str())) {\r\n          bRet =\r\n              ::CopyFile((tmpFrom + _T(\"\\\\\") + FindFileData.cFileName).c_str(),\r\n                         tmpFile.c_str(), TRUE);\r\n        }\r\n      }\r\n      if (!FindNextFile(hFind, &FindFileData))\r\n        break;\r\n    }\r\n    FindClose(hFind);\r\n  }\r\n  return bRet;\r\n}\r\n\r\nBOOL DeepCopyFile(const tstring &strSrc, const tstring &strDst) {\r\n  BOOL bRet = FALSE;\r\n  if (PathFileExists(strSrc.c_str())) {\r\n    if (!StringHelper::CompareNoCase(strSrc, strDst)) {\r\n      if (PathFileExists(strDst.c_str())) {\r\n        SetFileAttributes(strDst.c_str(), FILE_ATTRIBUTE_NORMAL);\r\n      } else {\r\n        tstring strPath = GetPath(strDst);\r\n        ForceCreateDir(strPath.c_str());\r\n      }\r\n\r\n      if (!DeleteFile(strDst.c_str())) {\r\n        tstring strDstTmp = strDst + _T(\".tmp\");\r\n        MoveFileEx(strDst.c_str(), strDstTmp.c_str(),\r\n                   MOVEFILE_REPLACE_EXISTING);\r\n        if (!DeleteFile(strDstTmp.c_str())) {\r\n          MoveFileEx(strDstTmp.c_str(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);\r\n        }\r\n      }\r\n      ::CopyFile(strSrc.c_str(), strDst.c_str(), FALSE);\r\n      bRet = TRUE;\r\n    }\r\n  }\r\n  return bRet;\r\n}\r\n\r\nBOOL UnzipFileToPath(LPCTSTR lpszFile, LPCTSTR lpszDir) {\r\n  BOOL res = FALSE;\r\n  TCHAR szPath[MAX_PATH] = { 0 };\r\n  GetCurrentDirectory(MAX_PATH, szPath);\r\n  if (!SetCurrentDirectory(lpszDir))\r\n    return res;\r\n  HZIP hz = OpenZip((LPVOID)lpszFile, 0, ZIP_FILENAME);\r\n\r\n  if (hz) {\r\n    ZIPENTRYW ze = { 0 };\r\n    if (ZR_OK == GetZipItem(hz, -1, &ze)) {\r\n      res = TRUE;\r\n      int nCount = ze.index;\r\n      for (int i = 0; i < nCount; i++) {\r\n        GetZipItem(hz, i, &ze);\r\n        SetFileAttributes(ze.name, FILE_ATTRIBUTE_ARCHIVE);\r\n        if (UnzipItem(hz, i, ze.name, 0, ZIP_FILENAME) != ZR_OK) {\r\n          res = FALSE;\r\n          break;\r\n        }\r\n        SetFileAttributes(ze.name, FILE_ATTRIBUTE_NORMAL);\r\n      }\r\n    }\r\n    CloseZip(hz);\r\n  }\r\n  SetCurrentDirectory(szPath);\r\n  return res;\r\n}\r\n\r\nDWORD GetFileSize(const tstring& path) {\r\n  HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING,\r\n    FILE_ATTRIBUTE_NORMAL, NULL);\r\n  if (hFile && hFile != INVALID_HANDLE_VALUE) {\r\n    DWORD dwFileSize = ::GetFileSize(hFile, NULL);\r\n    CloseHandle(hFile);\r\n    return dwFileSize;\r\n  }\r\n  return INVALID_FILE_SIZE;\r\n}\r\n\r\n} // namespace FilePathHelper\r\n\r\nnamespace FileVersionHelper {\r\nBOOL GetFileVersion(LPCTSTR strFile, LPTSTR pszVersion, int nVersionLen) {\r\n  if (!strFile || !strFile[0] || !pszVersion || nVersionLen <= 0)\r\n    return FALSE;\r\n\r\n  TCHAR szVersionBuffer[8192] = {};\r\n  DWORD dwVerSize;\r\n  DWORD dwHandle;\r\n\r\n  dwVerSize = GetFileVersionInfoSize(strFile, &dwHandle);\r\n  if (dwVerSize == 0 || dwVerSize > (sizeof(szVersionBuffer) - 1))\r\n    return FALSE;\r\n\r\n  if (GetFileVersionInfo(strFile, 0, dwVerSize, szVersionBuffer)) {\r\n    VS_FIXEDFILEINFO *pInfo;\r\n    unsigned int nInfoLen;\r\n\r\n    if (VerQueryValue(szVersionBuffer, _T(\"\\\\\"), (void **)&pInfo, &nInfoLen)) {\r\n      _sntprintf_s(\r\n          pszVersion, nVersionLen, _TRUNCATE, _T(\"%d.%d.%d.%d\"),\r\n          HIWORD(pInfo->dwFileVersionMS), LOWORD(pInfo->dwFileVersionMS),\r\n          HIWORD(pInfo->dwFileVersionLS), LOWORD(pInfo->dwFileVersionLS));\r\n      pszVersion[nVersionLen - 1] = _T('\\0');\r\n      return TRUE;\r\n    }\r\n  }\r\n\r\n  return FALSE;\r\n}\r\n\r\ntstring GetFileVersion(LPCTSTR strFile) {\r\n  if (!strFile || !strFile[0])\r\n    return _T(\"\");\r\n\r\n  TCHAR szVersionBuffer[8192] = {};\r\n  if (GetFileVersion(strFile, szVersionBuffer, SIZEOF(szVersionBuffer))) {\r\n    return szVersionBuffer;\r\n  }\r\n  return _T(\"\");\r\n}\r\n\r\ntstring GetFileVersion(HMODULE hModule) {\r\n  if (!hModule)\r\n    return _T(\"\");\r\n\r\n  TCHAR szFilePath[MAX_PATH] = {};\r\n  GetModuleFileName(hModule, szFilePath, MAX_PATH);\r\n  return GetFileVersion(szFilePath);\r\n}\r\n\r\n} // namespace FileVersionHelper\r\n\r\nnamespace NetHelper {\r\nBOOL GetDomain(LPCTSTR url, LPTSTR buf, int cchBuf) {\r\n  if (!url || !url[0] || !buf || cchBuf <= 0)\r\n    return FALSE;\r\n\r\n  URL_COMPONENTS uc = {};\r\n  uc.dwStructSize = sizeof(uc);\r\n  uc.lpszHostName = buf;\r\n  uc.dwHostNameLength = cchBuf;\r\n\r\n  memset(buf, 0, cchBuf * sizeof(TCHAR));\r\n  __try {\r\n    if (!InternetCrackUrl(url, lstrlen(url), (DWORD)ICU_DECODE, &uc)) {\r\n      return FALSE;\r\n    } else {\r\n      LPTSTR lpstr = StrStr(buf, _T(\"\\\\\"));\r\n      if (lpstr)\r\n        *lpstr = 0;\r\n    }\r\n  } __except (EXCEPTION_EXECUTE_HANDLER) {\r\n  }\r\n\r\n  if (_tcslen(buf) == 0)\r\n    return FALSE;\r\n  return TRUE;\r\n}\r\n\r\n} // namespace NetHelper\r\n\r\nnamespace StringHelper {\r\ntstring Trim(tstring &s) {\r\n  if (s.empty()) {\r\n    return s;\r\n  }\r\n\r\n  s.erase(0, s.find_first_not_of(_T(\" \")));\r\n  s.erase(s.find_last_not_of(_T(\" \")) + 1);\r\n  return s;\r\n}\r\n\r\ntstring ReplaceAll(tstring &str, const tstring &old_value,\r\n                    const tstring &new_value) {\r\n  for (tstring::size_type pos(0); pos != tstring::npos;\r\n       pos += new_value.length()) {\r\n    if ((pos = str.find(old_value, pos)) != tstring::npos)\r\n      str.replace(pos, old_value.length(), new_value);\r\n    else\r\n      break;\r\n  }\r\n  return str;\r\n}\r\n\r\ntstring MakeLower(tstring &s) {\r\n  if (s.empty()) {\r\n    return s;\r\n  }\r\n\r\n  TCHAR *pBuf = new TCHAR[s.length() + 1];\r\n  _tcsncpy_s(pBuf, s.length() + 1, s.c_str(), _TRUNCATE);\r\n#if _MSC_VER < 1500\r\n  _tcslwr(pBuf);\r\n#else\r\n  _tcslwr_s(pBuf, s.length() + 1);\r\n#endif\r\n  s = pBuf;\r\n  delete[] pBuf;\r\n\r\n  return s;\r\n}\r\n\r\nBOOL CompareNoCase(tstring sA, tstring sB) {\r\n  MakeLower(sA);\r\n  MakeLower(sB);\r\n  if (0 == sA.compare(sB)) {\r\n    return TRUE;\r\n  } else {\r\n    return FALSE;\r\n  }\r\n}\r\n\r\nint FindNoCase(tstring sA, tstring sB) {\r\n  MakeLower(sA);\r\n  MakeLower(sB);\r\n  return sA.find(sB);\r\n}\r\n\r\nstd::string TString2String(tstring str) {\r\n  std::string result;\r\n#ifdef _UNICODE\r\n  result = Wstring2String(str.c_str());\r\n#else\r\n  result = str;\r\n#endif\r\n  return result;\r\n}\r\n\r\nstd::string Wstring2String(const wchar_t *pwc) {\r\n  if (!pwc || !pwc[0])\r\n    return \"\";\r\n\r\n  std::string result;\r\n\r\n  int nLen =\r\n      WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pwc, -1, NULL, 0, NULL, NULL);\r\n  if (nLen <= 0) {\r\n    return std::string(\"\");\r\n  }\r\n  char *presult = new char[nLen];\r\n  if (NULL == presult) {\r\n    return std::string(\"\");\r\n  }\r\n  WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pwc, -1, presult, nLen, NULL, NULL);\r\n  presult[nLen - 1] = 0;\r\n  result = presult;\r\n  delete[] presult;\r\n\r\n  return result;\r\n}\r\n\r\nstd::wstring String2WString(const char *pc) {\r\n  if (!pc || !pc[0])\r\n    return L\"\";\r\n\r\n  int nLen = strlen(pc);\r\n  int nSize = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pc, nLen, 0, 0);\r\n  if (nSize <= 0) {\r\n    return std::wstring(L\"\");\r\n  }\r\n  WCHAR *pDst = new WCHAR[nSize + 1];\r\n  if (NULL == pDst) {\r\n    return NULL;\r\n  }\r\n  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pc, nLen, pDst, nSize);\r\n  pDst[nSize] = 0;\r\n  if (0xFEFF == pDst[0]) {\r\n    for (int i = 0; i < nSize; i++) {\r\n      pDst[i] = pDst[i + 1];\r\n    }\r\n  }\r\n  std::wstring wcstr(pDst);\r\n  delete[] pDst;\r\n  return wcstr;\r\n}\r\n\r\ntstring String2TString(const char *pc) {\r\n  tstring result;\r\n#ifdef _UNICODE\r\n  result = String2WString(pc);\r\n#else\r\n  result = pc;\r\n#endif\r\n  return result;\r\n}\r\n} // namespace StringHelper\r\n\r\nnamespace OS {\r\n  using LPFN_ISWOW64PROCESS = BOOL(WINAPI*)(HANDLE, PBOOL);\r\n\r\n  typedef struct {\r\n    TCHAR szOperation[MAX_PATH];\r\n    TCHAR szFilePath[MAX_PATH + 1];\r\n    TCHAR szParam[MAX_PATH];\r\n    TCHAR szDirectory[MAX_PATH + 1];\r\n    int nShowCmd;\r\n  } SHELLEXECUTE_PARAM;\r\n\r\nBOOL AysnShellExecute(LPCTSTR lpszOperation, LPCTSTR lpszFilePath,\r\n                      LPCTSTR lpszParam, LPCTSTR lpszDirectory, int nShowCmd) {\r\n  SHELLEXECUTE_PARAM *pParam = new SHELLEXECUTE_PARAM;\r\n  memset(pParam, 0, sizeof(SHELLEXECUTE_PARAM));\r\n  if (lpszOperation)\r\n    _sntprintf_s(pParam->szOperation, _countof(pParam->szOperation),\r\n                 lpszOperation);\r\n  if (lpszFilePath)\r\n    _sntprintf_s(pParam->szFilePath, _countof(pParam->szFilePath),\r\n                 lpszFilePath);\r\n  if (lpszParam)\r\n    _sntprintf_s(pParam->szParam, _countof(pParam->szParam), lpszParam);\r\n  if (lpszDirectory)\r\n    _sntprintf_s(pParam->szDirectory, _countof(pParam->szDirectory),\r\n                 lpszDirectory);\r\n  pParam->nShowCmd = nShowCmd;\r\n\r\n  HANDLE hThread =\r\n      CreateThread(NULL, 0, ShellExecuteProc, (LPVOID)pParam, 0, NULL);\r\n  CloseHandle(hThread);\r\n  return TRUE;\r\n\r\n}\r\n\r\nDWORD WINAPI ShellExecuteProc(LPVOID lpParam) {\r\n  if (lpParam) {\r\n    SHELLEXECUTE_PARAM *pParam = (SHELLEXECUTE_PARAM *)lpParam;\r\n    ShellExecute(NULL, pParam->szOperation, pParam->szFilePath, pParam->szParam,\r\n                 pParam->szDirectory, pParam->nShowCmd);\r\n    delete pParam;\r\n  }\r\n  return 0;\r\n}\r\n\r\nvoid SafeTerminateThread(HANDLE hThread, DWORD dwExitCode /* = -1*/) {\r\n  ::SuspendThread(hThread);\r\n  ::TerminateThread(hThread, dwExitCode);\r\n  ::CloseHandle(hThread);\r\n}\r\n\r\nDWORD ProcesstoPid(const TCHAR *pid) {\r\n  DWORD dwpid = 0;\r\n  int nProcessCount = 0;\r\n  HANDLE hProcessSnap = NULL;\r\n  TCHAR buffer[MAX_PATH + 1];\r\n  PROCESSENTRY32 pe32 = {0};\r\n  int i;\r\n  hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\r\n  if (hProcessSnap == (HANDLE)-1) {\r\n    return dwpid;\r\n  }\r\n  pe32.dwSize = sizeof(PROCESSENTRY32);\r\n  if (Process32First(hProcessSnap, &pe32)) {\r\n    do {\r\n      lstrcpy(buffer, pe32.szExeFile);\r\n      for (i = lstrlen(buffer); i > 0; i--)\r\n        if (buffer[i] == _T('\\\\'))\r\n          break;\r\n      if (!lstrcmpi(pid, &buffer[i])) {\r\n        nProcessCount++;\r\n        dwpid = pe32.th32ProcessID;\r\n        break;\r\n      }\r\n    } while (Process32Next(hProcessSnap, &pe32));\r\n  } else {\r\n    return dwpid;\r\n  }\r\n  CloseHandle(hProcessSnap);\r\n  return dwpid;\r\n}\r\n\r\nBOOL IsWow64() {\r\n  BOOL bIsWow64 = FALSE;\r\n\r\n  LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(\r\n      GetModuleHandle(TEXT(\"kernel32\")), \"IsWow64Process\");\r\n\r\n  if (NULL != fnIsWow64Process) {\r\n    if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) {\r\n    }\r\n  }\r\n  return bIsWow64;\r\n}\r\n\r\nBOOL SetRegValue(HKEY hKey, LPCTSTR lpszKeyName, LPCTSTR lpszValueName, tstring& strVal) {\r\n  HKEY hResKey;\r\n  LONG lRet;\r\n  DWORD dwType = 0;\r\n  lRet =\r\n    RegCreateKeyEx(hKey, lpszKeyName, 0, REG_NONE, REG_OPTION_NON_VOLATILE,\r\n      KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hResKey, &dwType);\r\n  if (lRet != ERROR_SUCCESS)\r\n    return FALSE;\r\n\r\n  lRet = RegSetValueExW(hResKey, lpszValueName, NULL, REG_SZ,\r\n    (LPBYTE)strVal.c_str(), (strVal.length() + 1) * 2);\r\n  if (lRet != ERROR_SUCCESS)\r\n    return FALSE;\r\n\r\n  RegCloseKey(hResKey);\r\n\r\n  return TRUE;\r\n}\r\n\r\nBOOL CreateLowIntegrityProcess(LPCTSTR Param) {\r\n  DWORD dwError = ERROR_SUCCESS;\r\n  HANDLE hToken = NULL;\r\n  HANDLE hNewToken = NULL;\r\n  SID_IDENTIFIER_AUTHORITY MLAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;\r\n  PSID pIntegritySid = NULL;\r\n  TOKEN_MANDATORY_LABEL tml = { 0 };\r\n  STARTUPINFO si = { sizeof(si) };\r\n  PROCESS_INFORMATION pi = { 0 };\r\n  if (!OpenProcessToken(GetCurrentProcess(),\r\n    TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT |\r\n    TOKEN_ASSIGN_PRIMARY,\r\n    &hToken)) {\r\n    dwError = GetLastError();\r\n    goto Cleanup;\r\n  }\r\n  if (!DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation, TokenPrimary,\r\n    &hNewToken)) {\r\n    dwError = GetLastError();\r\n    goto Cleanup;\r\n  }\r\n  if (!AllocateAndInitializeSid(&MLAuthority, 1, SECURITY_MANDATORY_MEDIUM_RID,\r\n    0, 0, 0, 0, 0, 0, 0, &pIntegritySid)) {\r\n    dwError = GetLastError();\r\n    goto Cleanup;\r\n  }\r\n  tml.Label.Attributes = SE_GROUP_INTEGRITY;\r\n  tml.Label.Sid = pIntegritySid;\r\n  if (!SetTokenInformation(hNewToken, TokenIntegrityLevel, &tml,\r\n    (sizeof(tml) + GetLengthSid(pIntegritySid)))) {\r\n    dwError = GetLastError();\r\n    goto Cleanup;\r\n  }\r\n  if (!CreateProcessAsUser(hNewToken, NULL, (LPWSTR)Param, NULL, NULL,\r\n\r\n    FALSE, 0, NULL, NULL, &si, &pi)) {\r\n    dwError = GetLastError();\r\n    goto Cleanup;\r\n  }\r\n\r\nCleanup:\r\n\r\n  if (hToken) {\r\n    CloseHandle(hToken);\r\n    hToken = NULL;\r\n  }\r\n  if (hNewToken) {\r\n    CloseHandle(hNewToken);\r\n    hNewToken = NULL;\r\n  }\r\n  if (pIntegritySid) {\r\n    FreeSid(pIntegritySid);\r\n    pIntegritySid = NULL;\r\n  }\r\n  if (pi.hProcess) {\r\n    CloseHandle(pi.hProcess);\r\n    pi.hProcess = NULL;\r\n  }\r\n  if (pi.hThread) {\r\n    CloseHandle(pi.hThread);\r\n    pi.hThread = NULL;\r\n  }\r\n  if (ERROR_SUCCESS != dwError) {\r\n    SetLastError(dwError);\r\n    return FALSE;\r\n  }\r\n  else {\r\n    return TRUE;\r\n  }\r\n}\r\n\r\n} // namespace OS\r\n\r\nnamespace Window {\r\nHWND FindWindowByProcess(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,\r\n                         DWORD nProcessID) {\r\n  HWND hWnd = NULL;\r\n  if (nProcessID == 0)\r\n    nProcessID = GetCurrentProcessId();\r\n  DWORD dwWindowProcessID = 0;\r\n  do {\r\n    hWnd = FindWindowEx(NULL, hWnd, lpszClassName, lpszWindowName);\r\n    if (hWnd != NULL) {\r\n      GetWindowThreadProcessId(hWnd, &dwWindowProcessID);\r\n      if (dwWindowProcessID == nProcessID)\r\n        break;\r\n    }\r\n  } while (hWnd != NULL);\r\n\r\n  return hWnd;\r\n}\r\n\r\nvoid StretchForegroundWindow(HWND hWnd) {\r\n  HWND hForWnd = ::GetForegroundWindow();\r\n  if (hWnd == hForWnd)\r\n    return;\r\n\r\n  DWORD dwProcessId;\r\n  DWORD dwThread1 = GetWindowThreadProcessId(hWnd, &dwProcessId);\r\n  DWORD dwThread2 = GetWindowThreadProcessId(hForWnd, &dwProcessId);\r\n  if (dwThread1 != dwThread2) {\r\n    AttachThreadInput(dwThread1, dwThread2, TRUE);\r\n    SetForegroundWindow(hWnd);\r\n    AttachThreadInput(dwThread1, dwThread2, FALSE);\r\n  }\r\n  else {\r\n    SetForegroundWindow(hWnd);\r\n  }\r\n}\r\n\r\n} // namespace Window\r\n\r\nnamespace Device {\r\n  typedef struct _ASTAT_ {\r\n    ADAPTER_STATUS adapt;\r\n    NAME_BUFFER NameBuff[30];\r\n  } ASTAT, * PASTAT;\r\n\r\nASTAT Adapter;\r\nstatic char g_strTempBuf[1024];\r\n\r\nconst char* GetTheFirstMac() {\r\n  NCB ncb;\r\n  UCHAR uRetCode;\r\n  LANA_ENUM lana_enum_buf;\r\n\r\n  memset(g_strTempBuf, 0, sizeof(g_strTempBuf));\r\n\r\n  memset(&ncb, 0, sizeof(ncb));\r\n  ncb.ncb_command = NCBENUM;\r\n\r\n  ncb.ncb_buffer = (unsigned char*)&lana_enum_buf;\r\n  ncb.ncb_length = sizeof(lana_enum_buf);\r\n\r\n  uRetCode = Netbios(&ncb);\r\n\r\n  if (uRetCode != 0) {\r\n    return g_strTempBuf;\r\n  }\r\n\r\n  int nIndex = 0;\r\n\r\n  {\r\n    int lana_num = lana_enum_buf.lana[nIndex];\r\n\r\n    memset(&ncb, 0, sizeof(ncb));\r\n    ncb.ncb_command = NCBRESET;\r\n    ncb.ncb_lana_num = lana_num;\r\n\r\n    uRetCode = Netbios(&ncb);\r\n\r\n    memset(&ncb, 0, sizeof(ncb));\r\n    ncb.ncb_command = NCBASTAT;\r\n    ncb.ncb_lana_num = lana_num;\r\n\r\n    strcpy((char*)ncb.ncb_callname, \"*               \");\r\n    ncb.ncb_buffer = (unsigned char*)&Adapter;\r\n\r\n    ncb.ncb_length = sizeof(Adapter);\r\n\r\n    uRetCode = Netbios(&ncb);\r\n\r\n    if (uRetCode == 0) {\r\n      char szTemp[32] = { 0 };\r\n      _snprintf(\r\n        szTemp, 32, \"%02X%02X%02X%02X%02X%02X\",\r\n        Adapter.adapt.adapter_address[0], Adapter.adapt.adapter_address[1],\r\n        Adapter.adapt.adapter_address[2], Adapter.adapt.adapter_address[3],\r\n        Adapter.adapt.adapter_address[4], Adapter.adapt.adapter_address[5]);\r\n\r\n      strcat(g_strTempBuf, szTemp);\r\n    }\r\n  }\r\n\r\n  return g_strTempBuf;\r\n}\r\n\r\n} // namespace Device\r\n\r\n\r\n} // namespace SystemCommon\r\n"
  },
  {
    "path": "common/util/system.h",
    "content": "#pragma once\r\n\r\n#ifndef tstring\r\n#ifdef _UNICODE\r\n#define tstring std::wstring\r\n#else\r\n#define tstring std::string\r\n#endif\r\n#endif\r\n\r\nnamespace SystemCommon {\r\nnamespace FilePathHelper {\r\nBOOL ForceCreateDir(LPCTSTR pszFullPathFileName);\r\n\r\nBOOL CreateDir(LPCTSTR lpszPath);\r\n\r\nBOOL CreateMyDir(LPCTSTR pszDir);\r\n\r\nBOOL GetAppPath(HINSTANCE hInst, LPTSTR lpPath, DWORD dMaxLen, LPCTSTR pAddon);\r\n\r\ntstring GetAssignPath(DWORD assing, BOOL forceCreate);\r\n\r\ntstring GetFileName(tstring pathname);\r\n\r\ntstring GetPath(tstring pathname);\r\n\r\nBOOL DeepDeleteFile(const tstring &strFile);\r\n\r\nBOOL DeleteAllFiles(tstring strPath);\r\n\r\nBOOL GetBackslashDir(tstring &strPath);\r\n\r\nBOOL CopyFolder(const tstring &strSrc, const tstring &strDst,\r\n                BOOL bForce = FALSE);\r\n\r\nBOOL DeepCopyFile(const tstring &strSrc, const tstring &strDst);\r\n\r\nBOOL UnzipFileToPath(LPCTSTR lpszFile, LPCTSTR lpszDir);\r\n\r\nDWORD GetFileSize(const tstring& path);\r\n\r\n} // namespace FilePathHelper\r\n\r\n\r\nnamespace FileVersionHelper {\r\nBOOL GetFileVersion(LPCTSTR strFile, LPTSTR pszVersion, int nVersionLen);\r\n\r\ntstring GetFileVersion(LPCTSTR strFile);\r\n\r\ntstring GetFileVersion(HMODULE hModule);\r\n\r\n} // namespace FileVersionHelper\r\n\r\n\r\nnamespace NetHelper {\r\nBOOL GetDomain(LPCTSTR url, LPTSTR buf, int cbBuf);\r\n} // namespace NetHelper\r\n\r\n\r\nnamespace StringHelper {\r\ntstring Trim(tstring &s);\r\ntstring ReplaceAll(tstring &str, const tstring &old_value,\r\n                    const tstring &new_value);\r\n\r\ntstring MakeLower(tstring &s);\r\n\r\nBOOL CompareNoCase(tstring sA, tstring sB);\r\nint FindNoCase(tstring sA, tstring sB);\r\n\r\nstd::string TString2String(tstring str);\r\nstd::string Wstring2String(const wchar_t *pwc);\r\n\r\nstd::wstring String2WString(const char *pc);\r\ntstring String2TString(const char *pc);\r\n\r\n} // namespace StringHelper\r\n\r\n\r\nnamespace OS {\r\nBOOL AysnShellExecute(LPCTSTR lpszOperation, LPCTSTR lpszFile,\r\n                      LPCTSTR lpszParam = NULL, LPCTSTR lpszDirectory = NULL,\r\n                      int nShowCmd = SW_SHOW);\r\nDWORD WINAPI ShellExecuteProc(LPVOID lpParam);\r\nvoid SafeTerminateThread(HANDLE hThread, DWORD dwExitCode = -1);\r\n\r\nDWORD ProcesstoPid(const TCHAR *pid);\r\n\r\nBOOL IsWow64();\r\n\r\nBOOL SetRegValue(HKEY hKey, LPCTSTR lpszKeyName, LPCTSTR lpszValueName,\r\n  tstring& strVal);\r\n\r\nBOOL CreateLowIntegrityProcess(LPCTSTR);\r\n\r\n} // namespace OS\r\n\r\n\r\nnamespace Window {\r\nHWND FindWindowByProcess(LPCTSTR lpszClassName, LPCTSTR lpszWindowName = NULL,\r\n                         DWORD nProcessID = 0 /*Current Process*/);\r\nvoid StretchForegroundWindow(HWND);\r\n\r\n} // namespace Window\r\n\r\n\r\nnamespace Device {\r\n  const char* GetTheFirstMac();\r\n\r\n} // namespace Device\r\n\r\n}; // namespace SystemCommon\r\n"
  },
  {
    "path": "common/util/util_tools.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util_tools.h\"\n\nCriticalSection::CriticalSection(void) {\n#ifdef _WIN32\n  InitializeCriticalSection(&m_cs);\n#else\n  pthread_mutex_init(&m_cs, NULL);\n#endif\n}\n\nCriticalSection::~CriticalSection(void) {\n#ifdef _WIN32\n  DeleteCriticalSection(&m_cs);\n#else\n  pthread_mutex_destroy(&m_cs);\n#endif\n}\n\nvoid CriticalSection::Lock(void) {\n#ifdef _WIN32\n  EnterCriticalSection(&m_cs);\n#else\n  pthread_mutex_lock(&m_cs);\n#endif\n}\n\nvoid CriticalSection::UnLock(void) {\n#ifdef _WIN32\n  LeaveCriticalSection(&m_cs);\n#else\n  pthread_mutex_unlock(&m_cs);\n#endif\n}\n\nBOOL CriticalSection::TryLock(void) {\n  BOOL bReturn = FALSE;\n\n#ifdef _WIN32\n  bReturn = TryEnterCriticalSection(&m_cs);\n#else\n  bReturn = pthread_mutex_trylock(&m_cs);\n#endif\n\n  return bReturn;\n}\n"
  },
  {
    "path": "common/util/util_tools.h",
    "content": "#pragma once\n\n#include <io.h>\n\nclass CriticalSection {\npublic:\n  CriticalSection(void);\n  ~CriticalSection(void);\n\nprivate:\n#ifdef _WIN32\n  CRITICAL_SECTION m_cs;\n#else\n  pthread_mutex_t m_cs;\n#endif\n\npublic:\n  void Lock(void);\n  void UnLock(void);\n  BOOL TryLock(void);\n};\n\ntemplate <typename TLock> class AutoCritSecLock {\npublic:\n  AutoCritSecLock(TLock &cs, bool bInitialLock = true);\n  ~AutoCritSecLock() throw();\n\n  HRESULT Lock() throw();\n  void Unlock() throw();\n\nprivate:\n  TLock &m_cs;\n  bool m_bLocked;\n\n  AutoCritSecLock(const AutoCritSecLock &) throw();\n  AutoCritSecLock &operator=(const AutoCritSecLock &) throw();\n};\n\ntemplate <class TLock>\ninline AutoCritSecLock<TLock>::AutoCritSecLock(TLock &cs, bool bInitialLock)\n    : m_cs(cs), m_bLocked(false) {\n  if (bInitialLock) {\n    Lock();\n  }\n}\n\ntemplate <class TLock>\ninline AutoCritSecLock<TLock>::~AutoCritSecLock() throw() {\n  if (m_bLocked) {\n    Unlock();\n  }\n}\n\ntemplate <class TLock> inline HRESULT AutoCritSecLock<TLock>::Lock() throw() {\n  assert(!m_bLocked);\n  m_cs.Lock();\n  m_bLocked = true;\n  return (S_OK);\n}\n\ntemplate <class TLock> inline void AutoCritSecLock<TLock>::Unlock() throw() {\n  assert(m_bLocked);\n  m_cs.UnLock();\n  m_bLocked = false;\n}\n"
  },
  {
    "path": "common/xml/tinystr.cpp",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n#include \"stdafx.h\"\n\n#ifndef TIXML_USE_STL\n\n#include \"tinystr.h\"\n\n// Error value for find primitive\nconst TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);\n\n\n// Null rep.\nTiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\\0' } };\n\n\nvoid TiXmlString::reserve (size_type cap)\n{\n\tif (cap > capacity())\n\t{\n\t\tTiXmlString tmp;\n\t\ttmp.init(length(), cap);\n\t\tmemcpy(tmp.start(), data(), length());\n\t\tswap(tmp);\n\t}\n}\n\n\nTiXmlString& TiXmlString::assign(const char* str, size_type len)\n{\n\tsize_type cap = capacity();\n\tif (len > cap || cap > 3*(len + 8))\n\t{\n\t\tTiXmlString tmp;\n\t\ttmp.init(len);\n\t\tmemcpy(tmp.start(), str, len);\n\t\tswap(tmp);\n\t}\n\telse\n\t{\n\t\tmemmove(start(), str, len);\n\t\tset_size(len);\n\t}\n\treturn *this;\n}\n\n\nTiXmlString& TiXmlString::append(const char* str, size_type len)\n{\n\tsize_type newsize = length() + len;\n\tif (newsize > capacity())\n\t{\n\t\treserve (newsize + capacity());\n\t}\n\tmemmove(finish(), str, len);\n\tset_size(newsize);\n\treturn *this;\n}\n\n\nTiXmlString operator + (const TiXmlString & a, const TiXmlString & b)\n{\n\tTiXmlString tmp;\n\ttmp.reserve(a.length() + b.length());\n\ttmp += a;\n\ttmp += b;\n\treturn tmp;\n}\n\nTiXmlString operator + (const TiXmlString & a, const char* b)\n{\n\tTiXmlString tmp;\n\tTiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );\n\ttmp.reserve(a.length() + b_len);\n\ttmp += a;\n\ttmp.append(b, b_len);\n\treturn tmp;\n}\n\nTiXmlString operator + (const char* a, const TiXmlString & b)\n{\n\tTiXmlString tmp;\n\tTiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );\n\ttmp.reserve(a_len + b.length());\n\ttmp.append(a, a_len);\n\ttmp += b;\n\treturn tmp;\n}\n\n\n#endif\t// TIXML_USE_STL\n"
  },
  {
    "path": "common/xml/tinystr.h",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n\n#ifndef TIXML_USE_STL\n\n#ifndef TIXML_STRING_INCLUDED\n#define TIXML_STRING_INCLUDED\n\n#include <assert.h>\n#include <string.h>\n\n/*\tThe support for explicit isn't that universal, and it isn't really\n\trequired - it is used to check that the TiXmlString class isn't incorrectly\n\tused. Be nice to old compilers and macro it here:\n*/\n#if defined(_MSC_VER) && (_MSC_VER >= 1200 )\n\t// Microsoft visual studio, version 6 and higher.\n\t#define TIXML_EXPLICIT explicit\n#elif defined(__GNUC__) && (__GNUC__ >= 3 )\n\t// GCC version 3 and higher.s\n\t#define TIXML_EXPLICIT explicit\n#else\n\t#define TIXML_EXPLICIT\n#endif\n\n\n/*\n   TiXmlString is an emulation of a subset of the std::string template.\n   Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.\n   Only the member functions relevant to the TinyXML project have been implemented.\n   The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase\n   a string and there's no more room, we allocate a buffer twice as big as we need.\n*/\nclass TiXmlString\n{\n  public :\n\t// The size type used\n  \ttypedef size_t size_type;\n\n\t// Error value for find primitive\n\tstatic const size_type npos; // = -1;\n\n\n\t// TiXmlString empty constructor\n\tTiXmlString () : rep_(&nullrep_)\n\t{\n\t}\n\n\t// TiXmlString copy constructor\n\tTiXmlString ( const TiXmlString & copy) : rep_(0)\n\t{\n\t\tinit(copy.length());\n\t\tmemcpy(start(), copy.data(), length());\n\t}\n\n\t// TiXmlString constructor, based on a string\n\tTIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)\n\t{\n\t\tinit( static_cast<size_type>( strlen(copy) ));\n\t\tmemcpy(start(), copy, length());\n\t}\n\n\t// TiXmlString constructor, based on a string\n\tTIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)\n\t{\n\t\tinit(len);\n\t\tmemcpy(start(), str, len);\n\t}\n\n\t// TiXmlString destructor\n\t~TiXmlString ()\n\t{\n\t\tquit();\n\t}\n\n\tTiXmlString& operator = (const char * copy)\n\t{\n\t\treturn assign( copy, (size_type)strlen(copy));\n\t}\n\n\tTiXmlString& operator = (const TiXmlString & copy)\n\t{\n\t\treturn assign(copy.start(), copy.length());\n\t}\n\n\n\t// += operator. Maps to append\n\tTiXmlString& operator += (const char * suffix)\n\t{\n\t\treturn append(suffix, static_cast<size_type>( strlen(suffix) ));\n\t}\n\n\t// += operator. Maps to append\n\tTiXmlString& operator += (char single)\n\t{\n\t\treturn append(&single, 1);\n\t}\n\n\t// += operator. Maps to append\n\tTiXmlString& operator += (const TiXmlString & suffix)\n\t{\n\t\treturn append(suffix.data(), suffix.length());\n\t}\n\n\n\t// Convert a TiXmlString into a null-terminated char *\n\tconst char * c_str () const { return rep_->str; }\n\n\t// Convert a TiXmlString into a char * (need not be null terminated).\n\tconst char * data () const { return rep_->str; }\n\n\t// Return the length of a TiXmlString\n\tsize_type length () const { return rep_->size; }\n\n\t// Alias for length()\n\tsize_type size () const { return rep_->size; }\n\n\t// Checks if a TiXmlString is empty\n\tbool empty () const { return rep_->size == 0; }\n\n\t// Return capacity of string\n\tsize_type capacity () const { return rep_->capacity; }\n\n\n\t// single char extraction\n\tconst char& at (size_type index) const\n\t{\n\t\tassert( index < length() );\n\t\treturn rep_->str[ index ];\n\t}\n\n\t// [] operator\n\tchar& operator [] (size_type index) const\n\t{\n\t\tassert( index < length() );\n\t\treturn rep_->str[ index ];\n\t}\n\n\t// find a char in a string. Return TiXmlString::npos if not found\n\tsize_type find (char lookup) const\n\t{\n\t\treturn find(lookup, 0);\n\t}\n\n\t// find a char in a string from an offset. Return TiXmlString::npos if not found\n\tsize_type find (char tofind, size_type offset) const\n\t{\n\t\tif (offset >= length()) return npos;\n\n\t\tfor (const char* p = c_str() + offset; *p != '\\0'; ++p)\n\t\t{\n\t\t   if (*p == tofind) return static_cast< size_type >( p - c_str() );\n\t\t}\n\t\treturn npos;\n\t}\n\n\tvoid clear ()\n\t{\n\t\t//Lee:\n\t\t//The original was just too strange, though correct:\n\t\t//\tTiXmlString().swap(*this);\n\t\t//Instead use the quit & re-init:\n\t\tquit();\n\t\tinit(0,0);\n\t}\n\n\t/*\tFunction to reserve a big amount of data when we know we'll need it. Be aware that this\n\t\tfunction DOES NOT clear the content of the TiXmlString if any exists.\n\t*/\n\tvoid reserve (size_type cap);\n\n\tTiXmlString& assign (const char* str, size_type len);\n\n\tTiXmlString& append (const char* str, size_type len);\n\n\tvoid swap (TiXmlString& other)\n\t{\n\t\tRep* r = rep_;\n\t\trep_ = other.rep_;\n\t\tother.rep_ = r;\n\t}\n\n  private:\n\n\tvoid init(size_type sz) { init(sz, sz); }\n\tvoid set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\\0'; }\n\tchar* start() const { return rep_->str; }\n\tchar* finish() const { return rep_->str + rep_->size; }\n\n\tstruct Rep\n\t{\n\t\tsize_type size, capacity;\n\t\tchar str[1];\n\t};\n\n\tvoid init(size_type sz, size_type cap)\n\t{\n\t\tif (cap)\n\t\t{\n\t\t\t// Lee: the original form:\n\t\t\t//\trep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));\n\t\t\t// doesn't work in some cases of new being overloaded. Switching\n\t\t\t// to the normal allocation, although use an 'int' for systems\n\t\t\t// that are overly picky about structure alignment.\n\t\t\tconst size_type bytesNeeded = sizeof(Rep) + cap;\n\t\t\tconst size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); \n\t\t\trep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );\n\n\t\t\trep_->str[ rep_->size = sz ] = '\\0';\n\t\t\trep_->capacity = cap;\n\t\t}\n\t\telse\n\t\t{\n\t\t\trep_ = &nullrep_;\n\t\t}\n\t}\n\n\tvoid quit()\n\t{\n\t\tif (rep_ != &nullrep_)\n\t\t{\n\t\t\t// The rep_ is really an array of ints. (see the allocator, above).\n\t\t\t// Cast it back before delete, so the compiler won't incorrectly call destructors.\n\t\t\tdelete [] ( reinterpret_cast<int*>( rep_ ) );\n\t\t}\n\t}\n\n\tRep * rep_;\n\tstatic Rep nullrep_;\n\n} ;\n\n\ninline bool operator == (const TiXmlString & a, const TiXmlString & b)\n{\n\treturn    ( a.length() == b.length() )\t\t\t\t// optimization on some platforms\n\t       && ( strcmp(a.c_str(), b.c_str()) == 0 );\t// actual compare\n}\ninline bool operator < (const TiXmlString & a, const TiXmlString & b)\n{\n\treturn strcmp(a.c_str(), b.c_str()) < 0;\n}\n\ninline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }\ninline bool operator >  (const TiXmlString & a, const TiXmlString & b) { return b < a; }\ninline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }\ninline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }\n\ninline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }\ninline bool operator == (const char* a, const TiXmlString & b) { return b == a; }\ninline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }\ninline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }\n\nTiXmlString operator + (const TiXmlString & a, const TiXmlString & b);\nTiXmlString operator + (const TiXmlString & a, const char* b);\nTiXmlString operator + (const char* a, const TiXmlString & b);\n\n\n/*\n   TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.\n   Only the operators that we need for TinyXML have been developped.\n*/\nclass TiXmlOutStream : public TiXmlString\n{\npublic :\n\n\t// TiXmlOutStream << operator.\n\tTiXmlOutStream & operator << (const TiXmlString & in)\n\t{\n\t\t*this += in;\n\t\treturn *this;\n\t}\n\n\t// TiXmlOutStream << operator.\n\tTiXmlOutStream & operator << (const char * in)\n\t{\n\t\t*this += in;\n\t\treturn *this;\n\t}\n\n} ;\n\n#endif\t// TIXML_STRING_INCLUDED\n#endif\t// TIXML_USE_STL\n"
  },
  {
    "path": "common/xml/tinyxml.cpp",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n#include \"stdafx.h\"\n#include <ctype.h>\n\n#ifdef TIXML_USE_STL\n#include <sstream>\n#include <iostream>\n#endif\n\n#include \"tinyxml.h\"\n\nFILE* TiXmlFOpen( const char* filename, const char* mode );\n\nbool TiXmlBase::condenseWhiteSpace = true;\n\n// Microsoft compiler security\nFILE* TiXmlFOpen( const char* filename, const char* mode )\n{\n\treturn fopen( filename, mode );\n}\n\nvoid TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )\n{\n\tint i=0;\n\n\twhile( i<(int)str.length() )\n\t{\n\t\tunsigned char c = (unsigned char) str[i];\n\n\t\tif (    c == '&' \n\t\t     && i < ( (int)str.length() - 2 )\n\t\t\t && str[i+1] == '#'\n\t\t\t && str[i+2] == 'x' )\n\t\t{\n\t\t\t// Hexadecimal character reference.\n\t\t\t// Pass through unchanged.\n\t\t\t// &#xA9;\t-- copyright symbol, for example.\n\t\t\t//\n\t\t\t// The -1 is a bug fix from Rob Laveaux. It keeps\n\t\t\t// an overflow from happening if there is no ';'.\n\t\t\t// There are actually 2 ways to exit this loop -\n\t\t\t// while fails (error case) and break (semicolon found).\n\t\t\t// However, there is no mechanism (currently) for\n\t\t\t// this function to return an error.\n\t\t\twhile ( i<(int)str.length()-1 )\n\t\t\t{\n\t\t\t\toutString->append( str.c_str() + i, 1 );\n\t\t\t\t++i;\n\t\t\t\tif ( str[i] == ';' )\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if ( c == '&' )\n\t\t{\n\t\t\toutString->append( entity[0].str, entity[0].strLength );\n\t\t\t++i;\n\t\t}\n\t\telse if ( c == '<' )\n\t\t{\n\t\t\toutString->append( entity[1].str, entity[1].strLength );\n\t\t\t++i;\n\t\t}\n\t\telse if ( c == '>' )\n\t\t{\n\t\t\toutString->append( entity[2].str, entity[2].strLength );\n\t\t\t++i;\n\t\t}\n\t\telse if ( c == '\\\"' )\n\t\t{\n\t\t\toutString->append( entity[3].str, entity[3].strLength );\n\t\t\t++i;\n\t\t}\n\t\telse if ( c == '\\'' )\n\t\t{\n\t\t\toutString->append( entity[4].str, entity[4].strLength );\n\t\t\t++i;\n\t\t}\n\t\telse if ( c < 32 )\n\t\t{\n\t\t\t// Easy pass at non-alpha/numeric/symbol\n\t\t\t// Below 32 is symbolic.\n\t\t\tchar buf[ 32 ];\n\t\t\t\n\t\t\t#if defined(TIXML_SNPRINTF)\t\t\n\t\t\t\tTIXML_SNPRINTF( buf, sizeof(buf), \"&#x%02X;\", (unsigned) ( c & 0xff ) );\n\t\t\t#else\n\t\t\t\tsprintf( buf, \"&#x%02X;\", (unsigned) ( c & 0xff ) );\n\t\t\t#endif\t\t\n\n\t\t\t//*ME:\twarning C4267: convert 'size_t' to 'int'\n\t\t\t//*ME:\tInt-Cast to make compiler happy ...\n\t\t\toutString->append( buf, (int)strlen( buf ) );\n\t\t\t++i;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//char realc = (char) c;\n\t\t\t//outString->append( &realc, 1 );\n\t\t\t*outString += (char) c;\t// somewhat more efficient function call.\n\t\t\t++i;\n\t\t}\n\t}\n}\n\n\nTiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()\n{\n\tparent = 0;\n\ttype = _type;\n\tfirstChild = 0;\n\tlastChild = 0;\n\tprev = 0;\n\tnext = 0;\n}\n\n\nTiXmlNode::~TiXmlNode()\n{\n\tTiXmlNode* node = firstChild;\n\tTiXmlNode* temp = 0;\n\n\twhile ( node )\n\t{\n\t\ttemp = node;\n\t\tnode = node->next;\n\t\tdelete temp;\n\t}\t\n}\n\n\nvoid TiXmlNode::CopyTo( TiXmlNode* target ) const\n{\n\ttarget->SetValue (value.c_str() );\n\ttarget->userData = userData; \n\ttarget->location = location;\n}\n\n\nvoid TiXmlNode::Clear()\n{\n\tTiXmlNode* node = firstChild;\n\tTiXmlNode* temp = 0;\n\n\twhile ( node )\n\t{\n\t\ttemp = node;\n\t\tnode = node->next;\n\t\tdelete temp;\n\t}\t\n\n\tfirstChild = 0;\n\tlastChild = 0;\n}\n\n\nTiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )\n{\n\tassert( node->parent == 0 || node->parent == this );\n\tassert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );\n\n\tif ( node->Type() == TiXmlNode::TINYXML_DOCUMENT )\n\t{\n\t\tdelete node;\n\t\tif ( GetDocument() ) \n\t\t\tGetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\tnode->parent = this;\n\n\tnode->prev = lastChild;\n\tnode->next = 0;\n\n\tif ( lastChild )\n\t\tlastChild->next = node;\n\telse\n\t\tfirstChild = node;\t\t\t// it was an empty list.\n\n\tlastChild = node;\n\treturn node;\n}\n\n\nTiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )\n{\n\tif ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )\n\t{\n\t\tif ( GetDocument() ) \n\t\t\tGetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\tTiXmlNode* node = addThis.Clone();\n\tif ( !node )\n\t\treturn 0;\n\n\treturn LinkEndChild( node );\n}\n\n\nTiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )\n{\t\n\tif ( !beforeThis || beforeThis->parent != this ) {\n\t\treturn 0;\n\t}\n\tif ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )\n\t{\n\t\tif ( GetDocument() ) \n\t\t\tGetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\tTiXmlNode* node = addThis.Clone();\n\tif ( !node )\n\t\treturn 0;\n\tnode->parent = this;\n\n\tnode->next = beforeThis;\n\tnode->prev = beforeThis->prev;\n\tif ( beforeThis->prev )\n\t{\n\t\tbeforeThis->prev->next = node;\n\t}\n\telse\n\t{\n\t\tassert( firstChild == beforeThis );\n\t\tfirstChild = node;\n\t}\n\tbeforeThis->prev = node;\n\treturn node;\n}\n\n\nTiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )\n{\n\tif ( !afterThis || afterThis->parent != this ) {\n\t\treturn 0;\n\t}\n\tif ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )\n\t{\n\t\tif ( GetDocument() ) \n\t\t\tGetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\tTiXmlNode* node = addThis.Clone();\n\tif ( !node )\n\t\treturn 0;\n\tnode->parent = this;\n\n\tnode->prev = afterThis;\n\tnode->next = afterThis->next;\n\tif ( afterThis->next )\n\t{\n\t\tafterThis->next->prev = node;\n\t}\n\telse\n\t{\n\t\tassert( lastChild == afterThis );\n\t\tlastChild = node;\n\t}\n\tafterThis->next = node;\n\treturn node;\n}\n\n\nTiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )\n{\n\tif ( !replaceThis )\n\t\treturn 0;\n\n\tif ( replaceThis->parent != this )\n\t\treturn 0;\n\n\tif ( withThis.ToDocument() ) {\n\t\t// A document can never be a child.\tThanks to Noam.\n\t\tTiXmlDocument* document = GetDocument();\n\t\tif ( document ) \n\t\t\tdocument->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\tTiXmlNode* node = withThis.Clone();\n\tif ( !node )\n\t\treturn 0;\n\n\tnode->next = replaceThis->next;\n\tnode->prev = replaceThis->prev;\n\n\tif ( replaceThis->next )\n\t\treplaceThis->next->prev = node;\n\telse\n\t\tlastChild = node;\n\n\tif ( replaceThis->prev )\n\t\treplaceThis->prev->next = node;\n\telse\n\t\tfirstChild = node;\n\n\tdelete replaceThis;\n\tnode->parent = this;\n\treturn node;\n}\n\n\nbool TiXmlNode::RemoveChild( TiXmlNode* removeThis )\n{\n\tif ( !removeThis ) {\n\t\treturn false;\n\t}\n\n\tif ( removeThis->parent != this )\n\t{\t\n\t\tassert( 0 );\n\t\treturn false;\n\t}\n\n\tif ( removeThis->next )\n\t\tremoveThis->next->prev = removeThis->prev;\n\telse\n\t\tlastChild = removeThis->prev;\n\n\tif ( removeThis->prev )\n\t\tremoveThis->prev->next = removeThis->next;\n\telse\n\t\tfirstChild = removeThis->next;\n\n\tdelete removeThis;\n\treturn true;\n}\n\nconst TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const\n{\n\tconst TiXmlNode* node;\n\tfor ( node = firstChild; node; node = node->next )\n\t{\n\t\tif ( strcmp( node->Value(), _value ) == 0 )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlNode* TiXmlNode::LastChild( const char * _value ) const\n{\n\tconst TiXmlNode* node;\n\tfor ( node = lastChild; node; node = node->prev )\n\t{\n\t\tif ( strcmp( node->Value(), _value ) == 0 )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const\n{\n\tif ( !previous )\n\t{\n\t\treturn FirstChild();\n\t}\n\telse\n\t{\n\t\tassert( previous->parent == this );\n\t\treturn previous->NextSibling();\n\t}\n}\n\n\nconst TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const\n{\n\tif ( !previous )\n\t{\n\t\treturn FirstChild( val );\n\t}\n\telse\n\t{\n\t\tassert( previous->parent == this );\n\t\treturn previous->NextSibling( val );\n\t}\n}\n\n\nconst TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const \n{\n\tconst TiXmlNode* node;\n\tfor ( node = next; node; node = node->next )\n\t{\n\t\tif ( strcmp( node->Value(), _value ) == 0 )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const\n{\n\tconst TiXmlNode* node;\n\tfor ( node = prev; node; node = node->prev )\n\t{\n\t\tif ( strcmp( node->Value(), _value ) == 0 )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\n\nvoid TiXmlElement::RemoveAttribute( const char * name )\n{\n    #ifdef TIXML_USE_STL\n\tTIXML_STRING str( name );\n\tTiXmlAttribute* node = attributeSet.Find( str );\n\t#else\n\tTiXmlAttribute* node = attributeSet.Find( name );\n\t#endif\n\tif ( node )\n\t{\n\t\tattributeSet.Remove( node );\n\t\tdelete node;\n\t}\n}\n\nconst TiXmlElement* TiXmlNode::FirstChildElement() const\n{\n\tconst TiXmlNode* node;\n\n\tfor (\tnode = FirstChild();\n\t\t\tnode;\n\t\t\tnode = node->NextSibling() )\n\t{\n\t\tif ( node->ToElement() )\n\t\t\treturn node->ToElement();\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const\n{\n\tconst TiXmlNode* node;\n\n\tfor (\tnode = FirstChild( _value );\n\t\t\tnode;\n\t\t\tnode = node->NextSibling( _value ) )\n\t{\n\t\tif ( node->ToElement() )\n\t\t\treturn node->ToElement();\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlElement* TiXmlNode::NextSiblingElement() const\n{\n\tconst TiXmlNode* node;\n\n\tfor (\tnode = NextSibling();\n\t\t\tnode;\n\t\t\tnode = node->NextSibling() )\n\t{\n\t\tif ( node->ToElement() )\n\t\t\treturn node->ToElement();\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const\n{\n\tconst TiXmlNode* node;\n\n\tfor (\tnode = NextSibling( _value );\n\t\t\tnode;\n\t\t\tnode = node->NextSibling( _value ) )\n\t{\n\t\tif ( node->ToElement() )\n\t\t\treturn node->ToElement();\n\t}\n\treturn 0;\n}\n\n\nconst TiXmlDocument* TiXmlNode::GetDocument() const\n{\n\tconst TiXmlNode* node;\n\n\tfor( node = this; node; node = node->parent )\n\t{\n\t\tif ( node->ToDocument() )\n\t\t\treturn node->ToDocument();\n\t}\n\treturn 0;\n}\n\n\nTiXmlElement::TiXmlElement (const char * _value)\n\t: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )\n{\n\tfirstChild = lastChild = 0;\n\tvalue = _value;\n}\n\n\n#ifdef TIXML_USE_STL\nTiXmlElement::TiXmlElement( const std::string& _value ) \n\t: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )\n{\n\tfirstChild = lastChild = 0;\n\tvalue = _value;\n}\n#endif\n\n\nTiXmlElement::TiXmlElement( const TiXmlElement& copy)\n\t: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )\n{\n\tfirstChild = lastChild = 0;\n\tcopy.CopyTo( this );\t\n}\n\n\nTiXmlElement& TiXmlElement::operator=( const TiXmlElement& base )\n{\n\tClearThis();\n\tbase.CopyTo( this );\n\treturn *this;\n}\n\n\nTiXmlElement::~TiXmlElement()\n{\n\tClearThis();\n}\n\n\nvoid TiXmlElement::ClearThis()\n{\n\tClear();\n\twhile( attributeSet.First() )\n\t{\n\t\tTiXmlAttribute* node = attributeSet.First();\n\t\tattributeSet.Remove( node );\n\t\tdelete node;\n\t}\n}\n\n\nconst char* TiXmlElement::Attribute( const char* name ) const\n{\n\tconst TiXmlAttribute* node = attributeSet.Find( name );\n\tif ( node )\n\t\treturn node->Value();\n\treturn 0;\n}\n\n\n#ifdef TIXML_USE_STL\nconst std::string* TiXmlElement::Attribute( const std::string& name ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tif ( attrib )\n\t\treturn &attrib->ValueStr();\n\treturn 0;\n}\n#endif\n\n\nconst char* TiXmlElement::Attribute( const char* name, int* i ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tconst char* result = 0;\n\n\tif ( attrib ) {\n\t\tresult = attrib->Value();\n\t\tif ( i ) {\n\t\t\tattrib->QueryIntValue( i );\n\t\t}\n\t}\n\treturn result;\n}\n\n\n#ifdef TIXML_USE_STL\nconst std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tconst std::string* result = 0;\n\n\tif ( attrib ) {\n\t\tresult = &attrib->ValueStr();\n\t\tif ( i ) {\n\t\t\tattrib->QueryIntValue( i );\n\t\t}\n\t}\n\treturn result;\n}\n#endif\n\n\nconst char* TiXmlElement::Attribute( const char* name, double* d ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tconst char* result = 0;\n\n\tif ( attrib ) {\n\t\tresult = attrib->Value();\n\t\tif ( d ) {\n\t\t\tattrib->QueryDoubleValue( d );\n\t\t}\n\t}\n\treturn result;\n}\n\n\n#ifdef TIXML_USE_STL\nconst std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tconst std::string* result = 0;\n\n\tif ( attrib ) {\n\t\tresult = &attrib->ValueStr();\n\t\tif ( d ) {\n\t\t\tattrib->QueryDoubleValue( d );\n\t\t}\n\t}\n\treturn result;\n}\n#endif\n\n\nint TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tif ( !attrib )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\treturn attrib->QueryIntValue( ival );\n}\n\n\nint TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const\n{\n\tconst TiXmlAttribute* node = attributeSet.Find( name );\n\tif ( !node )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\n\tint ival = 0;\n\tint result = node->QueryIntValue( &ival );\n\t*value = (unsigned)ival;\n\treturn result;\n}\n\n\nint TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const\n{\n\tconst TiXmlAttribute* node = attributeSet.Find( name );\n\tif ( !node )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\t\n\tint result = TIXML_WRONG_TYPE;\n\tif (    StringEqual( node->Value(), \"true\", true, TIXML_ENCODING_UNKNOWN ) \n\t\t || StringEqual( node->Value(), \"yes\", true, TIXML_ENCODING_UNKNOWN ) \n\t\t || StringEqual( node->Value(), \"1\", true, TIXML_ENCODING_UNKNOWN ) ) \n\t{\n\t\t*bval = true;\n\t\tresult = TIXML_SUCCESS;\n\t}\n\telse if (    StringEqual( node->Value(), \"false\", true, TIXML_ENCODING_UNKNOWN ) \n\t\t\t  || StringEqual( node->Value(), \"no\", true, TIXML_ENCODING_UNKNOWN ) \n\t\t\t  || StringEqual( node->Value(), \"0\", true, TIXML_ENCODING_UNKNOWN ) ) \n\t{\n\t\t*bval = false;\n\t\tresult = TIXML_SUCCESS;\n\t}\n\treturn result;\n}\n\n\n\n#ifdef TIXML_USE_STL\nint TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tif ( !attrib )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\treturn attrib->QueryIntValue( ival );\n}\n#endif\n\n\nint TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tif ( !attrib )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\treturn attrib->QueryDoubleValue( dval );\n}\n\n\n#ifdef TIXML_USE_STL\nint TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const\n{\n\tconst TiXmlAttribute* attrib = attributeSet.Find( name );\n\tif ( !attrib )\n\t\treturn TIXML_NO_ATTRIBUTE;\n\treturn attrib->QueryDoubleValue( dval );\n}\n#endif\n\n\nvoid TiXmlElement::SetAttribute( const char * name, int val )\n{\t\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( name );\n\tif ( attrib ) {\n\t\tattrib->SetIntValue( val );\n\t}\n}\n\n\n#ifdef TIXML_USE_STL\nvoid TiXmlElement::SetAttribute( const std::string& name, int val )\n{\t\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( name );\n\tif ( attrib ) {\n\t\tattrib->SetIntValue( val );\n\t}\n}\n#endif\n\n\nvoid TiXmlElement::SetDoubleAttribute( const char * name, double val )\n{\t\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( name );\n\tif ( attrib ) {\n\t\tattrib->SetDoubleValue( val );\n\t}\n}\n\n\n#ifdef TIXML_USE_STL\nvoid TiXmlElement::SetDoubleAttribute( const std::string& name, double val )\n{\t\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( name );\n\tif ( attrib ) {\n\t\tattrib->SetDoubleValue( val );\n\t}\n}\n#endif \n\n\nvoid TiXmlElement::SetAttribute( const char * cname, const char * cvalue )\n{\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( cname );\n\tif ( attrib ) {\n\t\tattrib->SetValue( cvalue );\n\t}\n}\n\n\n#ifdef TIXML_USE_STL\nvoid TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value )\n{\n\tTiXmlAttribute* attrib = attributeSet.FindOrCreate( _name );\n\tif ( attrib ) {\n\t\tattrib->SetValue( _value );\n\t}\n}\n#endif\n\n\nvoid TiXmlElement::Print( FILE* cfile, int depth ) const\n{\n\tint i;\n\tassert( cfile );\n\tfor ( i=0; i<depth; i++ ) {\n\t\tfprintf( cfile, \"    \" );\n\t}\n\n\tfprintf( cfile, \"<%s\", value.c_str() );\n\n\tconst TiXmlAttribute* attrib;\n\tfor ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )\n\t{\n\t\tfprintf( cfile, \" \" );\n\t\tattrib->Print( cfile, depth );\n\t}\n\n\t// There are 3 different formatting approaches:\n\t// 1) An element without children is printed as a <foo /> node\n\t// 2) An element with only a text child is printed as <foo> text </foo>\n\t// 3) An element with children is printed on multiple lines.\n\tTiXmlNode* node;\n\tif ( !firstChild )\n\t{\n\t\tfprintf( cfile, \" />\" );\n\t}\n\telse if ( firstChild == lastChild && firstChild->ToText() )\n\t{\n\t\tfprintf( cfile, \">\" );\n\t\tfirstChild->Print( cfile, depth + 1 );\n\t\tfprintf( cfile, \"</%s>\", value.c_str() );\n\t}\n\telse\n\t{\n\t\tfprintf( cfile, \">\" );\n\n\t\tfor ( node = firstChild; node; node=node->NextSibling() )\n\t\t{\n\t\t\tif ( !node->ToText() )\n\t\t\t{\n\t\t\t\tfprintf( cfile, \"\\n\" );\n\t\t\t}\n\t\t\tnode->Print( cfile, depth+1 );\n\t\t}\n\t\tfprintf( cfile, \"\\n\" );\n\t\tfor( i=0; i<depth; ++i ) {\n\t\t\tfprintf( cfile, \"    \" );\n\t\t}\n\t\tfprintf( cfile, \"</%s>\", value.c_str() );\n\t}\n}\n\n\nvoid TiXmlElement::CopyTo( TiXmlElement* target ) const\n{\n\t// superclass:\n\tTiXmlNode::CopyTo( target );\n\n\t// Element class: \n\t// Clone the attributes, then clone the children.\n\tconst TiXmlAttribute* attribute = 0;\n\tfor(\tattribute = attributeSet.First();\n\tattribute;\n\tattribute = attribute->Next() )\n\t{\n\t\ttarget->SetAttribute( attribute->Name(), attribute->Value() );\n\t}\n\n\tTiXmlNode* node = 0;\n\tfor ( node = firstChild; node; node = node->NextSibling() )\n\t{\n\t\ttarget->LinkEndChild( node->Clone() );\n\t}\n}\n\nbool TiXmlElement::Accept( TiXmlVisitor* visitor ) const\n{\n\tif ( visitor->VisitEnter( *this, attributeSet.First() ) ) \n\t{\n\t\tfor ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )\n\t\t{\n\t\t\tif ( !node->Accept( visitor ) )\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn visitor->VisitExit( *this );\n}\n\n\nTiXmlNode* TiXmlElement::Clone() const\n{\n\tTiXmlElement* clone = new TiXmlElement( Value() );\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nconst char* TiXmlElement::GetText() const\n{\n\tconst TiXmlNode* child = this->FirstChild();\n\tif ( child ) {\n\t\tconst TiXmlText* childText = child->ToText();\n\t\tif ( childText ) {\n\t\t\treturn childText->Value();\n\t\t}\n\t}\n\treturn 0;\n}\n\n\nTiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )\n{\n\ttabsize = 4;\n\tuseMicrosoftBOM = false;\n\tClearError();\n}\n\nTiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )\n{\n\ttabsize = 4;\n\tuseMicrosoftBOM = false;\n\tvalue = documentName;\n\tClearError();\n}\n\n\n#ifdef TIXML_USE_STL\nTiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )\n{\n\ttabsize = 4;\n\tuseMicrosoftBOM = false;\n    value = documentName;\n\tClearError();\n}\n#endif\n\n\nTiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )\n{\n\tcopy.CopyTo( this );\n}\n\n\nTiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy )\n{\n\tClear();\n\tcopy.CopyTo( this );\n\treturn *this;\n}\n\n\nbool TiXmlDocument::LoadFile( TiXmlEncoding encoding )\n{\n\treturn LoadFile( Value(), encoding );\n}\n\n\nbool TiXmlDocument::SaveFile() const\n{\n\treturn SaveFile( Value() );\n}\n\nbool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )\n{\n\tTIXML_STRING filename( _filename );\n\tvalue = filename;\n\n\t// reading in binary mode so that tinyxml can normalize the EOL\n\tFILE* file = TiXmlFOpen( value.c_str (), \"rb\" );\t\n\n\tif ( file )\n\t{\n\t\tbool result = LoadFile( file, encoding );\n\t\tfclose( file );\n\t\treturn result;\n\t}\n\telse\n\t{\n\t\tSetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn false;\n\t}\n}\n\nbool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )\n{\n\tif ( !file ) \n\t{\n\t\tSetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn false;\n\t}\n\n\t// Delete the existing data:\n\tClear();\n\tlocation.Clear();\n\n\t// Get the file size, so we can pre-allocate the string. HUGE speed impact.\n\tlong length = 0;\n\tfseek( file, 0, SEEK_END );\n\tlength = ftell( file );\n\tfseek( file, 0, SEEK_SET );\n\n\t// Strange case, but good to handle up front.\n\tif ( length <= 0 )\n\t{\n\t\tSetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn false;\n\t}\n\n\t// Subtle bug here. TinyXml did use fgets. But from the XML spec:\n\t// 2.11 End-of-Line Handling\n\t// <snip>\n\t// <quote>\n\t// ...the XML processor MUST behave as if it normalized all line breaks in external \n\t// parsed entities (including the document entity) on input, before parsing, by translating \n\t// both the two-character sequence #xD #xA and any #xD that is not followed by #xA to \n\t// a single #xA character.\n\t// </quote>\n\t//\n\t// It is not clear fgets does that, and certainly isn't clear it works cross platform. \n\t// Generally, you expect fgets to translate from the convention of the OS to the c/unix\n\t// convention, and not work generally.\n\n\t/*\n\twhile( fgets( buf, sizeof(buf), file ) )\n\t{\n\t\tdata += buf;\n\t}\n\t*/\n\n\tchar* buf = new char[ length+1 ];\n\tbuf[0] = 0;\n\n\tif ( fread( buf, length, 1, file ) != 1 ) {\n\t\tdelete [] buf;\n\t\tSetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn false;\n\t}\n\n\t// Process the buffer in place to normalize new lines. (See comment above.)\n\t// Copies from the 'p' to 'q' pointer, where p can advance faster if\n\t// a newline-carriage return is hit.\n\t//\n\t// Wikipedia:\n\t// Systems based on ASCII or a compatible character set use either LF  (Line feed, '\\n', 0x0A, 10 in decimal) or \n\t// CR (Carriage return, '\\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)...\n\t//\t\t* LF:    Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others\n    //\t\t* 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\n    //\t\t* CR:    Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9\n\n\tconst char* p = buf;\t// the read head\n\tchar* q = buf;\t\t\t// the write head\n\tconst char CR = 0x0d;\n\tconst char LF = 0x0a;\n\n\tbuf[length] = 0;\n\twhile( *p ) {\n\t\tassert( p < (buf+length) );\n\t\tassert( q <= (buf+length) );\n\t\tassert( q <= p );\n\n\t\tif ( *p == CR ) {\n\t\t\t*q++ = LF;\n\t\t\tp++;\n\t\t\tif ( *p == LF ) {\t\t// check for CR+LF (and skip LF)\n\t\t\t\tp++;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t*q++ = *p++;\n\t\t}\n\t}\n\tassert( q <= (buf+length) );\n\t*q = 0;\n\n\tParse( buf, 0, encoding );\n\n\tdelete [] buf;\n\treturn !Error();\n}\n\n\nbool TiXmlDocument::SaveFile( const char * filename ) const\n{\n\t// The old c stuff lives on...\n\tFILE* fp = TiXmlFOpen( filename, \"w\" );\n\tif ( fp )\n\t{\n\t\tbool result = SaveFile( fp );\n\t\tfclose( fp );\n\t\treturn result;\n\t}\n\treturn false;\n}\n\n\nbool TiXmlDocument::SaveFile( FILE* fp ) const\n{\n\tif ( useMicrosoftBOM ) \n\t{\n\t\tconst unsigned char TIXML_UTF_LEAD_0 = 0xefU;\n\t\tconst unsigned char TIXML_UTF_LEAD_1 = 0xbbU;\n\t\tconst unsigned char TIXML_UTF_LEAD_2 = 0xbfU;\n\n\t\tfputc( TIXML_UTF_LEAD_0, fp );\n\t\tfputc( TIXML_UTF_LEAD_1, fp );\n\t\tfputc( TIXML_UTF_LEAD_2, fp );\n\t}\n\tPrint( fp, 0 );\n\treturn (ferror(fp) == 0);\n}\n\n\nvoid TiXmlDocument::CopyTo( TiXmlDocument* target ) const\n{\n\tTiXmlNode::CopyTo( target );\n\n\ttarget->error = error;\n\ttarget->errorId = errorId;\n\ttarget->errorDesc = errorDesc;\n\ttarget->tabsize = tabsize;\n\ttarget->errorLocation = errorLocation;\n\ttarget->useMicrosoftBOM = useMicrosoftBOM;\n\n\tTiXmlNode* node = 0;\n\tfor ( node = firstChild; node; node = node->NextSibling() )\n\t{\n\t\ttarget->LinkEndChild( node->Clone() );\n\t}\t\n}\n\n\nTiXmlNode* TiXmlDocument::Clone() const\n{\n\tTiXmlDocument* clone = new TiXmlDocument();\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nvoid TiXmlDocument::Print( FILE* cfile, int depth ) const\n{\n\tassert( cfile );\n\tfor ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )\n\t{\n\t\tnode->Print( cfile, depth );\n\t\tfprintf( cfile, \"\\n\" );\n\t}\n}\n\n\nbool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const\n{\n\tif ( visitor->VisitEnter( *this ) )\n\t{\n\t\tfor ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )\n\t\t{\n\t\t\tif ( !node->Accept( visitor ) )\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn visitor->VisitExit( *this );\n}\n\n\nconst TiXmlAttribute* TiXmlAttribute::Next() const\n{\n\t// We are using knowledge of the sentinel. The sentinel\n\t// have a value or name.\n\tif ( next->value.empty() && next->name.empty() )\n\t\treturn 0;\n\treturn next;\n}\n\n/*\nTiXmlAttribute* TiXmlAttribute::Next()\n{\n\t// We are using knowledge of the sentinel. The sentinel\n\t// have a value or name.\n\tif ( next->value.empty() && next->name.empty() )\n\t\treturn 0;\n\treturn next;\n}\n*/\n\nconst TiXmlAttribute* TiXmlAttribute::Previous() const\n{\n\t// We are using knowledge of the sentinel. The sentinel\n\t// have a value or name.\n\tif ( prev->value.empty() && prev->name.empty() )\n\t\treturn 0;\n\treturn prev;\n}\n\n/*\nTiXmlAttribute* TiXmlAttribute::Previous()\n{\n\t// We are using knowledge of the sentinel. The sentinel\n\t// have a value or name.\n\tif ( prev->value.empty() && prev->name.empty() )\n\t\treturn 0;\n\treturn prev;\n}\n*/\n\nvoid TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const\n{\n\tTIXML_STRING n, v;\n\n\tEncodeString( name, &n );\n\tEncodeString( value, &v );\n\n\tif (value.find ('\\\"') == TIXML_STRING::npos) {\n\t\tif ( cfile ) {\n\t\t\tfprintf (cfile, \"%s=\\\"%s\\\"\", n.c_str(), v.c_str() );\n\t\t}\n\t\tif ( str ) {\n\t\t\t(*str) += n; (*str) += \"=\\\"\"; (*str) += v; (*str) += \"\\\"\";\n\t\t}\n\t}\n\telse {\n\t\tif ( cfile ) {\n\t\t\tfprintf (cfile, \"%s='%s'\", n.c_str(), v.c_str() );\n\t\t}\n\t\tif ( str ) {\n\t\t\t(*str) += n; (*str) += \"='\"; (*str) += v; (*str) += \"'\";\n\t\t}\n\t}\n}\n\n\nint TiXmlAttribute::QueryIntValue( int* ival ) const\n{\n\tif ( TIXML_SSCANF( value.c_str(), \"%d\", ival ) == 1 )\n\t\treturn TIXML_SUCCESS;\n\treturn TIXML_WRONG_TYPE;\n}\n\nint TiXmlAttribute::QueryDoubleValue( double* dval ) const\n{\n\tif ( TIXML_SSCANF( value.c_str(), \"%lf\", dval ) == 1 )\n\t\treturn TIXML_SUCCESS;\n\treturn TIXML_WRONG_TYPE;\n}\n\nvoid TiXmlAttribute::SetIntValue( int _value )\n{\n\tchar buf [64];\n\t#if defined(TIXML_SNPRINTF)\t\t\n\t\tTIXML_SNPRINTF(buf, sizeof(buf), \"%d\", _value);\n\t#else\n\t\tsprintf (buf, \"%d\", _value);\n\t#endif\n\tSetValue (buf);\n}\n\nvoid TiXmlAttribute::SetDoubleValue( double _value )\n{\n\tchar buf [256];\n\t#if defined(TIXML_SNPRINTF)\t\t\n\t\tTIXML_SNPRINTF( buf, sizeof(buf), \"%g\", _value);\n\t#else\n\t\tsprintf (buf, \"%g\", _value);\n\t#endif\n\tSetValue (buf);\n}\n\nint TiXmlAttribute::IntValue() const\n{\n\treturn atoi (value.c_str ());\n}\n\ndouble  TiXmlAttribute::DoubleValue() const\n{\n\treturn atof (value.c_str ());\n}\n\n\nTiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT )\n{\n\tcopy.CopyTo( this );\n}\n\n\nTiXmlComment& TiXmlComment::operator=( const TiXmlComment& base )\n{\n\tClear();\n\tbase.CopyTo( this );\n\treturn *this;\n}\n\n\nvoid TiXmlComment::Print( FILE* cfile, int depth ) const\n{\n\tassert( cfile );\n\tfor ( int i=0; i<depth; i++ )\n\t{\n\t\tfprintf( cfile,  \"    \" );\n\t}\n\tfprintf( cfile, \"<!--%s-->\", value.c_str() );\n}\n\n\nvoid TiXmlComment::CopyTo( TiXmlComment* target ) const\n{\n\tTiXmlNode::CopyTo( target );\n}\n\n\nbool TiXmlComment::Accept( TiXmlVisitor* visitor ) const\n{\n\treturn visitor->Visit( *this );\n}\n\n\nTiXmlNode* TiXmlComment::Clone() const\n{\n\tTiXmlComment* clone = new TiXmlComment();\n\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nvoid TiXmlText::Print( FILE* cfile, int depth ) const\n{\n\tassert( cfile );\n\tif ( cdata )\n\t{\n\t\tint i;\n\t\tfprintf( cfile, \"\\n\" );\n\t\tfor ( i=0; i<depth; i++ ) {\n\t\t\tfprintf( cfile, \"    \" );\n\t\t}\n\t\tfprintf( cfile, \"<![CDATA[%s]]>\\n\", value.c_str() );\t// unformatted output\n\t}\n\telse\n\t{\n\t\tTIXML_STRING buffer;\n\t\tEncodeString( value, &buffer );\n\t\tfprintf( cfile, \"%s\", buffer.c_str() );\n\t}\n}\n\n\nvoid TiXmlText::CopyTo( TiXmlText* target ) const\n{\n\tTiXmlNode::CopyTo( target );\n\ttarget->cdata = cdata;\n}\n\n\nbool TiXmlText::Accept( TiXmlVisitor* visitor ) const\n{\n\treturn visitor->Visit( *this );\n}\n\n\nTiXmlNode* TiXmlText::Clone() const\n{\t\n\tTiXmlText* clone = 0;\n\tclone = new TiXmlText( \"\" );\n\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nTiXmlDeclaration::TiXmlDeclaration( const char * _version,\n\t\t\t\t\t\t\t\t\tconst char * _encoding,\n\t\t\t\t\t\t\t\t\tconst char * _standalone )\n\t: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )\n{\n\tversion = _version;\n\tencoding = _encoding;\n\tstandalone = _standalone;\n}\n\n\n#ifdef TIXML_USE_STL\nTiXmlDeclaration::TiXmlDeclaration(\tconst std::string& _version,\n\t\t\t\t\t\t\t\t\tconst std::string& _encoding,\n\t\t\t\t\t\t\t\t\tconst std::string& _standalone )\n\t: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )\n{\n\tversion = _version;\n\tencoding = _encoding;\n\tstandalone = _standalone;\n}\n#endif\n\n\nTiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )\n\t: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )\n{\n\tcopy.CopyTo( this );\t\n}\n\n\nTiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )\n{\n\tClear();\n\tcopy.CopyTo( this );\n\treturn *this;\n}\n\n\nvoid TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const\n{\n\tif ( cfile ) fprintf( cfile, \"<?xml \" );\n\tif ( str )\t (*str) += \"<?xml \";\n\n\tif ( !version.empty() ) {\n\t\tif ( cfile ) fprintf (cfile, \"version=\\\"%s\\\" \", version.c_str ());\n\t\tif ( str ) { (*str) += \"version=\\\"\"; (*str) += version; (*str) += \"\\\" \"; }\n\t}\n\tif ( !encoding.empty() ) {\n\t\tif ( cfile ) fprintf (cfile, \"encoding=\\\"%s\\\" \", encoding.c_str ());\n\t\tif ( str ) { (*str) += \"encoding=\\\"\"; (*str) += encoding; (*str) += \"\\\" \"; }\n\t}\n\tif ( !standalone.empty() ) {\n\t\tif ( cfile ) fprintf (cfile, \"standalone=\\\"%s\\\" \", standalone.c_str ());\n\t\tif ( str ) { (*str) += \"standalone=\\\"\"; (*str) += standalone; (*str) += \"\\\" \"; }\n\t}\n\tif ( cfile ) fprintf( cfile, \"?>\" );\n\tif ( str )\t (*str) += \"?>\";\n}\n\n\nvoid TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const\n{\n\tTiXmlNode::CopyTo( target );\n\n\ttarget->version = version;\n\ttarget->encoding = encoding;\n\ttarget->standalone = standalone;\n}\n\n\nbool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const\n{\n\treturn visitor->Visit( *this );\n}\n\n\nTiXmlNode* TiXmlDeclaration::Clone() const\n{\t\n\tTiXmlDeclaration* clone = new TiXmlDeclaration();\n\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nvoid TiXmlUnknown::Print( FILE* cfile, int depth ) const\n{\n\tfor ( int i=0; i<depth; i++ )\n\t\tfprintf( cfile, \"    \" );\n\tfprintf( cfile, \"<%s>\", value.c_str() );\n}\n\n\nvoid TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const\n{\n\tTiXmlNode::CopyTo( target );\n}\n\n\nbool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const\n{\n\treturn visitor->Visit( *this );\n}\n\n\nTiXmlNode* TiXmlUnknown::Clone() const\n{\n\tTiXmlUnknown* clone = new TiXmlUnknown();\n\n\tif ( !clone )\n\t\treturn 0;\n\n\tCopyTo( clone );\n\treturn clone;\n}\n\n\nTiXmlAttributeSet::TiXmlAttributeSet()\n{\n\tsentinel.next = &sentinel;\n\tsentinel.prev = &sentinel;\n}\n\n\nTiXmlAttributeSet::~TiXmlAttributeSet()\n{\n\tassert( sentinel.next == &sentinel );\n\tassert( sentinel.prev == &sentinel );\n}\n\n\nvoid TiXmlAttributeSet::Add( TiXmlAttribute* addMe )\n{\n    #ifdef TIXML_USE_STL\n\tassert( !Find( TIXML_STRING( addMe->Name() ) ) );\t// Shouldn't be multiply adding to the set.\n\t#else\n\tassert( !Find( addMe->Name() ) );\t// Shouldn't be multiply adding to the set.\n\t#endif\n\n\taddMe->next = &sentinel;\n\taddMe->prev = sentinel.prev;\n\n\tsentinel.prev->next = addMe;\n\tsentinel.prev      = addMe;\n}\n\nvoid TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )\n{\n\tTiXmlAttribute* node;\n\n\tfor( node = sentinel.next; node != &sentinel; node = node->next )\n\t{\n\t\tif ( node == removeMe )\n\t\t{\n\t\t\tnode->prev->next = node->next;\n\t\t\tnode->next->prev = node->prev;\n\t\t\tnode->next = 0;\n\t\t\tnode->prev = 0;\n\t\t\treturn;\n\t\t}\n\t}\n\tassert( 0 );\t\t// we tried to remove a non-linked attribute.\n}\n\n\n#ifdef TIXML_USE_STL\nTiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const\n{\n\tfor( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )\n\t{\n\t\tif ( node->name == name )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\nTiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name )\n{\n\tTiXmlAttribute* attrib = Find( _name );\n\tif ( !attrib ) {\n\t\tattrib = new TiXmlAttribute();\n\t\tAdd( attrib );\n\t\tattrib->SetName( _name );\n\t}\n\treturn attrib;\n}\n#endif\n\n\nTiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const\n{\n\tfor( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )\n\t{\n\t\tif ( strcmp( node->name.c_str(), name ) == 0 )\n\t\t\treturn node;\n\t}\n\treturn 0;\n}\n\n\nTiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name )\n{\n\tTiXmlAttribute* attrib = Find( _name );\n\tif ( !attrib ) {\n\t\tattrib = new TiXmlAttribute();\n\t\tAdd( attrib );\n\t\tattrib->SetName( _name );\n\t}\n\treturn attrib;\n}\n\n\n#ifdef TIXML_USE_STL\t\nstd::istream& operator>> (std::istream & in, TiXmlNode & base)\n{\n\tTIXML_STRING tag;\n\ttag.reserve( 8 * 1000 );\n\tbase.StreamIn( &in, &tag );\n\n\tbase.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );\n\treturn in;\n}\n#endif\n\n\n#ifdef TIXML_USE_STL\t\nstd::ostream& operator<< (std::ostream & out, const TiXmlNode & base)\n{\n\tTiXmlPrinter printer;\n\tprinter.SetStreamPrinting();\n\tbase.Accept( &printer );\n\tout << printer.Str();\n\n\treturn out;\n}\n\n\nstd::string& operator<< (std::string& out, const TiXmlNode& base )\n{\n\tTiXmlPrinter printer;\n\tprinter.SetStreamPrinting();\n\tbase.Accept( &printer );\n\tout.append( printer.Str() );\n\n\treturn out;\n}\n#endif\n\n\nTiXmlHandle TiXmlHandle::FirstChild() const\n{\n\tif ( node )\n\t{\n\t\tTiXmlNode* child = node->FirstChild();\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::FirstChild( const char * value ) const\n{\n\tif ( node )\n\t{\n\t\tTiXmlNode* child = node->FirstChild( value );\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::FirstChildElement() const\n{\n\tif ( node )\n\t{\n\t\tTiXmlElement* child = node->FirstChildElement();\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const\n{\n\tif ( node )\n\t{\n\t\tTiXmlElement* child = node->FirstChildElement( value );\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::Child( int count ) const\n{\n\tif ( node )\n\t{\n\t\tint i;\n\t\tTiXmlNode* child = node->FirstChild();\n\t\tfor (\ti=0;\n\t\t\t\tchild && i<count;\n\t\t\t\tchild = child->NextSibling(), ++i )\n\t\t{\n\t\t\t// nothing\n\t\t}\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::Child( const char* value, int count ) const\n{\n\tif ( node )\n\t{\n\t\tint i;\n\t\tTiXmlNode* child = node->FirstChild( value );\n\t\tfor (\ti=0;\n\t\t\t\tchild && i<count;\n\t\t\t\tchild = child->NextSibling( value ), ++i )\n\t\t{\n\t\t\t// nothing\n\t\t}\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::ChildElement( int count ) const\n{\n\tif ( node )\n\t{\n\t\tint i;\n\t\tTiXmlElement* child = node->FirstChildElement();\n\t\tfor (\ti=0;\n\t\t\t\tchild && i<count;\n\t\t\t\tchild = child->NextSiblingElement(), ++i )\n\t\t{\n\t\t\t// nothing\n\t\t}\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nTiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const\n{\n\tif ( node )\n\t{\n\t\tint i;\n\t\tTiXmlElement* child = node->FirstChildElement( value );\n\t\tfor (\ti=0;\n\t\t\t\tchild && i<count;\n\t\t\t\tchild = child->NextSiblingElement( value ), ++i )\n\t\t{\n\t\t\t// nothing\n\t\t}\n\t\tif ( child )\n\t\t\treturn TiXmlHandle( child );\n\t}\n\treturn TiXmlHandle( 0 );\n}\n\n\nbool TiXmlPrinter::VisitEnter( const TiXmlDocument& )\n{\n\treturn true;\n}\n\nbool TiXmlPrinter::VisitExit( const TiXmlDocument& )\n{\n\treturn true;\n}\n\nbool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )\n{\n\tDoIndent();\n\tbuffer += \"<\";\n\tbuffer += element.Value();\n\n\tfor( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )\n\t{\n\t\tbuffer += \" \";\n\t\tattrib->Print( 0, 0, &buffer );\n\t}\n\n\tif ( !element.FirstChild() ) \n\t{\n\t\tbuffer += \" />\";\n\t\tDoLineBreak();\n\t}\n\telse \n\t{\n\t\tbuffer += \">\";\n\t\tif (    element.FirstChild()->ToText()\n\t\t\t  && element.LastChild() == element.FirstChild()\n\t\t\t  && element.FirstChild()->ToText()->CDATA() == false )\n\t\t{\n\t\t\tsimpleTextPrint = true;\n\t\t\t// no DoLineBreak()!\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoLineBreak();\n\t\t}\n\t}\n\t++depth;\t\n\treturn true;\n}\n\n\nbool TiXmlPrinter::VisitExit( const TiXmlElement& element )\n{\n\t--depth;\n\tif ( !element.FirstChild() ) \n\t{\n\t\t// nothing.\n\t}\n\telse \n\t{\n\t\tif ( simpleTextPrint )\n\t\t{\n\t\t\tsimpleTextPrint = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoIndent();\n\t\t}\n\t\tbuffer += \"</\";\n\t\tbuffer += element.Value();\n\t\tbuffer += \">\";\n\t\tDoLineBreak();\n\t}\n\treturn true;\n}\n\n\nbool TiXmlPrinter::Visit( const TiXmlText& text )\n{\n\tif ( text.CDATA() )\n\t{\n\t\tDoIndent();\n\t\tbuffer += \"<![CDATA[\";\n\t\tbuffer += text.Value();\n\t\tbuffer += \"]]>\";\n\t\tDoLineBreak();\n\t}\n\telse if ( simpleTextPrint )\n\t{\n\t\tTIXML_STRING str;\n\t\tTiXmlBase::EncodeString( text.ValueTStr(), &str );\n\t\tbuffer += str;\n\t}\n\telse\n\t{\n\t\tDoIndent();\n\t\tTIXML_STRING str;\n\t\tTiXmlBase::EncodeString( text.ValueTStr(), &str );\n\t\tbuffer += str;\n\t\tDoLineBreak();\n\t}\n\treturn true;\n}\n\n\nbool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )\n{\n\tDoIndent();\n\tdeclaration.Print( 0, 0, &buffer );\n\tDoLineBreak();\n\treturn true;\n}\n\n\nbool TiXmlPrinter::Visit( const TiXmlComment& comment )\n{\n\tDoIndent();\n\tbuffer += \"<!--\";\n\tbuffer += comment.Value();\n\tbuffer += \"-->\";\n\tDoLineBreak();\n\treturn true;\n}\n\n\nbool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )\n{\n\tDoIndent();\n\tbuffer += \"<\";\n\tbuffer += unknown.Value();\n\tbuffer += \">\";\n\tDoLineBreak();\n\treturn true;\n}\n\n"
  },
  {
    "path": "common/xml/tinyxml.h",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n\n#ifndef TINYXML_INCLUDED\n#define TINYXML_INCLUDED\n\n#ifdef _MSC_VER\n#pragma warning( push )\n#pragma warning( disable : 4530 )\n#pragma warning( disable : 4786 )\n#endif\n\n#include <ctype.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n// Help out windows:\n#if defined( _DEBUG ) && !defined( DEBUG )\n#define DEBUG\n#endif\n\n#ifdef TIXML_USE_STL\n\t#include <string>\n \t#include <iostream>\n\t#include <sstream>\n\t#define TIXML_STRING\t\tstd::string\n#else\n\t#include \"tinystr.h\"\n\t#define TIXML_STRING\t\tTiXmlString\n#endif\n\n// Deprecated library function hell. Compilers want to use the\n// new safe versions. This probably doesn't fully address the problem,\n// but it gets closer. There are too many compilers for me to fully\n// test. If you get compilation troubles, undefine TIXML_SAFE\n#define TIXML_SAFE\n\n#ifdef TIXML_SAFE\n\t#if defined(_MSC_VER) && (_MSC_VER >= 1400 )\n\t\t// Microsoft visual studio, version 2005 and higher.\n\t\t#define TIXML_SNPRINTF _snprintf_s\n\t\t#define TIXML_SSCANF   sscanf_s\n\t#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )\n\t\t// Microsoft visual studio, version 6 and higher.\n\t\t//#pragma message( \"Using _sn* functions.\" )\n\t\t#define TIXML_SNPRINTF _snprintf\n\t\t#define TIXML_SSCANF   sscanf\n\t#elif defined(__GNUC__) && (__GNUC__ >= 3 )\n\t\t// GCC version 3 and higher.s\n\t\t//#warning( \"Using sn* functions.\" )\n\t\t#define TIXML_SNPRINTF snprintf\n\t\t#define TIXML_SSCANF   sscanf\n\t#else\n\t\t#define TIXML_SNPRINTF snprintf\n\t\t#define TIXML_SSCANF   sscanf\n\t#endif\n#endif\t\n\nclass TiXmlDocument;\nclass TiXmlElement;\nclass TiXmlComment;\nclass TiXmlUnknown;\nclass TiXmlAttribute;\nclass TiXmlText;\nclass TiXmlDeclaration;\nclass TiXmlParsingData;\n\nconst int TIXML_MAJOR_VERSION = 2;\nconst int TIXML_MINOR_VERSION = 6;\nconst int TIXML_PATCH_VERSION = 2;\n\n/*\tInternal structure for tracking location of items \n\tin the XML file.\n*/\nstruct TiXmlCursor\n{\n\tTiXmlCursor()\t\t{ Clear(); }\n\tvoid Clear()\t\t{ row = col = -1; }\n\n\tint row;\t// 0 based.\n\tint col;\t// 0 based.\n};\n\n\n/**\n\tImplements the interface to the \"Visitor pattern\" (see the Accept() method.)\n\tIf you call the Accept() method, it requires being passed a TiXmlVisitor\n\tclass to handle callbacks. For nodes that contain other nodes (Document, Element)\n\tyou will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves\n\tare simply called with Visit().\n\n\tIf you return 'true' from a Visit method, recursive parsing will continue. If you return\n\tfalse, <b>no children of this node or its sibilings</b> will be Visited.\n\n\tAll flavors of Visit methods have a default implementation that returns 'true' (continue \n\tvisiting). You need to only override methods that are interesting to you.\n\n\tGenerally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.\n\n\tYou should never change the document from a callback.\n\n\t@sa TiXmlNode::Accept()\n*/\nclass TiXmlVisitor\n{\npublic:\n\tvirtual ~TiXmlVisitor() {}\n\n\t/// Visit a document.\n\tvirtual bool VisitEnter( const TiXmlDocument& /*doc*/ )\t\t\t{ return true; }\n\t/// Visit a document.\n\tvirtual bool VisitExit( const TiXmlDocument& /*doc*/ )\t\t\t{ return true; }\n\n\t/// Visit an element.\n\tvirtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ )\t{ return true; }\n\t/// Visit an element.\n\tvirtual bool VisitExit( const TiXmlElement& /*element*/ )\t\t{ return true; }\n\n\t/// Visit a declaration\n\tvirtual bool Visit( const TiXmlDeclaration& /*declaration*/ )\t{ return true; }\n\t/// Visit a text node\n\tvirtual bool Visit( const TiXmlText& /*text*/ )\t\t\t\t\t{ return true; }\n\t/// Visit a comment node\n\tvirtual bool Visit( const TiXmlComment& /*comment*/ )\t\t\t{ return true; }\n\t/// Visit an unknown node\n\tvirtual bool Visit( const TiXmlUnknown& /*unknown*/ )\t\t\t{ return true; }\n};\n\n// Only used by Attribute::Query functions\nenum \n{ \n\tTIXML_SUCCESS,\n\tTIXML_NO_ATTRIBUTE,\n\tTIXML_WRONG_TYPE\n};\n\n\n// Used by the parsing routines.\nenum TiXmlEncoding\n{\n\tTIXML_ENCODING_UNKNOWN,\n\tTIXML_ENCODING_UTF8,\n\tTIXML_ENCODING_LEGACY\n};\n\nconst TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;\n\n/** TiXmlBase is a base class for every class in TinyXml.\n\tIt does little except to establish that TinyXml classes\n\tcan be printed and provide some utility functions.\n\n\tIn XML, the document and elements can contain\n\tother elements and other types of nodes.\n\n\t@verbatim\n\tA Document can contain:\tElement\t(container or leaf)\n\t\t\t\t\t\t\tComment (leaf)\n\t\t\t\t\t\t\tUnknown (leaf)\n\t\t\t\t\t\t\tDeclaration( leaf )\n\n\tAn Element can contain:\tElement (container or leaf)\n\t\t\t\t\t\t\tText\t(leaf)\n\t\t\t\t\t\t\tAttributes (not on tree)\n\t\t\t\t\t\t\tComment (leaf)\n\t\t\t\t\t\t\tUnknown (leaf)\n\n\tA Decleration contains: Attributes (not on tree)\n\t@endverbatim\n*/\nclass TiXmlBase\n{\n\tfriend class TiXmlNode;\n\tfriend class TiXmlElement;\n\tfriend class TiXmlDocument;\n\npublic:\n\tTiXmlBase()\t:\tuserData(0)\t\t{}\n\tvirtual ~TiXmlBase()\t\t\t{}\n\n\t/**\tAll TinyXml classes can print themselves to a filestream\n\t\tor the string class (TiXmlString in non-STL mode, std::string\n\t\tin STL mode.) Either or both cfile and str can be null.\n\t\t\n\t\tThis is a formatted print, and will insert \n\t\ttabs and newlines.\n\t\t\n\t\t(For an unformatted stream, use the << operator.)\n\t*/\n\tvirtual void Print( FILE* cfile, int depth ) const = 0;\n\n\t/**\tThe world does not agree on whether white space should be kept or\n\t\tnot. In order to make everyone happy, these global, static functions\n\t\tare provided to set whether or not TinyXml will condense all white space\n\t\tinto a single space or not. The default is to condense. Note changing this\n\t\tvalue is not thread safe.\n\t*/\n\tstatic void SetCondenseWhiteSpace( bool condense )\t\t{ condenseWhiteSpace = condense; }\n\n\t/// Return the current white space setting.\n\tstatic bool IsWhiteSpaceCondensed()\t\t\t\t\t\t{ return condenseWhiteSpace; }\n\n\t/** Return the position, in the original source file, of this node or attribute.\n\t\tThe row and column are 1-based. (That is the first row and first column is\n\t\t1,1). If the returns values are 0 or less, then the parser does not have\n\t\ta row and column value.\n\n\t\tGenerally, the row and column value will be set when the TiXmlDocument::Load(),\n\t\tTiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set\n\t\twhen the DOM was created from operator>>.\n\n\t\tThe values reflect the initial load. Once the DOM is modified programmatically\n\t\t(by adding or changing nodes and attributes) the new values will NOT update to\n\t\treflect changes in the document.\n\n\t\tThere is a minor performance cost to computing the row and column. Computation\n\t\tcan be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.\n\n\t\t@sa TiXmlDocument::SetTabSize()\n\t*/\n\tint Row() const\t\t\t{ return location.row + 1; }\n\tint Column() const\t\t{ return location.col + 1; }\t///< See Row()\n\n\tvoid  SetUserData( void* user )\t\t\t{ userData = user; }\t///< Set a pointer to arbitrary user data.\n\tvoid* GetUserData()\t\t\t\t\t\t{ return userData; }\t///< Get a pointer to arbitrary user data.\n\tconst void* GetUserData() const \t\t{ return userData; }\t///< Get a pointer to arbitrary user data.\n\n\t// Table that returs, for a given lead byte, the total number of bytes\n\t// in the UTF-8 sequence.\n\tstatic const int utf8ByteTable[256];\n\n\tvirtual const char* Parse(\tconst char* p, \n\t\t\t\t\t\t\t\tTiXmlParsingData* data, \n\t\t\t\t\t\t\t\tTiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;\n\n\t/** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, \n\t\tor they will be transformed into entities!\n\t*/\n\tstatic void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );\n\n\tenum\n\t{\n\t\tTIXML_NO_ERROR = 0,\n\t\tTIXML_ERROR,\n\t\tTIXML_ERROR_OPENING_FILE,\n\t\tTIXML_ERROR_PARSING_ELEMENT,\n\t\tTIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,\n\t\tTIXML_ERROR_READING_ELEMENT_VALUE,\n\t\tTIXML_ERROR_READING_ATTRIBUTES,\n\t\tTIXML_ERROR_PARSING_EMPTY,\n\t\tTIXML_ERROR_READING_END_TAG,\n\t\tTIXML_ERROR_PARSING_UNKNOWN,\n\t\tTIXML_ERROR_PARSING_COMMENT,\n\t\tTIXML_ERROR_PARSING_DECLARATION,\n\t\tTIXML_ERROR_DOCUMENT_EMPTY,\n\t\tTIXML_ERROR_EMBEDDED_NULL,\n\t\tTIXML_ERROR_PARSING_CDATA,\n\t\tTIXML_ERROR_DOCUMENT_TOP_ONLY,\n\n\t\tTIXML_ERROR_STRING_COUNT\n\t};\n\nprotected:\n\n\tstatic const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );\n\n\tinline static bool IsWhiteSpace( char c )\t\t\n\t{ \n\t\treturn ( isspace( (unsigned char) c ) || c == '\\n' || c == '\\r' ); \n\t}\n\tinline static bool IsWhiteSpace( int c )\n\t{\n\t\tif ( c < 256 )\n\t\t\treturn IsWhiteSpace( (char) c );\n\t\treturn false;\t// Again, only truly correct for English/Latin...but usually works.\n\t}\n\n\t#ifdef TIXML_USE_STL\n\tstatic bool\tStreamWhiteSpace( std::istream * in, TIXML_STRING * tag );\n\tstatic bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );\n\t#endif\n\n\t/*\tReads an XML name into the string provided. Returns\n\t\ta pointer just past the last character of the name,\n\t\tor 0 if the function has an error.\n\t*/\n\tstatic const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );\n\n\t/*\tReads text. Returns a pointer past the given end tag.\n\t\tWickedly complex options, but it keeps the (sensitive) code in one place.\n\t*/\n\tstatic const char* ReadText(\tconst char* in,\t\t\t\t// where to start\n\t\t\t\t\t\t\t\t\tTIXML_STRING* text,\t\t\t// the string read\n\t\t\t\t\t\t\t\t\tbool ignoreWhiteSpace,\t\t// whether to keep the white space\n\t\t\t\t\t\t\t\t\tconst char* endTag,\t\t\t// what ends this text\n\t\t\t\t\t\t\t\t\tbool ignoreCase,\t\t\t// whether to ignore case in the end tag\n\t\t\t\t\t\t\t\t\tTiXmlEncoding encoding );\t// the current encoding\n\n\t// If an entity has been found, transform it into a character.\n\tstatic const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );\n\n\t// Get a character, while interpreting entities.\n\t// The length can be from 0 to 4 bytes.\n\tinline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )\n\t{\n\t\tassert( p );\n\t\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t\t{\n\t\t\t*length = utf8ByteTable[ *((const unsigned char*)p) ];\n\t\t\tassert( *length >= 0 && *length < 5 );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*length = 1;\n\t\t}\n\n\t\tif ( *length == 1 )\n\t\t{\n\t\t\tif ( *p == '&' )\n\t\t\t\treturn GetEntity( p, _value, length, encoding );\n\t\t\t*_value = *p;\n\t\t\treturn p+1;\n\t\t}\n\t\telse if ( *length )\n\t\t{\n\t\t\t//strncpy( _value, p, *length );\t// lots of compilers don't like this function (unsafe),\n\t\t\t\t\t\t\t\t\t\t\t\t// and the null terminator isn't needed\n\t\t\tfor( int i=0; p[i] && i<*length; ++i ) {\n\t\t\t\t_value[i] = p[i];\n\t\t\t}\n\t\t\treturn p + (*length);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Not valid text.\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t// Return true if the next characters in the stream are any of the endTag sequences.\n\t// Ignore case only works for english, and should only be relied on when comparing\n\t// to English words: StringEqual( p, \"version\", true ) is fine.\n\tstatic bool StringEqual(\tconst char* p,\n\t\t\t\t\t\t\t\tconst char* endTag,\n\t\t\t\t\t\t\t\tbool ignoreCase,\n\t\t\t\t\t\t\t\tTiXmlEncoding encoding );\n\n\tstatic const char* errorString[ TIXML_ERROR_STRING_COUNT ];\n\n\tTiXmlCursor location;\n\n    /// Field containing a generic user pointer\n\tvoid*\t\t\tuserData;\n\t\n\t// None of these methods are reliable for any language except English.\n\t// Good for approximation, not great for accuracy.\n\tstatic int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );\n\tstatic int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );\n\tinline static int ToLower( int v, TiXmlEncoding encoding )\n\t{\n\t\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t\t{\n\t\t\tif ( v < 128 ) return tolower( v );\n\t\t\treturn v;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn tolower( v );\n\t\t}\n\t}\n\tstatic void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );\n\nprivate:\n\tTiXmlBase( const TiXmlBase& );\t\t\t\t// not implemented.\n\tvoid operator=( const TiXmlBase& base );\t// not allowed.\n\n\tstruct Entity\n\t{\n\t\tconst char*     str;\n\t\tunsigned int\tstrLength;\n\t\tchar\t\t    chr;\n\t};\n\tenum\n\t{\n\t\tNUM_ENTITY = 5,\n\t\tMAX_ENTITY_LENGTH = 6\n\n\t};\n\tstatic Entity entity[ NUM_ENTITY ];\n\tstatic bool condenseWhiteSpace;\n};\n\n\n/** The parent class for everything in the Document Object Model.\n\t(Except for attributes).\n\tNodes have siblings, a parent, and children. A node can be\n\tin a document, or stand on its own. The type of a TiXmlNode\n\tcan be queried, and it can be cast to its more defined type.\n*/\nclass TiXmlNode : public TiXmlBase\n{\n\tfriend class TiXmlDocument;\n\tfriend class TiXmlElement;\n\npublic:\n\t#ifdef TIXML_USE_STL\t\n\n\t    /** An input stream operator, for every class. Tolerant of newlines and\n\t\t    formatting, but doesn't expect them.\n\t    */\n\t    friend std::istream& operator >> (std::istream& in, TiXmlNode& base);\n\n\t    /** An output stream operator, for every class. Note that this outputs\n\t\t    without any newlines or formatting, as opposed to Print(), which\n\t\t    includes tabs and new lines.\n\n\t\t    The operator<< and operator>> are not completely symmetric. Writing\n\t\t    a node to a stream is very well defined. You'll get a nice stream\n\t\t    of output, without any extra whitespace or newlines.\n\t\t    \n\t\t    But reading is not as well defined. (As it always is.) If you create\n\t\t    a TiXmlElement (for example) and read that from an input stream,\n\t\t    the text needs to define an element or junk will result. This is\n\t\t    true of all input streams, but it's worth keeping in mind.\n\n\t\t    A TiXmlDocument will read nodes until it reads a root element, and\n\t\t\tall the children of that root element.\n\t    */\t\n\t    friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);\n\n\t\t/// Appends the XML node or attribute to a std::string.\n\t\tfriend std::string& operator<< (std::string& out, const TiXmlNode& base );\n\n\t#endif\n\n\t/** The types of XML nodes supported by TinyXml. (All the\n\t\t\tunsupported types are picked up by UNKNOWN.)\n\t*/\n\tenum NodeType\n\t{\n\t\tTINYXML_DOCUMENT,\n\t\tTINYXML_ELEMENT,\n\t\tTINYXML_COMMENT,\n\t\tTINYXML_UNKNOWN,\n\t\tTINYXML_TEXT,\n\t\tTINYXML_DECLARATION,\n\t\tTINYXML_TYPECOUNT\n\t};\n\n\tvirtual ~TiXmlNode();\n\n\t/** The meaning of 'value' changes for the specific type of\n\t\tTiXmlNode.\n\t\t@verbatim\n\t\tDocument:\tfilename of the xml file\n\t\tElement:\tname of the element\n\t\tComment:\tthe comment text\n\t\tUnknown:\tthe tag contents\n\t\tText:\t\tthe text string\n\t\t@endverbatim\n\n\t\tThe subclasses will wrap this function.\n\t*/\n\tconst char *Value() const { return value.c_str (); }\n\n    #ifdef TIXML_USE_STL\n\t/** Return Value() as a std::string. If you only use STL,\n\t    this is more efficient than calling Value().\n\t\tOnly available in STL mode.\n\t*/\n\tconst std::string& ValueStr() const { return value; }\n\t#endif\n\n\tconst TIXML_STRING& ValueTStr() const { return value; }\n\n\t/** Changes the value of the node. Defined as:\n\t\t@verbatim\n\t\tDocument:\tfilename of the xml file\n\t\tElement:\tname of the element\n\t\tComment:\tthe comment text\n\t\tUnknown:\tthe tag contents\n\t\tText:\t\tthe text string\n\t\t@endverbatim\n\t*/\n\tvoid SetValue(const char * _value) { value = _value;}\n\n    #ifdef TIXML_USE_STL\n\t/// STL std::string form.\n\tvoid SetValue( const std::string& _value )\t{ value = _value; }\n\t#endif\n\n\t/// Delete all the children of this node. Does not affect 'this'.\n\tvoid Clear();\n\n\t/// One step up the DOM.\n\tTiXmlNode* Parent()\t\t\t\t\t\t\t{ return parent; }\n\tconst TiXmlNode* Parent() const\t\t\t\t{ return parent; }\n\n\tconst TiXmlNode* FirstChild()\tconst\t\t{ return firstChild; }\t///< The first child of this node. Will be null if there are no children.\n\tTiXmlNode* FirstChild()\t\t\t\t\t\t{ return firstChild; }\n\tconst TiXmlNode* FirstChild( const char * value ) const;\t\t\t///< The first child of this node with the matching 'value'. Will be null if none found.\n\t/// The first child of this node with the matching 'value'. Will be null if none found.\n\tTiXmlNode* FirstChild( const char * _value ) {\n\t\t// Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)\n\t\t// call the method, cast the return back to non-const.\n\t\treturn const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));\n\t}\n\tconst TiXmlNode* LastChild() const\t{ return lastChild; }\t\t/// The last child of this node. Will be null if there are no children.\n\tTiXmlNode* LastChild()\t{ return lastChild; }\n\t\n\tconst TiXmlNode* LastChild( const char * value ) const;\t\t\t/// The last child of this node matching 'value'. Will be null if there are no children.\n\tTiXmlNode* LastChild( const char * _value ) {\n\t\treturn const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));\n\t}\n\n    #ifdef TIXML_USE_STL\n\tconst TiXmlNode* FirstChild( const std::string& _value ) const\t{\treturn FirstChild (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlNode* FirstChild( const std::string& _value )\t\t\t\t{\treturn FirstChild (_value.c_str ());\t}\t///< STL std::string form.\n\tconst TiXmlNode* LastChild( const std::string& _value ) const\t{\treturn LastChild (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlNode* LastChild( const std::string& _value )\t\t\t\t{\treturn LastChild (_value.c_str ());\t}\t///< STL std::string form.\n\t#endif\n\n\t/** An alternate way to walk the children of a node.\n\t\tOne way to iterate over nodes is:\n\t\t@verbatim\n\t\t\tfor( child = parent->FirstChild(); child; child = child->NextSibling() )\n\t\t@endverbatim\n\n\t\tIterateChildren does the same thing with the syntax:\n\t\t@verbatim\n\t\t\tchild = 0;\n\t\t\twhile( child = parent->IterateChildren( child ) )\n\t\t@endverbatim\n\n\t\tIterateChildren takes the previous child as input and finds\n\t\tthe next one. If the previous child is null, it returns the\n\t\tfirst. IterateChildren will return null when done.\n\t*/\n\tconst TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;\n\tTiXmlNode* IterateChildren( const TiXmlNode* previous ) {\n\t\treturn const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );\n\t}\n\n\t/// This flavor of IterateChildren searches for children with a particular 'value'\n\tconst TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;\n\tTiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {\n\t\treturn const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );\n\t}\n\n    #ifdef TIXML_USE_STL\n\tconst TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const\t{\treturn IterateChildren (_value.c_str (), previous);\t}\t///< STL std::string form.\n\tTiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) {\treturn IterateChildren (_value.c_str (), previous);\t}\t///< STL std::string form.\n\t#endif\n\n\t/** Add a new node related to this. Adds a child past the LastChild.\n\t\tReturns a pointer to the new object or NULL if an error occured.\n\t*/\n\tTiXmlNode* InsertEndChild( const TiXmlNode& addThis );\n\n\n\t/** Add a new node related to this. Adds a child past the LastChild.\n\n\t\tNOTE: the node to be added is passed by pointer, and will be\n\t\thenceforth owned (and deleted) by tinyXml. This method is efficient\n\t\tand avoids an extra copy, but should be used with care as it\n\t\tuses a different memory model than the other insert functions.\n\n\t\t@sa InsertEndChild\n\t*/\n\tTiXmlNode* LinkEndChild( TiXmlNode* addThis );\n\n\t/** Add a new node related to this. Adds a child before the specified child.\n\t\tReturns a pointer to the new object or NULL if an error occured.\n\t*/\n\tTiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );\n\n\t/** Add a new node related to this. Adds a child after the specified child.\n\t\tReturns a pointer to the new object or NULL if an error occured.\n\t*/\n\tTiXmlNode* InsertAfterChild(  TiXmlNode* afterThis, const TiXmlNode& addThis );\n\n\t/** Replace a child of this node.\n\t\tReturns a pointer to the new object or NULL if an error occured.\n\t*/\n\tTiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );\n\n\t/// Delete a child of this node.\n\tbool RemoveChild( TiXmlNode* removeThis );\n\n\t/// Navigate to a sibling node.\n\tconst TiXmlNode* PreviousSibling() const\t\t\t{ return prev; }\n\tTiXmlNode* PreviousSibling()\t\t\t\t\t\t{ return prev; }\n\n\t/// Navigate to a sibling node.\n\tconst TiXmlNode* PreviousSibling( const char * ) const;\n\tTiXmlNode* PreviousSibling( const char *_prev ) {\n\t\treturn const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );\n\t}\n\n    #ifdef TIXML_USE_STL\n\tconst TiXmlNode* PreviousSibling( const std::string& _value ) const\t{\treturn PreviousSibling (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlNode* PreviousSibling( const std::string& _value ) \t\t\t{\treturn PreviousSibling (_value.c_str ());\t}\t///< STL std::string form.\n\tconst TiXmlNode* NextSibling( const std::string& _value) const\t\t{\treturn NextSibling (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlNode* NextSibling( const std::string& _value) \t\t\t\t\t{\treturn NextSibling (_value.c_str ());\t}\t///< STL std::string form.\n\t#endif\n\n\t/// Navigate to a sibling node.\n\tconst TiXmlNode* NextSibling() const\t\t\t\t{ return next; }\n\tTiXmlNode* NextSibling()\t\t\t\t\t\t\t{ return next; }\n\n\t/// Navigate to a sibling node with the given 'value'.\n\tconst TiXmlNode* NextSibling( const char * ) const;\n\tTiXmlNode* NextSibling( const char* _next ) {\n\t\treturn const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );\n\t}\n\n\t/** Convenience function to get through elements.\n\t\tCalls NextSibling and ToElement. Will skip all non-Element\n\t\tnodes. Returns 0 if there is not another element.\n\t*/\n\tconst TiXmlElement* NextSiblingElement() const;\n\tTiXmlElement* NextSiblingElement() {\n\t\treturn const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );\n\t}\n\n\t/** Convenience function to get through elements.\n\t\tCalls NextSibling and ToElement. Will skip all non-Element\n\t\tnodes. Returns 0 if there is not another element.\n\t*/\n\tconst TiXmlElement* NextSiblingElement( const char * ) const;\n\tTiXmlElement* NextSiblingElement( const char *_next ) {\n\t\treturn const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );\n\t}\n\n    #ifdef TIXML_USE_STL\n\tconst TiXmlElement* NextSiblingElement( const std::string& _value) const\t{\treturn NextSiblingElement (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlElement* NextSiblingElement( const std::string& _value)\t\t\t\t{\treturn NextSiblingElement (_value.c_str ());\t}\t///< STL std::string form.\n\t#endif\n\n\t/// Convenience function to get through elements.\n\tconst TiXmlElement* FirstChildElement()\tconst;\n\tTiXmlElement* FirstChildElement() {\n\t\treturn const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );\n\t}\n\n\t/// Convenience function to get through elements.\n\tconst TiXmlElement* FirstChildElement( const char * _value ) const;\n\tTiXmlElement* FirstChildElement( const char * _value ) {\n\t\treturn const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );\n\t}\n\n    #ifdef TIXML_USE_STL\n\tconst TiXmlElement* FirstChildElement( const std::string& _value ) const\t{\treturn FirstChildElement (_value.c_str ());\t}\t///< STL std::string form.\n\tTiXmlElement* FirstChildElement( const std::string& _value )\t\t\t\t{\treturn FirstChildElement (_value.c_str ());\t}\t///< STL std::string form.\n\t#endif\n\n\t/** Query the type (as an enumerated value, above) of this node.\n\t\tThe possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT,\n\t\t\t\t\t\t\t\tTINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION.\n\t*/\n\tint Type() const\t{ return type; }\n\n\t/** Return a pointer to the Document this node lives in.\n\t\tReturns null if not in a document.\n\t*/\n\tconst TiXmlDocument* GetDocument() const;\n\tTiXmlDocument* GetDocument() {\n\t\treturn const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );\n\t}\n\n\t/// Returns true if this node has no children.\n\tbool NoChildren() const\t\t\t\t\t\t{ return !firstChild; }\n\n\tvirtual const TiXmlDocument*    ToDocument()    const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual const TiXmlElement*     ToElement()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual const TiXmlComment*     ToComment()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual const TiXmlUnknown*     ToUnknown()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual const TiXmlText*        ToText()        const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\n\tvirtual TiXmlDocument*          ToDocument()    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual TiXmlElement*           ToElement()\t    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual TiXmlComment*           ToComment()     { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual TiXmlUnknown*           ToUnknown()\t    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual TiXmlText*\t            ToText()        { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\tvirtual TiXmlDeclaration*       ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.\n\n\t/** Create an exact duplicate of this node and return it. The memory must be deleted\n\t\tby the caller. \n\t*/\n\tvirtual TiXmlNode* Clone() const = 0;\n\n\t/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the \n\t\tXML tree will be conditionally visited and the host will be called back\n\t\tvia the TiXmlVisitor interface.\n\n\t\tThis is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse\n\t\tthe XML for the callbacks, so the performance of TinyXML is unchanged by using this\n\t\tinterface versus any other.)\n\n\t\tThe interface has been based on ideas from:\n\n\t\t- http://www.saxproject.org/\n\t\t- http://c2.com/cgi/wiki?HierarchicalVisitorPattern \n\n\t\tWhich are both good references for \"visiting\".\n\n\t\tAn example of using Accept():\n\t\t@verbatim\n\t\tTiXmlPrinter printer;\n\t\ttinyxmlDoc.Accept( &printer );\n\t\tconst char* xmlcstr = printer.CStr();\n\t\t@endverbatim\n\t*/\n\tvirtual bool Accept( TiXmlVisitor* visitor ) const = 0;\n\nprotected:\n\tTiXmlNode( NodeType _type );\n\n\t// Copy to the allocated object. Shared functionality between Clone, Copy constructor,\n\t// and the assignment operator.\n\tvoid CopyTo( TiXmlNode* target ) const;\n\n\t#ifdef TIXML_USE_STL\n\t    // The real work of the input operator.\n\tvirtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;\n\t#endif\n\n\t// Figure out what is at *p, and parse it. Returns null if it is not an xml node.\n\tTiXmlNode* Identify( const char* start, TiXmlEncoding encoding );\n\n\tTiXmlNode*\t\tparent;\n\tNodeType\t\ttype;\n\n\tTiXmlNode*\t\tfirstChild;\n\tTiXmlNode*\t\tlastChild;\n\n\tTIXML_STRING\tvalue;\n\n\tTiXmlNode*\t\tprev;\n\tTiXmlNode*\t\tnext;\n\nprivate:\n\tTiXmlNode( const TiXmlNode& );\t\t\t\t// not implemented.\n\tvoid operator=( const TiXmlNode& base );\t// not allowed.\n};\n\n\n/** An attribute is a name-value pair. Elements have an arbitrary\n\tnumber of attributes, each with a unique name.\n\n\t@note The attributes are not TiXmlNodes, since they are not\n\t\t  part of the tinyXML document object model. There are other\n\t\t  suggested ways to look at this problem.\n*/\nclass TiXmlAttribute : public TiXmlBase\n{\n\tfriend class TiXmlAttributeSet;\n\npublic:\n\t/// Construct an empty attribute.\n\tTiXmlAttribute() : TiXmlBase()\n\t{\n\t\tdocument = 0;\n\t\tprev = next = 0;\n\t}\n\n\t#ifdef TIXML_USE_STL\n\t/// std::string constructor.\n\tTiXmlAttribute( const std::string& _name, const std::string& _value )\n\t{\n\t\tname = _name;\n\t\tvalue = _value;\n\t\tdocument = 0;\n\t\tprev = next = 0;\n\t}\n\t#endif\n\n\t/// Construct an attribute with a name and value.\n\tTiXmlAttribute( const char * _name, const char * _value )\n\t{\n\t\tname = _name;\n\t\tvalue = _value;\n\t\tdocument = 0;\n\t\tprev = next = 0;\n\t}\n\n\tconst char*\t\tName()  const\t\t{ return name.c_str(); }\t\t///< Return the name of this attribute.\n\tconst char*\t\tValue() const\t\t{ return value.c_str(); }\t\t///< Return the value of this attribute.\n\t#ifdef TIXML_USE_STL\n\tconst std::string& ValueStr() const\t{ return value; }\t\t\t\t///< Return the value of this attribute.\n\t#endif\n\tint\t\t\t\tIntValue() const;\t\t\t\t\t\t\t\t\t///< Return the value of this attribute, converted to an integer.\n\tdouble\t\t\tDoubleValue() const;\t\t\t\t\t\t\t\t///< Return the value of this attribute, converted to a double.\n\n\t// Get the tinyxml string representation\n\tconst TIXML_STRING& NameTStr() const { return name; }\n\n\t/** QueryIntValue examines the value string. It is an alternative to the\n\t\tIntValue() method with richer error checking.\n\t\tIf the value is an integer, it is stored in 'value' and \n\t\tthe call returns TIXML_SUCCESS. If it is not\n\t\tan integer, it returns TIXML_WRONG_TYPE.\n\n\t\tA specialized but useful call. Note that for success it returns 0,\n\t\twhich is the opposite of almost all other TinyXml calls.\n\t*/\n\tint QueryIntValue( int* _value ) const;\n\t/// QueryDoubleValue examines the value string. See QueryIntValue().\n\tint QueryDoubleValue( double* _value ) const;\n\n\tvoid SetName( const char* _name )\t{ name = _name; }\t\t\t\t///< Set the name of this attribute.\n\tvoid SetValue( const char* _value )\t{ value = _value; }\t\t\t\t///< Set the value.\n\n\tvoid SetIntValue( int _value );\t\t\t\t\t\t\t\t\t\t///< Set the value from an integer.\n\tvoid SetDoubleValue( double _value );\t\t\t\t\t\t\t\t///< Set the value from a double.\n\n    #ifdef TIXML_USE_STL\n\t/// STL std::string form.\n\tvoid SetName( const std::string& _name )\t{ name = _name; }\t\n\t/// STL std::string form.\t\n\tvoid SetValue( const std::string& _value )\t{ value = _value; }\n\t#endif\n\n\t/// Get the next sibling attribute in the DOM. Returns null at end.\n\tconst TiXmlAttribute* Next() const;\n\tTiXmlAttribute* Next() {\n\t\treturn const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); \n\t}\n\n\t/// Get the previous sibling attribute in the DOM. Returns null at beginning.\n\tconst TiXmlAttribute* Previous() const;\n\tTiXmlAttribute* Previous() {\n\t\treturn const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); \n\t}\n\n\tbool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }\n\tbool operator<( const TiXmlAttribute& rhs )\t const { return name < rhs.name; }\n\tbool operator>( const TiXmlAttribute& rhs )  const { return name > rhs.name; }\n\n\t/*\tAttribute parsing starts: first letter of the name\n\t\t\t\t\t\t returns: the next char after the value end quote\n\t*/\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\t// Prints this Attribute to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth ) const {\n\t\tPrint( cfile, depth, 0 );\n\t}\n\tvoid Print( FILE* cfile, int depth, TIXML_STRING* str ) const;\n\n\t// [internal use]\n\t// Set the document pointer so the attribute can report errors.\n\tvoid SetDocument( TiXmlDocument* doc )\t{ document = doc; }\n\nprivate:\n\tTiXmlAttribute( const TiXmlAttribute& );\t\t\t\t// not implemented.\n\tvoid operator=( const TiXmlAttribute& base );\t// not allowed.\n\n\tTiXmlDocument*\tdocument;\t// A pointer back to a document, for error reporting.\n\tTIXML_STRING name;\n\tTIXML_STRING value;\n\tTiXmlAttribute*\tprev;\n\tTiXmlAttribute*\tnext;\n};\n\n\n/*\tA class used to manage a group of attributes.\n\tIt is only used internally, both by the ELEMENT and the DECLARATION.\n\t\n\tThe set can be changed transparent to the Element and Declaration\n\tclasses that use it, but NOT transparent to the Attribute\n\twhich has to implement a next() and previous() method. Which makes\n\tit a bit problematic and prevents the use of STL.\n\n\tThis version is implemented with circular lists because:\n\t\t- I like circular lists\n\t\t- it demonstrates some independence from the (typical) doubly linked list.\n*/\nclass TiXmlAttributeSet\n{\npublic:\n\tTiXmlAttributeSet();\n\t~TiXmlAttributeSet();\n\n\tvoid Add( TiXmlAttribute* attribute );\n\tvoid Remove( TiXmlAttribute* attribute );\n\n\tconst TiXmlAttribute* First()\tconst\t{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }\n\tTiXmlAttribute* First()\t\t\t\t\t{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }\n\tconst TiXmlAttribute* Last() const\t\t{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }\n\tTiXmlAttribute* Last()\t\t\t\t\t{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }\n\n\tTiXmlAttribute*\tFind( const char* _name ) const;\n\tTiXmlAttribute* FindOrCreate( const char* _name );\n\n#\tifdef TIXML_USE_STL\n\tTiXmlAttribute*\tFind( const std::string& _name ) const;\n\tTiXmlAttribute* FindOrCreate( const std::string& _name );\n#\tendif\n\n\nprivate:\n\t//*ME:\tBecause of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),\n\t//*ME:\tthis class must be also use a hidden/disabled copy-constructor !!!\n\tTiXmlAttributeSet( const TiXmlAttributeSet& );\t// not allowed\n\tvoid operator=( const TiXmlAttributeSet& );\t// not allowed (as TiXmlAttribute)\n\n\tTiXmlAttribute sentinel;\n};\n\n\n/** The element is a container class. It has a value, the element name,\n\tand can contain other elements, text, comments, and unknowns.\n\tElements also contain an arbitrary number of attributes.\n*/\nclass TiXmlElement : public TiXmlNode\n{\npublic:\n\t/// Construct an element.\n\tTiXmlElement (const char * in_value);\n\n\t#ifdef TIXML_USE_STL\n\t/// std::string constructor.\n\tTiXmlElement( const std::string& _value );\n\t#endif\n\n\tTiXmlElement( const TiXmlElement& );\n\n\tTiXmlElement& operator=( const TiXmlElement& base );\n\n\tvirtual ~TiXmlElement();\n\n\t/** Given an attribute name, Attribute() returns the value\n\t\tfor the attribute of that name, or null if none exists.\n\t*/\n\tconst char* Attribute( const char* name ) const;\n\n\t/** Given an attribute name, Attribute() returns the value\n\t\tfor the attribute of that name, or null if none exists.\n\t\tIf the attribute exists and can be converted to an integer,\n\t\tthe integer value will be put in the return 'i', if 'i'\n\t\tis non-null.\n\t*/\n\tconst char* Attribute( const char* name, int* i ) const;\n\n\t/** Given an attribute name, Attribute() returns the value\n\t\tfor the attribute of that name, or null if none exists.\n\t\tIf the attribute exists and can be converted to an double,\n\t\tthe double value will be put in the return 'd', if 'd'\n\t\tis non-null.\n\t*/\n\tconst char* Attribute( const char* name, double* d ) const;\n\n\t/** QueryIntAttribute examines the attribute - it is an alternative to the\n\t\tAttribute() method with richer error checking.\n\t\tIf the attribute is an integer, it is stored in 'value' and \n\t\tthe call returns TIXML_SUCCESS. If it is not\n\t\tan integer, it returns TIXML_WRONG_TYPE. If the attribute\n\t\tdoes not exist, then TIXML_NO_ATTRIBUTE is returned.\n\t*/\t\n\tint QueryIntAttribute( const char* name, int* _value ) const;\n\t/// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute().\n\tint QueryUnsignedAttribute( const char* name, unsigned* _value ) const;\n\t/** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). \n\t\tNote that '1', 'true', or 'yes' are considered true, while '0', 'false'\n\t\tand 'no' are considered false.\n\t*/\n\tint QueryBoolAttribute( const char* name, bool* _value ) const;\n\t/// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().\n\tint QueryDoubleAttribute( const char* name, double* _value ) const;\n\t/// QueryFloatAttribute examines the attribute - see QueryIntAttribute().\n\tint QueryFloatAttribute( const char* name, float* _value ) const {\n\t\tdouble d;\n\t\tint result = QueryDoubleAttribute( name, &d );\n\t\tif ( result == TIXML_SUCCESS ) {\n\t\t\t*_value = (float)d;\n\t\t}\n\t\treturn result;\n\t}\n\n    #ifdef TIXML_USE_STL\n\t/// QueryStringAttribute examines the attribute - see QueryIntAttribute().\n\tint QueryStringAttribute( const char* name, std::string* _value ) const {\n\t\tconst char* cstr = Attribute( name );\n\t\tif ( cstr ) {\n\t\t\t*_value = std::string( cstr );\n\t\t\treturn TIXML_SUCCESS;\n\t\t}\n\t\treturn TIXML_NO_ATTRIBUTE;\n\t}\n\n\t/** Template form of the attribute query which will try to read the\n\t\tattribute into the specified type. Very easy, very powerful, but\n\t\tbe careful to make sure to call this with the correct type.\n\t\t\n\t\tNOTE: This method doesn't work correctly for 'string' types that contain spaces.\n\n\t\t@return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE\n\t*/\n\ttemplate< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const\n\t{\n\t\tconst TiXmlAttribute* node = attributeSet.Find( name );\n\t\tif ( !node )\n\t\t\treturn TIXML_NO_ATTRIBUTE;\n\n\t\tstd::stringstream sstream( node->ValueStr() );\n\t\tsstream >> *outValue;\n\t\tif ( !sstream.fail() )\n\t\t\treturn TIXML_SUCCESS;\n\t\treturn TIXML_WRONG_TYPE;\n\t}\n\n\tint QueryValueAttribute( const std::string& name, std::string* outValue ) const\n\t{\n\t\tconst TiXmlAttribute* node = attributeSet.Find( name );\n\t\tif ( !node )\n\t\t\treturn TIXML_NO_ATTRIBUTE;\n\t\t*outValue = node->ValueStr();\n\t\treturn TIXML_SUCCESS;\n\t}\n\t#endif\n\n\t/** Sets an attribute of name to a given value. The attribute\n\t\twill be created if it does not exist, or changed if it does.\n\t*/\n\tvoid SetAttribute( const char* name, const char * _value );\n\n    #ifdef TIXML_USE_STL\n\tconst std::string* Attribute( const std::string& name ) const;\n\tconst std::string* Attribute( const std::string& name, int* i ) const;\n\tconst std::string* Attribute( const std::string& name, double* d ) const;\n\tint QueryIntAttribute( const std::string& name, int* _value ) const;\n\tint QueryDoubleAttribute( const std::string& name, double* _value ) const;\n\n\t/// STL std::string form.\n\tvoid SetAttribute( const std::string& name, const std::string& _value );\n\t///< STL std::string form.\n\tvoid SetAttribute( const std::string& name, int _value );\n\t///< STL std::string form.\n\tvoid SetDoubleAttribute( const std::string& name, double value );\n\t#endif\n\n\t/** Sets an attribute of name to a given value. The attribute\n\t\twill be created if it does not exist, or changed if it does.\n\t*/\n\tvoid SetAttribute( const char * name, int value );\n\n\t/** Sets an attribute of name to a given value. The attribute\n\t\twill be created if it does not exist, or changed if it does.\n\t*/\n\tvoid SetDoubleAttribute( const char * name, double value );\n\n\t/** Deletes an attribute with the given name.\n\t*/\n\tvoid RemoveAttribute( const char * name );\n    #ifdef TIXML_USE_STL\n\tvoid RemoveAttribute( const std::string& name )\t{\tRemoveAttribute (name.c_str ());\t}\t///< STL std::string form.\n\t#endif\n\n\tconst TiXmlAttribute* FirstAttribute() const\t{ return attributeSet.First(); }\t\t///< Access the first attribute in this element.\n\tTiXmlAttribute* FirstAttribute() \t\t\t\t{ return attributeSet.First(); }\n\tconst TiXmlAttribute* LastAttribute()\tconst \t{ return attributeSet.Last(); }\t\t///< Access the last attribute in this element.\n\tTiXmlAttribute* LastAttribute()\t\t\t\t\t{ return attributeSet.Last(); }\n\n\t/** Convenience function for easy access to the text inside an element. Although easy\n\t\tand concise, GetText() is limited compared to getting the TiXmlText child\n\t\tand accessing it directly.\n\t\n\t\tIf the first child of 'this' is a TiXmlText, the GetText()\n\t\treturns the character string of the Text node, else null is returned.\n\n\t\tThis is a convenient method for getting the text of simple contained text:\n\t\t@verbatim\n\t\t<foo>This is text</foo>\n\t\tconst char* str = fooElement->GetText();\n\t\t@endverbatim\n\n\t\t'str' will be a pointer to \"This is text\". \n\t\t\n\t\tNote that this function can be misleading. If the element foo was created from\n\t\tthis XML:\n\t\t@verbatim\n\t\t<foo><b>This is text</b></foo> \n\t\t@endverbatim\n\n\t\tthen the value of str would be null. The first child node isn't a text node, it is\n\t\tanother element. From this XML:\n\t\t@verbatim\n\t\t<foo>This is <b>text</b></foo> \n\t\t@endverbatim\n\t\tGetText() will return \"This is \".\n\n\t\tWARNING: GetText() accesses a child node - don't become confused with the \n\t\t\t\t similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are \n\t\t\t\t safe type casts on the referenced node.\n\t*/\n\tconst char* GetText() const;\n\n\t/// Creates a new Element and returns it - the returned element is a copy.\n\tvirtual TiXmlNode* Clone() const;\n\t// Print the Element to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth ) const;\n\n\t/*\tAttribtue parsing starts: next char past '<'\n\t\t\t\t\t\t returns: next char past '>'\n\t*/\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlElement*     ToElement()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual TiXmlElement*           ToElement()\t          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* visitor ) const;\n\nprotected:\n\n\tvoid CopyTo( TiXmlElement* target ) const;\n\tvoid ClearThis();\t// like clear, but initializes 'this' object as well\n\n\t// Used to be public [internal use]\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n\t/*\t[internal use]\n\t\tReads the \"value\" of the element -- another element, or text.\n\t\tThis should terminate with the current end tag.\n\t*/\n\tconst char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );\n\nprivate:\n\tTiXmlAttributeSet attributeSet;\n};\n\n\n/**\tAn XML comment.\n*/\nclass TiXmlComment : public TiXmlNode\n{\npublic:\n\t/// Constructs an empty comment.\n\tTiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {}\n\t/// Construct a comment from text.\n\tTiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {\n\t\tSetValue( _value );\n\t}\n\tTiXmlComment( const TiXmlComment& );\n\tTiXmlComment& operator=( const TiXmlComment& base );\n\n\tvirtual ~TiXmlComment()\t{}\n\n\t/// Returns a copy of this Comment.\n\tvirtual TiXmlNode* Clone() const;\n\t// Write this Comment to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth ) const;\n\n\t/*\tAttribtue parsing starts: at the ! of the !--\n\t\t\t\t\t\t returns: next char past '>'\n\t*/\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlComment*  ToComment() const\t{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual\t\t  TiXmlComment*  ToComment()\t\t{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* visitor ) const;\n\nprotected:\n\tvoid CopyTo( TiXmlComment* target ) const;\n\n\t// used to be public\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n//\tvirtual void StreamOut( TIXML_OSTREAM * out ) const;\n\nprivate:\n\n};\n\n\n/** XML text. A text node can have 2 ways to output the next. \"normal\" output \n\tand CDATA. It will default to the mode it was parsed from the XML file and\n\tyou generally want to leave it alone, but you can change the output mode with \n\tSetCDATA() and query it with CDATA().\n*/\nclass TiXmlText : public TiXmlNode\n{\n\tfriend class TiXmlElement;\npublic:\n\t/** Constructor for text element. By default, it is treated as \n\t\tnormal, encoded text. If you want it be output as a CDATA text\n\t\telement, set the parameter _cdata to 'true'\n\t*/\n\tTiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)\n\t{\n\t\tSetValue( initValue );\n\t\tcdata = false;\n\t}\n\tvirtual ~TiXmlText() {}\n\n\t#ifdef TIXML_USE_STL\n\t/// Constructor.\n\tTiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)\n\t{\n\t\tSetValue( initValue );\n\t\tcdata = false;\n\t}\n\t#endif\n\n\tTiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT )\t{ copy.CopyTo( this ); }\n\tTiXmlText& operator=( const TiXmlText& base )\t\t\t\t\t\t\t \t{ base.CopyTo( this ); return *this; }\n\n\t// Write this text object to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth ) const;\n\n\t/// Queries whether this represents text using a CDATA section.\n\tbool CDATA() const\t\t\t\t{ return cdata; }\n\t/// Turns on or off a CDATA representation of text.\n\tvoid SetCDATA( bool _cdata )\t{ cdata = _cdata; }\n\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual TiXmlText*       ToText()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* content ) const;\n\nprotected :\n\t///  [internal use] Creates a new Element and returns it.\n\tvirtual TiXmlNode* Clone() const;\n\tvoid CopyTo( TiXmlText* target ) const;\n\n\tbool Blank() const;\t// returns true if all white space and new lines\n\t// [internal use]\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n\nprivate:\n\tbool cdata;\t\t\t// true if this should be input and output as a CDATA style text element\n};\n\n\n/** In correct XML the declaration is the first entry in the file.\n\t@verbatim\n\t\t<?xml version=\"1.0\" standalone=\"yes\"?>\n\t@endverbatim\n\n\tTinyXml will happily read or write files without a declaration,\n\thowever. There are 3 possible attributes to the declaration:\n\tversion, encoding, and standalone.\n\n\tNote: In this version of the code, the attributes are\n\thandled as special cases, not generic attributes, simply\n\tbecause there can only be at most 3 and they are always the same.\n*/\nclass TiXmlDeclaration : public TiXmlNode\n{\npublic:\n\t/// Construct an empty declaration.\n\tTiXmlDeclaration()   : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {}\n\n#ifdef TIXML_USE_STL\n\t/// Constructor.\n\tTiXmlDeclaration(\tconst std::string& _version,\n\t\t\t\t\t\tconst std::string& _encoding,\n\t\t\t\t\t\tconst std::string& _standalone );\n#endif\n\n\t/// Construct.\n\tTiXmlDeclaration(\tconst char* _version,\n\t\t\t\t\t\tconst char* _encoding,\n\t\t\t\t\t\tconst char* _standalone );\n\n\tTiXmlDeclaration( const TiXmlDeclaration& copy );\n\tTiXmlDeclaration& operator=( const TiXmlDeclaration& copy );\n\n\tvirtual ~TiXmlDeclaration()\t{}\n\n\t/// Version. Will return an empty string if none was found.\n\tconst char *Version() const\t\t\t{ return version.c_str (); }\n\t/// Encoding. Will return an empty string if none was found.\n\tconst char *Encoding() const\t\t{ return encoding.c_str (); }\n\t/// Is this a standalone document?\n\tconst char *Standalone() const\t\t{ return standalone.c_str (); }\n\n\t/// Creates a copy of this Declaration and returns it.\n\tvirtual TiXmlNode* Clone() const;\n\t// Print this declaration to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;\n\tvirtual void Print( FILE* cfile, int depth ) const {\n\t\tPrint( cfile, depth, 0 );\n\t}\n\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual TiXmlDeclaration*       ToDeclaration()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* visitor ) const;\n\nprotected:\n\tvoid CopyTo( TiXmlDeclaration* target ) const;\n\t// used to be public\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n\nprivate:\n\n\tTIXML_STRING version;\n\tTIXML_STRING encoding;\n\tTIXML_STRING standalone;\n};\n\n\n/** Any tag that tinyXml doesn't recognize is saved as an\n\tunknown. It is a tag of text, but should not be modified.\n\tIt will be written back to the XML, unchanged, when the file\n\tis saved.\n\n\tDTD tags get thrown into TiXmlUnknowns.\n*/\nclass TiXmlUnknown : public TiXmlNode\n{\npublic:\n\tTiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )\t{}\n\tvirtual ~TiXmlUnknown() {}\n\n\tTiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )\t\t{ copy.CopyTo( this ); }\n\tTiXmlUnknown& operator=( const TiXmlUnknown& copy )\t\t\t\t\t\t\t\t\t\t{ copy.CopyTo( this ); return *this; }\n\n\t/// Creates a copy of this Unknown and returns it.\n\tvirtual TiXmlNode* Clone() const;\n\t// Print this Unknown to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth ) const;\n\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlUnknown*     ToUnknown()     const\t{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual TiXmlUnknown*           ToUnknown()\t\t\t\t{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* content ) const;\n\nprotected:\n\tvoid CopyTo( TiXmlUnknown* target ) const;\n\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n\nprivate:\n\n};\n\n\n/** Always the top level node. A document binds together all the\n\tXML pieces. It can be saved, loaded, and printed to the screen.\n\tThe 'value' of a document node is the xml file name.\n*/\nclass TiXmlDocument : public TiXmlNode\n{\npublic:\n\t/// Create an empty document, that has no name.\n\tTiXmlDocument();\n\t/// Create a document with a name. The name of the document is also the filename of the xml.\n\tTiXmlDocument( const char * documentName );\n\n\t#ifdef TIXML_USE_STL\n\t/// Constructor.\n\tTiXmlDocument( const std::string& documentName );\n\t#endif\n\n\tTiXmlDocument( const TiXmlDocument& copy );\n\tTiXmlDocument& operator=( const TiXmlDocument& copy );\n\n\tvirtual ~TiXmlDocument() {}\n\n\t/** Load a file using the current document value.\n\t\tReturns true if successful. Will delete any existing\n\t\tdocument data before loading.\n\t*/\n\tbool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );\n\t/// Save a file using the current document value. Returns true if successful.\n\tbool SaveFile() const;\n\t/// Load a file using the given filename. Returns true if successful.\n\tbool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );\n\t/// Save a file using the given filename. Returns true if successful.\n\tbool SaveFile( const char * filename ) const;\n\t/** Load a file using the given FILE*. Returns true if successful. Note that this method\n\t\tdoesn't stream - the entire object pointed at by the FILE*\n\t\twill be interpreted as an XML file. TinyXML doesn't stream in XML from the current\n\t\tfile location. Streaming may be added in the future.\n\t*/\n\tbool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );\n\t/// Save a file using the given FILE*. Returns true if successful.\n\tbool SaveFile( FILE* ) const;\n\n\t#ifdef TIXML_USE_STL\n\tbool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING )\t\t\t///< STL std::string version.\n\t{\n\t\treturn LoadFile( filename.c_str(), encoding );\n\t}\n\tbool SaveFile( const std::string& filename ) const\t\t///< STL std::string version.\n\t{\n\t\treturn SaveFile( filename.c_str() );\n\t}\n\t#endif\n\n\t/** Parse the given null terminated block of xml data. Passing in an encoding to this\n\t\tmethod (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml\n\t\tto use that encoding, regardless of what TinyXml might otherwise try to detect.\n\t*/\n\tvirtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );\n\n\t/** Get the root element -- the only top level element -- of the document.\n\t\tIn well formed XML, there should only be one. TinyXml is tolerant of\n\t\tmultiple elements at the document level.\n\t*/\n\tconst TiXmlElement* RootElement() const\t\t{ return FirstChildElement(); }\n\tTiXmlElement* RootElement()\t\t\t\t\t{ return FirstChildElement(); }\n\n\t/** If an error occurs, Error will be set to true. Also,\n\t\t- The ErrorId() will contain the integer identifier of the error (not generally useful)\n\t\t- The ErrorDesc() method will return the name of the error. (very useful)\n\t\t- The ErrorRow() and ErrorCol() will return the location of the error (if known)\n\t*/\t\n\tbool Error() const\t\t\t\t\t\t{ return error; }\n\n\t/// Contains a textual (english) description of the error if one occurs.\n\tconst char * ErrorDesc() const\t{ return errorDesc.c_str (); }\n\n\t/** Generally, you probably want the error string ( ErrorDesc() ). But if you\n\t\tprefer the ErrorId, this function will fetch it.\n\t*/\n\tint ErrorId()\tconst\t\t\t\t{ return errorId; }\n\n\t/** Returns the location (if known) of the error. The first column is column 1, \n\t\tand the first row is row 1. A value of 0 means the row and column wasn't applicable\n\t\t(memory errors, for example, have no row/column) or the parser lost the error. (An\n\t\terror in the error reporting, in that case.)\n\n\t\t@sa SetTabSize, Row, Column\n\t*/\n\tint ErrorRow() const\t{ return errorLocation.row+1; }\n\tint ErrorCol() const\t{ return errorLocation.col+1; }\t///< The column where the error occured. See ErrorRow()\n\n\t/** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())\n\t\tto report the correct values for row and column. It does not change the output\n\t\tor input in any way.\n\t\t\n\t\tBy calling this method, with a tab size\n\t\tgreater than 0, the row and column of each node and attribute is stored\n\t\twhen the file is loaded. Very useful for tracking the DOM back in to\n\t\tthe source file.\n\n\t\tThe tab size is required for calculating the location of nodes. If not\n\t\tset, the default of 4 is used. The tabsize is set per document. Setting\n\t\tthe tabsize to 0 disables row/column tracking.\n\n\t\tNote that row and column tracking is not supported when using operator>>.\n\n\t\tThe tab size needs to be enabled before the parse or load. Correct usage:\n\t\t@verbatim\n\t\tTiXmlDocument doc;\n\t\tdoc.SetTabSize( 8 );\n\t\tdoc.Load( \"myfile.xml\" );\n\t\t@endverbatim\n\n\t\t@sa Row, Column\n\t*/\n\tvoid SetTabSize( int _tabsize )\t\t{ tabsize = _tabsize; }\n\n\tint TabSize() const\t{ return tabsize; }\n\n\t/** If you have handled the error, it can be reset with this call. The error\n\t\tstate is automatically cleared if you Parse a new XML block.\n\t*/\n\tvoid ClearError()\t\t\t\t\t\t{\terror = false; \n\t\t\t\t\t\t\t\t\t\t\t\terrorId = 0; \n\t\t\t\t\t\t\t\t\t\t\t\terrorDesc = \"\"; \n\t\t\t\t\t\t\t\t\t\t\t\terrorLocation.row = errorLocation.col = 0; \n\t\t\t\t\t\t\t\t\t\t\t\t//errorLocation.last = 0; \n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t/** Write the document to standard out using formatted printing (\"pretty print\"). */\n\tvoid Print() const\t\t\t\t\t\t{ Print( stdout, 0 ); }\n\n\t/* Write the document to a string using formatted printing (\"pretty print\"). This\n\t\twill allocate a character array (new char[]) and return it as a pointer. The\n\t\tcalling code pust call delete[] on the return char* to avoid a memory leak.\n\t*/\n\t//char* PrintToMemory() const; \n\n\t/// Print this Document to a FILE stream.\n\tvirtual void Print( FILE* cfile, int depth = 0 ) const;\n\t// [internal use]\n\tvoid SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );\n\n\tvirtual const TiXmlDocument*    ToDocument()    const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\tvirtual TiXmlDocument*          ToDocument()          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.\n\n\t/** Walk the XML tree visiting this node and all of its children. \n\t*/\n\tvirtual bool Accept( TiXmlVisitor* content ) const;\n\nprotected :\n\t// [internal use]\n\tvirtual TiXmlNode* Clone() const;\n\t#ifdef TIXML_USE_STL\n\tvirtual void StreamIn( std::istream * in, TIXML_STRING * tag );\n\t#endif\n\nprivate:\n\tvoid CopyTo( TiXmlDocument* target ) const;\n\n\tbool error;\n\tint  errorId;\n\tTIXML_STRING errorDesc;\n\tint tabsize;\n\tTiXmlCursor errorLocation;\n\tbool useMicrosoftBOM;\t\t// the UTF-8 BOM were found when read. Note this, and try to write.\n};\n\n\n/**\n\tA TiXmlHandle is a class that wraps a node pointer with null checks; this is\n\tan incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml\n\tDOM structure. It is a separate utility class.\n\n\tTake an example:\n\t@verbatim\n\t<Document>\n\t\t<Element attributeA = \"valueA\">\n\t\t\t<Child attributeB = \"value1\" />\n\t\t\t<Child attributeB = \"value2\" />\n\t\t</Element>\n\t<Document>\n\t@endverbatim\n\n\tAssuming you want the value of \"attributeB\" in the 2nd \"Child\" element, it's very \n\teasy to write a *lot* of code that looks like:\n\n\t@verbatim\n\tTiXmlElement* root = document.FirstChildElement( \"Document\" );\n\tif ( root )\n\t{\n\t\tTiXmlElement* element = root->FirstChildElement( \"Element\" );\n\t\tif ( element )\n\t\t{\n\t\t\tTiXmlElement* child = element->FirstChildElement( \"Child\" );\n\t\t\tif ( child )\n\t\t\t{\n\t\t\t\tTiXmlElement* child2 = child->NextSiblingElement( \"Child\" );\n\t\t\t\tif ( child2 )\n\t\t\t\t{\n\t\t\t\t\t// Finally do something useful.\n\t@endverbatim\n\n\tAnd that doesn't even cover \"else\" cases. TiXmlHandle addresses the verbosity\n\tof such code. A TiXmlHandle checks for null\tpointers so it is perfectly safe \n\tand correct to use:\n\n\t@verbatim\n\tTiXmlHandle docHandle( &document );\n\tTiXmlElement* child2 = docHandle.FirstChild( \"Document\" ).FirstChild( \"Element\" ).Child( \"Child\", 1 ).ToElement();\n\tif ( child2 )\n\t{\n\t\t// do something useful\n\t@endverbatim\n\n\tWhich is MUCH more concise and useful.\n\n\tIt is also safe to copy handles - internally they are nothing more than node pointers.\n\t@verbatim\n\tTiXmlHandle handleCopy = handle;\n\t@endverbatim\n\n\tWhat they should not be used for is iteration:\n\n\t@verbatim\n\tint i=0; \n\twhile ( true )\n\t{\n\t\tTiXmlElement* child = docHandle.FirstChild( \"Document\" ).FirstChild( \"Element\" ).Child( \"Child\", i ).ToElement();\n\t\tif ( !child )\n\t\t\tbreak;\n\t\t// do something\n\t\t++i;\n\t}\n\t@endverbatim\n\n\tIt seems reasonable, but it is in fact two embedded while loops. The Child method is \n\ta linear walk to find the element, so this code would iterate much more than it needs \n\tto. Instead, prefer:\n\n\t@verbatim\n\tTiXmlElement* child = docHandle.FirstChild( \"Document\" ).FirstChild( \"Element\" ).FirstChild( \"Child\" ).ToElement();\n\n\tfor( child; child; child=child->NextSiblingElement() )\n\t{\n\t\t// do something\n\t}\n\t@endverbatim\n*/\nclass TiXmlHandle\n{\npublic:\n\t/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.\n\tTiXmlHandle( TiXmlNode* _node )\t\t\t\t\t{ this->node = _node; }\n\t/// Copy constructor\n\tTiXmlHandle( const TiXmlHandle& ref )\t\t\t{ this->node = ref.node; }\n\tTiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; }\n\n\t/// Return a handle to the first child node.\n\tTiXmlHandle FirstChild() const;\n\t/// Return a handle to the first child node with the given name.\n\tTiXmlHandle FirstChild( const char * value ) const;\n\t/// Return a handle to the first child element.\n\tTiXmlHandle FirstChildElement() const;\n\t/// Return a handle to the first child element with the given name.\n\tTiXmlHandle FirstChildElement( const char * value ) const;\n\n\t/** Return a handle to the \"index\" child with the given name. \n\t\tThe first child is 0, the second 1, etc.\n\t*/\n\tTiXmlHandle Child( const char* value, int index ) const;\n\t/** Return a handle to the \"index\" child. \n\t\tThe first child is 0, the second 1, etc.\n\t*/\n\tTiXmlHandle Child( int index ) const;\n\t/** Return a handle to the \"index\" child element with the given name. \n\t\tThe first child element is 0, the second 1, etc. Note that only TiXmlElements\n\t\tare indexed: other types are not counted.\n\t*/\n\tTiXmlHandle ChildElement( const char* value, int index ) const;\n\t/** Return a handle to the \"index\" child element. \n\t\tThe first child element is 0, the second 1, etc. Note that only TiXmlElements\n\t\tare indexed: other types are not counted.\n\t*/\n\tTiXmlHandle ChildElement( int index ) const;\n\n\t#ifdef TIXML_USE_STL\n\tTiXmlHandle FirstChild( const std::string& _value ) const\t\t\t\t{ return FirstChild( _value.c_str() ); }\n\tTiXmlHandle FirstChildElement( const std::string& _value ) const\t\t{ return FirstChildElement( _value.c_str() ); }\n\n\tTiXmlHandle Child( const std::string& _value, int index ) const\t\t\t{ return Child( _value.c_str(), index ); }\n\tTiXmlHandle ChildElement( const std::string& _value, int index ) const\t{ return ChildElement( _value.c_str(), index ); }\n\t#endif\n\n\t/** Return the handle as a TiXmlNode. This may return null.\n\t*/\n\tTiXmlNode* ToNode() const\t\t\t{ return node; } \n\t/** Return the handle as a TiXmlElement. This may return null.\n\t*/\n\tTiXmlElement* ToElement() const\t\t{ return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }\n\t/**\tReturn the handle as a TiXmlText. This may return null.\n\t*/\n\tTiXmlText* ToText() const\t\t\t{ return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }\n\t/** Return the handle as a TiXmlUnknown. This may return null.\n\t*/\n\tTiXmlUnknown* ToUnknown() const\t\t{ return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }\n\n\t/** @deprecated use ToNode. \n\t\tReturn the handle as a TiXmlNode. This may return null.\n\t*/\n\tTiXmlNode* Node() const\t\t\t{ return ToNode(); } \n\t/** @deprecated use ToElement. \n\t\tReturn the handle as a TiXmlElement. This may return null.\n\t*/\n\tTiXmlElement* Element() const\t{ return ToElement(); }\n\t/**\t@deprecated use ToText()\n\t\tReturn the handle as a TiXmlText. This may return null.\n\t*/\n\tTiXmlText* Text() const\t\t\t{ return ToText(); }\n\t/** @deprecated use ToUnknown()\n\t\tReturn the handle as a TiXmlUnknown. This may return null.\n\t*/\n\tTiXmlUnknown* Unknown() const\t{ return ToUnknown(); }\n\nprivate:\n\tTiXmlNode* node;\n};\n\n\n/** Print to memory functionality. The TiXmlPrinter is useful when you need to:\n\n\t-# Print to memory (especially in non-STL mode)\n\t-# Control formatting (line endings, etc.)\n\n\tWhen constructed, the TiXmlPrinter is in its default \"pretty printing\" mode.\n\tBefore calling Accept() you can call methods to control the printing\n\tof the XML document. After TiXmlNode::Accept() is called, the printed document can\n\tbe accessed via the CStr(), Str(), and Size() methods.\n\n\tTiXmlPrinter uses the Visitor API.\n\t@verbatim\n\tTiXmlPrinter printer;\n\tprinter.SetIndent( \"\\t\" );\n\n\tdoc.Accept( &printer );\n\tfprintf( stdout, \"%s\", printer.CStr() );\n\t@endverbatim\n*/\nclass TiXmlPrinter : public TiXmlVisitor\n{\npublic:\n\tTiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),\n\t\t\t\t\t buffer(), indent( \"    \" ), lineBreak( \"\\n\" ) {}\n\n\tvirtual bool VisitEnter( const TiXmlDocument& doc );\n\tvirtual bool VisitExit( const TiXmlDocument& doc );\n\n\tvirtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );\n\tvirtual bool VisitExit( const TiXmlElement& element );\n\n\tvirtual bool Visit( const TiXmlDeclaration& declaration );\n\tvirtual bool Visit( const TiXmlText& text );\n\tvirtual bool Visit( const TiXmlComment& comment );\n\tvirtual bool Visit( const TiXmlUnknown& unknown );\n\n\t/** Set the indent characters for printing. By default 4 spaces\n\t\tbut tab (\\t) is also useful, or null/empty string for no indentation.\n\t*/\n\tvoid SetIndent( const char* _indent )\t\t\t{ indent = _indent ? _indent : \"\" ; }\n\t/// Query the indention string.\n\tconst char* Indent()\t\t\t\t\t\t\t{ return indent.c_str(); }\n\t/** Set the line breaking string. By default set to newline (\\n). \n\t\tSome operating systems prefer other characters, or can be\n\t\tset to the null/empty string for no indenation.\n\t*/\n\tvoid SetLineBreak( const char* _lineBreak )\t\t{ lineBreak = _lineBreak ? _lineBreak : \"\"; }\n\t/// Query the current line breaking string.\n\tconst char* LineBreak()\t\t\t\t\t\t\t{ return lineBreak.c_str(); }\n\n\t/** Switch over to \"stream printing\" which is the most dense formatting without \n\t\tlinebreaks. Common when the XML is needed for network transmission.\n\t*/\n\tvoid SetStreamPrinting()\t\t\t\t\t\t{ indent = \"\";\n\t\t\t\t\t\t\t\t\t\t\t\t\t  lineBreak = \"\";\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\t\n\t/// Return the result.\n\tconst char* CStr()\t\t\t\t\t\t\t\t{ return buffer.c_str(); }\n\t/// Return the length of the result string.\n\tsize_t Size()\t\t\t\t\t\t\t\t\t{ return buffer.size(); }\n\n\t#ifdef TIXML_USE_STL\n\t/// Return the result.\n\tconst std::string& Str()\t\t\t\t\t\t{ return buffer; }\n\t#endif\n\nprivate:\n\tvoid DoIndent()\t{\n\t\tfor( int i=0; i<depth; ++i )\n\t\t\tbuffer += indent;\n\t}\n\tvoid DoLineBreak() {\n\t\tbuffer += lineBreak;\n\t}\n\n\tint depth;\n\tbool simpleTextPrint;\n\tTIXML_STRING buffer;\n\tTIXML_STRING indent;\n\tTIXML_STRING lineBreak;\n};\n\n\n#ifdef _MSC_VER\n#pragma warning( pop )\n#endif\n\n#endif\n"
  },
  {
    "path": "common/xml/tinyxmlerror.cpp",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\nOriginal code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied \nwarranty. In no event will the authors be held liable for any \ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any \npurpose, including commercial applications, and to alter it and \nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n#include \"stdafx.h\"\n#include \"tinyxml.h\"\n\n// The goal of the seperate error file is to make the first\n// step towards localization. tinyxml (currently) only supports\n// english error messages, but the could now be translated.\n//\n// It also cleans up the code a bit.\n//\n\nconst char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] =\n{\n\t\"No error\",\n\t\"Error\",\n\t\"Failed to open file\",\n\t\"Error parsing Element.\",\n\t\"Failed to read Element name\",\n\t\"Error reading Element value.\",\n\t\"Error reading Attributes.\",\n\t\"Error: empty tag.\",\n\t\"Error reading end tag.\",\n\t\"Error parsing Unknown.\",\n\t\"Error parsing Comment.\",\n\t\"Error parsing Declaration.\",\n\t\"Error document empty.\",\n\t\"Error null (0) or unexpected EOF found in input stream.\",\n\t\"Error parsing CDATA.\",\n\t\"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.\",\n};\n"
  },
  {
    "path": "common/xml/tinyxmlparser.cpp",
    "content": "/*\nwww.sourceforge.net/projects/tinyxml\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied \nwarranty. In no event will the authors be held liable for any \ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any \npurpose, including commercial applications, and to alter it and \nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must \nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and \nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source \ndistribution.\n*/\n#include \"stdafx.h\"\n#include <ctype.h>\n#include <stddef.h>\n\n#include \"tinyxml.h\"\n\n//#define DEBUG_PARSER\n#if defined( DEBUG_PARSER )\n#\tif defined( DEBUG ) && defined( _MSC_VER )\n#\t\tinclude <windows.h>\n#\t\tdefine TIXML_LOG OutputDebugString\n#\telse\n#\t\tdefine TIXML_LOG printf\n#\tendif\n#endif\n\n// Note tha \"PutString\" hardcodes the same list. This\n// is less flexible than it appears. Changing the entries\n// or order will break putstring.\t\nTiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = \n{\n\t{ \"&amp;\",  5, '&' },\n\t{ \"&lt;\",   4, '<' },\n\t{ \"&gt;\",   4, '>' },\n\t{ \"&quot;\", 6, '\\\"' },\n\t{ \"&apos;\", 6, '\\'' }\n};\n\n// Bunch of unicode info at:\n//\t\thttp://www.unicode.org/faq/utf_bom.html\n// Including the basic of this table, which determines the #bytes in the\n// sequence from the lead byte. 1 placed for invalid sequences --\n// although the result will be junk, pass it through as much as possible.\n// Beware of the non-characters in UTF-8:\t\n//\t\t\t\tef bb bf (Microsoft \"lead bytes\")\n//\t\t\t\tef bf be\n//\t\t\t\tef bf bf \n\nconst unsigned char TIXML_UTF_LEAD_0 = 0xefU;\nconst unsigned char TIXML_UTF_LEAD_1 = 0xbbU;\nconst unsigned char TIXML_UTF_LEAD_2 = 0xbfU;\n\nconst int TiXmlBase::utf8ByteTable[256] = \n{\n\t//\t0\t1\t2\t3\t4\t5\t6\t7\t8\t9\ta\tb\tc\td\te\tf\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x00\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x10\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x20\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x30\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x40\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x50\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x60\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x70\tEnd of ASCII range\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x80 0x80 to 0xc1 invalid\n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0x90 \n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0xa0 \n\t\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t// 0xb0 \n\t\t1,\t1,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t// 0xc0 0xc2 to 0xdf 2 byte\n\t\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t2,\t// 0xd0\n\t\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t3,\t// 0xe0 0xe0 to 0xef 3 byte\n\t\t4,\t4,\t4,\t4,\t4,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1,\t1\t// 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid\n};\n\n\nvoid TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )\n{\n\tconst unsigned long BYTE_MASK = 0xBF;\n\tconst unsigned long BYTE_MARK = 0x80;\n\tconst unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };\n\n\tif (input < 0x80) \n\t\t*length = 1;\n\telse if ( input < 0x800 )\n\t\t*length = 2;\n\telse if ( input < 0x10000 )\n\t\t*length = 3;\n\telse if ( input < 0x200000 )\n\t\t*length = 4;\n\telse\n\t\t{ *length = 0; return; }\t// This code won't covert this correctly anyway.\n\n\toutput += *length;\n\n\t// Scary scary fall throughs.\n\tswitch (*length) \n\t{\n\t\tcase 4:\n\t\t\t--output; \n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK); \n\t\t\tinput >>= 6;\n\t\tcase 3:\n\t\t\t--output; \n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK); \n\t\t\tinput >>= 6;\n\t\tcase 2:\n\t\t\t--output; \n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK); \n\t\t\tinput >>= 6;\n\t\tcase 1:\n\t\t\t--output; \n\t\t\t*output = (char)(input | FIRST_BYTE_MARK[*length]);\n\t}\n}\n\n\n/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )\n{\n\t// This will only work for low-ascii, everything else is assumed to be a valid\n\t// letter. I'm not sure this is the best approach, but it is quite tricky trying\n\t// to figure out alhabetical vs. not across encoding. So take a very \n\t// conservative approach.\n\n//\tif ( encoding == TIXML_ENCODING_UTF8 )\n//\t{\n\t\tif ( anyByte < 127 )\n\t\t\treturn isalpha( anyByte );\n\t\telse\n\t\t\treturn 1;\t// What else to do? The unicode set is huge...get the english ones right.\n//\t}\n//\telse\n//\t{\n//\t\treturn isalpha( anyByte );\n//\t}\n}\n\n\n/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )\n{\n\t// This will only work for low-ascii, everything else is assumed to be a valid\n\t// letter. I'm not sure this is the best approach, but it is quite tricky trying\n\t// to figure out alhabetical vs. not across encoding. So take a very \n\t// conservative approach.\n\n//\tif ( encoding == TIXML_ENCODING_UTF8 )\n//\t{\n\t\tif ( anyByte < 127 )\n\t\t\treturn isalnum( anyByte );\n\t\telse\n\t\t\treturn 1;\t// What else to do? The unicode set is huge...get the english ones right.\n//\t}\n//\telse\n//\t{\n//\t\treturn isalnum( anyByte );\n//\t}\n}\n\n\nclass TiXmlParsingData\n{\n\tfriend class TiXmlDocument;\n  public:\n\tvoid Stamp( const char* now, TiXmlEncoding encoding );\n\n\tconst TiXmlCursor& Cursor() const\t{ return cursor; }\n\n  private:\n\t// Only used by the document!\n\tTiXmlParsingData( const char* start, int _tabsize, int row, int col )\n\t{\n\t\tassert( start );\n\t\tstamp = start;\n\t\ttabsize = _tabsize;\n\t\tcursor.row = row;\n\t\tcursor.col = col;\n\t}\n\n\tTiXmlCursor\t\tcursor;\n\tconst char*\t\tstamp;\n\tint\t\t\t\ttabsize;\n};\n\n\nvoid TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )\n{\n\tassert( now );\n\n\t// Do nothing if the tabsize is 0.\n\tif ( tabsize < 1 )\n\t{\n\t\treturn;\n\t}\n\n\t// Get the current row, column.\n\tint row = cursor.row;\n\tint col = cursor.col;\n\tconst char* p = stamp;\n\tassert( p );\n\n\twhile ( p < now )\n\t{\n\t\t// Treat p as unsigned, so we have a happy compiler.\n\t\tconst unsigned char* pU = (const unsigned char*)p;\n\n\t\t// Code contributed by Fletcher Dunn: (modified by lee)\n\t\tswitch (*pU) {\n\t\t\tcase 0:\n\t\t\t\t// We *should* never get here, but in case we do, don't\n\t\t\t\t// advance past the terminating null character, ever\n\t\t\t\treturn;\n\n\t\t\tcase '\\r':\n\t\t\t\t// bump down to the next line\n\t\t\t\t++row;\n\t\t\t\tcol = 0;\t\t\t\t\n\t\t\t\t// Eat the character\n\t\t\t\t++p;\n\n\t\t\t\t// Check for \\r\\n sequence, and treat this as a single character\n\t\t\t\tif (*p == '\\n') {\n\t\t\t\t\t++p;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '\\n':\n\t\t\t\t// bump down to the next line\n\t\t\t\t++row;\n\t\t\t\tcol = 0;\n\n\t\t\t\t// Eat the character\n\t\t\t\t++p;\n\n\t\t\t\t// Check for \\n\\r sequence, and treat this as a single\n\t\t\t\t// character.  (Yes, this bizarre thing does occur still\n\t\t\t\t// on some arcane platforms...)\n\t\t\t\tif (*p == '\\r') {\n\t\t\t\t\t++p;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase '\\t':\n\t\t\t\t// Eat the character\n\t\t\t\t++p;\n\n\t\t\t\t// Skip to next tab stop\n\t\t\t\tcol = (col / tabsize + 1) * tabsize;\n\t\t\t\tbreak;\n\n\t\t\tcase TIXML_UTF_LEAD_0:\n\t\t\t\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t\t\t\t{\n\t\t\t\t\tif ( *(p+1) && *(p+2) )\n\t\t\t\t\t{\n\t\t\t\t\t\t// In these cases, don't advance the column. These are\n\t\t\t\t\t\t// 0-width spaces.\n\t\t\t\t\t\tif ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )\n\t\t\t\t\t\t\tp += 3;\t\n\t\t\t\t\t\telse if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )\n\t\t\t\t\t\t\tp += 3;\t\n\t\t\t\t\t\telse if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )\n\t\t\t\t\t\t\tp += 3;\t\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{ p +=3; ++col; }\t// A normal character.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t++p;\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t\t\t\t{\n\t\t\t\t\t// Eat the 1 to 4 byte utf8 character.\n\t\t\t\t\tint step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];\n\t\t\t\t\tif ( step == 0 )\n\t\t\t\t\t\tstep = 1;\t\t// Error case from bad encoding, but handle gracefully.\n\t\t\t\t\tp += step;\n\n\t\t\t\t\t// Just advance one column, of course.\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t++p;\n\t\t\t\t\t++col;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tcursor.row = row;\n\tcursor.col = col;\n\tassert( cursor.row >= -1 );\n\tassert( cursor.col >= -1 );\n\tstamp = p;\n\tassert( stamp );\n}\n\n\nconst char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )\n{\n\tif ( !p || !*p )\n\t{\n\t\treturn 0;\n\t}\n\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t{\n\t\twhile ( *p )\n\t\t{\n\t\t\tconst unsigned char* pU = (const unsigned char*)p;\n\t\t\t\n\t\t\t// Skip the stupid Microsoft UTF-8 Byte order marks\n\t\t\tif (\t*(pU+0)==TIXML_UTF_LEAD_0\n\t\t\t\t && *(pU+1)==TIXML_UTF_LEAD_1 \n\t\t\t\t && *(pU+2)==TIXML_UTF_LEAD_2 )\n\t\t\t{\n\t\t\t\tp += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if(*(pU+0)==TIXML_UTF_LEAD_0\n\t\t\t\t && *(pU+1)==0xbfU\n\t\t\t\t && *(pU+2)==0xbeU )\n\t\t\t{\n\t\t\t\tp += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if(*(pU+0)==TIXML_UTF_LEAD_0\n\t\t\t\t && *(pU+1)==0xbfU\n\t\t\t\t && *(pU+2)==0xbfU )\n\t\t\t{\n\t\t\t\tp += 3;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( IsWhiteSpace( *p ) )\t\t// Still using old rules for white space.\n\t\t\t\t++p;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\twhile ( *p && IsWhiteSpace( *p ) )\n\t\t\t++p;\n\t}\n\n\treturn p;\n}\n\n#ifdef TIXML_USE_STL\n/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )\n{\n\tfor( ;; )\n\t{\n\t\tif ( !in->good() ) return false;\n\n\t\tint c = in->peek();\n\t\t// At this scope, we can't get to a document. So fail silently.\n\t\tif ( !IsWhiteSpace( c ) || c <= 0 )\n\t\t\treturn true;\n\n\t\t*tag += (char) in->get();\n\t}\n}\n\n/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )\n{\n\t//assert( character > 0 && character < 128 );\t// else it won't work in utf-8\n\twhile ( in->good() )\n\t{\n\t\tint c = in->peek();\n\t\tif ( c == character )\n\t\t\treturn true;\n\t\tif ( c <= 0 )\t\t// Silent failure: can't get document at this scope\n\t\t\treturn false;\n\n\t\tin->get();\n\t\t*tag += (char) c;\n\t}\n\treturn false;\n}\n#endif\n\n// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The\n// \"assign\" optimization removes over 10% of the execution time.\n//\nconst char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )\n{\n\t// Oddly, not supported on some comilers,\n\t//name->clear();\n\t// So use this:\n\t*name = \"\";\n\tassert( p );\n\n\t// Names start with letters or underscores.\n\t// Of course, in unicode, tinyxml has no idea what a letter *is*. The\n\t// algorithm is generous.\n\t//\n\t// After that, they can be letters, underscores, numbers,\n\t// hyphens, or colons. (Colons are valid ony for namespaces,\n\t// but tinyxml can't tell namespaces from names.)\n\tif (    p && *p \n\t\t && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )\n\t{\n\t\tconst char* start = p;\n\t\twhile(\t\tp && *p\n\t\t\t\t&&\t(\t\tIsAlphaNum( (unsigned char ) *p, encoding ) \n\t\t\t\t\t\t || *p == '_'\n\t\t\t\t\t\t || *p == '-'\n\t\t\t\t\t\t || *p == '.'\n\t\t\t\t\t\t || *p == ':' ) )\n\t\t{\n\t\t\t//(*name) += *p; // expensive\n\t\t\t++p;\n\t\t}\n\t\tif ( p-start > 0 ) {\n\t\t\tname->assign( start, p-start );\n\t\t}\n\t\treturn p;\n\t}\n\treturn 0;\n}\n\nconst char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )\n{\n\t// Presume an entity, and pull it out.\n    TIXML_STRING ent;\n\tint i;\n\t*length = 0;\n\n\tif ( *(p+1) && *(p+1) == '#' && *(p+2) )\n\t{\n\t\tunsigned long ucs = 0;\n\t\tptrdiff_t delta = 0;\n\t\tunsigned mult = 1;\n\n\t\tif ( *(p+2) == 'x' )\n\t\t{\n\t\t\t// Hexadecimal.\n\t\t\tif ( !*(p+3) ) return 0;\n\n\t\t\tconst char* q = p+3;\n\t\t\tq = strchr( q, ';' );\n\n\t\t\tif ( !q || !*q ) return 0;\n\n\t\t\tdelta = q-p;\n\t\t\t--q;\n\n\t\t\twhile ( *q != 'x' )\n\t\t\t{\n\t\t\t\tif ( *q >= '0' && *q <= '9' )\n\t\t\t\t\tucs += mult * (*q - '0');\n\t\t\t\telse if ( *q >= 'a' && *q <= 'f' )\n\t\t\t\t\tucs += mult * (*q - 'a' + 10);\n\t\t\t\telse if ( *q >= 'A' && *q <= 'F' )\n\t\t\t\t\tucs += mult * (*q - 'A' + 10 );\n\t\t\t\telse \n\t\t\t\t\treturn 0;\n\t\t\t\tmult *= 16;\n\t\t\t\t--q;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Decimal.\n\t\t\tif ( !*(p+2) ) return 0;\n\n\t\t\tconst char* q = p+2;\n\t\t\tq = strchr( q, ';' );\n\n\t\t\tif ( !q || !*q ) return 0;\n\n\t\t\tdelta = q-p;\n\t\t\t--q;\n\n\t\t\twhile ( *q != '#' )\n\t\t\t{\n\t\t\t\tif ( *q >= '0' && *q <= '9' )\n\t\t\t\t\tucs += mult * (*q - '0');\n\t\t\t\telse \n\t\t\t\t\treturn 0;\n\t\t\t\tmult *= 10;\n\t\t\t\t--q;\n\t\t\t}\n\t\t}\n\t\tif ( encoding == TIXML_ENCODING_UTF8 )\n\t\t{\n\t\t\t// convert the UCS to UTF-8\n\t\t\tConvertUTF32ToUTF8( ucs, value, length );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*value = (char)ucs;\n\t\t\t*length = 1;\n\t\t}\n\t\treturn p + delta + 1;\n\t}\n\n\t// Now try to match it.\n\tfor( i=0; i<NUM_ENTITY; ++i )\n\t{\n\t\tif ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )\n\t\t{\n\t\t\tassert( strlen( entity[i].str ) == entity[i].strLength );\n\t\t\t*value = entity[i].chr;\n\t\t\t*length = 1;\n\t\t\treturn ( p + entity[i].strLength );\n\t\t}\n\t}\n\n\t// So it wasn't an entity, its unrecognized, or something like that.\n\t*value = *p;\t// Don't put back the last one, since we return it!\n\t//*length = 1;\t// Leave unrecognized entities - this doesn't really work.\n\t\t\t\t\t// Just writes strange XML.\n\treturn p+1;\n}\n\n\nbool TiXmlBase::StringEqual( const char* p,\n\t\t\t\t\t\t\t const char* tag,\n\t\t\t\t\t\t\t bool ignoreCase,\n\t\t\t\t\t\t\t TiXmlEncoding encoding )\n{\n\tassert( p );\n\tassert( tag );\n\tif ( !p || !*p )\n\t{\n\t\tassert( 0 );\n\t\treturn false;\n\t}\n\n\tconst char* q = p;\n\n\tif ( ignoreCase )\n\t{\n\t\twhile ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )\n\t\t{\n\t\t\t++q;\n\t\t\t++tag;\n\t\t}\n\n\t\tif ( *tag == 0 )\n\t\t\treturn true;\n\t}\n\telse\n\t{\n\t\twhile ( *q && *tag && *q == *tag )\n\t\t{\n\t\t\t++q;\n\t\t\t++tag;\n\t\t}\n\n\t\tif ( *tag == 0 )\t\t// Have we found the end of the tag, and everything equal?\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\nconst char* TiXmlBase::ReadText(\tconst char* p, \n\t\t\t\t\t\t\t\t\tTIXML_STRING * text, \n\t\t\t\t\t\t\t\t\tbool trimWhiteSpace, \n\t\t\t\t\t\t\t\t\tconst char* endTag, \n\t\t\t\t\t\t\t\t\tbool caseInsensitive,\n\t\t\t\t\t\t\t\t\tTiXmlEncoding encoding )\n{\n    *text = \"\";\n\tif (    !trimWhiteSpace\t\t\t// certain tags always keep whitespace\n\t\t || !condenseWhiteSpace )\t// if true, whitespace is always kept\n\t{\n\t\t// Keep all the white space.\n\t\twhile (\t   p && *p\n\t\t\t\t&& !StringEqual( p, endTag, caseInsensitive, encoding )\n\t\t\t  )\n\t\t{\n\t\t\tint len;\n\t\t\tchar cArr[4] = { 0, 0, 0, 0 };\n\t\t\tp = GetChar( p, cArr, &len, encoding );\n\t\t\ttext->append( cArr, len );\n\t\t}\n\t}\n\telse\n\t{\n\t\tbool whitespace = false;\n\n\t\t// Remove leading white space:\n\t\tp = SkipWhiteSpace( p, encoding );\n\t\twhile (\t   p && *p\n\t\t\t\t&& !StringEqual( p, endTag, caseInsensitive, encoding ) )\n\t\t{\n\t\t\tif ( *p == '\\r' || *p == '\\n' )\n\t\t\t{\n\t\t\t\twhitespace = true;\n\t\t\t\t++p;\n\t\t\t}\n\t\t\telse if ( IsWhiteSpace( *p ) )\n\t\t\t{\n\t\t\t\twhitespace = true;\n\t\t\t\t++p;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If we've found whitespace, add it before the\n\t\t\t\t// new character. Any whitespace just becomes a space.\n\t\t\t\tif ( whitespace )\n\t\t\t\t{\n\t\t\t\t\t(*text) += ' ';\n\t\t\t\t\twhitespace = false;\n\t\t\t\t}\n\t\t\t\tint len;\n\t\t\t\tchar cArr[4] = { 0, 0, 0, 0 };\n\t\t\t\tp = GetChar( p, cArr, &len, encoding );\n\t\t\t\tif ( len == 1 )\n\t\t\t\t\t(*text) += cArr[0];\t// more efficient\n\t\t\t\telse\n\t\t\t\t\ttext->append( cArr, len );\n\t\t\t}\n\t\t}\n\t}\n\tif ( p && *p )\n\t\tp += strlen( endTag );\n\treturn ( p && *p ) ? p : 0;\n}\n\n#ifdef TIXML_USE_STL\n\nvoid TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )\n{\n\t// The basic issue with a document is that we don't know what we're\n\t// streaming. Read something presumed to be a tag (and hope), then\n\t// identify it, and call the appropriate stream method on the tag.\n\t//\n\t// This \"pre-streaming\" will never read the closing \">\" so the\n\t// sub-tag can orient itself.\n\n\tif ( !StreamTo( in, '<', tag ) ) \n\t{\n\t\tSetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn;\n\t}\n\n\twhile ( in->good() )\n\t{\n\t\tint tagIndex = (int) tag->length();\n\t\twhile ( in->good() && in->peek() != '>' )\n\t\t{\n\t\t\tint c = in->get();\n\t\t\tif ( c <= 0 )\n\t\t\t{\n\t\t\t\tSetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t(*tag) += (char) c;\n\t\t}\n\n\t\tif ( in->good() )\n\t\t{\n\t\t\t// We now have something we presume to be a node of \n\t\t\t// some sort. Identify it, and call the node to\n\t\t\t// continue streaming.\n\t\t\tTiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );\n\n\t\t\tif ( node )\n\t\t\t{\n\t\t\t\tnode->StreamIn( in, tag );\n\t\t\t\tbool isElement = node->ToElement() != 0;\n\t\t\t\tdelete node;\n\t\t\t\tnode = 0;\n\n\t\t\t\t// If this is the root element, we're done. Parsing will be\n\t\t\t\t// done by the >> operator.\n\t\t\t\tif ( isElement )\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t// We should have returned sooner.\n\tSetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );\n}\n\n#endif\n\nconst char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )\n{\n\tClearError();\n\n\t// Parse away, at the document level. Since a document\n\t// contains nothing but other tags, most of what happens\n\t// here is skipping white space.\n\tif ( !p || !*p )\n\t{\n\t\tSetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\t// Note that, for a document, this needs to come\n\t// before the while space skip, so that parsing\n\t// starts from the pointer we are given.\n\tlocation.Clear();\n\tif ( prevData )\n\t{\n\t\tlocation.row = prevData->cursor.row;\n\t\tlocation.col = prevData->cursor.col;\n\t}\n\telse\n\t{\n\t\tlocation.row = 0;\n\t\tlocation.col = 0;\n\t}\n\tTiXmlParsingData data( p, TabSize(), location.row, location.col );\n\tlocation = data.Cursor();\n\n\tif ( encoding == TIXML_ENCODING_UNKNOWN )\n\t{\n\t\t// Check for the Microsoft UTF-8 lead bytes.\n\t\tconst unsigned char* pU = (const unsigned char*)p;\n\t\tif (\t*(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0\n\t\t\t && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1\n\t\t\t && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )\n\t\t{\n\t\t\tencoding = TIXML_ENCODING_UTF8;\n\t\t\tuseMicrosoftBOM = true;\n\t\t}\n\t}\n\n    p = SkipWhiteSpace( p, encoding );\n\tif ( !p )\n\t{\n\t\tSetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\treturn 0;\n\t}\n\n\twhile ( p && *p )\n\t{\n\t\tTiXmlNode* node = Identify( p, encoding );\n\t\tif ( node )\n\t\t{\n\t\t\tp = node->Parse( p, &data, encoding );\n\t\t\tLinkEndChild( node );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbreak;\n\t\t}\n\n\t\t// Did we get encoding info?\n\t\tif (    encoding == TIXML_ENCODING_UNKNOWN\n\t\t\t && node->ToDeclaration() )\n\t\t{\n\t\t\tTiXmlDeclaration* dec = node->ToDeclaration();\n\t\t\tconst char* enc = dec->Encoding();\n\t\t\tassert( enc );\n\n\t\t\tif ( *enc == 0 )\n\t\t\t\tencoding = TIXML_ENCODING_UTF8;\n\t\t\telse if ( StringEqual( enc, \"UTF-8\", true, TIXML_ENCODING_UNKNOWN ) )\n\t\t\t\tencoding = TIXML_ENCODING_UTF8;\n\t\t\telse if ( StringEqual( enc, \"UTF8\", true, TIXML_ENCODING_UNKNOWN ) )\n\t\t\t\tencoding = TIXML_ENCODING_UTF8;\t// incorrect, but be nice\n\t\t\telse \n\t\t\t\tencoding = TIXML_ENCODING_LEGACY;\n\t\t}\n\n\t\tp = SkipWhiteSpace( p, encoding );\n\t}\n\n\t// Was this empty?\n\tif ( !firstChild ) {\n\t\tSetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );\n\t\treturn 0;\n\t}\n\n\t// All is well.\n\treturn p;\n}\n\nvoid TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\t\n\t// The first error in a chain is more accurate - don't set again!\n\tif ( error )\n\t\treturn;\n\n\tassert( err > 0 && err < TIXML_ERROR_STRING_COUNT );\n\terror   = true;\n\terrorId = err;\n\terrorDesc = errorString[ errorId ];\n\n\terrorLocation.Clear();\n\tif ( pError && data )\n\t{\n\t\tdata->Stamp( pError, encoding );\n\t\terrorLocation = data->Cursor();\n\t}\n}\n\n\nTiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )\n{\n\tTiXmlNode* returnNode = 0;\n\n\tp = SkipWhiteSpace( p, encoding );\n\tif( !p || !*p || *p != '<' )\n\t{\n\t\treturn 0;\n\t}\n\n\tp = SkipWhiteSpace( p, encoding );\n\n\tif ( !p || !*p )\n\t{\n\t\treturn 0;\n\t}\n\n\t// What is this thing? \n\t// - Elements start with a letter or underscore, but xml is reserved.\n\t// - Comments: <!--\n\t// - Decleration: <?xml\n\t// - Everthing else is unknown to tinyxml.\n\t//\n\n\tconst char* xmlHeader = { \"<?xml\" };\n\tconst char* commentHeader = { \"<!--\" };\n\tconst char* dtdHeader = { \"<!\" };\n\tconst char* cdataHeader = { \"<![CDATA[\" };\n\n\tif ( StringEqual( p, xmlHeader, true, encoding ) )\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing Declaration\\n\" );\n\t\t#endif\n\t\treturnNode = new TiXmlDeclaration();\n\t}\n\telse if ( StringEqual( p, commentHeader, false, encoding ) )\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing Comment\\n\" );\n\t\t#endif\n\t\treturnNode = new TiXmlComment();\n\t}\n\telse if ( StringEqual( p, cdataHeader, false, encoding ) )\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing CDATA\\n\" );\n\t\t#endif\n\t\tTiXmlText* text = new TiXmlText( \"\" );\n\t\ttext->SetCDATA( true );\n\t\treturnNode = text;\n\t}\n\telse if ( StringEqual( p, dtdHeader, false, encoding ) )\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing Unknown(1)\\n\" );\n\t\t#endif\n\t\treturnNode = new TiXmlUnknown();\n\t}\n\telse if (    IsAlpha( *(p+1), encoding )\n\t\t\t  || *(p+1) == '_' )\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing Element\\n\" );\n\t\t#endif\n\t\treturnNode = new TiXmlElement( \"\" );\n\t}\n\telse\n\t{\n\t\t#ifdef DEBUG_PARSER\n\t\t\tTIXML_LOG( \"XML parsing Unknown(2)\\n\" );\n\t\t#endif\n\t\treturnNode = new TiXmlUnknown();\n\t}\n\n\tif ( returnNode )\n\t{\n\t\t// Set the parent, so it can report errors\n\t\treturnNode->parent = this;\n\t}\n\treturn returnNode;\n}\n\n#ifdef TIXML_USE_STL\n\nvoid TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)\n{\n\t// We're called with some amount of pre-parsing. That is, some of \"this\"\n\t// element is in \"tag\". Go ahead and stream to the closing \">\"\n\twhile( in->good() )\n\t{\n\t\tint c = in->get();\n\t\tif ( c <= 0 )\n\t\t{\n\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\treturn;\n\t\t}\n\t\t(*tag) += (char) c ;\n\t\t\n\t\tif ( c == '>' )\n\t\t\tbreak;\n\t}\n\n\tif ( tag->length() < 3 ) return;\n\n\t// Okay...if we are a \"/>\" tag, then we're done. We've read a complete tag.\n\t// If not, identify and stream.\n\n\tif (    tag->at( tag->length() - 1 ) == '>' \n\t\t && tag->at( tag->length() - 2 ) == '/' )\n\t{\n\t\t// All good!\n\t\treturn;\n\t}\n\telse if ( tag->at( tag->length() - 1 ) == '>' )\n\t{\n\t\t// There is more. Could be:\n\t\t//\t\ttext\n\t\t//\t\tcdata text (which looks like another node)\n\t\t//\t\tclosing tag\n\t\t//\t\tanother node.\n\t\tfor ( ;; )\n\t\t{\n\t\t\tStreamWhiteSpace( in, tag );\n\n\t\t\t// Do we have text?\n\t\t\tif ( in->good() && in->peek() != '<' ) \n\t\t\t{\n\t\t\t\t// Yep, text.\n\t\t\t\tTiXmlText text( \"\" );\n\t\t\t\ttext.StreamIn( in, tag );\n\n\t\t\t\t// What follows text is a closing tag or another node.\n\t\t\t\t// Go around again and figure it out.\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// We now have either a closing tag...or another node.\n\t\t\t// We should be at a \"<\", regardless.\n\t\t\tif ( !in->good() ) return;\n\t\t\tassert( in->peek() == '<' );\n\t\t\tint tagIndex = (int) tag->length();\n\n\t\t\tbool closingTag = false;\n\t\t\tbool firstCharFound = false;\n\n\t\t\tfor( ;; )\n\t\t\t{\n\t\t\t\tif ( !in->good() )\n\t\t\t\t\treturn;\n\n\t\t\t\tint c = in->peek();\n\t\t\t\tif ( c <= 0 )\n\t\t\t\t{\n\t\t\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\t\t\tif ( document )\n\t\t\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif ( c == '>' )\n\t\t\t\t\tbreak;\n\n\t\t\t\t*tag += (char) c;\n\t\t\t\tin->get();\n\n\t\t\t\t// Early out if we find the CDATA id.\n\t\t\t\tif ( c == '[' && tag->size() >= 9 )\n\t\t\t\t{\n\t\t\t\t\tsize_t len = tag->size();\n\t\t\t\t\tconst char* start = tag->c_str() + len - 9;\n\t\t\t\t\tif ( strcmp( start, \"<![CDATA[\" ) == 0 ) {\n\t\t\t\t\t\tassert( !closingTag );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )\n\t\t\t\t{\n\t\t\t\t\tfirstCharFound = true;\n\t\t\t\t\tif ( c == '/' )\n\t\t\t\t\t\tclosingTag = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If it was a closing tag, then read in the closing '>' to clean up the input stream.\n\t\t\t// If it was not, the streaming will be done by the tag.\n\t\t\tif ( closingTag )\n\t\t\t{\n\t\t\t\tif ( !in->good() )\n\t\t\t\t\treturn;\n\n\t\t\t\tint c = in->get();\n\t\t\t\tif ( c <= 0 )\n\t\t\t\t{\n\t\t\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\t\t\tif ( document )\n\t\t\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tassert( c == '>' );\n\t\t\t\t*tag += (char) c;\n\n\t\t\t\t// We are done, once we've found our closing tag.\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// If not a closing tag, id it, and stream.\n\t\t\t\tconst char* tagloc = tag->c_str() + tagIndex;\n\t\t\t\tTiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );\n\t\t\t\tif ( !node )\n\t\t\t\t\treturn;\n\t\t\t\tnode->StreamIn( in, tag );\n\t\t\t\tdelete node;\n\t\t\t\tnode = 0;\n\n\t\t\t\t// No return: go around from the beginning: text, closing tag, or node.\n\t\t\t}\n\t\t}\n\t}\n}\n#endif\n\nconst char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tp = SkipWhiteSpace( p, encoding );\n\tTiXmlDocument* document = GetDocument();\n\n\tif ( !p || !*p )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );\n\t\treturn 0;\n\t}\n\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, encoding );\n\t\tlocation = data->Cursor();\n\t}\n\n\tif ( *p != '<' )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );\n\t\treturn 0;\n\t}\n\n\tp = SkipWhiteSpace( p+1, encoding );\n\n\t// Read the name.\n\tconst char* pErr = p;\n\n    p = ReadName( p, &value, encoding );\n\tif ( !p || !*p )\n\t{\n\t\tif ( document )\tdocument->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );\n\t\treturn 0;\n\t}\n\n    TIXML_STRING endTag (\"</\");\n\tendTag += value;\n\n\t// Check for and read attributes. Also look for an empty\n\t// tag or an end tag.\n\twhile ( p && *p )\n\t{\n\t\tpErr = p;\n\t\tp = SkipWhiteSpace( p, encoding );\n\t\tif ( !p || !*p )\n\t\t{\n\t\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );\n\t\t\treturn 0;\n\t\t}\n\t\tif ( *p == '/' )\n\t\t{\n\t\t\t++p;\n\t\t\t// Empty tag.\n\t\t\tif ( *p  != '>' )\n\t\t\t{\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );\t\t\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn (p+1);\n\t\t}\n\t\telse if ( *p == '>' )\n\t\t{\n\t\t\t// Done with attributes (if there were any.)\n\t\t\t// Read the value -- which can include other\n\t\t\t// elements -- read the end tag, and return.\n\t\t\t++p;\n\t\t\tp = ReadValue( p, data, encoding );\t\t// Note this is an Element method, and will set the error if one happens.\n\t\t\tif ( !p || !*p ) {\n\t\t\t\t// We were looking for the end tag, but found nothing.\n\t\t\t\t// Fix for [ 1663758 ] Failure to report error on bad XML\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t// We should find the end tag now\n\t\t\t// note that:\n\t\t\t// </foo > and\n\t\t\t// </foo> \n\t\t\t// are both valid end tags.\n\t\t\tif ( StringEqual( p, endTag.c_str(), false, encoding ) )\n\t\t\t{\n\t\t\t\tp += endTag.length();\n\t\t\t\tp = SkipWhiteSpace( p, encoding );\n\t\t\t\tif ( p && *p && *p == '>' ) {\n\t\t\t\t\t++p;\n\t\t\t\t\treturn p;\n\t\t\t\t}\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Try to read an attribute:\n\t\t\tTiXmlAttribute* attrib = new TiXmlAttribute();\n\t\t\tif ( !attrib )\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tattrib->SetDocument( document );\n\t\t\tpErr = p;\n\t\t\tp = attrib->Parse( p, data, encoding );\n\n\t\t\tif ( !p || !*p )\n\t\t\t{\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );\n\t\t\t\tdelete attrib;\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t// Handle the strange case of double attributes:\n\t\t\t#ifdef TIXML_USE_STL\n\t\t\tTiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );\n\t\t\t#else\n\t\t\tTiXmlAttribute* node = attributeSet.Find( attrib->Name() );\n\t\t\t#endif\n\t\t\tif ( node )\n\t\t\t{\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );\n\t\t\t\tdelete attrib;\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tattributeSet.Add( attrib );\n\t\t}\n\t}\n\treturn p;\n}\n\n\nconst char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tTiXmlDocument* document = GetDocument();\n\n\t// Read in text and elements in any order.\n\tconst char* pWithWhiteSpace = p;\n\tp = SkipWhiteSpace( p, encoding );\n\n\twhile ( p && *p )\n\t{\n\t\tif ( *p != '<' )\n\t\t{\n\t\t\t// Take what we have, make a text element.\n\t\t\tTiXmlText* textNode = new TiXmlText( \"\" );\n\n\t\t\tif ( !textNode )\n\t\t\t{\n\t\t\t    return 0;\n\t\t\t}\n\n\t\t\tif ( TiXmlBase::IsWhiteSpaceCondensed() )\n\t\t\t{\n\t\t\t\tp = textNode->Parse( p, data, encoding );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Special case: we want to keep the white space\n\t\t\t\t// so that leading spaces aren't removed.\n\t\t\t\tp = textNode->Parse( pWithWhiteSpace, data, encoding );\n\t\t\t}\n\n\t\t\tif ( !textNode->Blank() )\n\t\t\t\tLinkEndChild( textNode );\n\t\t\telse\n\t\t\t\tdelete textNode;\n\t\t} \n\t\telse \n\t\t{\n\t\t\t// We hit a '<'\n\t\t\t// Have we hit a new element or an end tag? This could also be\n\t\t\t// a TiXmlText in the \"CDATA\" style.\n\t\t\tif ( StringEqual( p, \"</\", false, encoding ) )\n\t\t\t{\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tTiXmlNode* node = Identify( p, encoding );\n\t\t\t\tif ( node )\n\t\t\t\t{\n\t\t\t\t\tp = node->Parse( p, data, encoding );\n\t\t\t\t\tLinkEndChild( node );\n\t\t\t\t}\t\t\t\t\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpWithWhiteSpace = p;\n\t\tp = SkipWhiteSpace( p, encoding );\n\t}\n\n\tif ( !p )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );\n\t}\t\n\treturn p;\n}\n\n\n#ifdef TIXML_USE_STL\nvoid TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )\n{\n\twhile ( in->good() )\n\t{\n\t\tint c = in->get();\t\n\t\tif ( c <= 0 )\n\t\t{\n\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\treturn;\n\t\t}\n\t\t(*tag) += (char) c;\n\n\t\tif ( c == '>' )\n\t\t{\n\t\t\t// All is well.\n\t\t\treturn;\t\t\n\t\t}\n\t}\n}\n#endif\n\n\nconst char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tTiXmlDocument* document = GetDocument();\n\tp = SkipWhiteSpace( p, encoding );\n\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, encoding );\n\t\tlocation = data->Cursor();\n\t}\n\tif ( !p || !*p || *p != '<' )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );\n\t\treturn 0;\n\t}\n\t++p;\n    value = \"\";\n\n\twhile ( p && *p && *p != '>' )\n\t{\n\t\tvalue += *p;\n\t\t++p;\n\t}\n\n\tif ( !p )\n\t{\n\t\tif ( document )\t\n\t\t\tdocument->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );\n\t}\n\tif ( p && *p == '>' )\n\t\treturn p+1;\n\treturn p;\n}\n\n#ifdef TIXML_USE_STL\nvoid TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )\n{\n\twhile ( in->good() )\n\t{\n\t\tint c = in->get();\t\n\t\tif ( c <= 0 )\n\t\t{\n\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\treturn;\n\t\t}\n\n\t\t(*tag) += (char) c;\n\n\t\tif ( c == '>' \n\t\t\t && tag->at( tag->length() - 2 ) == '-'\n\t\t\t && tag->at( tag->length() - 3 ) == '-' )\n\t\t{\n\t\t\t// All is well.\n\t\t\treturn;\t\t\n\t\t}\n\t}\n}\n#endif\n\n\nconst char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tTiXmlDocument* document = GetDocument();\n\tvalue = \"\";\n\n\tp = SkipWhiteSpace( p, encoding );\n\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, encoding );\n\t\tlocation = data->Cursor();\n\t}\n\tconst char* startTag = \"<!--\";\n\tconst char* endTag   = \"-->\";\n\n\tif ( !StringEqual( p, startTag, false, encoding ) )\n\t{\n\t\tif ( document )\n\t\t\tdocument->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );\n\t\treturn 0;\n\t}\n\tp += strlen( startTag );\n\n\t// [ 1475201 ] TinyXML parses entities in comments\n\t// Oops - ReadText doesn't work, because we don't want to parse the entities.\n\t// p = ReadText( p, &value, false, endTag, false, encoding );\n\t//\n\t// from the XML spec:\n\t/*\n\t [Definition: Comments may appear anywhere in a document outside other markup; in addition, \n\t              they may appear within the document type declaration at places allowed by the grammar. \n\t\t\t\t  They are not part of the document's character data; an XML processor MAY, but need not, \n\t\t\t\t  make it possible for an application to retrieve the text of comments. For compatibility, \n\t\t\t\t  the string \"--\" (double-hyphen) MUST NOT occur within comments.] Parameter entity \n\t\t\t\t  references MUST NOT be recognized within comments.\n\n\t\t\t\t  An example of a comment:\n\n\t\t\t\t  <!-- declarations for <head> & <body> -->\n\t*/\n\n    value = \"\";\n\t// Keep all the white space.\n\twhile (\tp && *p && !StringEqual( p, endTag, false, encoding ) )\n\t{\n\t\tvalue.append( p, 1 );\n\t\t++p;\n\t}\n\tif ( p && *p ) \n\t\tp += strlen( endTag );\n\n\treturn p;\n}\n\n\nconst char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tp = SkipWhiteSpace( p, encoding );\n\tif ( !p || !*p ) return 0;\n\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, encoding );\n\t\tlocation = data->Cursor();\n\t}\n\t// Read the name, the '=' and the value.\n\tconst char* pErr = p;\n\tp = ReadName( p, &name, encoding );\n\tif ( !p || !*p )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );\n\t\treturn 0;\n\t}\n\tp = SkipWhiteSpace( p, encoding );\n\tif ( !p || !*p || *p != '=' )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\n\t\treturn 0;\n\t}\n\n\t++p;\t// skip '='\n\tp = SkipWhiteSpace( p, encoding );\n\tif ( !p || !*p )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\n\t\treturn 0;\n\t}\n\t\n\tconst char* end;\n\tconst char SINGLE_QUOTE = '\\'';\n\tconst char DOUBLE_QUOTE = '\\\"';\n\n\tif ( *p == SINGLE_QUOTE )\n\t{\n\t\t++p;\n\t\tend = \"\\'\";\t\t// single quote in string\n\t\tp = ReadText( p, &value, false, end, false, encoding );\n\t}\n\telse if ( *p == DOUBLE_QUOTE )\n\t{\n\t\t++p;\n\t\tend = \"\\\"\";\t\t// double quote in string\n\t\tp = ReadText( p, &value, false, end, false, encoding );\n\t}\n\telse\n\t{\n\t\t// All attribute values should be in single or double quotes.\n\t\t// But this is such a common error that the parser will try\n\t\t// its best, even without them.\n\t\tvalue = \"\";\n\t\twhile (    p && *p\t\t\t\t\t\t\t\t\t\t\t// existence\n\t\t\t\t&& !IsWhiteSpace( *p )\t\t\t\t\t\t\t\t// whitespace\n\t\t\t\t&& *p != '/' && *p != '>' )\t\t\t\t\t\t\t// tag end\n\t\t{\n\t\t\tif ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {\n\t\t\t\t// [ 1451649 ] Attribute values with trailing quotes not handled correctly\n\t\t\t\t// We did not have an opening quote but seem to have a \n\t\t\t\t// closing one. Give up and throw an error.\n\t\t\t\tif ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tvalue += *p;\n\t\t\t++p;\n\t\t}\n\t}\n\treturn p;\n}\n\n#ifdef TIXML_USE_STL\nvoid TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )\n{\n\twhile ( in->good() )\n\t{\n\t\tint c = in->peek();\t\n\t\tif ( !cdata && (c == '<' ) ) \n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tif ( c <= 0 )\n\t\t{\n\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\treturn;\n\t\t}\n\n\t\t(*tag) += (char) c;\n\t\tin->get();\t// \"commits\" the peek made above\n\n\t\tif ( cdata && c == '>' && tag->size() >= 3 ) {\n\t\t\tsize_t len = tag->size();\n\t\t\tif ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {\n\t\t\t\t// terminator of cdata.\n\t\t\t\treturn;\n\t\t\t}\n\t\t}    \n\t}\n}\n#endif\n\nconst char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\n{\n\tvalue = \"\";\n\tTiXmlDocument* document = GetDocument();\n\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, encoding );\n\t\tlocation = data->Cursor();\n\t}\n\n\tconst char* const startTag = \"<![CDATA[\";\n\tconst char* const endTag   = \"]]>\";\n\n\tif ( cdata || StringEqual( p, startTag, false, encoding ) )\n\t{\n\t\tcdata = true;\n\n\t\tif ( !StringEqual( p, startTag, false, encoding ) )\n\t\t{\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );\n\t\t\treturn 0;\n\t\t}\n\t\tp += strlen( startTag );\n\n\t\t// Keep all the white space, ignore the encoding, etc.\n\t\twhile (\t   p && *p\n\t\t\t\t&& !StringEqual( p, endTag, false, encoding )\n\t\t\t  )\n\t\t{\n\t\t\tvalue += *p;\n\t\t\t++p;\n\t\t}\n\n\t\tTIXML_STRING dummy; \n\t\tp = ReadText( p, &dummy, false, endTag, false, encoding );\n\t\treturn p;\n\t}\n\telse\n\t{\n\t\tbool ignoreWhite = true;\n\n\t\tconst char* end = \"<\";\n\t\tp = ReadText( p, &value, ignoreWhite, end, false, encoding );\n\t\tif ( p && *p )\n\t\t\treturn p-1;\t// don't truncate the '<'\n\t\treturn 0;\n\t}\n}\n\n#ifdef TIXML_USE_STL\nvoid TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )\n{\n\twhile ( in->good() )\n\t{\n\t\tint c = in->get();\n\t\tif ( c <= 0 )\n\t\t{\n\t\t\tTiXmlDocument* document = GetDocument();\n\t\t\tif ( document )\n\t\t\t\tdocument->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\n\t\t\treturn;\n\t\t}\n\t\t(*tag) += (char) c;\n\n\t\tif ( c == '>' )\n\t\t{\n\t\t\t// All is well.\n\t\t\treturn;\n\t\t}\n\t}\n}\n#endif\n\nconst char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )\n{\n\tp = SkipWhiteSpace( p, _encoding );\n\t// Find the beginning, find the end, and look for\n\t// the stuff in-between.\n\tTiXmlDocument* document = GetDocument();\n\tif ( !p || !*p || !StringEqual( p, \"<?xml\", true, _encoding ) )\n\t{\n\t\tif ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );\n\t\treturn 0;\n\t}\n\tif ( data )\n\t{\n\t\tdata->Stamp( p, _encoding );\n\t\tlocation = data->Cursor();\n\t}\n\tp += 5;\n\n\tversion = \"\";\n\tencoding = \"\";\n\tstandalone = \"\";\n\n\twhile ( p && *p )\n\t{\n\t\tif ( *p == '>' )\n\t\t{\n\t\t\t++p;\n\t\t\treturn p;\n\t\t}\n\n\t\tp = SkipWhiteSpace( p, _encoding );\n\t\tif ( StringEqual( p, \"version\", true, _encoding ) )\n\t\t{\n\t\t\tTiXmlAttribute attrib;\n\t\t\tp = attrib.Parse( p, data, _encoding );\t\t\n\t\t\tversion = attrib.Value();\n\t\t}\n\t\telse if ( StringEqual( p, \"encoding\", true, _encoding ) )\n\t\t{\n\t\t\tTiXmlAttribute attrib;\n\t\t\tp = attrib.Parse( p, data, _encoding );\t\t\n\t\t\tencoding = attrib.Value();\n\t\t}\n\t\telse if ( StringEqual( p, \"standalone\", true, _encoding ) )\n\t\t{\n\t\t\tTiXmlAttribute attrib;\n\t\t\tp = attrib.Parse( p, data, _encoding );\t\t\n\t\t\tstandalone = attrib.Value();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Read over whatever it is.\n\t\t\twhile( p && *p && *p != '>' && !IsWhiteSpace( *p ) )\n\t\t\t\t++p;\n\t\t}\n\t}\n\treturn 0;\n}\n\nbool TiXmlText::Blank() const\n{\n\tfor ( unsigned i=0; i<value.length(); i++ )\n\t\tif ( !IsWhiteSpace( value[i] ) )\n\t\t\treturn false;\n\treturn true;\n}\n\n"
  },
  {
    "path": "common/xml/xmlhelper.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util/base.h\"\n#include \"xmlhelper.h\"\n\nCXmlHelper::CXmlHelper() {}\n\nCXmlHelper::~CXmlHelper() {}\n\nBOOL CXmlHelper::LoadFile(LPCTSTR pFileName) {\n#ifdef UNICODE\n  USES_CONVERSION;\n  LPCSTR pAnsiFileName = T2A(pFileName);\n  return m_xmlDoc.LoadFile(pAnsiFileName);\n#else\n  return m_xmlDoc.LoadFile(pFileName);\n#endif\n}\n\nBOOL CXmlHelper::loadResFile(HINSTANCE hInstance, LPCTSTR lpszResName,\n                             LPCTSTR lpszResType) {\n  HRSRC hRes = FindResource(hInstance, lpszResName, lpszResType);\n  if (hRes) {\n    HGLOBAL hGlobal = LoadResource(hInstance, hRes);\n    if (hGlobal) {\n      LPVOID lpResource = ::LockResource(hGlobal);\n      if (lpResource) {\n\n        TCHAR szTempPath[MAX_PATH] = {0};\n        TCHAR szTempFile[MAX_PATH] = {0};\n        GetTempPath(SIZEOF(szTempPath) - 1, szTempPath);\n        GetTempFileName(szTempPath, _T(\"GH_\"), 0, szTempFile);\n\n        HANDLE hFile = CreateFile(szTempFile, GENERIC_WRITE, 0, NULL,\n                                  CREATE_ALWAYS, 0, NULL);\n        DWORD dwBytesWritten = 0;\n        if (hFile != INVALID_HANDLE_VALUE) {\n          WriteFile(hFile, lpResource, SizeofResource(_hInstance, hRes),\n                    &dwBytesWritten, NULL);\n          CloseHandle(hFile);\n        }\n\n        FreeResource(hGlobal);\n\n        BOOL bRet = LoadFile(szTempFile);\n        SetFileAttributes(szTempFile, FILE_ATTRIBUTE_NORMAL);\n        DeleteFile(szTempFile);\n        return bRet;\n      }\n      FreeResource(hGlobal);\n    }\n  }\n  return FALSE;\n}\n\nBOOL CXmlHelper::LoadStringW(WCHAR *lpzXmlStr) {\n  string strXml = Util::Base::UnicodeToUTF8(lpzXmlStr);\n  m_xmlDoc.Parse(strXml.c_str(), 0, TIXML_ENCODING_UTF8);\n  return TRUE;\n}\n\nBOOL CXmlHelper::LoadString(LPCTSTR pXmlStr) {\n#ifdef UNICODE\n  USES_CONVERSION;\n  LPCSTR pAnsiXmlStr = T2A(pXmlStr);\n  m_xmlDoc.Parse(pAnsiXmlStr);\n#else\n  m_xmlDoc.Parse(pXmlStr);\n#endif\n\n  return TRUE;\n}\n\nXmlElementPtr CXmlHelper::GetRoot() { return m_xmlDoc.RootElement(); }\n\ntstring CXmlHelper::GetElementName(XmlElementPtr pElement) {\n  return Util::Base::UTF8ToUnicode(pElement->Value());\n}\n\ntstring CXmlHelper::GetElementValue(XmlElementPtr pElement) {\n  return Util::Base::UTF8ToUnicode(pElement->GetText());\n}\n\nstd::vector<XmlElementPtr> CXmlHelper::GetChild(XmlElementPtr pElement) {\n  std::vector<XmlElementPtr> vecChild;\n  XmlElementPtr pChild = pElement->FirstChildElement();\n  while (pChild) {\n    vecChild.push_back(pChild);\n\n    pChild = pChild->NextSiblingElement();\n  }\n\n  return vecChild;\n}\n\ntstring CXmlHelper::GetAttributeString(XmlElementPtr pElement,\n                                       string lpszAttriName) {\n  LPCSTR lpszValue = pElement->Attribute(lpszAttriName.c_str());\n  return Util::Base::UTF8ToUnicode(lpszValue);\n}\n\nint CXmlHelper::GetAttributeInt(XmlElementPtr pElement, string lpszAttriName) {\n  int nValue = 0;\n  pElement->Attribute(lpszAttriName.c_str(), &nValue);\n  return nValue;\n}\n\nBOOL CXmlHelper::GetAttributeBool(XmlElementPtr pElement,\n                                  string lpszAttriName) {\n  bool bValue = TRUE;\n  pElement->QueryBoolAttribute(lpszAttriName.c_str(), &bValue);\n  if (bValue)\n    return TRUE;\n  else\n    return FALSE;\n}\n\ndouble CXmlHelper::GetAttributeDouble(XmlElementPtr pElement,\n                                      string lpszAttriName) {\n  double dValue = 0.0;\n  pElement->QueryDoubleAttribute(lpszAttriName.c_str(), &dValue);\n  return dValue;\n}\n\nvoid CXmlHelper::InsertDeclaration(string strVer, string strEncode) {\n  TiXmlDeclaration *dec =\n      new TiXmlDeclaration(strVer.c_str(), strEncode.c_str(), \"\");\n  m_xmlDoc.LinkEndChild(dec);\n}\nXmlElementPtr CXmlHelper::InsertChild(string strName) {\n  TiXmlElement *pChild = new TiXmlElement(strName.c_str());\n  m_xmlDoc.LinkEndChild(pChild);\n\n  return pChild;\n}\n\nvoid CXmlHelper::InsertChild(XmlElementPtr pElement) {\n  m_xmlDoc.LinkEndChild(pElement);\n}\n\nXmlElementPtr CXmlHelper::InsertChild(XmlElementPtr pElement, string strName) {\n  TiXmlElement *pChild = new TiXmlElement(strName.c_str());\n  if (pChild) {\n    pElement->LinkEndChild(pChild);\n  }\n\n  return pChild;\n}\n\nvoid CXmlHelper::SetElementString(XmlElementPtr pElement, tstring strVal) {\n#ifdef UNICODE\n  TiXmlText *pStrName = new TiXmlText(Util::Base::UnicodeToUTF8(strVal.c_str()).c_str());\n#else\n  TiXmlText *pStrName = new TiXmlText(strVal.c_str());\n#endif\n  pElement->LinkEndChild(pStrName);\n}\n\nvoid CXmlHelper::SetElementInt(XmlElementPtr pElement, int nVal) {\n  TCHAR szVal[64] = {0};\n  StringCchPrintf(szVal, 64, _T(\"%d\"), nVal);\n  SetElementString(pElement, szVal);\n}\n\nvoid CXmlHelper::SetAttributeString(XmlElementPtr pElement, string strAttriName,\n                                    tstring strAttriVal) {\n#ifdef UNICODE\n  pElement->SetAttribute(strAttriName.c_str(),\n                         Util::Base::UnicodeToUTF8(strAttriVal.c_str()).c_str());\n#else\n  pElement->SetAttribute(strAttriName.c_str(), strAttriVal.c_str());\n#endif\n}\n\nvoid CXmlHelper::SetAttributeInt(XmlElementPtr pElement, string strAttriName,\n                                 int nAttriVal) {\n  TCHAR szVal[64] = {0};\n  StringCchPrintf(szVal, 64, _T(\"%d\"), nAttriVal);\n  SetAttributeString(pElement, strAttriName, szVal);\n}\n\nvoid CXmlHelper::SaveFile(LPCTSTR pFileName) {\n#ifdef UNICODE\n  USES_CONVERSION;\n  LPCSTR pAnsiFileName = T2A(pFileName);\n  m_xmlDoc.SaveFile(pAnsiFileName);\n#else\n  m_xmlDoc.SaveFile(pFileName);\n#endif\n}\n"
  },
  {
    "path": "common/xml/xmlhelper.h",
    "content": "#pragma once\n\n#include <strsafe.h>\n#include <string>\n#include <vector>\n#include \"tinyxml.h\"\n\n#ifndef tstring\n#ifdef _UNICODE\n#define tstring std::wstring\n#else\n#define tstring std::string\n#endif\n#endif\n\ntypedef TiXmlDocument XmlDocument;\ntypedef TiXmlElement *XmlElementPtr;\ntypedef TiXmlAttribute *XmlAttributePtr;\n\nclass CXmlHelper {\n  using string = std::string;\n  using wstring = std::wstring;\npublic:\n  CXmlHelper();\n  virtual ~CXmlHelper();\n\n  static CXmlHelper &GetInstance() {\n    static CXmlHelper This;\n    return This;\n  }\n\n  BOOL LoadFile(LPCTSTR pFileName);\n  BOOL loadResFile(HINSTANCE hInstance, LPCTSTR lpszResName,\n                   LPCTSTR lpszResType);\n  BOOL LoadString(LPCTSTR lpszXmlStr);\n  BOOL LoadStringW(WCHAR *lpzXmlStr);\n  XmlElementPtr GetRoot();\n  std::vector<XmlElementPtr> GetChild(XmlElementPtr pElement);\n  tstring GetElementName(XmlElementPtr pElement);\n  tstring GetElementValue(XmlElementPtr pElement);\n  tstring GetAttributeString(XmlElementPtr pElement, string lpszAttriName);\n  int GetAttributeInt(XmlElementPtr pElement, string lpszAttriName);\n  BOOL GetAttributeBool(XmlElementPtr pElement, string lpszAttriName);\n  double GetAttributeDouble(XmlElementPtr pElement, string lpszAttriName);\n\n  void InsertDeclaration(string strVer = \"1.0\", string strEncode = \"UTF-8\");\n  void InsertChild(XmlElementPtr pElement);\n  XmlElementPtr InsertChild(string strName);\n  XmlElementPtr InsertChild(XmlElementPtr pElement, string strName);\n  void SetElementString(XmlElementPtr pElement, tstring strVal);\n  void SetElementInt(XmlElementPtr pElement, int nVal);\n  void SetAttributeString(XmlElementPtr pElement, string strAttriName,\n                          tstring strAttriVal);\n  void SetAttributeInt(XmlElementPtr pElement, string strAttriName,\n                       int nAttriVal);\n  void SaveFile(LPCTSTR pFileName);\n\nprivate:\n  XmlDocument m_xmlDoc;\n\n};\n"
  },
  {
    "path": "common/xzip/XUnzip.cpp",
    "content": "// XUnzip.cpp  Version 1.3\n//\n// Authors:      Mark Adler et al. (see below)\n//\n// Modified by:  Lucian Wischik\n//               lu@wischik.com\n//\n// Version 1.0   - Turned C files into just a single CPP file\n//               - Made them compile cleanly as C++ files\n//               - Gave them simpler APIs\n//               - Added the ability to zip/unzip directly in memory without\n//                 any intermediate files\n//\n// Modified by:  Hans Dietrich\n//               hdietrich@gmail.com\n//\n// Version 1.3:  - Corrected size bug introduced by 1.2\n//\n// Version 1.2:  - Many bug fixes.  See CodeProject article for list.\n//\n// Version 1.1:  - Added Unicode support to CreateZip() and ZipAdd()\n//               - Changed file names to avoid conflicts with Lucian's files\n//\n///////////////////////////////////////////////////////////////////////////////\n//\n// Lucian Wischik's comments:\n// --------------------------\n// THIS FILE is almost entirely based upon code by Info-ZIP.\n// It has been modified by Lucian Wischik.\n// The original code may be found at http://www.info-zip.org\n// The original copyright text follows.\n//\n///////////////////////////////////////////////////////////////////////////////\n//\n// Original authors' comments:\n// ---------------------------\n// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The\n// definitive version of this document should be available at\n// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.\n//\n// Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.\n//\n// For the purposes of this copyright and license, \"Info-ZIP\" is defined as\n// the following set of individuals:\n//\n//   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,\n//   Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,\n//   Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz,\n//   David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko,\n//   Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs,\n//   Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler,\n//   Antoine Verheijen, Paul von Behren, Rich Wales, Mike White\n//\n// This software is provided \"as is\", without warranty of any kind, express\n// or implied.  In no event shall Info-ZIP or its contributors be held liable\n// for any direct, indirect, incidental, special or consequential damages\n// arising out of the use of or inability to use this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//    1. Redistributions of source code must retain the above copyright notice,\n//       definition, disclaimer, and this list of conditions.\n//\n//    2. Redistributions in binary form (compiled executables) must reproduce\n//       the above copyright notice, definition, disclaimer, and this list of\n//       conditions in documentation and/or other materials provided with the\n//       distribution. The sole exception to this condition is redistribution\n//       of a standard UnZipSFX binary as part of a self-extracting archive;\n//       that is permitted without inclusion of this license, as long as the\n//       normal UnZipSFX banner has not been removed from the binary or\n//       disabled.\n//\n//    3. Altered versions--including, but not limited to, ports to new\n//       operating systems, existing ports with new graphical interfaces, and\n//       dynamic, shared, or static library versions--must be plainly marked\n//       as such and must not be misrepresented as being the original source.\n//       Such altered versions also must not be misrepresented as being\n//       Info-ZIP releases--including, but not limited to, labeling of the\n//       altered versions with the names \"Info-ZIP\" (or any variation thereof,\n//       including, but not limited to, different capitalizations),\n//       \"Pocket UnZip\", \"WiZ\" or \"MacZip\" without the explicit permission of\n//       Info-ZIP.  Such altered versions are further prohibited from\n//       misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or\n//       of the Info-ZIP URL(s).\n//\n//    4. Info-ZIP retains the right to use the names \"Info-ZIP\", \"Zip\", \"UnZip\",\n//       \"UnZipSFX\", \"WiZ\", \"Pocket UnZip\", \"Pocket Zip\", and \"MacZip\" for its\n//       own source and binary releases.\n//\n///////////////////////////////////////////////////////////////////////////////\n\n#define _USE_32BIT_TIME_T //+++1.2\n\n#define STRICT\n#define WIN32_LEAN_AND_MEAN\n\n#include \"stdafx.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <tchar.h>\n#include <time.h>\n#include \"XUnzip.h\"\n\n#pragma warning(disable : 4996) // disable bogus deprecation warning\n\n// THIS FILE is almost entirely based upon code by Jean-loup Gailly\n// and Mark Adler. It has been modified by Lucian Wischik.\n// The original code may be found at http://www.gzip.org/zlib/\n// The original copyright text follows.\n//\n//\n//\n// zlib.h -- interface of the 'zlib' general purpose compression library\n//  version 1.1.3, July 9th, 1998\n//\n//  Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler\n//\n//  This software is provided 'as-is', without any express or implied\n//  warranty.  In no event will the authors be held liable for any damages\n//  arising from the use of this software.\n//\n//  Permission is granted to anyone to use this software for any purpose,\n//  including commercial applications, and to alter it and redistribute it\n//  freely, subject to the following restrictions:\n//\n//  1. The origin of this software must not be misrepresented; you must not\n//     claim that you wrote the original software. If you use this software\n//     in a product, an acknowledgment in the product documentation would be\n//     appreciated but is not required.\n//  2. Altered source versions must be plainly marked as such, and must not be\n//     misrepresented as being the original software.\n//  3. This notice may not be removed or altered from any source distribution.\n//\n//  Jean-loup Gailly        Mark Adler\n//  jloup@gzip.org          madler@alumni.caltech.edu\n//\n//\n//  The data format used by the zlib library is described by RFCs (Request for\n//  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt\n//  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).\n//\n//\n//     The 'zlib' compression library provides in-memory compression and\n//  decompression functions, including integrity checks of the uncompressed\n//  data.  This version of the library supports only one compression method\n//  (deflation) but other algorithms will be added later and will have the same\n//  stream interface.\n//\n//     Compression can be done in a single step if the buffers are large\n//  enough (for example if an input file is mmap'ed), or can be done by\n//  repeated calls of the compression function.  In the latter case, the\n//  application must provide more input and/or consume the output\n//  (providing more output space) before each call.\n//\n//     The library also supports reading and writing files in gzip (.gz) format\n//  with an interface similar to that of stdio.\n//\n//     The library does not install any signal handler. The decoder checks\n//  the consistency of the compressed data, so the library should never\n//  crash even in case of corrupted input.\n//\n// for more info about .ZIP format, see\n// ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip\n//   PkWare has also a specification at ftp://ftp.pkware.com/probdesc.zip\n\n#define zmalloc(len) malloc(len)\n\n#define zfree(p) free(p)\n\n/*\nvoid *zmalloc(unsigned int len)\n{ char *buf = new char[len+32];\n  for (int i=0; i<16; i++)\n  { buf[i]=i;\n    buf[len+31-i]=i;\n  }\n  *((unsigned int*)buf) = len;\n  char c[1000]; wsprintf(c,\"malloc 0x%lx  - %lu\",buf+16,len);\n  OutputDebugString(c);\n  return buf+16;\n}\n\nvoid zfree(void *buf)\n{ char c[1000]; wsprintf(c,\"free   0x%lx\",buf);\n  OutputDebugString(c);\n  char *p = ((char*)buf)-16;\n  unsigned int len = *((unsigned int*)p);\n  bool blown=false;\n  for (int i=0; i<16; i++)\n  { char lo = p[i];\n    char hi = p[len+31-i];\n    if (hi!=i || (lo!=i && i>4)) blown=true;\n  }\n  if (blown)\n  { OutputDebugString(\"BLOWN!!!\");\n  }\n  delete[] p;\n}\n*/\n\n#pragma warning(disable : 4702) // unreachable code\n\nstatic ZRESULT zopenerror = ZR_OK; //+++1.2\n\ntypedef struct tm_unz_s {\n  unsigned int tm_sec;  // seconds after the minute - [0,59]\n  unsigned int tm_min;  // minutes after the hour - [0,59]\n  unsigned int tm_hour; // hours since midnight - [0,23]\n  unsigned int tm_mday; // day of the month - [1,31]\n  unsigned int tm_mon;  // months since January - [0,11]\n  unsigned int tm_year; // years - [1980..2044]\n} tm_unz;\n\n// unz_global_info structure contain global data about the ZIPfile\ntypedef struct unz_global_info_s {\n  unsigned long\n      number_entry; // total number of entries in the central dir on this disk\n  unsigned long size_comment; // size of the global comment of the zipfile\n} unz_global_info;\n\n// unz_file_info contain information about a file in the zipfile\ntypedef struct unz_file_info_s {\n  unsigned long version;            // version made by                 2 bytes\n  unsigned long version_needed;     // version needed to extract       2 bytes\n  unsigned long flag;               // general purpose bit flag        2 bytes\n  unsigned long compression_method; // compression method              2 bytes\n  unsigned long dosDate;            // last mod file date in Dos fmt   4 bytes\n  unsigned long crc;                // crc-32                          4 bytes\n  unsigned long compressed_size;    // compressed size                 4 bytes\n  unsigned long uncompressed_size;  // uncompressed size               4 bytes\n  unsigned long size_filename;      // filename length                 2 bytes\n  unsigned long size_file_extra;    // extra field length              2 bytes\n  unsigned long size_file_comment;  // file comment length             2 bytes\n  unsigned long disk_num_start;     // disk number start               2 bytes\n  unsigned long internal_fa;        // internal file attributes        2 bytes\n  unsigned long external_fa;        // external file attributes        4 bytes\n  tm_unz tmu_date;\n} unz_file_info;\n\n#define UNZ_OK (0)\n#define UNZ_END_OF_LIST_OF_FILE (-100)\n#define UNZ_ERRNO (Z_ERRNO)\n#define UNZ_EOF (0)\n#define UNZ_PARAMERROR (-102)\n#define UNZ_BADZIPFILE (-103)\n#define UNZ_INTERNALERROR (-104)\n#define UNZ_CRCERROR (-105)\n\n#define ZLIB_VERSION \"1.1.3\"\n\n// Allowed flush values; see deflate() for details\n#define Z_NO_FLUSH 0\n#define Z_SYNC_FLUSH 2\n#define Z_FULL_FLUSH 3\n#define Z_FINISH 4\n\n// compression levels\n#define Z_NO_COMPRESSION 0\n#define Z_BEST_SPEED 1\n#define Z_BEST_COMPRESSION 9\n#define Z_DEFAULT_COMPRESSION (-1)\n\n// compression strategy; see deflateInit2() for details\n#define Z_FILTERED 1\n#define Z_HUFFMAN_ONLY 2\n#define Z_DEFAULT_STRATEGY 0\n\n// Possible values of the data_type field\n#define Z_BINARY 0\n#define Z_ASCII 1\n#define Z_UNKNOWN 2\n\n// The deflate compression method (the only one supported in this version)\n#define Z_DEFLATED 8\n\n// for initializing zalloc, zfree, opaque\n#define Z_NULL 0\n\n// case sensitivity when searching for filenames\n#define CASE_SENSITIVE 1\n#define CASE_INSENSITIVE 2\n\n// Return codes for the compression/decompression functions. Negative\n// values are errors, positive values are used for special but normal events.\n#define Z_OK 0\n#define Z_STREAM_END 1\n#define Z_NEED_DICT 2\n#define Z_ERRNO (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR (-3)\n#define Z_MEM_ERROR (-4)\n#define Z_BUF_ERROR (-5)\n#define Z_VERSION_ERROR (-6)\n\n// Basic data types\ntypedef unsigned char Byte;  // 8 bits\ntypedef unsigned int uInt;   // 16 bits or more\ntypedef unsigned long uLong; // 32 bits or more\ntypedef void *voidpf;\ntypedef void *voidp;\ntypedef long z_off_t;\n\ntypedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size);\ntypedef void (*free_func)(voidpf opaque, voidpf address);\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n  Byte *next_in;  // next input byte\n  uInt avail_in;  // number of bytes available at next_in\n  uLong total_in; // total nb of input bytes read so far\n\n  Byte *next_out;  // next output byte should be put there\n  uInt avail_out;  // remaining free space at next_out\n  uLong total_out; // total nb of bytes output so far\n\n  char *msg;                    // last error message, NULL if no error\n  struct internal_state *state; // not visible by applications\n\n  alloc_func zalloc; // used to allocate the internal state\n  free_func zfree;   // used to free the internal state\n  voidpf opaque;     // private data object passed to zalloc and zfree\n\n  int data_type;  // best guess about the data type: ascii or binary\n  uLong adler;    // adler32 value of the uncompressed data\n  uLong reserved; // reserved for future use\n} z_stream;\n\ntypedef z_stream *z_streamp;\n\n//   The application must update next_in and avail_in when avail_in has\n//   dropped to zero. It must update next_out and avail_out when avail_out\n//   has dropped to zero. The application must initialize zalloc, zfree and\n//   opaque before calling the init function. All other fields are set by the\n//   compression library and must not be updated by the application.\n//\n//   The opaque value provided by the application will be passed as the first\n//   parameter for calls of zalloc and zfree. This can be useful for custom\n//   memory management. The compression library attaches no meaning to the\n//   opaque value.\n//\n//   zalloc must return Z_NULL if there is not enough memory for the object.\n//   If zlib is used in a multi-threaded application, zalloc and zfree must be\n//   thread safe.\n//\n//   The fields total_in and total_out can be used for statistics or\n//   progress reports. After compression, total_in holds the total size of\n//   the uncompressed data and may be saved for use in the decompressor\n//   (particularly if the decompressor wants to decompress everything in\n//   a single step).\n//\n\n// basic functions\n\nconst char *zlibVersion();\n// The application can compare zlibVersion and ZLIB_VERSION for consistency.\n// If the first character differs, the library code actually used is\n// not compatible with the zlib.h header file used by the application.\n// This check is automatically made by inflateInit.\n\nint inflate(z_streamp strm, int flush);\n//\n//    inflate decompresses as much data as possible, and stops when the input\n//  buffer becomes empty or the output buffer becomes full. It may some\n//  introduce some output latency (reading input without producing any output)\n//  except when forced to flush.\n//\n//  The detailed semantics are as follows. inflate performs one or both of the\n//  following actions:\n//\n//  - Decompress more input starting at next_in and update next_in and avail_in\n//    accordingly. If not all input can be processed (because there is not\n//    enough room in the output buffer), next_in is updated and processing\n//    will resume at this point for the next call of inflate().\n//\n//  - Provide more output starting at next_out and update next_out and avail_out\n//    accordingly.  inflate() provides as much output as possible, until there\n//    is no more input data or no more space in the output buffer (see below\n//    about the flush parameter).\n//\n//  Before the call of inflate(), the application should ensure that at least\n//  one of the actions is possible, by providing more input and/or consuming\n//  more output, and updating the next_* and avail_* values accordingly.\n//  The application can consume the uncompressed output when it wants, for\n//  example when the output buffer is full (avail_out == 0), or after each\n//  call of inflate(). If inflate returns Z_OK and with zero avail_out, it\n//  must be called again after making room in the output buffer because there\n//  might be more output pending.\n//\n//    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much\n//  output as possible to the output buffer. The flushing behavior of inflate is\n//  not specified for values of the flush parameter other than Z_SYNC_FLUSH\n//  and Z_FINISH, but the current implementation actually flushes as much output\n//  as possible anyway.\n//\n//    inflate() should normally be called until it returns Z_STREAM_END or an\n//  error. However if all decompression is to be performed in a single step\n//  (a single call of inflate), the parameter flush should be set to\n//  Z_FINISH. In this case all pending input is processed and all pending\n//  output is flushed; avail_out must be large enough to hold all the\n//  uncompressed data. (The size of the uncompressed data may have been saved\n//  by the compressor for this purpose.) The next operation on this stream must\n//  be inflateEnd to deallocate the decompression state. The use of Z_FINISH\n//  is never required, but can be used to inform inflate that a faster routine\n//  may be used for the single inflate() call.\n//\n//     If a preset dictionary is needed at this point (see inflateSetDictionary\n//  below), inflate sets strm-adler to the adler32 checksum of the\n//  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise\n//  it sets strm->adler to the adler32 checksum of all output produced\n//  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or\n//  an error code as described below. At the end of the stream, inflate()\n//  checks that its computed adler32 checksum is equal to that saved by the\n//  compressor and returns Z_STREAM_END only if the checksum is correct.\n//\n//    inflate() returns Z_OK if some progress has been made (more input\n//    processed\n//  or more output produced), Z_STREAM_END if the end of the compressed data has\n//  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n//  preset dictionary is needed at this point, Z_DATA_ERROR if the input data\n//  was corrupted (input stream not conforming to the zlib format or incorrect\n//  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent\n//  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not\n//  enough memory, Z_BUF_ERROR if no progress is possible or if there was not\n//  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR\n//  case, the application may then call inflateSync to look for a good\n//  compression block.\n//\n\nint inflateEnd(z_streamp strm);\n//\n//     All dynamically allocated data structures for this stream are freed.\n//   This function discards any unprocessed input and does not flush any\n//   pending output.\n//\n//     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state\n//   was inconsistent. In the error case, msg may be set but then points to a\n//   static string (which must not be deallocated).\n\n// Advanced functions\n\n//  The following functions are needed only in some special applications.\n\nint inflateSetDictionary(z_streamp strm, const Byte *dictionary,\n                         uInt dictLength);\n//\n//     Initializes the decompression dictionary from the given uncompressed byte\n//   sequence. This function must be called immediately after a call of inflate\n//   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor\n//   can be determined from the Adler32 value returned by this call of\n//   inflate. The compressor and decompressor must use exactly the same\n//   dictionary.\n//\n//     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n//   parameter is invalid (such as NULL dictionary) or the stream state is\n//   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n//   expected one (incorrect Adler32 value). inflateSetDictionary does not\n//   perform any decompression: this will be done by subsequent calls of\n//   inflate().\n\nint inflateSync(z_streamp strm);\n//\n//    Skips invalid compressed data until a full flush point can be found, or\n//    until all\n//  available input is skipped. No output is provided.\n//\n//    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR\n//  if no more input was provided, Z_DATA_ERROR if no flush point has been\n//  found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the\n//  success case, the application may save the current current value of total_in\n//  which indicates where valid compressed data was found. In the error case,\n//  the application may repeatedly call inflateSync, providing more input each\n//  time, until success or end of the input data.\n\nint inflateReset(z_streamp strm);\n//     This function is equivalent to inflateEnd followed by inflateInit,\n//   but does not free and reallocate all the internal decompression state.\n//   The stream will keep attributes that may have been set by inflateInit2.\n//\n//      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n//   stream state was inconsistent (such as zalloc or state being NULL).\n//\n\n// checksum functions\n// These functions are not related to compression but are exported\n// anyway because they might be useful in applications using the\n// compression library.\n\nuLong adler32(uLong adler, const Byte *buf, uInt len);\n//     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n//   return the updated checksum. If buf is NULL, this function returns\n//   the required initial value for the checksum.\n//   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed\n//   much faster. Usage example:\n//\n//     uLong adler = adler32(0L, Z_NULL, 0);\n//\n//     while (read_buffer(buffer, length) != EOF) {\n//       adler = adler32(adler, buffer, length);\n//     }\n//     if (adler != original_adler) error();\n\nuLong ucrc32(uLong crc, const Byte *buf, uInt len);\n//     Update a running crc with the bytes buf[0..len-1] and return the updated\n//   crc. If buf is NULL, this function returns the required initial value\n//   for the crc. Pre- and post-conditioning (one's complement) is performed\n//   within this function so it shouldn't be done by the application.\n//   Usage example:\n//\n//     uLong crc = crc32(0L, Z_NULL, 0);\n//\n//     while (read_buffer(buffer, length) != EOF) {\n//       crc = crc32(crc, buffer, length);\n//     }\n//     if (crc != original_crc) error();\n\nconst char *zError(int err);\nint inflateSyncPoint(z_streamp z);\nconst uLong *get_crc_table(void);\n\ntypedef unsigned char uch;\ntypedef uch uchf;\ntypedef unsigned short ush;\ntypedef ush ushf;\ntypedef unsigned long ulg;\n\nconst char *const z_errmsg[10] = { // indexed by 2-zlib_error\n    \"need dictionary\",             // Z_NEED_DICT       2\n    \"stream end\",                  // Z_STREAM_END      1\n    \"\",                            // Z_OK              0\n    \"file error\",                  // Z_ERRNO         (-1)\n    \"stream error\",                // Z_STREAM_ERROR  (-2)\n    \"data error\",                  // Z_DATA_ERROR    (-3)\n    \"insufficient memory\",         // Z_MEM_ERROR     (-4)\n    \"buffer error\",                // Z_BUF_ERROR     (-5)\n    \"incompatible version\",        // Z_VERSION_ERROR (-6)\n    \"\"};\n\n#define ERR_MSG(err) z_errmsg[Z_NEED_DICT - (err)]\n\n#define ERR_RETURN(strm, err) return (strm->msg = (char *)ERR_MSG(err), (err))\n// To be used only when the state is known to be valid\n\n// common constants\n\n#define STORED_BLOCK 0\n#define STATIC_TREES 1\n#define DYN_TREES 2\n// The three kinds of block type\n\n#define MIN_MATCH 3\n#define MAX_MATCH 258\n// The minimum and maximum match lengths\n\n#define PRESET_DICT 0x20 // preset dictionary flag in zlib header\n\n// target dependencies\n\n#define OS_CODE 0x0b // Window 95 & Windows NT\n\n// functions\n\n#define zmemzero(dest, len) memset(dest, 0, len)\n\n// Diagnostic functions\n#undef Assert\n#undef Trace\n#undef Tracev\n#undef Tracevv\n#undef Tracec\n#undef Tracecv\n\n#ifdef DEBUG\n\nint z_verbose = 0;\nvoid z_error(char *m) {\n  fprintf(stderr, \"%s\\n\", m);\n  exit(1);\n}\n\n#define Assert(cond, msg)                                                      \\\n  {                                                                            \\\n    if (!(cond))                                                               \\\n      z_error(msg);                                                            \\\n  }\n#define Trace(x)                                                               \\\n  {                                                                            \\\n    if (z_verbose >= 0)                                                        \\\n      fprintf x;                                                               \\\n  }\n#define Tracev(x)                                                              \\\n  {                                                                            \\\n    if (z_verbose > 0)                                                         \\\n      fprintf x;                                                               \\\n  }\n#define Tracevv(x)                                                             \\\n  {                                                                            \\\n    if (z_verbose > 1)                                                         \\\n      fprintf x;                                                               \\\n  }\n#define Tracec(c, x)                                                           \\\n  {                                                                            \\\n    if (z_verbose > 0 && (c))                                                  \\\n      fprintf x;                                                               \\\n  }\n#define Tracecv(c, x)                                                          \\\n  {                                                                            \\\n    if (z_verbose > 1 && (c))                                                  \\\n      fprintf x;                                                               \\\n  }\n\n#else\n\n#ifndef __noop\n#if _MSC_VER < 1300\n#define __noop ((void)0)\n#endif\n#endif\n\n#define Assert(cond, msg) __noop\n#define Trace(x) __noop\n#define Tracev(x) __noop\n#define Tracevv(x) __noop\n#define Tracec(c, x) __noop\n#define Tracecv(c, x) __noop\n\n#endif\n\ntypedef uLong (*check_func)(uLong check, const Byte *buf, uInt len);\nvoidpf zcalloc(voidpf opaque, unsigned items, unsigned size);\nvoid zcfree(voidpf opaque, voidpf ptr);\n\n#define ZALLOC(strm, items, size)                                              \\\n  (*((strm)->zalloc))((strm)->opaque, (items), (size))\n#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))\n\n// void ZFREE(z_streamp strm,voidpf addr)\n//{ *((strm)->zfree))((strm)->opaque, addr);\n// }\n\n#define TRY_FREE(s, p)                                                         \\\n  {                                                                            \\\n    if (p)                                                                     \\\n      ZFREE(s, p);                                                             \\\n  }\n\n// Huffman code lookup table entry--this entry is four bytes for machines\n// that have 16-bit pointers (e.g. PC's in the small or medium model).\n\ntypedef struct inflate_huft_s inflate_huft;\n\nstruct inflate_huft_s {\n  union {\n    struct {\n      Byte Exop; // number of extra bits or operation\n      Byte Bits; // number of bits in this code or subcode\n    } what;\n    uInt pad; // pad structure to a power of 2 (4 bytes for\n  } word;     //  16-bit, 8 bytes for 32-bit int's)\n  uInt base;  // literal, length base, distance base, or table offset\n};\n\n// Maximum size of dynamic tree.  The maximum found in a long but non-\n//   exhaustive search was 1004 huft structures (850 for length/literals\n//   and 154 for distances, the latter actually the result of an\n//   exhaustive search).  The actual maximum is not known, but the\n//   value below is more than safe.\n#define MANY 1440\n\nint inflate_trees_bits(uInt *,          // 19 code lengths\n                       uInt *,          // bits tree desired/actual depth\n                       inflate_huft **, // bits tree result\n                       inflate_huft *,  // space for trees\n                       z_streamp);      // for messages\n\nint inflate_trees_dynamic(uInt,            // number of literal/length codes\n                          uInt,            // number of distance codes\n                          uInt *,          // that many (total) code lengths\n                          uInt *,          // literal desired/actual bit depth\n                          uInt *,          // distance desired/actual bit depth\n                          inflate_huft **, // literal/length tree result\n                          inflate_huft **, // distance tree result\n                          inflate_huft *,  // space for trees\n                          z_streamp);      // for messages\n\nint inflate_trees_fixed(uInt *, // literal desired/actual bit depth\n                        uInt *, // distance desired/actual bit depth\n                        const inflate_huft **, // literal/length tree result\n                        const inflate_huft **, // distance tree result\n                        z_streamp);            // for memory allocation\n\nstruct inflate_blocks_state;\ntypedef struct inflate_blocks_state inflate_blocks_statef;\n\ninflate_blocks_statef *inflate_blocks_new(z_streamp z,\n                                          check_func c, // check function\n                                          uInt w);      // window size\n\nint inflate_blocks(inflate_blocks_statef *, z_streamp,\n                   int); // initial return code\n\nvoid inflate_blocks_reset(inflate_blocks_statef *, z_streamp,\n                          uLong *); // check value on output\n\nint inflate_blocks_free(inflate_blocks_statef *, z_streamp);\n\nvoid inflate_set_dictionary(inflate_blocks_statef *s,\n                            const Byte *d, // dictionary\n                            uInt n);       // dictionary length\n\nint inflate_blocks_sync_point(inflate_blocks_statef *s);\n\nstruct inflate_codes_state;\ntypedef struct inflate_codes_state inflate_codes_statef;\n\ninflate_codes_statef *inflate_codes_new(uInt, uInt, const inflate_huft *,\n                                        const inflate_huft *, z_streamp);\n\nint inflate_codes(inflate_blocks_statef *, z_streamp, int);\n\nvoid inflate_codes_free(inflate_codes_statef *, z_streamp);\n\ntypedef enum {\n  IBM_TYPE,   // get type bits (3, including end bit)\n  IBM_LENS,   // get lengths for stored\n  IBM_STORED, // processing stored block\n  IBM_TABLE,  // get table lengths\n  IBM_BTREE,  // get bit lengths tree for a dynamic block\n  IBM_DTREE,  // get length, distance trees for a dynamic block\n  IBM_CODES,  // processing fixed or dynamic block\n  IBM_DRY,    // output remaining window bytes\n  IBM_DONE,   // finished last block, done\n  IBM_BAD\n} // got a data error--stuck here\ninflate_block_mode;\n\n// inflate blocks semi-private state\nstruct inflate_blocks_state {\n\n  // mode\n  inflate_block_mode mode; // current inflate_block mode\n\n  // mode dependent information\n  union {\n    uInt left; // if STORED, bytes left to copy\n    struct {\n      uInt table;       // table lengths (14 bits)\n      uInt index;       // index into blens (or border)\n      uInt *blens;      // bit lengths of codes\n      uInt bb;          // bit length tree depth\n      inflate_huft *tb; // bit length decoding tree\n    } trees;            // if DTREE, decoding info for trees\n    struct {\n      inflate_codes_statef *codes;\n    } decode; // if CODES, current state\n  } sub;      // submode\n  uInt last;  // true if this block is the last block\n\n  // mode independent information\n  uInt bitk;           // bits in bit buffer\n  uLong bitb;          // bit buffer\n  inflate_huft *hufts; // single malloc for tree space\n  Byte *window;        // sliding window\n  Byte *end;           // one byte after sliding window\n  Byte *read;          // window read pointer\n  Byte *write;         // window write pointer\n  check_func checkfn;  // check function\n  uLong check;         // check on output\n};\n\n// defines for inflate input/output\n//   update pointers and return\n#define UPDBITS                                                                \\\n  {                                                                            \\\n    s->bitb = b;                                                               \\\n    s->bitk = k;                                                               \\\n  }\n#define UPDIN                                                                  \\\n  {                                                                            \\\n    z->avail_in = n;                                                           \\\n    z->total_in += (uLong)(p - z->next_in);                                    \\\n    z->next_in = p;                                                            \\\n  }\n#define UPDOUT                                                                 \\\n  { s->write = q; }\n#define UPDATE                                                                 \\\n  { UPDBITS UPDIN UPDOUT }\n#define LEAVE                                                                  \\\n  { UPDATE return inflate_flush(s, z, r); }\n//   get bytes and bits\n#define LOADIN                                                                 \\\n  {                                                                            \\\n    p = z->next_in;                                                            \\\n    n = z->avail_in;                                                           \\\n    b = s->bitb;                                                               \\\n    k = s->bitk;                                                               \\\n  }\n#define NEEDBYTE                                                               \\\n  {                                                                            \\\n    if (n)                                                                     \\\n      r = Z_OK;                                                                \\\n    else                                                                       \\\n      LEAVE                                                                    \\\n  }\n#define NEXTBYTE (n--, *p++)\n#define NEEDBITS(j)                                                            \\\n  {                                                                            \\\n    while (k < (j)) {                                                          \\\n      NEEDBYTE;                                                                \\\n      b |= ((uLong)NEXTBYTE) << k;                                             \\\n      k += 8;                                                                  \\\n    }                                                                          \\\n  }\n#define DUMPBITS(j)                                                            \\\n  {                                                                            \\\n    b >>= (j);                                                                 \\\n    k -= (j);                                                                  \\\n  }\n//   output bytes\n#define WAVAIL (uInt)(q < s->read ? s->read - q - 1 : s->end - q)\n#define LOADOUT                                                                \\\n  {                                                                            \\\n    q = s->write;                                                              \\\n    m = (uInt)WAVAIL;                                                          \\\n    m;                                                                         \\\n  }\n#define WRAP                                                                   \\\n  {                                                                            \\\n    if (q == s->end && s->read != s->window) {                                 \\\n      q = s->window;                                                           \\\n      m = (uInt)WAVAIL;                                                        \\\n    }                                                                          \\\n  }\n#define FLUSH                                                                  \\\n  {                                                                            \\\n    UPDOUT r = inflate_flush(s, z, r);                                         \\\n    LOADOUT                                                                    \\\n  }\n#define NEEDOUT                                                                \\\n  {                                                                            \\\n    if (m == 0) {                                                              \\\n      WRAP if (m == 0) { FLUSH WRAP if (m == 0) LEAVE }                        \\\n    }                                                                          \\\n    r = Z_OK;                                                                  \\\n  }\n#define OUTBYTE(a)                                                             \\\n  {                                                                            \\\n    *q++ = (Byte)(a);                                                          \\\n    m--;                                                                       \\\n  }\n//   load local pointers\n#define LOAD                                                                   \\\n  { LOADIN LOADOUT }\n\n// masks for lower bits (size given to avoid silly warnings with Visual C++)\n// And'ing with mask[n] masks the lower n bits\nconst uInt inflate_mask[17] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f,\n                               0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff,\n                               0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff};\n\n// copy as much as possible from the sliding window to the output area\nint inflate_flush(inflate_blocks_statef *, z_streamp, int);\n\nint inflate_fast(uInt, uInt, const inflate_huft *, const inflate_huft *,\n                 inflate_blocks_statef *, z_streamp);\n\nconst uInt fixed_bl = 9;\nconst uInt fixed_bd = 5;\nconst inflate_huft fixed_tl[] = {\n    {{{96, 7}}, 256}, {{{0, 8}}, 80},  {{{0, 8}}, 16}, {{{84, 8}}, 115},\n    {{{82, 7}}, 31},  {{{0, 8}}, 112}, {{{0, 8}}, 48}, {{{0, 9}}, 192},\n    {{{80, 7}}, 10},  {{{0, 8}}, 96},  {{{0, 8}}, 32}, {{{0, 9}}, 160},\n    {{{0, 8}}, 0},    {{{0, 8}}, 128}, {{{0, 8}}, 64}, {{{0, 9}}, 224},\n    {{{80, 7}}, 6},   {{{0, 8}}, 88},  {{{0, 8}}, 24}, {{{0, 9}}, 144},\n    {{{83, 7}}, 59},  {{{0, 8}}, 120}, {{{0, 8}}, 56}, {{{0, 9}}, 208},\n    {{{81, 7}}, 17},  {{{0, 8}}, 104}, {{{0, 8}}, 40}, {{{0, 9}}, 176},\n    {{{0, 8}}, 8},    {{{0, 8}}, 136}, {{{0, 8}}, 72}, {{{0, 9}}, 240},\n    {{{80, 7}}, 4},   {{{0, 8}}, 84},  {{{0, 8}}, 20}, {{{85, 8}}, 227},\n    {{{83, 7}}, 43},  {{{0, 8}}, 116}, {{{0, 8}}, 52}, {{{0, 9}}, 200},\n    {{{81, 7}}, 13},  {{{0, 8}}, 100}, {{{0, 8}}, 36}, {{{0, 9}}, 168},\n    {{{0, 8}}, 4},    {{{0, 8}}, 132}, {{{0, 8}}, 68}, {{{0, 9}}, 232},\n    {{{80, 7}}, 8},   {{{0, 8}}, 92},  {{{0, 8}}, 28}, {{{0, 9}}, 152},\n    {{{84, 7}}, 83},  {{{0, 8}}, 124}, {{{0, 8}}, 60}, {{{0, 9}}, 216},\n    {{{82, 7}}, 23},  {{{0, 8}}, 108}, {{{0, 8}}, 44}, {{{0, 9}}, 184},\n    {{{0, 8}}, 12},   {{{0, 8}}, 140}, {{{0, 8}}, 76}, {{{0, 9}}, 248},\n    {{{80, 7}}, 3},   {{{0, 8}}, 82},  {{{0, 8}}, 18}, {{{85, 8}}, 163},\n    {{{83, 7}}, 35},  {{{0, 8}}, 114}, {{{0, 8}}, 50}, {{{0, 9}}, 196},\n    {{{81, 7}}, 11},  {{{0, 8}}, 98},  {{{0, 8}}, 34}, {{{0, 9}}, 164},\n    {{{0, 8}}, 2},    {{{0, 8}}, 130}, {{{0, 8}}, 66}, {{{0, 9}}, 228},\n    {{{80, 7}}, 7},   {{{0, 8}}, 90},  {{{0, 8}}, 26}, {{{0, 9}}, 148},\n    {{{84, 7}}, 67},  {{{0, 8}}, 122}, {{{0, 8}}, 58}, {{{0, 9}}, 212},\n    {{{82, 7}}, 19},  {{{0, 8}}, 106}, {{{0, 8}}, 42}, {{{0, 9}}, 180},\n    {{{0, 8}}, 10},   {{{0, 8}}, 138}, {{{0, 8}}, 74}, {{{0, 9}}, 244},\n    {{{80, 7}}, 5},   {{{0, 8}}, 86},  {{{0, 8}}, 22}, {{{192, 8}}, 0},\n    {{{83, 7}}, 51},  {{{0, 8}}, 118}, {{{0, 8}}, 54}, {{{0, 9}}, 204},\n    {{{81, 7}}, 15},  {{{0, 8}}, 102}, {{{0, 8}}, 38}, {{{0, 9}}, 172},\n    {{{0, 8}}, 6},    {{{0, 8}}, 134}, {{{0, 8}}, 70}, {{{0, 9}}, 236},\n    {{{80, 7}}, 9},   {{{0, 8}}, 94},  {{{0, 8}}, 30}, {{{0, 9}}, 156},\n    {{{84, 7}}, 99},  {{{0, 8}}, 126}, {{{0, 8}}, 62}, {{{0, 9}}, 220},\n    {{{82, 7}}, 27},  {{{0, 8}}, 110}, {{{0, 8}}, 46}, {{{0, 9}}, 188},\n    {{{0, 8}}, 14},   {{{0, 8}}, 142}, {{{0, 8}}, 78}, {{{0, 9}}, 252},\n    {{{96, 7}}, 256}, {{{0, 8}}, 81},  {{{0, 8}}, 17}, {{{85, 8}}, 131},\n    {{{82, 7}}, 31},  {{{0, 8}}, 113}, {{{0, 8}}, 49}, {{{0, 9}}, 194},\n    {{{80, 7}}, 10},  {{{0, 8}}, 97},  {{{0, 8}}, 33}, {{{0, 9}}, 162},\n    {{{0, 8}}, 1},    {{{0, 8}}, 129}, {{{0, 8}}, 65}, {{{0, 9}}, 226},\n    {{{80, 7}}, 6},   {{{0, 8}}, 89},  {{{0, 8}}, 25}, {{{0, 9}}, 146},\n    {{{83, 7}}, 59},  {{{0, 8}}, 121}, {{{0, 8}}, 57}, {{{0, 9}}, 210},\n    {{{81, 7}}, 17},  {{{0, 8}}, 105}, {{{0, 8}}, 41}, {{{0, 9}}, 178},\n    {{{0, 8}}, 9},    {{{0, 8}}, 137}, {{{0, 8}}, 73}, {{{0, 9}}, 242},\n    {{{80, 7}}, 4},   {{{0, 8}}, 85},  {{{0, 8}}, 21}, {{{80, 8}}, 258},\n    {{{83, 7}}, 43},  {{{0, 8}}, 117}, {{{0, 8}}, 53}, {{{0, 9}}, 202},\n    {{{81, 7}}, 13},  {{{0, 8}}, 101}, {{{0, 8}}, 37}, {{{0, 9}}, 170},\n    {{{0, 8}}, 5},    {{{0, 8}}, 133}, {{{0, 8}}, 69}, {{{0, 9}}, 234},\n    {{{80, 7}}, 8},   {{{0, 8}}, 93},  {{{0, 8}}, 29}, {{{0, 9}}, 154},\n    {{{84, 7}}, 83},  {{{0, 8}}, 125}, {{{0, 8}}, 61}, {{{0, 9}}, 218},\n    {{{82, 7}}, 23},  {{{0, 8}}, 109}, {{{0, 8}}, 45}, {{{0, 9}}, 186},\n    {{{0, 8}}, 13},   {{{0, 8}}, 141}, {{{0, 8}}, 77}, {{{0, 9}}, 250},\n    {{{80, 7}}, 3},   {{{0, 8}}, 83},  {{{0, 8}}, 19}, {{{85, 8}}, 195},\n    {{{83, 7}}, 35},  {{{0, 8}}, 115}, {{{0, 8}}, 51}, {{{0, 9}}, 198},\n    {{{81, 7}}, 11},  {{{0, 8}}, 99},  {{{0, 8}}, 35}, {{{0, 9}}, 166},\n    {{{0, 8}}, 3},    {{{0, 8}}, 131}, {{{0, 8}}, 67}, {{{0, 9}}, 230},\n    {{{80, 7}}, 7},   {{{0, 8}}, 91},  {{{0, 8}}, 27}, {{{0, 9}}, 150},\n    {{{84, 7}}, 67},  {{{0, 8}}, 123}, {{{0, 8}}, 59}, {{{0, 9}}, 214},\n    {{{82, 7}}, 19},  {{{0, 8}}, 107}, {{{0, 8}}, 43}, {{{0, 9}}, 182},\n    {{{0, 8}}, 11},   {{{0, 8}}, 139}, {{{0, 8}}, 75}, {{{0, 9}}, 246},\n    {{{80, 7}}, 5},   {{{0, 8}}, 87},  {{{0, 8}}, 23}, {{{192, 8}}, 0},\n    {{{83, 7}}, 51},  {{{0, 8}}, 119}, {{{0, 8}}, 55}, {{{0, 9}}, 206},\n    {{{81, 7}}, 15},  {{{0, 8}}, 103}, {{{0, 8}}, 39}, {{{0, 9}}, 174},\n    {{{0, 8}}, 7},    {{{0, 8}}, 135}, {{{0, 8}}, 71}, {{{0, 9}}, 238},\n    {{{80, 7}}, 9},   {{{0, 8}}, 95},  {{{0, 8}}, 31}, {{{0, 9}}, 158},\n    {{{84, 7}}, 99},  {{{0, 8}}, 127}, {{{0, 8}}, 63}, {{{0, 9}}, 222},\n    {{{82, 7}}, 27},  {{{0, 8}}, 111}, {{{0, 8}}, 47}, {{{0, 9}}, 190},\n    {{{0, 8}}, 15},   {{{0, 8}}, 143}, {{{0, 8}}, 79}, {{{0, 9}}, 254},\n    {{{96, 7}}, 256}, {{{0, 8}}, 80},  {{{0, 8}}, 16}, {{{84, 8}}, 115},\n    {{{82, 7}}, 31},  {{{0, 8}}, 112}, {{{0, 8}}, 48}, {{{0, 9}}, 193},\n    {{{80, 7}}, 10},  {{{0, 8}}, 96},  {{{0, 8}}, 32}, {{{0, 9}}, 161},\n    {{{0, 8}}, 0},    {{{0, 8}}, 128}, {{{0, 8}}, 64}, {{{0, 9}}, 225},\n    {{{80, 7}}, 6},   {{{0, 8}}, 88},  {{{0, 8}}, 24}, {{{0, 9}}, 145},\n    {{{83, 7}}, 59},  {{{0, 8}}, 120}, {{{0, 8}}, 56}, {{{0, 9}}, 209},\n    {{{81, 7}}, 17},  {{{0, 8}}, 104}, {{{0, 8}}, 40}, {{{0, 9}}, 177},\n    {{{0, 8}}, 8},    {{{0, 8}}, 136}, {{{0, 8}}, 72}, {{{0, 9}}, 241},\n    {{{80, 7}}, 4},   {{{0, 8}}, 84},  {{{0, 8}}, 20}, {{{85, 8}}, 227},\n    {{{83, 7}}, 43},  {{{0, 8}}, 116}, {{{0, 8}}, 52}, {{{0, 9}}, 201},\n    {{{81, 7}}, 13},  {{{0, 8}}, 100}, {{{0, 8}}, 36}, {{{0, 9}}, 169},\n    {{{0, 8}}, 4},    {{{0, 8}}, 132}, {{{0, 8}}, 68}, {{{0, 9}}, 233},\n    {{{80, 7}}, 8},   {{{0, 8}}, 92},  {{{0, 8}}, 28}, {{{0, 9}}, 153},\n    {{{84, 7}}, 83},  {{{0, 8}}, 124}, {{{0, 8}}, 60}, {{{0, 9}}, 217},\n    {{{82, 7}}, 23},  {{{0, 8}}, 108}, {{{0, 8}}, 44}, {{{0, 9}}, 185},\n    {{{0, 8}}, 12},   {{{0, 8}}, 140}, {{{0, 8}}, 76}, {{{0, 9}}, 249},\n    {{{80, 7}}, 3},   {{{0, 8}}, 82},  {{{0, 8}}, 18}, {{{85, 8}}, 163},\n    {{{83, 7}}, 35},  {{{0, 8}}, 114}, {{{0, 8}}, 50}, {{{0, 9}}, 197},\n    {{{81, 7}}, 11},  {{{0, 8}}, 98},  {{{0, 8}}, 34}, {{{0, 9}}, 165},\n    {{{0, 8}}, 2},    {{{0, 8}}, 130}, {{{0, 8}}, 66}, {{{0, 9}}, 229},\n    {{{80, 7}}, 7},   {{{0, 8}}, 90},  {{{0, 8}}, 26}, {{{0, 9}}, 149},\n    {{{84, 7}}, 67},  {{{0, 8}}, 122}, {{{0, 8}}, 58}, {{{0, 9}}, 213},\n    {{{82, 7}}, 19},  {{{0, 8}}, 106}, {{{0, 8}}, 42}, {{{0, 9}}, 181},\n    {{{0, 8}}, 10},   {{{0, 8}}, 138}, {{{0, 8}}, 74}, {{{0, 9}}, 245},\n    {{{80, 7}}, 5},   {{{0, 8}}, 86},  {{{0, 8}}, 22}, {{{192, 8}}, 0},\n    {{{83, 7}}, 51},  {{{0, 8}}, 118}, {{{0, 8}}, 54}, {{{0, 9}}, 205},\n    {{{81, 7}}, 15},  {{{0, 8}}, 102}, {{{0, 8}}, 38}, {{{0, 9}}, 173},\n    {{{0, 8}}, 6},    {{{0, 8}}, 134}, {{{0, 8}}, 70}, {{{0, 9}}, 237},\n    {{{80, 7}}, 9},   {{{0, 8}}, 94},  {{{0, 8}}, 30}, {{{0, 9}}, 157},\n    {{{84, 7}}, 99},  {{{0, 8}}, 126}, {{{0, 8}}, 62}, {{{0, 9}}, 221},\n    {{{82, 7}}, 27},  {{{0, 8}}, 110}, {{{0, 8}}, 46}, {{{0, 9}}, 189},\n    {{{0, 8}}, 14},   {{{0, 8}}, 142}, {{{0, 8}}, 78}, {{{0, 9}}, 253},\n    {{{96, 7}}, 256}, {{{0, 8}}, 81},  {{{0, 8}}, 17}, {{{85, 8}}, 131},\n    {{{82, 7}}, 31},  {{{0, 8}}, 113}, {{{0, 8}}, 49}, {{{0, 9}}, 195},\n    {{{80, 7}}, 10},  {{{0, 8}}, 97},  {{{0, 8}}, 33}, {{{0, 9}}, 163},\n    {{{0, 8}}, 1},    {{{0, 8}}, 129}, {{{0, 8}}, 65}, {{{0, 9}}, 227},\n    {{{80, 7}}, 6},   {{{0, 8}}, 89},  {{{0, 8}}, 25}, {{{0, 9}}, 147},\n    {{{83, 7}}, 59},  {{{0, 8}}, 121}, {{{0, 8}}, 57}, {{{0, 9}}, 211},\n    {{{81, 7}}, 17},  {{{0, 8}}, 105}, {{{0, 8}}, 41}, {{{0, 9}}, 179},\n    {{{0, 8}}, 9},    {{{0, 8}}, 137}, {{{0, 8}}, 73}, {{{0, 9}}, 243},\n    {{{80, 7}}, 4},   {{{0, 8}}, 85},  {{{0, 8}}, 21}, {{{80, 8}}, 258},\n    {{{83, 7}}, 43},  {{{0, 8}}, 117}, {{{0, 8}}, 53}, {{{0, 9}}, 203},\n    {{{81, 7}}, 13},  {{{0, 8}}, 101}, {{{0, 8}}, 37}, {{{0, 9}}, 171},\n    {{{0, 8}}, 5},    {{{0, 8}}, 133}, {{{0, 8}}, 69}, {{{0, 9}}, 235},\n    {{{80, 7}}, 8},   {{{0, 8}}, 93},  {{{0, 8}}, 29}, {{{0, 9}}, 155},\n    {{{84, 7}}, 83},  {{{0, 8}}, 125}, {{{0, 8}}, 61}, {{{0, 9}}, 219},\n    {{{82, 7}}, 23},  {{{0, 8}}, 109}, {{{0, 8}}, 45}, {{{0, 9}}, 187},\n    {{{0, 8}}, 13},   {{{0, 8}}, 141}, {{{0, 8}}, 77}, {{{0, 9}}, 251},\n    {{{80, 7}}, 3},   {{{0, 8}}, 83},  {{{0, 8}}, 19}, {{{85, 8}}, 195},\n    {{{83, 7}}, 35},  {{{0, 8}}, 115}, {{{0, 8}}, 51}, {{{0, 9}}, 199},\n    {{{81, 7}}, 11},  {{{0, 8}}, 99},  {{{0, 8}}, 35}, {{{0, 9}}, 167},\n    {{{0, 8}}, 3},    {{{0, 8}}, 131}, {{{0, 8}}, 67}, {{{0, 9}}, 231},\n    {{{80, 7}}, 7},   {{{0, 8}}, 91},  {{{0, 8}}, 27}, {{{0, 9}}, 151},\n    {{{84, 7}}, 67},  {{{0, 8}}, 123}, {{{0, 8}}, 59}, {{{0, 9}}, 215},\n    {{{82, 7}}, 19},  {{{0, 8}}, 107}, {{{0, 8}}, 43}, {{{0, 9}}, 183},\n    {{{0, 8}}, 11},   {{{0, 8}}, 139}, {{{0, 8}}, 75}, {{{0, 9}}, 247},\n    {{{80, 7}}, 5},   {{{0, 8}}, 87},  {{{0, 8}}, 23}, {{{192, 8}}, 0},\n    {{{83, 7}}, 51},  {{{0, 8}}, 119}, {{{0, 8}}, 55}, {{{0, 9}}, 207},\n    {{{81, 7}}, 15},  {{{0, 8}}, 103}, {{{0, 8}}, 39}, {{{0, 9}}, 175},\n    {{{0, 8}}, 7},    {{{0, 8}}, 135}, {{{0, 8}}, 71}, {{{0, 9}}, 239},\n    {{{80, 7}}, 9},   {{{0, 8}}, 95},  {{{0, 8}}, 31}, {{{0, 9}}, 159},\n    {{{84, 7}}, 99},  {{{0, 8}}, 127}, {{{0, 8}}, 63}, {{{0, 9}}, 223},\n    {{{82, 7}}, 27},  {{{0, 8}}, 111}, {{{0, 8}}, 47}, {{{0, 9}}, 191},\n    {{{0, 8}}, 15},   {{{0, 8}}, 143}, {{{0, 8}}, 79}, {{{0, 9}}, 255}};\nconst inflate_huft fixed_td[] = {\n    {{{80, 5}}, 1},  {{{87, 5}}, 257},  {{{83, 5}}, 17},  {{{91, 5}}, 4097},\n    {{{81, 5}}, 5},  {{{89, 5}}, 1025}, {{{85, 5}}, 65},  {{{93, 5}}, 16385},\n    {{{80, 5}}, 3},  {{{88, 5}}, 513},  {{{84, 5}}, 33},  {{{92, 5}}, 8193},\n    {{{82, 5}}, 9},  {{{90, 5}}, 2049}, {{{86, 5}}, 129}, {{{192, 5}}, 24577},\n    {{{80, 5}}, 2},  {{{87, 5}}, 385},  {{{83, 5}}, 25},  {{{91, 5}}, 6145},\n    {{{81, 5}}, 7},  {{{89, 5}}, 1537}, {{{85, 5}}, 97},  {{{93, 5}}, 24577},\n    {{{80, 5}}, 4},  {{{88, 5}}, 769},  {{{84, 5}}, 49},  {{{92, 5}}, 12289},\n    {{{82, 5}}, 13}, {{{90, 5}}, 3073}, {{{86, 5}}, 193}, {{{192, 5}}, 24577}};\n\n// copy as much as possible from the sliding window to the output area\nint inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) {\n  uInt n;\n  Byte *p;\n  Byte *q;\n\n  // local copies of source and destination pointers\n  p = z->next_out;\n  q = s->read;\n\n  // compute number of bytes to copy as far as end of window\n  n = (uInt)((q <= s->write ? s->write : s->end) - q);\n  if (n > z->avail_out)\n    n = z->avail_out;\n  if (n && r == Z_BUF_ERROR)\n    r = Z_OK;\n\n  // update counters\n  z->avail_out -= n;\n  z->total_out += n;\n\n  // update check information\n  if (s->checkfn != Z_NULL)\n    z->adler = s->check = (*s->checkfn)(s->check, q, n);\n\n  // copy as far as end of window\n  if (n != 0) // check for n!=0 to avoid waking up CodeGuard\n  {\n    memcpy(p, q, n);\n    p += n;\n    q += n;\n  }\n\n  // see if more to copy at beginning of window\n  if (q == s->end) {\n    // wrap pointers\n    q = s->window;\n    if (s->write == s->end)\n      s->write = s->window;\n\n    // compute bytes to copy\n    n = (uInt)(s->write - q);\n    if (n > z->avail_out)\n      n = z->avail_out;\n    if (n && r == Z_BUF_ERROR)\n      r = Z_OK;\n\n    // update counters\n    z->avail_out -= n;\n    z->total_out += n;\n\n    // update check information\n    if (s->checkfn != Z_NULL)\n      z->adler = s->check = (*s->checkfn)(s->check, q, n);\n\n    // copy\n    memcpy(p, q, n);\n    p += n;\n    q += n;\n  }\n\n  // update pointers\n  z->next_out = p;\n  s->read = q;\n\n  // done\n  return r;\n}\n\n// simplify the use of the inflate_huft type with some defines\n#define exop word.what.Exop\n#define bits word.what.Bits\n\ntypedef enum { // waiting for \"i:\"=input, \"o:\"=output, \"x:\"=nothing\n  START,       // x: set up for LEN\n  LEN,         // i: get length/literal/eob next\n  LENEXT,      // i: getting length extra (have base)\n  DIST,        // i: get distance next\n  DISTEXT,     // i: getting distance extra\n  COPY,        // o: copying bytes in window, waiting for space\n  LIT,         // o: got literal, waiting for output space\n  WASH,        // o: got eob, possibly still output waiting\n  END,         // x: got eob and all data flushed\n  BADCODE\n} // x: got error\ninflate_codes_mode;\n\n// inflate codes private state\nstruct inflate_codes_state {\n\n  // mode\n  inflate_codes_mode mode; // current inflate_codes mode\n\n  // mode dependent information\n  uInt len;\n  union {\n    struct {\n      const inflate_huft *tree; // pointer into tree\n      uInt need;                // bits needed\n    } code;                     // if LEN or DIST, where in tree\n    uInt lit;                   // if LIT, literal\n    struct {\n      uInt get;  // bits to get for extra\n      uInt dist; // distance back to copy from\n    } copy;      // if EXT or COPY, where and how much\n  } sub;         // submode\n\n  // mode independent information\n  Byte lbits;                // ltree bits decoded per branch\n  Byte dbits;                // dtree bits decoder per branch\n  const inflate_huft *ltree; // literal/length/eob tree\n  const inflate_huft *dtree; // distance tree\n};\n\ninflate_codes_statef *inflate_codes_new(\n    uInt bl, uInt bd, const inflate_huft *tl,\n    const inflate_huft *td, // need separate declaration for Borland C++\n    z_streamp z) {\n  inflate_codes_statef *c;\n\n  if ((c = (inflate_codes_statef *)ZALLOC(\n           z, 1, sizeof(struct inflate_codes_state))) != Z_NULL) {\n    c->mode = START;\n    c->lbits = (Byte)bl;\n    c->dbits = (Byte)bd;\n    c->ltree = tl;\n    c->dtree = td;\n    Tracev((stderr, \"inflate:       codes new\\n\"));\n  }\n  return c;\n}\n\nint inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) {\n  uInt j;                // temporary storage\n  const inflate_huft *t; // temporary pointer\n  uInt e;                // extra bits or operation\n  uLong b;               // bit buffer\n  uInt k;                // bits in bit buffer\n  Byte *p;               // input data pointer\n  uInt n;                // bytes available there\n  Byte *q;               // output window write pointer\n  uInt m;                // bytes to end of window or read pointer\n  Byte *f;               // pointer to copy strings from\n  inflate_codes_statef *c = s->sub.decode.codes; // codes state\n\n  // copy input/output information to locals (UPDATE macro restores)\n  LOAD\n\n      // process input and output based on current state\n      for (;;) switch (\n          c->mode) { // waiting for \"i:\"=input, \"o:\"=output, \"x:\"=nothing\n  case START:        // x: set up for LEN\n#ifndef SLOW\n    if (m >= 258 && n >= 10) {\n      UPDATE\n      r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);\n      LOAD if (r != Z_OK) {\n        c->mode = r == Z_STREAM_END ? WASH : BADCODE;\n        break;\n      }\n    }\n#endif // !SLOW\n    c->sub.code.need = c->lbits;\n    c->sub.code.tree = c->ltree;\n    c->mode = LEN;\n  case LEN: // i: get length/literal/eob next\n    j = c->sub.code.need;\n    NEEDBITS(j)\n    t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);\n    DUMPBITS(t->bits)\n    e = (uInt)(t->exop);\n    if (e == 0) // literal\n    {\n      c->sub.lit = t->base;\n      Tracevv((stderr,\n               t->base >= 0x20 && t->base < 0x7f\n                   ? \"inflate:         literal '%c'\\n\"\n                   : \"inflate:         literal 0x%02x\\n\",\n               t->base));\n      c->mode = LIT;\n      break;\n    }\n    if (e & 16) // length\n    {\n      c->sub.copy.get = e & 15;\n      c->len = t->base;\n      c->mode = LENEXT;\n      break;\n    }\n    if ((e & 64) == 0) // next table\n    {\n      c->sub.code.need = e;\n      c->sub.code.tree = t + t->base;\n      break;\n    }\n    if (e & 32) // end of block\n    {\n      Tracevv((stderr, \"inflate:         end of block\\n\"));\n      c->mode = WASH;\n      break;\n    }\n    c->mode = BADCODE; // invalid code\n    z->msg = (char *)\"invalid literal/length code\";\n    r = Z_DATA_ERROR;\n    LEAVE\n  case LENEXT: // i: getting length extra (have base)\n    j = c->sub.copy.get;\n    NEEDBITS(j)\n    c->len += (uInt)b & inflate_mask[j];\n    DUMPBITS(j)\n    c->sub.code.need = c->dbits;\n    c->sub.code.tree = c->dtree;\n    Tracevv((stderr, \"inflate:         length %u\\n\", c->len));\n    c->mode = DIST;\n  case DIST: // i: get distance next\n    j = c->sub.code.need;\n    NEEDBITS(j)\n    t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);\n    DUMPBITS(t->bits)\n    e = (uInt)(t->exop);\n    if (e & 16) // distance\n    {\n      c->sub.copy.get = e & 15;\n      c->sub.copy.dist = t->base;\n      c->mode = DISTEXT;\n      break;\n    }\n    if ((e & 64) == 0) // next table\n    {\n      c->sub.code.need = e;\n      c->sub.code.tree = t + t->base;\n      break;\n    }\n    c->mode = BADCODE; // invalid code\n    z->msg = (char *)\"invalid distance code\";\n    r = Z_DATA_ERROR;\n    LEAVE\n  case DISTEXT: // i: getting distance extra\n    j = c->sub.copy.get;\n    NEEDBITS(j)\n    c->sub.copy.dist += (uInt)b & inflate_mask[j];\n    DUMPBITS(j)\n    Tracevv((stderr, \"inflate:         distance %u\\n\", c->sub.copy.dist));\n    c->mode = COPY;\n  case COPY: // o: copying bytes in window, waiting for space\n    f = (uInt)(q - s->window) < c->sub.copy.dist\n            ? s->end - (c->sub.copy.dist - (q - s->window))\n            : q - c->sub.copy.dist;\n    while (c->len) {\n      NEEDOUT\n      OUTBYTE(*f++)\n      if (f == s->end)\n        f = s->window;\n      c->len--;\n    }\n    c->mode = START;\n    break;\n  case LIT: // o: got literal, waiting for output space\n    NEEDOUT\n    OUTBYTE(c->sub.lit)\n    c->mode = START;\n    break;\n  case WASH:   // o: got eob, possibly more output\n    if (k > 7) // return unused byte, if any\n    {\n      Assert(k < 16, \"inflate_codes grabbed too many bytes\");\n      k -= 8;\n      n++;\n      p--; // can always return one\n    }\n    FLUSH\n    if (s->read != s->write)\n      LEAVE\n    c->mode = END;\n  case END:\n    r = Z_STREAM_END;\n    LEAVE\n  case BADCODE: // x: got error\n    r = Z_DATA_ERROR;\n    LEAVE\n  default:\n    r = Z_STREAM_ERROR;\n    LEAVE\n  }\n}\n\nvoid inflate_codes_free(inflate_codes_statef *c, z_streamp z) {\n  ZFREE(z, c);\n  Tracev((stderr, \"inflate:       codes free\\n\"));\n}\n\n// infblock.c -- interpret and process block types to last block\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n\n// struct inflate_codes_state {int dummy;}; // for buggy compilers\n\n// Table for deflate from PKZIP's appnote.txt.\nconst uInt border[] = { // Order of the bit length code lengths\n    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n//\n// Notes beyond the 1.93a appnote.txt:\n//\n// 1. Distance pointers never point before the beginning of the output stream.\n// 2. Distance pointers can point back across blocks, up to 32k away.\n// 3. There is an implied maximum of 7 bits for the bit length table and\n//    15 bits for the actual data.\n// 4. If only one code exists, then it is encoded using one bit.  (Zero\n//    would be more efficient, but perhaps a little confusing.)  If two\n//    codes exist, they are coded using one bit each (0 and 1).\n// 5. There is no way of sending zero distance codes--a dummy must be\n//    sent if there are none.  (History: a pre 2.0 version of PKZIP would\n//    store blocks with no distance codes, but this was discovered to be\n//    too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow\n//    zero distance codes, which is sent as one code of zero bits in\n//    length.\n// 6. There are up to 286 literal/length codes.  Code 256 represents the\n//    end-of-block.  Note however that the static length tree defines\n//    288 codes just to fill out the Huffman codes.  Codes 286 and 287\n//    cannot be used though, since there is no length base or extra bits\n//    defined for them.  Similarily, there are up to 30 distance codes.\n//    However, static trees define 32 codes (all 5 bits) to fill out the\n//    Huffman codes, but the last two had better not show up in the data.\n// 7. Unzip can check dynamic Huffman blocks for complete code sets.\n//    The exception is that a single code would not be complete (see #4).\n// 8. The five bits following the block type is really the number of\n//    literal codes sent minus 257.\n// 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits\n//    (1+6+6).  Therefore, to output three times the length, you output\n//    three codes (1+1+1), whereas to output four times the same length,\n//    you only need two codes (1+3).  Hmm.\n// 10. In the tree reconstruction algorithm, Code = Code + Increment\n//    only if BitLength(i) is not zero.  (Pretty obvious.)\n// 11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)\n// 12. Note: length code 284 can represent 227-258, but length code 285\n//    really is 258.  The last length deserves its own, short code\n//    since it gets used a lot in very redundant files.  The length\n//    258 is special since 258 - 3 (the min match length) is 255.\n// 13. The literal/length and distance code bit lengths are read as a\n//    single stream of lengths.  It is possible (and advantageous) for\n//    a repeat code (16, 17, or 18) to go across the boundary between\n//    the two sets of lengths.\n\nvoid inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) {\n  if (c != Z_NULL)\n    *c = s->check;\n  if (s->mode == IBM_BTREE || s->mode == IBM_DTREE)\n    ZFREE(z, s->sub.trees.blens);\n  if (s->mode == IBM_CODES)\n    inflate_codes_free(s->sub.decode.codes, z);\n  s->mode = IBM_TYPE;\n  s->bitk = 0;\n  s->bitb = 0;\n  s->read = s->write = s->window;\n  if (s->checkfn != Z_NULL)\n    z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0);\n  Tracev((stderr, \"inflate:   blocks reset\\n\"));\n}\n\ninflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) {\n  inflate_blocks_statef *s;\n\n  if ((s = (inflate_blocks_statef *)ZALLOC(\n           z, 1, sizeof(struct inflate_blocks_state))) == Z_NULL)\n    return s;\n  if ((s->hufts = (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) ==\n      Z_NULL) {\n    ZFREE(z, s);\n    return Z_NULL;\n  }\n  if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) {\n    ZFREE(z, s->hufts);\n    ZFREE(z, s);\n    return Z_NULL;\n  }\n  s->end = s->window + w;\n  s->checkfn = c;\n  s->mode = IBM_TYPE;\n  Tracev((stderr, \"inflate:   blocks allocated\\n\"));\n  inflate_blocks_reset(s, z, Z_NULL);\n  return s;\n}\n\nint inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) {\n  uInt t;  // temporary storage\n  uLong b; // bit buffer\n  uInt k;  // bits in bit buffer\n  Byte *p; // input data pointer\n  uInt n;  // bytes available there\n  Byte *q; // output window write pointer\n  uInt m;  // bytes to end of window or read pointer\n\n  // copy input/output information to locals (UPDATE macro restores)\n  LOAD\n\n      // process input based on current state\n      for (;;) switch (s->mode) {\n  case IBM_TYPE:\n    NEEDBITS(3)\n    t = (uInt)b & 7;\n    s->last = t & 1;\n    switch (t >> 1) {\n    case 0: // stored\n      Tracev(\n          (stderr, \"inflate:     stored block%s\\n\", s->last ? \" (last)\" : \"\"));\n      DUMPBITS(3)\n      t = k & 7; // go to byte boundary\n      DUMPBITS(t)\n      s->mode = IBM_LENS; // get length of stored block\n      break;\n    case 1: // fixed\n      Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n              s->last ? \" (last)\" : \"\"));\n      {\n        uInt bl, bd;\n        const inflate_huft *tl, *td;\n\n        inflate_trees_fixed(&bl, &bd, &tl, &td, z);\n        s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);\n        if (s->sub.decode.codes == Z_NULL) {\n          r = Z_MEM_ERROR;\n          LEAVE\n        }\n      }\n      DUMPBITS(3)\n      s->mode = IBM_CODES;\n      break;\n    case 2: // dynamic\n      Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n              s->last ? \" (last)\" : \"\"));\n      DUMPBITS(3)\n      s->mode = IBM_TABLE;\n      break;\n    case 3: // illegal\n      DUMPBITS(3)\n      s->mode = IBM_BAD;\n      z->msg = (char *)\"invalid block type\";\n      r = Z_DATA_ERROR;\n      LEAVE\n    }\n    break;\n  case IBM_LENS:\n    NEEDBITS(32)\n    if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) {\n      s->mode = IBM_BAD;\n      z->msg = (char *)\"invalid stored block lengths\";\n      r = Z_DATA_ERROR;\n      LEAVE\n    }\n    s->sub.left = (uInt)b & 0xffff;\n    b = k = 0; // dump bits\n    Tracev((stderr, \"inflate:       stored length %u\\n\", s->sub.left));\n    s->mode = s->sub.left ? IBM_STORED : (s->last ? IBM_DRY : IBM_TYPE);\n    break;\n  case IBM_STORED:\n    if (n == 0)\n      LEAVE\n    NEEDOUT\n    t = s->sub.left;\n    if (t > n)\n      t = n;\n    if (t > m)\n      t = m;\n    memcpy(q, p, t);\n    p += t;\n    n -= t;\n    q += t;\n    m -= t;\n    if ((s->sub.left -= t) != 0)\n      break;\n    Tracev(\n        (stderr, \"inflate:       stored end, %lu total out\\n\",\n         z->total_out + (q >= s->read ? q - s->read\n                                      : (s->end - s->read) + (q - s->window))));\n    s->mode = s->last ? IBM_DRY : IBM_TYPE;\n    break;\n  case IBM_TABLE:\n    NEEDBITS(14)\n    s->sub.trees.table = t = (uInt)b & 0x3fff;\n    // remove this section to workaround bug in pkzip\n    if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) {\n      s->mode = IBM_BAD;\n      z->msg = (char *)\"too many length or distance symbols\";\n      r = Z_DATA_ERROR;\n      LEAVE\n    }\n    // end remove\n    t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);\n    if ((s->sub.trees.blens = (uInt *)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) {\n      r = Z_MEM_ERROR;\n      LEAVE\n    }\n    DUMPBITS(14)\n    s->sub.trees.index = 0;\n    Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n    s->mode = IBM_BTREE;\n  case IBM_BTREE:\n    while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) {\n      NEEDBITS(3)\n      s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;\n      DUMPBITS(3)\n    }\n    while (s->sub.trees.index < 19)\n      s->sub.trees.blens[border[s->sub.trees.index++]] = 0;\n    s->sub.trees.bb = 7;\n    t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,\n                           &s->sub.trees.tb, s->hufts, z);\n    if (t != Z_OK) {\n      ZFREE(z, s->sub.trees.blens);\n      r = t;\n      if (r == Z_DATA_ERROR)\n        s->mode = IBM_BAD;\n      LEAVE\n    }\n    s->sub.trees.index = 0;\n    Tracev((stderr, \"inflate:       bits tree ok\\n\"));\n    s->mode = IBM_DTREE;\n  case IBM_DTREE:\n    while (t = s->sub.trees.table,\n           s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) {\n      inflate_huft *h;\n      uInt i, j, c;\n\n      t = s->sub.trees.bb;\n      NEEDBITS(t)\n      h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);\n      t = h->bits;\n      c = h->base;\n      if (c < 16) {\n        DUMPBITS(t)\n        s->sub.trees.blens[s->sub.trees.index++] = c;\n      } else // c == 16..18\n      {\n        i = c == 18 ? 7 : c - 14;\n        j = c == 18 ? 11 : 3;\n        NEEDBITS(t + i)\n        DUMPBITS(t)\n        j += (uInt)b & inflate_mask[i];\n        DUMPBITS(i)\n        i = s->sub.trees.index;\n        t = s->sub.trees.table;\n        if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||\n            (c == 16 && i < 1)) {\n          ZFREE(z, s->sub.trees.blens);\n          s->mode = IBM_BAD;\n          z->msg = (char *)\"invalid bit length repeat\";\n          r = Z_DATA_ERROR;\n          LEAVE\n        }\n        c = c == 16 ? s->sub.trees.blens[i - 1] : 0;\n        do {\n          s->sub.trees.blens[i++] = c;\n        } while (--j);\n        s->sub.trees.index = i;\n      }\n    }\n    s->sub.trees.tb = Z_NULL;\n    {\n      uInt bl, bd;\n      inflate_huft *tl, *td;\n      inflate_codes_statef *c;\n\n      bl = 9; // must be <= 9 for lookahead assumptions\n      bd = 6; // must be <= 9 for lookahead assumptions\n      t = s->sub.trees.table;\n      t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),\n                                s->sub.trees.blens, &bl, &bd, &tl, &td,\n                                s->hufts, z);\n      ZFREE(z, s->sub.trees.blens);\n      if (t != Z_OK) {\n        if (t == (uInt)Z_DATA_ERROR)\n          s->mode = IBM_BAD;\n        r = t;\n        LEAVE\n      }\n      Tracev((stderr, \"inflate:       trees ok\\n\"));\n      if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) {\n        r = Z_MEM_ERROR;\n        LEAVE\n      }\n      s->sub.decode.codes = c;\n    }\n    s->mode = IBM_CODES;\n  case IBM_CODES:\n    UPDATE\n    if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)\n      return inflate_flush(s, z, r);\n    r = Z_OK;\n    inflate_codes_free(s->sub.decode.codes, z);\n    LOAD Tracev(\n        (stderr, \"inflate:       codes end, %lu total out\\n\",\n         z->total_out + (q >= s->read ? q - s->read\n                                      : (s->end - s->read) + (q - s->window))));\n    if (!s->last) {\n      s->mode = IBM_TYPE;\n      break;\n    }\n    s->mode = IBM_DRY;\n  case IBM_DRY:\n    FLUSH\n    if (s->read != s->write)\n      LEAVE\n    s->mode = IBM_DONE;\n  case IBM_DONE:\n    r = Z_STREAM_END;\n    LEAVE\n  case IBM_BAD:\n    r = Z_DATA_ERROR;\n    LEAVE\n  default:\n    r = Z_STREAM_ERROR;\n    LEAVE\n  }\n}\n\nint inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) {\n  inflate_blocks_reset(s, z, Z_NULL);\n  ZFREE(z, s->window);\n  ZFREE(z, s->hufts);\n  ZFREE(z, s);\n  Tracev((stderr, \"inflate:   blocks freed\\n\"));\n  return Z_OK;\n}\n\n// inftrees.c -- generate Huffman trees for efficient decoding\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n//\n\nextern const char inflate_copyright[] =\n    \" \"; // inflate 1.1.3 Copyright 1995-1998 Mark Adler \";\n// If you use the zlib library in a product, an acknowledgment is welcome\n// in the documentation of your product. If for some reason you cannot\n// include such an acknowledgment, I would appreciate that you keep this\n// copyright string in the executable of your product.\n\nint huft_build(uInt *,          // code lengths in bits\n               uInt,            // number of codes\n               uInt,            // number of \"simple\" codes\n               const uInt *,    // list of base values for non-simple codes\n               const uInt *,    // list of extra bits for non-simple codes\n               inflate_huft **, // result: starting table\n               uInt *,          // maximum lookup bits (returns actual)\n               inflate_huft *,  // space for trees\n               uInt *,          // hufts used in space\n               uInt *);         // space for values\n\n// Tables for deflate from PKZIP's appnote.txt.\nconst uInt cplens[31] = { // Copy lengths for literal codes 257..285\n    3,  4,  5,  6,  7,  8,  9,  10,  11,  13,  15,  17,  19,  23, 27, 31,\n    35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0,  0};\n// see note #13 above about 258\nconst uInt cplext[31] = { // Extra bits for literal codes 257..285\n    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,   2,  2,\n    3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; // 112==invalid\nconst uInt cpdist[30] = { // Copy offsets for distance codes 0..29\n    1,    2,    3,    4,    5,    7,    9,    13,    17,    25,\n    33,   49,   65,   97,   129,  193,  257,  385,   513,   769,\n    1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};\nconst uInt cpdext[30] = { // Extra bits for distance codes\n    0, 0, 0, 0, 1, 1, 2, 2,  3,  3,  4,  4,  5,  5,  6,\n    6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};\n\n//\n//   Huffman code decoding is performed using a multi-level table lookup.\n//   The fastest way to decode is to simply build a lookup table whose\n//   size is determined by the longest code.  However, the time it takes\n//   to build this table can also be a factor if the data being decoded\n//   is not very long.  The most common codes are necessarily the\n//   shortest codes, so those codes dominate the decoding time, and hence\n//   the speed.  The idea is you can have a shorter table that decodes the\n//   shorter, more probable codes, and then point to subsidiary tables for\n//   the longer codes.  The time it costs to decode the longer codes is\n//   then traded against the time it takes to make longer tables.\n//\n//   This results of this trade are in the variables lbits and dbits\n//   below.  lbits is the number of bits the first level table for literal/\n//   length codes can decode in one step, and dbits is the same thing for\n//   the distance codes.  Subsequent tables are also less than or equal to\n//   those sizes.  These values may be adjusted either when all of the\n//   codes are shorter than that, in which case the longest code length in\n//   bits is used, or when the shortest code is *longer* than the requested\n//   table size, in which case the length of the shortest code in bits is\n//   used.\n//\n//   There are two different values for the two tables, since they code a\n//   different number of possibilities each.  The literal/length table\n//   codes 286 possible values, or in a flat code, a little over eight\n//   bits.  The distance table codes 30 possible values, or a little less\n//   than five bits, flat.  The optimum values for speed end up being\n//   about one bit more than those, so lbits is 8+1 and dbits is 5+1.\n//   The optimum values may differ though from machine to machine, and\n//   possibly even between compilers.  Your mileage may vary.\n//\n\n// If BMAX needs to be larger than 16, then h and x[] should be uLong.\n#define BMAX 15 // maximum bit length of any code\n\nint huft_build(uInt *b,          // code lengths in bits (all assumed <= BMAX)\n               uInt n,           // number of codes (assumed <= 288)\n               uInt s,           // number of simple-valued codes (0..s-1)\n               const uInt *d,    // list of base values for non-simple codes\n               const uInt *e,    // list of extra bits for non-simple codes\n               inflate_huft **t, // result: starting table\n               uInt *m,          // maximum lookup bits, returns actual\n               inflate_huft *hp, // space for trees\n               uInt *hn,         // hufts used in space\n               uInt *v)          // working area: values in order of bit length\n// Given a list of code lengths and a maximum table size, make a set of\n// tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR\n// if the given code set is incomplete (the tables are still built in this\n// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of\n// lengths), or Z_MEM_ERROR if not enough memory.\n{\n\n  uInt a;                  // counter for codes of length k\n  uInt c[BMAX + 1];        // bit length count table\n  uInt f;                  // i repeats in table every f entries\n  int g;                   // maximum code length\n  int h;                   // table level\n  register uInt i;         // counter, current code\n  register uInt j;         // counter\n  register int k;          // number of bits in current code\n  int l;                   // bits per table (returned in m)\n  uInt mask;               // (1 << w) - 1, to avoid cc -O bug on HP\n  register uInt *p;        // pointer into c[], b[], or v[]\n  inflate_huft *q;         // points to current table\n  struct inflate_huft_s r; // table entry for structure assignment\n  inflate_huft *u[BMAX];   // table stack\n  register int w;          // bits before this table == (l * h)\n  uInt x[BMAX + 1];        // bit offsets, then code stack\n  uInt *xp;                // pointer into x\n  int y;                   // number of dummy codes added\n  uInt z;                  // number of entries in current table\n\n  // Generate counts for each bit length\n  p = c;\n#define C0 *p++ = 0;\n#define C2 C0 C0 C0 C0\n#define C4 C2 C2 C2 C2\n  C4;\n  p; // clear c[]--assume BMAX+1 is 16\n  p = b;\n  i = n;\n  do {\n    c[*p++]++; // assume all entries <= BMAX\n  } while (--i);\n  if (c[0] == n) // null input--all zero length codes\n  {\n    *t = (inflate_huft *)Z_NULL;\n    *m = 0;\n    return Z_OK;\n  }\n\n  // Find minimum and maximum length, bound *m by those\n  l = *m;\n  for (j = 1; j <= BMAX; j++)\n    if (c[j])\n      break;\n  k = j; // minimum code length\n  if ((uInt)l < j)\n    l = j;\n  for (i = BMAX; i; i--)\n    if (c[i])\n      break;\n  g = i; // maximum code length\n  if ((uInt)l > i)\n    l = i;\n  *m = l;\n\n  // Adjust last length count to fill out codes, if needed\n  for (y = 1 << j; j < i; j++, y <<= 1)\n    if ((y -= c[j]) < 0)\n      return Z_DATA_ERROR;\n  if ((y -= c[i]) < 0)\n    return Z_DATA_ERROR;\n  c[i] += y;\n\n  // Generate starting offsets into the value table for each length\n  x[1] = j = 0;\n  p = c + 1;\n  xp = x + 2;\n  while (--i) { // note that i == g from above\n    *xp++ = (j += *p++);\n  }\n\n  // Make a table of values in order of bit lengths\n  p = b;\n  i = 0;\n  do {\n    if ((j = *p++) != 0)\n      v[x[j]++] = i;\n  } while (++i < n);\n  n = x[g]; // set n to length of v\n\n  // Generate the Huffman codes and for each, make the table entries\n  x[0] = i = 0;                  // first Huffman code is zero\n  p = v;                         // grab values in bit order\n  h = -1;                        // no tables yet--level -1\n  w = -l;                        // bits decoded == (l * h)\n  u[0] = (inflate_huft *)Z_NULL; // just to keep compilers happy\n  q = (inflate_huft *)Z_NULL;    // ditto\n  z = 0;                         // ditto\n\n  // go through the bit lengths (k already is bits in shortest code)\n  for (; k <= g; k++) {\n    a = c[k];\n    while (a--) {\n      // here i is the Huffman code of length k bits for value *p\n      // make tables up to required level\n      while (k > w + l) {\n        h++;\n        w += l; // previous table always l bits\n\n        // compute minimum size table less than or equal to l bits\n        z = g - w;\n        z = z > (uInt)l ? l : z;            // table size upper limit\n        if ((f = 1 << (j = k - w)) > a + 1) // try a k-w bit table\n        {                                   // too few codes for k-w bit table\n          f -= a + 1;                       // deduct codes from patterns left\n          xp = c + k;\n          if (j < z)\n            while (++j < z) // try smaller tables up to z bits\n            {\n              if ((f <<= 1) <= *++xp)\n                break;  // enough codes to use up j bits\n              f -= *xp; // else deduct codes from patterns\n            }\n        }\n        z = 1 << j; // table entries for j-bit table\n\n        // allocate new table\n        if (*hn + z > MANY)   // (note: doesn't matter for fixed)\n          return Z_MEM_ERROR; // not enough memory\n        u[h] = q = hp + *hn;\n        *hn += z;\n\n        // connect to last table, if there is one\n        if (h) {\n          x[h] = i;         // save pattern for backing up\n          r.bits = (Byte)l; // bits to dump before this table\n          r.exop = (Byte)j; // bits in this table\n          j = i >> (w - l);\n          r.base = (uInt)(q - u[h - 1] - j); // offset to this table\n          u[h - 1][j] = r;                   // connect to last table\n        } else\n          *t = q; // first table is returned result\n      }\n\n      // set up table entry in r\n      r.bits = (Byte)(k - w);\n      if (p >= v + n)\n        r.exop = 128 + 64; // out of values--invalid code\n      else if (*p < s) {\n        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); // 256 is end-of-block\n        r.base = *p++; // simple code is just the value\n      } else {\n        r.exop = (Byte)(e[*p - s] + 16 + 64); // non-simple--look up in lists\n        r.base = d[*p++ - s];\n      }\n\n      // fill code-like entries with r\n      f = 1 << (k - w);\n      for (j = i >> w; j < z; j += f)\n        q[j] = r;\n\n      // backwards increment the k-bit code i\n      for (j = 1 << (k - 1); i & j; j >>= 1)\n        i ^= j;\n      i ^= j;\n\n      // backup over finished tables\n      mask = (1 << w) - 1; // needed on HP, cc -O bug\n      while ((i & mask) != x[h]) {\n        h--; // don't need to update q\n        w -= l;\n        mask = (1 << w) - 1;\n      }\n    }\n  }\n\n  // Return Z_BUF_ERROR if we were given an incomplete table\n  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;\n}\n\nint inflate_trees_bits(uInt *c,           // 19 code lengths\n                       uInt *bb,          // bits tree desired/actual depth\n                       inflate_huft **tb, // bits tree result\n                       inflate_huft *hp,  // space for trees\n                       z_streamp z)       // for messages\n{\n  int r;\n  uInt hn = 0; // hufts used in space\n  uInt *v;     // work area for huft_build\n\n  if ((v = (uInt *)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)\n    return Z_MEM_ERROR;\n  r = huft_build(c, 19, 19, (uInt *)Z_NULL, (uInt *)Z_NULL, tb, bb, hp, &hn, v);\n  if (r == Z_DATA_ERROR)\n    z->msg = (char *)\"oversubscribed dynamic bit lengths tree\";\n  else if (r == Z_BUF_ERROR || *bb == 0) {\n    z->msg = (char *)\"incomplete dynamic bit lengths tree\";\n    r = Z_DATA_ERROR;\n  }\n  ZFREE(z, v);\n  return r;\n}\n\nint inflate_trees_dynamic(uInt nl,  // number of literal/length codes\n                          uInt nd,  // number of distance codes\n                          uInt *c,  // that many (total) code lengths\n                          uInt *bl, // literal desired/actual bit depth\n                          uInt *bd, // distance desired/actual bit depth\n                          inflate_huft **tl, // literal/length tree result\n                          inflate_huft **td, // distance tree result\n                          inflate_huft *hp,  // space for trees\n                          z_streamp z)       // for messages\n{\n  int r;\n  uInt hn = 0; // hufts used in space\n  uInt *v;     // work area for huft_build\n\n  // allocate work area\n  if ((v = (uInt *)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)\n    return Z_MEM_ERROR;\n\n  // build literal/length tree\n  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);\n  if (r != Z_OK || *bl == 0) {\n    if (r == Z_DATA_ERROR)\n      z->msg = (char *)\"oversubscribed literal/length tree\";\n    else if (r != Z_MEM_ERROR) {\n      z->msg = (char *)\"incomplete literal/length tree\";\n      r = Z_DATA_ERROR;\n    }\n    ZFREE(z, v);\n    return r;\n  }\n\n  // build distance tree\n  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);\n  if (r != Z_OK || (*bd == 0 && nl > 257)) {\n    if (r == Z_DATA_ERROR)\n      z->msg = (char *)\"oversubscribed distance tree\";\n    else if (r == Z_BUF_ERROR) {\n      z->msg = (char *)\"incomplete distance tree\";\n      r = Z_DATA_ERROR;\n    } else if (r != Z_MEM_ERROR) {\n      z->msg = (char *)\"empty distance tree with lengths\";\n      r = Z_DATA_ERROR;\n    }\n    ZFREE(z, v);\n    return r;\n  }\n\n  // done\n  ZFREE(z, v);\n  return Z_OK;\n}\n\nint inflate_trees_fixed(uInt *bl, // literal desired/actual bit depth\n                        uInt *bd, // distance desired/actual bit depth\n                        const inflate_huft **tl, // literal/length tree result\n                        const inflate_huft **td, // distance tree result\n                        z_streamp)               // for memory allocation\n{\n  *bl = fixed_bl;\n  *bd = fixed_bd;\n  *tl = fixed_tl;\n  *td = fixed_td;\n  return Z_OK;\n}\n\n// inffast.c -- process literals and length/distance pairs fast\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n//\n\n// struct inflate_codes_state {int dummy;}; // for buggy compilers\n\n// macros for bit input with no checking and for returning unused bytes\n#define GRABBITS(j)                                                            \\\n  {                                                                            \\\n    while (k < (j)) {                                                          \\\n      b |= ((uLong)NEXTBYTE) << k;                                             \\\n      k += 8;                                                                  \\\n    }                                                                          \\\n  }\n#define UNGRAB                                                                 \\\n  {                                                                            \\\n    c = z->avail_in - n;                                                       \\\n    c = (k >> 3) < c ? k >> 3 : c;                                             \\\n    n += c;                                                                    \\\n    p -= c;                                                                    \\\n    k -= c << 3;                                                               \\\n  }\n\n// Called with number of bytes left to write in window at least 258\n// (the maximum string length) and number of input bytes available\n// at least ten.  The ten bytes are six bytes for the longest length/\n// distance pair plus four bytes for overloading the bit buffer.\n\nint inflate_fast(\n    uInt bl, uInt bd, const inflate_huft *tl,\n    const inflate_huft *td, // need separate declaration for Borland C++\n    inflate_blocks_statef *s, z_streamp z) {\n  const inflate_huft *t; // temporary pointer\n  uInt e;                // extra bits or operation\n  uLong b;               // bit buffer\n  uInt k;                // bits in bit buffer\n  Byte *p;               // input data pointer\n  uInt n;                // bytes available there\n  Byte *q;               // output window write pointer\n  uInt m;                // bytes to end of window or read pointer\n  uInt ml;               // mask for literal/length tree\n  uInt md;               // mask for distance tree\n  uInt c;                // bytes to copy\n  uInt d;                // distance back to copy from\n  Byte *r;               // copy source pointer\n\n  // load input, output, bit values\n  LOAD\n\n      // initialize masks\n      ml = inflate_mask[bl];\n  md = inflate_mask[bd];\n\n  // do until not enough input or output space for fast loop\n  do { // assume called with m >= 258 && n >= 10\n    // get literal/length code\n    GRABBITS(20) // max bits for literal/length code\n    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) {\n      DUMPBITS(t->bits)\n      Tracevv((stderr,\n               t->base >= 0x20 && t->base < 0x7f\n                   ? \"inflate:         * literal '%c'\\n\"\n                   : \"inflate:         * literal 0x%02x\\n\",\n               t->base));\n      *q++ = (Byte)t->base;\n      m--;\n      continue;\n    }\n    for (;;) {\n      DUMPBITS(t->bits)\n      if (e & 16) {\n        // get extra bits for length\n        e &= 15;\n        c = t->base + ((uInt)b & inflate_mask[e]);\n        DUMPBITS(e)\n        Tracevv((stderr, \"inflate:         * length %u\\n\", c));\n\n        // decode distance base of block to copy\n        GRABBITS(15); // max bits for distance code\n        e = (t = td + ((uInt)b & md))->exop;\n        for (;;) {\n          DUMPBITS(t->bits)\n          if (e & 16) {\n            // get extra bits to add to distance base\n            e &= 15;\n            GRABBITS(e) // get extra bits (up to 13)\n            d = t->base + ((uInt)b & inflate_mask[e]);\n            DUMPBITS(e)\n            Tracevv((stderr, \"inflate:         * distance %u\\n\", d));\n\n            // do the copy\n            m -= c;\n            if ((uInt)(q - s->window) >= d) // offset before dest\n            {                               //  just copy\n              r = q - d;\n              *q++ = *r++;\n              c--; // minimum count is three,\n              *q++ = *r++;\n              c--; //  so unroll loop a little\n            } else // else offset after destination\n            {\n              e = d - (uInt)(q - s->window); // bytes from offset to end\n              r = s->end - e;                // pointer to offset\n              if (c > e)                     // if source crosses,\n              {\n                c -= e; // copy to end of window\n                do {\n                  *q++ = *r++;\n                } while (--e);\n                r = s->window; // copy rest from start of window\n              }\n            }\n            do { // copy all or what's left\n              *q++ = *r++;\n            } while (--c);\n            break;\n          } else if ((e & 64) == 0) {\n            t += t->base;\n            e = (t += ((uInt)b & inflate_mask[e]))->exop;\n          } else {\n            z->msg = (char *)\"invalid distance code\";\n            UNGRAB\n            UPDATE\n            return Z_DATA_ERROR;\n          }\n        };\n        break;\n      }\n      if ((e & 64) == 0) {\n        t += t->base;\n        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) {\n          DUMPBITS(t->bits)\n          Tracevv((stderr,\n                   t->base >= 0x20 && t->base < 0x7f\n                       ? \"inflate:         * literal '%c'\\n\"\n                       : \"inflate:         * literal 0x%02x\\n\",\n                   t->base));\n          *q++ = (Byte)t->base;\n          m--;\n          break;\n        }\n      } else if (e & 32) {\n        Tracevv((stderr, \"inflate:         * end of block\\n\"));\n        UNGRAB\n        UPDATE\n        return Z_STREAM_END;\n      } else {\n        z->msg = (char *)\"invalid literal/length code\";\n        UNGRAB\n        UPDATE\n        return Z_DATA_ERROR;\n      }\n    };\n  } while (m >= 258 && n >= 10);\n\n  // not enough input or output--restore pointers and return\n  UNGRAB\n  UPDATE\n  return Z_OK;\n}\n\n// crc32.c -- compute the CRC-32 of a data stream\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n\n// @(#) $Id$\n\n// Table of CRC-32's of all single-byte values (made by make_crc_table)\nconst uLong crc_table[256] = {\n    0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,\n    0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,\n    0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,\n    0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,\n    0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,\n    0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,\n    0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,\n    0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,\n    0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,\n    0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,\n    0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,\n    0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,\n    0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,\n    0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,\n    0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,\n    0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,\n    0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,\n    0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,\n    0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,\n    0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,\n    0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,\n    0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,\n    0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,\n    0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,\n    0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,\n    0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,\n    0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,\n    0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,\n    0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,\n    0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,\n    0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,\n    0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,\n    0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,\n    0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,\n    0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,\n    0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,\n    0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,\n    0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,\n    0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,\n    0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,\n    0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,\n    0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,\n    0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,\n    0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,\n    0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,\n    0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,\n    0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,\n    0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,\n    0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,\n    0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,\n    0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,\n    0x2d02ef8dL};\n\nconst uLong *get_crc_table() { return (const uLong *)crc_table; }\n\n#define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);\n#define CRC_DO2(buf)                                                           \\\n  CRC_DO1(buf);                                                                \\\n  CRC_DO1(buf);\n#define CRC_DO4(buf)                                                           \\\n  CRC_DO2(buf);                                                                \\\n  CRC_DO2(buf);\n#define CRC_DO8(buf)                                                           \\\n  CRC_DO4(buf);                                                                \\\n  CRC_DO4(buf);\n\nuLong ucrc32(uLong crc, const Byte *buf, uInt len) {\n  if (buf == Z_NULL)\n    return 0L;\n  crc = crc ^ 0xffffffffL;\n  while (len >= 8) {\n    CRC_DO8(buf);\n    len -= 8;\n  }\n  if (len)\n    do {\n      CRC_DO1(buf);\n    } while (--len);\n  return crc ^ 0xffffffffL;\n}\n\n// adler32.c -- compute the Adler-32 checksum of a data stream\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n\n// @(#) $Id$\n\n#define BASE 65521L // largest prime smaller than 65536\n#define NMAX 5552\n// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1\n\n#define AD_DO1(buf, i)                                                         \\\n  {                                                                            \\\n    s1 += buf[i];                                                              \\\n    s2 += s1;                                                                  \\\n  }\n#define AD_DO2(buf, i)                                                         \\\n  AD_DO1(buf, i);                                                              \\\n  AD_DO1(buf, i + 1);\n#define AD_DO4(buf, i)                                                         \\\n  AD_DO2(buf, i);                                                              \\\n  AD_DO2(buf, i + 2);\n#define AD_DO8(buf, i)                                                         \\\n  AD_DO4(buf, i);                                                              \\\n  AD_DO4(buf, i + 4);\n#define AD_DO16(buf)                                                           \\\n  AD_DO8(buf, 0);                                                              \\\n  AD_DO8(buf, 8);\n\n// =========================================================================\nuLong adler32(uLong adler, const Byte *buf, uInt len) {\n  unsigned long s1 = adler & 0xffff;\n  unsigned long s2 = (adler >> 16) & 0xffff;\n  int k;\n\n  if (buf == Z_NULL)\n    return 1L;\n\n  while (len > 0) {\n    k = len < NMAX ? len : NMAX;\n    len -= k;\n    while (k >= 16) {\n      AD_DO16(buf);\n      buf += 16;\n      k -= 16;\n    }\n    if (k != 0)\n      do {\n        s1 += *buf++;\n        s2 += s1;\n      } while (--k);\n    s1 %= BASE;\n    s2 %= BASE;\n  }\n  return (s2 << 16) | s1;\n}\n\n// zutil.c -- target dependent utility functions for the compression library\n// Copyright (C) 1995-1998 Jean-loup Gailly.\n// For conditions of distribution and use, see copyright notice in zlib.h\n// @(#) $Id$\n\nconst char *zlibVersion() { return ZLIB_VERSION; }\n\n// exported to allow conversion of error code to string for compress() and\n// uncompress()\nconst char *zError(int err) { return ERR_MSG(err); }\n\nvoidpf zcalloc(voidpf opaque, unsigned items, unsigned size) {\n  if (opaque)\n    items += size - size; // make compiler happy\n  return (voidpf)calloc(items, size);\n}\n\nvoid zcfree(voidpf opaque, voidpf ptr) {\n  zfree(ptr);\n  if (opaque)\n    return; // make compiler happy\n}\n\n// inflate.c -- zlib interface to inflate modules\n// Copyright (C) 1995-1998 Mark Adler\n// For conditions of distribution and use, see copyright notice in zlib.h\n\n// struct inflate_blocks_state {int dummy;}; // for buggy compilers\n\ntypedef enum {\n  IM_METHOD, // waiting for method byte\n  IM_FLAG,   // waiting for flag byte\n  IM_DICT4,  // four dictionary check bytes to go\n  IM_DICT3,  // three dictionary check bytes to go\n  IM_DICT2,  // two dictionary check bytes to go\n  IM_DICT1,  // one dictionary check byte to go\n  IM_DICT0,  // waiting for inflateSetDictionary\n  IM_BLOCKS, // decompressing blocks\n  IM_CHECK4, // four check bytes to go\n  IM_CHECK3, // three check bytes to go\n  IM_CHECK2, // two check bytes to go\n  IM_CHECK1, // one check byte to go\n  IM_DONE,   // finished check, done\n  IM_BAD\n} // got an error--stay here\ninflate_mode;\n\n// inflate private state\nstruct internal_state {\n\n  // mode\n  inflate_mode mode; // current inflate mode\n\n  // mode dependent information\n  union {\n    uInt method; // if IM_FLAGS, method byte\n    struct {\n      uLong was;  // computed check value\n      uLong need; // stream check value\n    } check;      // if CHECK, check values to compare\n    uInt marker;  // if IM_BAD, inflateSync's marker bytes count\n  } sub;          // submode\n\n  // mode independent information\n  int nowrap;                    // flag for no wrapper\n  uInt wbits;                    // log2(window size)  (8..15, defaults to 15)\n  inflate_blocks_statef *blocks; // current inflate_blocks state\n};\n\nint inflateReset(z_streamp z) {\n  if (z == Z_NULL || z->state == Z_NULL)\n    return Z_STREAM_ERROR;\n  z->total_in = z->total_out = 0;\n  z->msg = Z_NULL;\n  z->state->mode = z->state->nowrap ? IM_BLOCKS : IM_METHOD;\n  inflate_blocks_reset(z->state->blocks, z, Z_NULL);\n  Tracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nint inflateEnd(z_streamp z) {\n  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)\n    return Z_STREAM_ERROR;\n  if (z->state->blocks != Z_NULL)\n    inflate_blocks_free(z->state->blocks, z);\n  ZFREE(z, z->state);\n  z->state = Z_NULL;\n  Tracev((stderr, \"inflate: end\\n\"));\n  return Z_OK;\n}\n\nint inflateInit2(z_streamp z) {\n  const char *version = ZLIB_VERSION;\n  int stream_size = sizeof(z_stream);\n  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||\n      stream_size != sizeof(z_stream))\n    return Z_VERSION_ERROR;\n\n  int w = -15; // MAX_WBITS: 32K LZ77 window.\n  // Warning: reducing MAX_WBITS makes minigzip unable to extract .gz files\n  // created by gzip. The memory requirements for deflate are (in bytes):\n  //            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n  // that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n  // plus a few kilobytes for small objects. For example, if you want to reduce\n  // the default memory requirements from 256K to 128K, compile with\n  //     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n  // Of course this will generally degrade compression (there's no free lunch).\n  //\n  //   The memory requirements for inflate are (in bytes) 1 << windowBits\n  // that is, 32K for windowBits=15 (default value) plus a few kilobytes\n  // for small objects.\n\n  // initialize state\n  if (z == Z_NULL)\n    return Z_STREAM_ERROR;\n  z->msg = Z_NULL;\n  if (z->zalloc == Z_NULL) {\n    z->zalloc = zcalloc;\n    z->opaque = (voidpf)0;\n  }\n  if (z->zfree == Z_NULL)\n    z->zfree = zcfree;\n  if ((z->state = (struct internal_state *)ZALLOC(\n           z, 1, sizeof(struct internal_state))) == Z_NULL)\n    return Z_MEM_ERROR;\n  z->state->blocks = Z_NULL;\n\n  // handle undocumented nowrap option (no zlib header or check)\n  z->state->nowrap = 0;\n  if (w < 0) {\n    w = -w;\n    z->state->nowrap = 1;\n  }\n\n  // set window size\n  if (w < 8 || w > 15) {\n    inflateEnd(z);\n    return Z_STREAM_ERROR;\n  }\n  z->state->wbits = (uInt)w;\n\n  // create inflate_blocks state\n  if ((z->state->blocks = inflate_blocks_new(\n           z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) == Z_NULL) {\n    inflateEnd(z);\n    return Z_MEM_ERROR;\n  }\n  Tracev((stderr, \"inflate: allocated\\n\"));\n\n  // reset state\n  inflateReset(z);\n  return Z_OK;\n}\n\n#define IM_NEEDBYTE                                                            \\\n  {                                                                            \\\n    if (z->avail_in == 0)                                                      \\\n      return r;                                                                \\\n    r = f;                                                                     \\\n  }\n#define IM_NEXTBYTE (z->avail_in--, z->total_in++, *z->next_in++)\n\nint inflate(z_streamp z, int f) {\n  int r;\n  uInt b;\n\n  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)\n    return Z_STREAM_ERROR;\n  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;\n  r = Z_BUF_ERROR;\n  for (;;)\n    switch (z->state->mode) {\n    case IM_METHOD:\n      IM_NEEDBYTE\n      if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED) {\n        z->state->mode = IM_BAD;\n        z->msg = (char *)\"unknown compression method\";\n        z->state->sub.marker = 5; // can't try inflateSync\n        break;\n      }\n      if ((z->state->sub.method >> 4) + 8 > z->state->wbits) {\n        z->state->mode = IM_BAD;\n        z->msg = (char *)\"invalid window size\";\n        z->state->sub.marker = 5; // can't try inflateSync\n        break;\n      }\n      z->state->mode = IM_FLAG;\n    case IM_FLAG:\n      IM_NEEDBYTE\n      b = IM_NEXTBYTE;\n      if (((z->state->sub.method << 8) + b) % 31) {\n        z->state->mode = IM_BAD;\n        z->msg = (char *)\"incorrect header check\";\n        z->state->sub.marker = 5; // can't try inflateSync\n        break;\n      }\n      Tracev((stderr, \"inflate: zlib header ok\\n\"));\n      if (!(b & PRESET_DICT)) {\n        z->state->mode = IM_BLOCKS;\n        break;\n      }\n      z->state->mode = IM_DICT4;\n    case IM_DICT4:\n      IM_NEEDBYTE\n      z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24;\n      z->state->mode = IM_DICT3;\n    case IM_DICT3:\n      IM_NEEDBYTE\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16;\n      z->state->mode = IM_DICT2;\n    case IM_DICT2:\n      IM_NEEDBYTE\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8;\n      z->state->mode = IM_DICT1;\n    case IM_DICT1:\n      IM_NEEDBYTE;\n      r;\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE;\n      z->adler = z->state->sub.check.need;\n      z->state->mode = IM_DICT0;\n      return Z_NEED_DICT;\n    case IM_DICT0:\n      z->state->mode = IM_BAD;\n      z->msg = (char *)\"need dictionary\";\n      z->state->sub.marker = 0; // can try inflateSync\n      return Z_STREAM_ERROR;\n    case IM_BLOCKS:\n      r = inflate_blocks(z->state->blocks, z, r);\n      if (r == Z_DATA_ERROR) {\n        z->state->mode = IM_BAD;\n        z->state->sub.marker = 0; // can try inflateSync\n        break;\n      }\n      if (r == Z_OK)\n        r = f;\n      if (r != Z_STREAM_END)\n        return r;\n      r = f;\n      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);\n      if (z->state->nowrap) {\n        z->state->mode = IM_DONE;\n        break;\n      }\n      z->state->mode = IM_CHECK4;\n    case IM_CHECK4:\n      IM_NEEDBYTE\n      z->state->sub.check.need = (uLong)IM_NEXTBYTE << 24;\n      z->state->mode = IM_CHECK3;\n    case IM_CHECK3:\n      IM_NEEDBYTE\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE << 16;\n      z->state->mode = IM_CHECK2;\n    case IM_CHECK2:\n      IM_NEEDBYTE\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE << 8;\n      z->state->mode = IM_CHECK1;\n    case IM_CHECK1:\n      IM_NEEDBYTE\n      z->state->sub.check.need += (uLong)IM_NEXTBYTE;\n\n      if (z->state->sub.check.was != z->state->sub.check.need) {\n        z->state->mode = IM_BAD;\n        z->msg = (char *)\"incorrect data check\";\n        z->state->sub.marker = 5; // can't try inflateSync\n        break;\n      }\n      Tracev((stderr, \"inflate: zlib check ok\\n\"));\n      z->state->mode = IM_DONE;\n    case IM_DONE:\n      return Z_STREAM_END;\n    case IM_BAD:\n      return Z_DATA_ERROR;\n    default:\n      return Z_STREAM_ERROR;\n    }\n}\n\n#ifdef _UNICODE\n\nstatic int GetAnsiFileName(LPCWSTR name, char *buf, int nBufSize) {\n  memset(buf, 0, nBufSize);\n\n  int n = WideCharToMultiByte(CP_ACP,   // code page\n                              0,        // performance and mapping flags\n                              name,     // wide-character string\n                              -1,       // number of chars in string\n                              buf,      // buffer for new string\n                              nBufSize, // size of buffer\n                              NULL,     // default for unmappable chars\n                              NULL);    // set when default char used\n  return n;\n}\n\nstatic int GetUnicodeFileName(const char *name, LPWSTR buf, int nBufSize) {\n  memset(buf, 0, nBufSize * sizeof(TCHAR));\n\n  int n = MultiByteToWideChar(CP_ACP,    // code page\n                              0,         // character-type options\n                              name,      // string to map\n                              -1,        // number of bytes in string\n                              buf,       // wide-character buffer\n                              nBufSize); // size of buffer\n\n  return n;\n}\n\n#endif\n\n// unzip.c -- IO on .zip files using zlib\n// Version 0.15 beta, Mar 19th, 1998,\n// Read unzip.h for more info\n\n#define UNZ_BUFSIZE (16384)\n#define UNZ_MAXFILENAMEINZIP (256)\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n\nconst char unz_copyright[] = \" \"; // unzip 0.15 Copyright 1998 Gilles Vollant \";\n\n// unz_file_info_interntal contain internal info about a file in zipfile\ntypedef struct unz_file_info_internal_s {\n  uLong offset_curfile; // relative offset of local header 4 bytes\n} unz_file_info_internal;\n\ntypedef struct {\n  bool is_handle; // either a handle or memory\n  bool canseek;\n  // for handles:\n  HANDLE h;\n  bool herr;\n  unsigned long initial_offset;\n  // for memory:\n  void *buf;\n  unsigned int len, pos; // if it's a memory block\n} LUFILE;\n\nLUFILE *lufopen(void *z, unsigned int len, DWORD flags, ZRESULT *err) {\n  if (flags != ZIP_HANDLE && flags != ZIP_FILENAME && flags != ZIP_MEMORY) {\n    *err = ZR_ARGS;\n    return NULL;\n  }\n  //\n  HANDLE h = 0;\n  bool canseek = false;\n  *err = ZR_OK;\n  if (flags == ZIP_HANDLE || flags == ZIP_FILENAME) {\n    if (flags == ZIP_HANDLE) {\n      HANDLE hf = z;\n\n      BOOL res = DuplicateHandle(GetCurrentProcess(), hf, GetCurrentProcess(),\n                                 &h, 0, FALSE, DUPLICATE_SAME_ACCESS);\n\n      if (!res) {\n        *err = ZR_NODUPH;\n        return NULL;\n      }\n    } else {\n      h = CreateFile((const TCHAR *)z, GENERIC_READ, FILE_SHARE_READ, NULL,\n                     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n\n      if (h == INVALID_HANDLE_VALUE) {\n        *err = ZR_NOFILE;\n        return NULL;\n      }\n    }\n    DWORD type = GetFileType(h);\n    canseek = (type == FILE_TYPE_DISK);\n  }\n  LUFILE *lf = new LUFILE;\n  if (flags == ZIP_HANDLE || flags == ZIP_FILENAME) {\n    lf->is_handle = true;\n    lf->canseek = canseek;\n    lf->h = h;\n    lf->herr = false;\n    lf->initial_offset = 0;\n    if (canseek)\n      lf->initial_offset = SetFilePointer(h, 0, NULL, FILE_CURRENT);\n  } else {\n    lf->is_handle = false;\n    lf->canseek = true;\n    lf->buf = z;\n    lf->len = len;\n    lf->pos = 0;\n    lf->initial_offset = 0;\n  }\n  *err = ZR_OK;\n  return lf;\n}\n\nint lufclose(LUFILE *stream) {\n  if (stream == NULL)\n    return EOF;\n  if (stream->is_handle)\n    CloseHandle(stream->h);\n  delete stream;\n  return 0;\n}\n\nint luferror(LUFILE *stream) {\n  if (stream->is_handle && stream->herr)\n    return 1;\n  else\n    return 0;\n}\n\nlong int luftell(LUFILE *stream) {\n  if (stream->is_handle && stream->canseek)\n    return SetFilePointer(stream->h, 0, NULL, FILE_CURRENT) -\n           stream->initial_offset;\n  else if (stream->is_handle)\n    return 0;\n  else\n    return stream->pos;\n}\n\nint lufseek(LUFILE *stream, long offset, int whence) {\n  if (stream->is_handle && stream->canseek) {\n    if (whence == SEEK_SET)\n      SetFilePointer(stream->h, stream->initial_offset + offset, 0, FILE_BEGIN);\n    else if (whence == SEEK_CUR)\n      SetFilePointer(stream->h, offset, NULL, FILE_CURRENT);\n    else if (whence == SEEK_END)\n      SetFilePointer(stream->h, offset, NULL, FILE_END);\n    else\n      return 19; // EINVAL\n    return 0;\n  } else if (stream->is_handle)\n    return 29; // ESPIPE\n  else {\n    if (whence == SEEK_SET)\n      stream->pos = offset;\n    else if (whence == SEEK_CUR)\n      stream->pos += offset;\n    else if (whence == SEEK_END)\n      stream->pos = stream->len + offset;\n    return 0;\n  }\n}\n\nsize_t lufread(void *ptr, size_t size, size_t n, LUFILE *stream) {\n  unsigned int toread = (unsigned int)(size * n);\n  if (stream->is_handle) {\n    DWORD red;\n    BOOL res = ReadFile(stream->h, ptr, toread, &red, NULL);\n    if (!res)\n      stream->herr = true;\n    return red / size;\n  }\n  if (stream->pos + toread > stream->len)\n    toread = stream->len - stream->pos;\n  memcpy(ptr, (char *)stream->buf + stream->pos, toread);\n  DWORD red = toread;\n  stream->pos += red;\n  return red / size;\n}\n\n// file_in_zip_read_info_s contain internal information about a file in zipfile,\n//  when reading and decompress it\ntypedef struct {\n  char *read_buffer; // internal buffer for compressed data\n  z_stream stream;   // zLib stream structure for inflate\n\n  uLong pos_in_zipfile;     // position in byte on the zipfile, for fseek\n  uLong stream_initialised; // flag set if stream structure is initialised\n\n  uLong offset_local_extrafield; // offset of the local extra field\n  uInt size_local_extrafield;    // size of the local extra field\n  uLong pos_local_extrafield;    // position in the local extra field in read\n\n  uLong crc32;                   // crc32 of all data uncompressed\n  uLong crc32_wait;              // crc32 we must obtain after decompress all\n  uLong rest_read_compressed;    // number of byte to be decompressed\n  uLong rest_read_uncompressed;  // number of byte to be obtained after decomp\n  LUFILE *file;                  // io structore of the zipfile\n  uLong compression_method;      // compression method (0==store)\n  uLong byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx)\n} file_in_zip_read_info_s;\n\n// unz_s contain internal information about the zipfile\ntypedef struct {\n  LUFILE *file;                  // io structore of the zipfile\n  unz_global_info gi;            // public global information\n  uLong byte_before_the_zipfile; // byte before the zipfile, (>0 for sfx)\n  uLong num_file;                // number of the current file in the zipfile\n  uLong pos_in_central_dir;      // pos of the current file in the central dir\n  uLong current_file_ok;         // flag about the usability of the current file\n  uLong central_pos;             // position of the beginning of the central dir\n\n  uLong size_central_dir;   // size of the central directory\n  uLong offset_central_dir; // offset of start of central directory with respect\n                            // to the starting disk number\n\n  unz_file_info cur_file_info; // public info about the current file in zip\n  unz_file_info_internal cur_file_info_internal; // private info about it\n  file_in_zip_read_info_s *pfile_in_zip_read;    // structure about the current\n                                              // file if we are decompressing it\n} unz_s, *unzFile;\n\nint unzStringFileNameCompare(const char *fileName1, const char *fileName2,\n                             int iCaseSensitivity);\n//   Compare two filename (fileName1,fileName2).\n\nz_off_t unztell(unzFile file);\n//  Give the current position in uncompressed data\n\nint unzeof(unzFile file);\n//  return 1 if the end of file was reached, 0 elsewhere\n\nint unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len);\n//  Read extra field from the current file (opened by unzOpenCurrentFile)\n//  This is the local-header version of the extra field (sometimes, there is\n//    more info in the local-header version than in the central-header)\n//\n//  if buf==NULL, it return the size of the local extra field\n//\n//  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n//\tbuf.\n//  the return value is the number of bytes copied in buf, or (if <0)\n//\tthe error code\n\n// ===========================================================================\n//   Read a byte from a gz_stream; update next_in and avail_in. Return EOF\n// for end of file.\n// IN assertion: the stream s has been sucessfully opened for reading.\n\nint unzlocal_getByte(LUFILE *fin, int *pi) {\n  unsigned char c;\n  int err = (int)lufread(&c, 1, 1, fin);\n  if (err == 1) {\n    *pi = (int)c;\n    return UNZ_OK;\n  } else {\n    if (luferror(fin))\n      return UNZ_ERRNO;\n    else\n      return UNZ_EOF;\n  }\n}\n\n// ===========================================================================\n// Reads a long in LSB order from the given gz_stream. Sets\nint unzlocal_getShort(LUFILE *fin, uLong *pX) {\n  uLong x;\n  int i;\n  int err;\n\n  err = unzlocal_getByte(fin, &i);\n  x = (uLong)i;\n\n  if (err == UNZ_OK)\n    err = unzlocal_getByte(fin, &i);\n  x += ((uLong)i) << 8;\n\n  if (err == UNZ_OK)\n    *pX = x;\n  else\n    *pX = 0;\n  return err;\n}\n\nint unzlocal_getLong(LUFILE *fin, uLong *pX) {\n  uLong x;\n  int i;\n  int err;\n\n  err = unzlocal_getByte(fin, &i);\n  x = (uLong)i;\n\n  if (err == UNZ_OK)\n    err = unzlocal_getByte(fin, &i);\n  x += ((uLong)i) << 8;\n\n  if (err == UNZ_OK)\n    err = unzlocal_getByte(fin, &i);\n  x += ((uLong)i) << 16;\n\n  if (err == UNZ_OK)\n    err = unzlocal_getByte(fin, &i);\n  x += ((uLong)i) << 24;\n\n  if (err == UNZ_OK)\n    *pX = x;\n  else\n    *pX = 0;\n  return err;\n}\n\n// My own strcmpi / strcasecmp\nint strcmpcasenosensitive_internal(const char *fileName1,\n                                   const char *fileName2) {\n  for (;;) {\n    char c1 = *(fileName1++);\n    char c2 = *(fileName2++);\n    if ((c1 >= 'a') && (c1 <= 'z'))\n      c1 -= (char)0x20;\n    if ((c2 >= 'a') && (c2 <= 'z'))\n      c2 -= (char)0x20;\n    if (c1 == '\\0')\n      return ((c2 == '\\0') ? 0 : -1);\n    if (c2 == '\\0')\n      return 1;\n    if (c1 < c2)\n      return -1;\n    if (c1 > c2)\n      return 1;\n  }\n}\n\n//\n// Compare two filename (fileName1,fileName2).\n// If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n// If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or\n// strcasecmp)\n//\nint unzStringFileNameCompare(const char *fileName1, const char *fileName2,\n                             int iCaseSensitivity) {\n  if (iCaseSensitivity == 1)\n    return strcmp(fileName1, fileName2);\n  else\n    return strcmpcasenosensitive_internal(fileName1, fileName2);\n}\n\n#define BUFREADCOMMENT (0x400)\n\n//  Locate the Central directory of a zipfile (at the end, just before\n// the global comment)\nuLong unzlocal_SearchCentralDir(LUFILE *fin) {\n  if (lufseek(fin, 0, SEEK_END) != 0)\n    return 0;\n  uLong uSizeFile = luftell(fin);\n\n  uLong uMaxBack = 0xffff; // maximum size of global comment\n  if (uMaxBack > uSizeFile)\n    uMaxBack = uSizeFile;\n\n  unsigned char *buf = (unsigned char *)zmalloc(BUFREADCOMMENT + 4);\n  if (buf == NULL)\n    return 0;\n  uLong uPosFound = 0;\n\n  uLong uBackRead = 4;\n  while (uBackRead < uMaxBack) {\n    uLong uReadSize, uReadPos;\n    int i;\n    if (uBackRead + BUFREADCOMMENT > uMaxBack)\n      uBackRead = uMaxBack;\n    else\n      uBackRead += BUFREADCOMMENT;\n    uReadPos = uSizeFile - uBackRead;\n    uReadSize = ((BUFREADCOMMENT + 4) < (uSizeFile - uReadPos))\n                    ? (BUFREADCOMMENT + 4)\n                    : (uSizeFile - uReadPos);\n    if (lufseek(fin, uReadPos, SEEK_SET) != 0)\n      break;\n    if (lufread(buf, (uInt)uReadSize, 1, fin) != 1)\n      break;\n    for (i = (int)uReadSize - 3; (i--) > 0;) {\n      if (((*(buf + i)) == 0x50) && ((*(buf + i + 1)) == 0x4b) &&\n          ((*(buf + i + 2)) == 0x05) && ((*(buf + i + 3)) == 0x06)) {\n        uPosFound = uReadPos + i;\n        break;\n      }\n    }\n    if (uPosFound != 0)\n      break;\n  }\n  if (buf)\n    zfree(buf);\n  return uPosFound;\n}\n\nint unzGoToFirstFile(unzFile file);\nint unzCloseCurrentFile(unzFile file);\n\n// Open a Zip file.\n// If the zipfile cannot be opened (file don't exist or in not valid), return\n// NULL. Otherwise, the return value is a unzFile Handle, usable with other\n// unzip functions\nunzFile unzOpenInternal(LUFILE *fin) {\n  zopenerror = ZR_OK; //+++1.2\n  if (fin == NULL) {\n    zopenerror = ZR_ARGS;\n    return NULL;\n  } //+++1.2\n  if (unz_copyright[0] != ' ') {\n    lufclose(fin);\n    zopenerror = ZR_CORRUPT;\n    return NULL;\n  } //+++1.2\n\n  int err = UNZ_OK;\n  unz_s us;\n  uLong central_pos, uL;\n  central_pos = unzlocal_SearchCentralDir(fin);\n  if (central_pos == 0)\n    err = UNZ_ERRNO;\n  if (lufseek(fin, central_pos, SEEK_SET) != 0)\n    err = UNZ_ERRNO;\n  // the signature, already checked\n  if (unzlocal_getLong(fin, &uL) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // number of this disk\n  uLong number_disk; // number of the current dist, used for spanning ZIP,\n                     // unsupported, always 0\n  if (unzlocal_getShort(fin, &number_disk) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // number of the disk with the start of the central directory\n  uLong number_disk_with_CD; // number the the disk with central dir, used for\n                             // spaning ZIP, unsupported, always 0\n  if (unzlocal_getShort(fin, &number_disk_with_CD) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // total number of entries in the central dir on this disk\n  if (unzlocal_getShort(fin, &us.gi.number_entry) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // total number of entries in the central dir\n  uLong number_entry_CD; // total number of entries in the central dir (same\n                         // than number_entry on nospan)\n  if (unzlocal_getShort(fin, &number_entry_CD) != UNZ_OK)\n    err = UNZ_ERRNO;\n  if ((number_entry_CD != us.gi.number_entry) || (number_disk_with_CD != 0) ||\n      (number_disk != 0))\n    err = UNZ_BADZIPFILE;\n  // size of the central directory\n  if (unzlocal_getLong(fin, &us.size_central_dir) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // offset of start of central directory with respect to the starting disk\n  // number\n  if (unzlocal_getLong(fin, &us.offset_central_dir) != UNZ_OK)\n    err = UNZ_ERRNO;\n  // zipfile comment length\n  if (unzlocal_getShort(fin, &us.gi.size_comment) != UNZ_OK)\n    err = UNZ_ERRNO;\n  if ((central_pos + fin->initial_offset <\n       us.offset_central_dir + us.size_central_dir) &&\n      (err == UNZ_OK))\n    err = UNZ_BADZIPFILE;\n  // if (err!=UNZ_OK) {lufclose(fin);return NULL;}\n  if (err != UNZ_OK) {\n    lufclose(fin);\n    zopenerror = err;\n    return NULL;\n  } //+++1.2\n\n  us.file = fin;\n  us.byte_before_the_zipfile = central_pos + fin->initial_offset -\n                               (us.offset_central_dir + us.size_central_dir);\n  us.central_pos = central_pos;\n  us.pfile_in_zip_read = NULL;\n  fin->initial_offset =\n      0; // since the zipfile itself is expected to handle this\n\n  unz_s *s = (unz_s *)zmalloc(sizeof(unz_s));\n  *s = us;\n  unzGoToFirstFile((unzFile)s);\n  return (unzFile)s;\n}\n\n//  Close a ZipFile opened with unzipOpen.\n//  If there is files inside the .Zip opened with unzipOpenCurrentFile (see\n//  later),\n//    these files MUST be closed with unzipCloseCurrentFile before call\n//    unzipClose.\n//  return UNZ_OK if there is no problem.\nint unzClose(unzFile file) {\n  unz_s *s;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n\n  if (s->pfile_in_zip_read != NULL)\n    unzCloseCurrentFile(file);\n\n  lufclose(s->file);\n  if (s)\n    zfree(s); // unused s=0;\n  return UNZ_OK;\n}\n\n//  Write info about the ZipFile in the *pglobal_info structure.\n//  No preparation of the structure is needed\n//  return UNZ_OK if there is no problem.\nint unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info) {\n  unz_s *s;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  *pglobal_info = s->gi;\n  return UNZ_OK;\n}\n\n//   Translate date/time from Dos format to tm_unz (readable more easilty)\nvoid unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz *ptm) {\n  uLong uDate;\n  uDate = (uLong)(ulDosDate >> 16);\n  ptm->tm_mday = (uInt)(uDate & 0x1f);\n  ptm->tm_mon = (uInt)((((uDate)&0x1E0) / 0x20) - 1);\n  ptm->tm_year = (uInt)(((uDate & 0x0FE00) / 0x0200) + 1980);\n\n  ptm->tm_hour = (uInt)((ulDosDate & 0xF800) / 0x800);\n  ptm->tm_min = (uInt)((ulDosDate & 0x7E0) / 0x20);\n  ptm->tm_sec = (uInt)(2 * (ulDosDate & 0x1f));\n}\n\n//  Get Info about the current file in the zipfile, with internal only info\nint unzlocal_GetCurrentFileInfoInternal(\n    unzFile file, unz_file_info *pfile_info,\n    unz_file_info_internal *pfile_info_internal, char *szFileName,\n    uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize,\n    char *szComment, uLong commentBufferSize);\n\nint unzlocal_GetCurrentFileInfoInternal(\n    unzFile file, unz_file_info *pfile_info,\n    unz_file_info_internal *pfile_info_internal, char *szFileName,\n    uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize,\n    char *szComment, uLong commentBufferSize) {\n  unz_s *s;\n  unz_file_info file_info;\n  unz_file_info_internal file_info_internal;\n  int err = UNZ_OK;\n  uLong uMagic;\n  long lSeek = 0;\n\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  if (lufseek(s->file, s->pos_in_central_dir + s->byte_before_the_zipfile,\n              SEEK_SET) != 0)\n    err = UNZ_ERRNO;\n\n  // we check the magic\n  if (err == UNZ_OK)\n    if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)\n      err = UNZ_ERRNO;\n    else if (uMagic != 0x02014b50)\n      err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getShort(s->file, &file_info.version) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.version_needed) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.flag) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.compression_method) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &file_info.dosDate) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  unzlocal_DosDateToTmuDate(file_info.dosDate, &file_info.tmu_date);\n\n  if (unzlocal_getLong(s->file, &file_info.crc) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &file_info.compressed_size) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &file_info.uncompressed_size) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.size_filename) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.size_file_extra) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.size_file_comment) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.disk_num_start) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &file_info.internal_fa) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &file_info.external_fa) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &file_info_internal.offset_curfile) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  lSeek += file_info.size_filename;\n  if ((err == UNZ_OK) && (szFileName != NULL)) {\n    uLong uSizeRead;\n    if (file_info.size_filename < fileNameBufferSize) {\n      *(szFileName + file_info.size_filename) = '\\0';\n      uSizeRead = file_info.size_filename;\n    } else\n      uSizeRead = fileNameBufferSize;\n\n    if ((file_info.size_filename > 0) && (fileNameBufferSize > 0))\n      if (lufread(szFileName, (uInt)uSizeRead, 1, s->file) != 1)\n        err = UNZ_ERRNO;\n    lSeek -= uSizeRead;\n  }\n\n  if ((err == UNZ_OK) && (extraField != NULL)) {\n    uLong uSizeRead;\n    if (file_info.size_file_extra < extraFieldBufferSize)\n      uSizeRead = file_info.size_file_extra;\n    else\n      uSizeRead = extraFieldBufferSize;\n\n    if (lSeek != 0)\n      if (lufseek(s->file, lSeek, SEEK_CUR) == 0)\n        lSeek = 0;\n      else\n        err = UNZ_ERRNO;\n    if ((file_info.size_file_extra > 0) && (extraFieldBufferSize > 0))\n      if (lufread(extraField, (uInt)uSizeRead, 1, s->file) != 1)\n        err = UNZ_ERRNO;\n    lSeek += file_info.size_file_extra - uSizeRead;\n  } else\n    lSeek += file_info.size_file_extra;\n\n  if ((err == UNZ_OK) && (szComment != NULL)) {\n    uLong uSizeRead;\n    if (file_info.size_file_comment < commentBufferSize) {\n      *(szComment + file_info.size_file_comment) = '\\0';\n      uSizeRead = file_info.size_file_comment;\n    } else\n      uSizeRead = commentBufferSize;\n\n    if (lSeek != 0)\n      if (lufseek(s->file, lSeek, SEEK_CUR) == 0) {\n      } // unused lSeek=0;\n      else\n        err = UNZ_ERRNO;\n    if ((file_info.size_file_comment > 0) && (commentBufferSize > 0))\n      if (lufread(szComment, (uInt)uSizeRead, 1, s->file) != 1)\n        err = UNZ_ERRNO;\n    // unused lSeek+=file_info.size_file_comment - uSizeRead;\n  } else {\n  } // unused lSeek+=file_info.size_file_comment;\n\n  if ((err == UNZ_OK) && (pfile_info != NULL))\n    *pfile_info = file_info;\n\n  if ((err == UNZ_OK) && (pfile_info_internal != NULL))\n    *pfile_info_internal = file_info_internal;\n\n  return err;\n}\n\n//  Write info about the ZipFile in the *pglobal_info structure.\n//  No preparation of the structure is needed\n//  return UNZ_OK if there is no problem.\nint unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info,\n                          char *szFileName, uLong fileNameBufferSize,\n                          void *extraField, uLong extraFieldBufferSize,\n                          char *szComment, uLong commentBufferSize) {\n  return unzlocal_GetCurrentFileInfoInternal(\n      file, pfile_info, NULL, szFileName, fileNameBufferSize, extraField,\n      extraFieldBufferSize, szComment, commentBufferSize);\n}\n\n//  Set the current file of the zipfile to the first file.\n//  return UNZ_OK if there is no problem\nint unzGoToFirstFile(unzFile file) {\n  int err;\n  unz_s *s;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  s->pos_in_central_dir = s->offset_central_dir;\n  s->num_file = 0;\n  err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,\n                                            &s->cur_file_info_internal, NULL, 0,\n                                            NULL, 0, NULL, 0);\n  s->current_file_ok = (err == UNZ_OK);\n  return err;\n}\n\n//  Set the current file of the zipfile to the next file.\n//  return UNZ_OK if there is no problem\n//  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\nint unzGoToNextFile(unzFile file) {\n  unz_s *s;\n  int err;\n\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  if (!s->current_file_ok)\n    return UNZ_END_OF_LIST_OF_FILE;\n  if (s->num_file + 1 == s->gi.number_entry)\n    return UNZ_END_OF_LIST_OF_FILE;\n\n  s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +\n                           s->cur_file_info.size_file_extra +\n                           s->cur_file_info.size_file_comment;\n  s->num_file++;\n  err = unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,\n                                            &s->cur_file_info_internal, NULL, 0,\n                                            NULL, 0, NULL, 0);\n  s->current_file_ok = (err == UNZ_OK);\n  return err;\n}\n\n//  Try locate the file szFileName in the zipfile.\n//  For the iCaseSensitivity signification, see unzStringFileNameCompare\n//  return value :\n//  UNZ_OK if the file is found. It becomes the current file.\n//  UNZ_END_OF_LIST_OF_FILE if the file is not found\nint unzLocateFile(unzFile file, const TCHAR *szFileName, int iCaseSensitivity) {\n  unz_s *s;\n  int err;\n\n  uLong num_fileSaved;\n  uLong pos_in_central_dirSaved;\n\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n\n  if (_tcslen(szFileName) >= UNZ_MAXFILENAMEINZIP)\n    return UNZ_PARAMERROR;\n\n  char szFileNameA[MAX_PATH];\n\n#ifdef _UNICODE\n  GetAnsiFileName(szFileName, szFileNameA, MAX_PATH - 1);\n#else\n  strcpy(szFileNameA, szFileName);\n#endif\n\n  s = (unz_s *)file;\n  if (!s->current_file_ok)\n    return UNZ_END_OF_LIST_OF_FILE;\n\n  num_fileSaved = s->num_file;\n  pos_in_central_dirSaved = s->pos_in_central_dir;\n\n  err = unzGoToFirstFile(file);\n\n  while (err == UNZ_OK) {\n    char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1];\n    unzGetCurrentFileInfo(file, NULL, szCurrentFileName,\n                          sizeof(szCurrentFileName) - 1, NULL, 0, NULL, 0);\n    if (unzStringFileNameCompare(szCurrentFileName, szFileNameA,\n                                 iCaseSensitivity) == 0)\n      return UNZ_OK;\n    err = unzGoToNextFile(file);\n  }\n\n  s->num_file = num_fileSaved;\n  s->pos_in_central_dir = pos_in_central_dirSaved;\n  return err;\n}\n\n//  Read the local header of the current zipfile\n//  Check the coherency of the local header and info in the end of central\n//        directory about this file\n//  store in *piSizeVar the size of extra info in local header\n//        (filename and size of extra field data)\nint unzlocal_CheckCurrentFileCoherencyHeader(unz_s *s, uInt *piSizeVar,\n                                             uLong *poffset_local_extrafield,\n                                             uInt *psize_local_extrafield) {\n  uLong uMagic, uData, uFlags;\n  uLong size_filename;\n  uLong size_extra_field;\n  int err = UNZ_OK;\n\n  *piSizeVar = 0;\n  *poffset_local_extrafield = 0;\n  *psize_local_extrafield = 0;\n\n  if (lufseek(s->file,\n              s->cur_file_info_internal.offset_curfile +\n                  s->byte_before_the_zipfile,\n              SEEK_SET) != 0)\n    return UNZ_ERRNO;\n\n  if (err == UNZ_OK)\n    if (unzlocal_getLong(s->file, &uMagic) != UNZ_OK)\n      err = UNZ_ERRNO;\n    else if (uMagic != 0x04034b50)\n      err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getShort(s->file, &uData) != UNZ_OK)\n    err = UNZ_ERRNO;\n  //\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))\n  //\t\terr=UNZ_BADZIPFILE;\n  if (unzlocal_getShort(s->file, &uFlags) != UNZ_OK)\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getShort(s->file, &uData) != UNZ_OK)\n    err = UNZ_ERRNO;\n  else if ((err == UNZ_OK) && (uData != s->cur_file_info.compression_method))\n    err = UNZ_BADZIPFILE;\n\n  if ((err == UNZ_OK) && (s->cur_file_info.compression_method != 0) &&\n      (s->cur_file_info.compression_method != Z_DEFLATED))\n    err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // date/time\n    err = UNZ_ERRNO;\n\n  if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // crc\n    err = UNZ_ERRNO;\n  else if ((err == UNZ_OK) && (uData != s->cur_file_info.crc) &&\n           ((uFlags & 8) == 0))\n    err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // size compr\n    err = UNZ_ERRNO;\n  else if ((err == UNZ_OK) && (uData != s->cur_file_info.compressed_size) &&\n           ((uFlags & 8) == 0))\n    err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getLong(s->file, &uData) != UNZ_OK) // size uncompr\n    err = UNZ_ERRNO;\n  else if ((err == UNZ_OK) && (uData != s->cur_file_info.uncompressed_size) &&\n           ((uFlags & 8) == 0))\n    err = UNZ_BADZIPFILE;\n\n  if (unzlocal_getShort(s->file, &size_filename) != UNZ_OK)\n    err = UNZ_ERRNO;\n  else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename))\n    err = UNZ_BADZIPFILE;\n\n  *piSizeVar += (uInt)size_filename;\n\n  if (unzlocal_getShort(s->file, &size_extra_field) != UNZ_OK)\n    err = UNZ_ERRNO;\n  *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile +\n                              SIZEZIPLOCALHEADER + size_filename;\n  *psize_local_extrafield = (uInt)size_extra_field;\n\n  *piSizeVar += (uInt)size_extra_field;\n\n  return err;\n}\n\n//  Open for reading data the current file in the zipfile.\n//  If there is no error and the file is opened, the return value is UNZ_OK.\nint unzOpenCurrentFile(unzFile file) {\n  int err;\n  int Store;\n  uInt iSizeVar;\n  unz_s *s;\n  file_in_zip_read_info_s *pfile_in_zip_read_info;\n  uLong offset_local_extrafield; // offset of the local extra field\n  uInt size_local_extrafield;    // size of the local extra field\n\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  if (!s->current_file_ok)\n    return UNZ_PARAMERROR;\n\n  if (s->pfile_in_zip_read != NULL)\n    unzCloseCurrentFile(file);\n\n  if (unzlocal_CheckCurrentFileCoherencyHeader(\n          s, &iSizeVar, &offset_local_extrafield, &size_local_extrafield) !=\n      UNZ_OK)\n    return UNZ_BADZIPFILE;\n\n  pfile_in_zip_read_info =\n      (file_in_zip_read_info_s *)zmalloc(sizeof(file_in_zip_read_info_s));\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_INTERNALERROR;\n\n  pfile_in_zip_read_info->read_buffer = (char *)zmalloc(UNZ_BUFSIZE);\n  pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;\n  pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;\n  pfile_in_zip_read_info->pos_local_extrafield = 0;\n\n  if (pfile_in_zip_read_info->read_buffer == NULL) {\n    if (pfile_in_zip_read_info != 0)\n      zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0;\n    return UNZ_INTERNALERROR;\n  }\n\n  pfile_in_zip_read_info->stream_initialised = 0;\n\n  if ((s->cur_file_info.compression_method != 0) &&\n      (s->cur_file_info.compression_method !=\n       Z_DEFLATED)) { // unused err=UNZ_BADZIPFILE;\n  }\n  Store = s->cur_file_info.compression_method == 0;\n\n  pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc;\n  pfile_in_zip_read_info->crc32 = 0;\n  pfile_in_zip_read_info->compression_method =\n      s->cur_file_info.compression_method;\n  pfile_in_zip_read_info->file = s->file;\n  pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;\n\n  pfile_in_zip_read_info->stream.total_out = 0;\n\n  if (!Store) {\n    pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n    pfile_in_zip_read_info->stream.zfree = (free_func)0;\n    pfile_in_zip_read_info->stream.opaque = (voidpf)0;\n\n    err = inflateInit2(&pfile_in_zip_read_info->stream);\n    if (err == Z_OK)\n      pfile_in_zip_read_info->stream_initialised = 1;\n    // windowBits is passed < 0 to tell that there is no zlib header.\n    // Note that in this case inflate *requires* an extra \"dummy\" byte\n    // after the compressed stream in order to complete decompression and\n    // return Z_STREAM_END.\n    // In unzip, i don't wait absolutely Z_STREAM_END because I known the\n    // size of both compressed and uncompressed data\n  }\n  pfile_in_zip_read_info->rest_read_compressed =\n      s->cur_file_info.compressed_size;\n  pfile_in_zip_read_info->rest_read_uncompressed =\n      s->cur_file_info.uncompressed_size;\n\n  pfile_in_zip_read_info->pos_in_zipfile =\n      s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;\n\n  pfile_in_zip_read_info->stream.avail_in = (uInt)0;\n\n  s->pfile_in_zip_read = pfile_in_zip_read_info;\n  return UNZ_OK;\n}\n\n//  Read bytes from the current file.\n//  buf contain buffer where data must be copied\n//  len the size of buf.\n//  return the number of byte copied if somes bytes are copied\n//  return 0 if the end of file was reached\n//  return <0 with error code if there is an error\n//    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\nint unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {\n  int err = UNZ_OK;\n  uInt iRead = 0;\n\n  unz_s *s = (unz_s *)file;\n  if (s == NULL)\n    return UNZ_PARAMERROR;\n\n  file_in_zip_read_info_s *pfile_in_zip_read_info = s->pfile_in_zip_read;\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_PARAMERROR;\n  if ((pfile_in_zip_read_info->read_buffer == NULL))\n    return UNZ_END_OF_LIST_OF_FILE;\n  if (len == 0)\n    return 0;\n\n  pfile_in_zip_read_info->stream.next_out = (Byte *)buf;\n  pfile_in_zip_read_info->stream.avail_out = (uInt)len;\n\n  if (len > pfile_in_zip_read_info->rest_read_uncompressed) {\n    pfile_in_zip_read_info->stream.avail_out =\n        (uInt)pfile_in_zip_read_info->rest_read_uncompressed;\n  }\n\n  while (pfile_in_zip_read_info->stream.avail_out > 0) {\n    if ((pfile_in_zip_read_info->stream.avail_in == 0) &&\n        (pfile_in_zip_read_info->rest_read_compressed > 0)) {\n      uInt uReadThis = UNZ_BUFSIZE;\n      if (pfile_in_zip_read_info->rest_read_compressed < uReadThis)\n        uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;\n      if (uReadThis == 0)\n        return UNZ_EOF;\n      if (lufseek(pfile_in_zip_read_info->file,\n                  pfile_in_zip_read_info->pos_in_zipfile +\n                      pfile_in_zip_read_info->byte_before_the_zipfile,\n                  SEEK_SET) != 0)\n        return UNZ_ERRNO;\n      if (lufread(pfile_in_zip_read_info->read_buffer, uReadThis, 1,\n                  pfile_in_zip_read_info->file) != 1)\n        return UNZ_ERRNO;\n      pfile_in_zip_read_info->pos_in_zipfile += uReadThis;\n      pfile_in_zip_read_info->rest_read_compressed -= uReadThis;\n      pfile_in_zip_read_info->stream.next_in =\n          (Byte *)pfile_in_zip_read_info->read_buffer;\n      pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;\n    }\n\n    if (pfile_in_zip_read_info->compression_method == 0) {\n      uInt uDoCopy, i;\n      if (pfile_in_zip_read_info->stream.avail_out <\n          pfile_in_zip_read_info->stream.avail_in) {\n        uDoCopy = pfile_in_zip_read_info->stream.avail_out;\n      } else {\n        uDoCopy = pfile_in_zip_read_info->stream.avail_in;\n      }\n      for (i = 0; i < uDoCopy; i++) {\n        *(pfile_in_zip_read_info->stream.next_out + i) =\n            *(pfile_in_zip_read_info->stream.next_in + i);\n      }\n      pfile_in_zip_read_info->crc32 =\n          ucrc32(pfile_in_zip_read_info->crc32,\n                 pfile_in_zip_read_info->stream.next_out, uDoCopy);\n      pfile_in_zip_read_info->rest_read_uncompressed -= uDoCopy;\n      pfile_in_zip_read_info->stream.avail_in -= uDoCopy;\n      pfile_in_zip_read_info->stream.avail_out -= uDoCopy;\n      pfile_in_zip_read_info->stream.next_out += uDoCopy;\n      pfile_in_zip_read_info->stream.next_in += uDoCopy;\n      pfile_in_zip_read_info->stream.total_out += uDoCopy;\n      iRead += uDoCopy;\n    } else {\n      uLong uTotalOutBefore, uTotalOutAfter;\n      const Byte *bufBefore;\n      uLong uOutThis;\n      int flush = Z_SYNC_FLUSH;\n      uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;\n      bufBefore = pfile_in_zip_read_info->stream.next_out;\n      err = inflate(&pfile_in_zip_read_info->stream, flush);\n      uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;\n      uOutThis = uTotalOutAfter - uTotalOutBefore;\n      pfile_in_zip_read_info->crc32 =\n          ucrc32(pfile_in_zip_read_info->crc32, bufBefore, (uInt)(uOutThis));\n      pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;\n      iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);\n      if (err == Z_STREAM_END)\n        return (iRead == 0) ? UNZ_EOF : iRead; //+++1.3\n      // if (err==Z_STREAM_END) return (iRead==len) ? UNZ_EOF : iRead;\n      // //+++1.2\n\n      if (err != Z_OK)\n        break;\n    }\n  }\n\n  if (err == Z_OK)\n    return iRead;\n\n  return iRead;\n}\n\n//  Give the current position in uncompressed data\nz_off_t unztell(unzFile file) {\n  unz_s *s;\n  file_in_zip_read_info_s *pfile_in_zip_read_info;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  pfile_in_zip_read_info = s->pfile_in_zip_read;\n\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_PARAMERROR;\n\n  return (z_off_t)pfile_in_zip_read_info->stream.total_out;\n}\n\n//  return 1 if the end of file was reached, 0 elsewhere\nint unzeof(unzFile file) {\n  unz_s *s;\n  file_in_zip_read_info_s *pfile_in_zip_read_info;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  pfile_in_zip_read_info = s->pfile_in_zip_read;\n\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_PARAMERROR;\n\n  if (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n    return 1;\n  else\n    return 0;\n}\n\n//  Read extra field from the current file (opened by unzOpenCurrentFile)\n//  This is the local-header version of the extra field (sometimes, there is\n//    more info in the local-header version than in the central-header)\n//  if buf==NULL, it return the size of the local extra field that can be read\n//  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n//  buf. the return value is the number of bytes copied in buf, or (if <0) the\n//  error code\nint unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {\n  unz_s *s;\n  file_in_zip_read_info_s *pfile_in_zip_read_info;\n  uInt read_now;\n  uLong size_to_read;\n\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  pfile_in_zip_read_info = s->pfile_in_zip_read;\n\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_PARAMERROR;\n\n  size_to_read = (pfile_in_zip_read_info->size_local_extrafield -\n                  pfile_in_zip_read_info->pos_local_extrafield);\n\n  if (buf == NULL)\n    return (int)size_to_read;\n\n  if (len > size_to_read)\n    read_now = (uInt)size_to_read;\n  else\n    read_now = (uInt)len;\n\n  if (read_now == 0)\n    return 0;\n\n  if (lufseek(pfile_in_zip_read_info->file,\n              pfile_in_zip_read_info->offset_local_extrafield +\n                  pfile_in_zip_read_info->pos_local_extrafield,\n              SEEK_SET) != 0)\n    return UNZ_ERRNO;\n\n  if (lufread(buf, (uInt)size_to_read, 1, pfile_in_zip_read_info->file) != 1)\n    return UNZ_ERRNO;\n\n  return (int)read_now;\n}\n\n//  Close the file in zip opened with unzipOpenCurrentFile\n//  Return UNZ_CRCERROR if all the file was read but the CRC is not good\nint unzCloseCurrentFile(unzFile file) {\n  int err = UNZ_OK;\n\n  unz_s *s;\n  file_in_zip_read_info_s *pfile_in_zip_read_info;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  pfile_in_zip_read_info = s->pfile_in_zip_read;\n\n  if (pfile_in_zip_read_info == NULL)\n    return UNZ_PARAMERROR;\n\n  if (pfile_in_zip_read_info->rest_read_uncompressed == 0) {\n    if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)\n      err = UNZ_CRCERROR;\n  }\n\n  if (pfile_in_zip_read_info->read_buffer != 0) {\n    void *buf = pfile_in_zip_read_info->read_buffer;\n    zfree(buf);\n    pfile_in_zip_read_info->read_buffer = 0;\n  }\n  pfile_in_zip_read_info->read_buffer = NULL;\n  if (pfile_in_zip_read_info->stream_initialised)\n    inflateEnd(&pfile_in_zip_read_info->stream);\n\n  pfile_in_zip_read_info->stream_initialised = 0;\n  if (pfile_in_zip_read_info != 0)\n    zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0;\n\n  s->pfile_in_zip_read = NULL;\n\n  return err;\n}\n\n//  Get the global comment string of the ZipFile, in the szComment buffer.\n//  uSizeBuf is the size of the szComment buffer.\n//  return the number of byte copied or an error code <0\nint unzGetGlobalComment(unzFile file, char *szComment,\n                        uLong uSizeBuf) { // int err=UNZ_OK;\n  unz_s *s;\n  uLong uReadThis;\n  if (file == NULL)\n    return UNZ_PARAMERROR;\n  s = (unz_s *)file;\n  uReadThis = uSizeBuf;\n  if (uReadThis > s->gi.size_comment)\n    uReadThis = s->gi.size_comment;\n  if (lufseek(s->file, s->central_pos + 22, SEEK_SET) != 0)\n    return UNZ_ERRNO;\n  if (uReadThis > 0) {\n    *szComment = '\\0';\n    if (lufread(szComment, (uInt)uReadThis, 1, s->file) != 1)\n      return UNZ_ERRNO;\n  }\n  if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))\n    *(szComment + s->gi.size_comment) = '\\0';\n  return (int)uReadThis;\n}\n\nint unzOpenCurrentFile(unzFile file);\nint unzReadCurrentFile(unzFile file, void *buf, unsigned len);\nint unzCloseCurrentFile(unzFile file);\n\nFILETIME timet2filetime(time_t timer) {\n  struct tm *tm = gmtime(&timer);\n  SYSTEMTIME st;\n  st.wYear = (WORD)(tm->tm_year + 1900);\n  st.wMonth = (WORD)(tm->tm_mon + 1);\n  st.wDay = (WORD)(tm->tm_mday);\n  st.wHour = (WORD)(tm->tm_hour);\n  st.wMinute = (WORD)(tm->tm_min);\n  st.wSecond = (WORD)(tm->tm_sec);\n  st.wMilliseconds = 0;\n  FILETIME ft;\n  SystemTimeToFileTime(&st, &ft);\n  return ft;\n}\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\nclass TUnzip {\npublic:\n  TUnzip() : uf(0), currentfile(-1), czei(-1) {}\n\n  unzFile uf;\n  int currentfile;\n  ZIPENTRY cze;\n  int czei;\n  TCHAR rootdir[MAX_PATH];\n\n  ZRESULT Open(void *z, unsigned int len, DWORD flags);\n  ZRESULT Get(int index, ZIPENTRY *ze);\n  ZRESULT Find(const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);\n  ZRESULT Unzip(int index, void *dst, unsigned int len, DWORD flags);\n  ZRESULT Close();\n};\n\nZRESULT TUnzip::Open(void *z, unsigned int len, DWORD flags) {\n  if (uf != 0 || currentfile != -1)\n    return ZR_NOTINITED;\n  GetCurrentDirectory(MAX_PATH, rootdir);\n  _tcscat(rootdir, _T(\"\\\\\"));\n  if (flags == ZIP_HANDLE) {\n    DWORD type = GetFileType(z);\n    if (type != FILE_TYPE_DISK)\n      return ZR_SEEK;\n  }\n  ZRESULT e;\n  LUFILE *f = lufopen(z, len, flags, &e);\n  if (f == NULL)\n    return e;\n  uf = unzOpenInternal(f);\n  // return ZR_OK;\n  return zopenerror; //+++1.2\n}\n\nZRESULT TUnzip::Get(int index, ZIPENTRY *ze) {\n  if (index < -1 || index >= (int)uf->gi.number_entry)\n    return ZR_ARGS;\n  if (currentfile != -1)\n    unzCloseCurrentFile(uf);\n  currentfile = -1;\n  if (index == czei && index != -1) {\n    memcpy(ze, &cze, sizeof(ZIPENTRY));\n    return ZR_OK;\n  }\n  if (index == -1) {\n    ze->index = uf->gi.number_entry;\n    ze->name[0] = 0;\n    ze->attr = 0;\n    ze->atime.dwLowDateTime = 0;\n    ze->atime.dwHighDateTime = 0;\n    ze->ctime.dwLowDateTime = 0;\n    ze->ctime.dwHighDateTime = 0;\n    ze->mtime.dwLowDateTime = 0;\n    ze->mtime.dwHighDateTime = 0;\n    ze->comp_size = 0;\n    ze->unc_size = 0;\n    return ZR_OK;\n  }\n  if (index < (int)uf->num_file)\n    unzGoToFirstFile(uf);\n  while ((int)uf->num_file < index)\n    unzGoToNextFile(uf);\n  unz_file_info ufi;\n  char fn[MAX_PATH];\n  unzGetCurrentFileInfo(uf, &ufi, fn, MAX_PATH, NULL, 0, NULL, 0);\n\n  // now get the extra header. We do this ourselves, instead of\n  // calling unzOpenCurrentFile &c., to avoid allocating more than necessary.\n  unsigned int extralen, iSizeVar;\n  unsigned long offset;\n  int res = unzlocal_CheckCurrentFileCoherencyHeader(uf, &iSizeVar, &offset,\n                                                     &extralen);\n  if (res != UNZ_OK)\n    return ZR_CORRUPT;\n  if (lufseek(uf->file, offset, SEEK_SET) != 0)\n    return ZR_READ;\n  char *extra = new char[extralen];\n  if (lufread(extra, 1, (uInt)extralen, uf->file) != extralen) {\n    delete[] extra;\n    return ZR_READ;\n  }\n  //\n  ze->index = uf->num_file;\n  strcpy(ze->name, fn);\n  // zip has an 'attribute' 32bit value. Its lower half is windows stuff\n  // its upper half is standard unix attr.\n  unsigned long a = ufi.external_fa;\n  bool uisdir = (a & 0x40000000) != 0;\n  // bool uwriteable= (a&0x08000000)!=0;\n  bool uwriteable = (a & 0x00800000) != 0; // ***hd***\n  // bool ureadable=  (a&0x01000000)!=0;\n  // bool uexecutable=(a&0x00400000)!=0;\n  bool wreadonly = (a & 0x00000001) != 0;\n  bool whidden = (a & 0x00000002) != 0;\n  bool wsystem = (a & 0x00000004) != 0;\n  bool wisdir = (a & 0x00000010) != 0;\n  bool warchive = (a & 0x00000020) != 0;\n  ze->attr = FILE_ATTRIBUTE_NORMAL;\n  if (uisdir || wisdir)\n    ze->attr |= FILE_ATTRIBUTE_DIRECTORY;\n  if (warchive)\n    ze->attr |= FILE_ATTRIBUTE_ARCHIVE;\n  if (whidden)\n    ze->attr |= FILE_ATTRIBUTE_HIDDEN;\n  if (!uwriteable || wreadonly)\n    ze->attr |= FILE_ATTRIBUTE_READONLY;\n  if (wsystem)\n    ze->attr |= FILE_ATTRIBUTE_SYSTEM;\n  ze->comp_size = ufi.compressed_size;\n  ze->unc_size = ufi.uncompressed_size;\n  //\n  WORD dostime = (WORD)(ufi.dosDate & 0xFFFF);\n  WORD dosdate = (WORD)((ufi.dosDate >> 16) & 0xFFFF);\n  FILETIME ft;\n  DosDateTimeToFileTime(dosdate, dostime, &ft);\n  ze->atime = ft;\n  ze->ctime = ft;\n  ze->mtime = ft;\n  // the zip will always have at least that dostime. But if it also has\n  // an extra header, then we'll instead get the info from that.\n  unsigned int epos = 0;\n  while (epos + 4 < extralen) {\n    char etype[3];\n    etype[0] = extra[epos + 0];\n    etype[1] = extra[epos + 1];\n    etype[2] = 0;\n    int size = extra[epos + 2];\n    if (strcmp(etype, \"UT\") != 0) {\n      epos += 4 + size;\n      continue;\n    }\n    int flags = extra[epos + 4];\n    bool hasmtime = (flags & 1) != 0;\n    bool hasatime = (flags & 2) != 0;\n    bool hasctime = (flags & 4) != 0;\n    epos += 5;\n    if (hasmtime) {\n      time_t mtime = *(time_t *)(extra + epos);\n      epos += 4;\n      ze->mtime = timet2filetime(mtime);\n    }\n    if (hasatime) {\n      time_t atime = *(time_t *)(extra + epos);\n      epos += 4;\n      ze->atime = timet2filetime(atime);\n    }\n    if (hasctime) {\n      time_t ctime = *(time_t *)(extra + epos);\n      ze->ctime = timet2filetime(ctime);\n    }\n    break;\n  }\n  //\n  if (extra != 0)\n    delete[] extra;\n  memcpy(&cze, ze, sizeof(ZIPENTRY));\n  czei = index;\n  return ZR_OK;\n}\n\nZRESULT TUnzip::Find(const TCHAR *name, bool ic, int *index, ZIPENTRY *ze) {\n  int res = unzLocateFile(uf, name, ic ? CASE_INSENSITIVE : CASE_SENSITIVE);\n  if (res != UNZ_OK) {\n    if (index != 0)\n      *index = -1;\n    if (ze != NULL) {\n      ZeroMemory(ze, sizeof(ZIPENTRY));\n      ze->index = -1;\n    }\n    return ZR_NOTFOUND;\n  }\n  if (currentfile != -1)\n    unzCloseCurrentFile(uf);\n  currentfile = -1;\n  int i = (int)uf->num_file;\n  if (index != NULL)\n    *index = i;\n  if (ze != NULL) {\n    ZRESULT zres = Get(i, ze);\n    if (zres != ZR_OK)\n      return zres;\n  }\n  return ZR_OK;\n}\n\nvoid EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir) {\n  if (dir == NULL || dir[0] == _T('\\0'))\n    return;\n  const TCHAR *lastslash = dir, *c = lastslash;\n  while (*c != _T('\\0')) {\n    if (*c == _T('/') || *c == _T('\\\\'))\n      lastslash = c;\n    c++;\n  }\n  const TCHAR *name = lastslash;\n  if (lastslash != dir) {\n    TCHAR tmp[MAX_PATH];\n    _tcsncpy(tmp, dir, lastslash - dir);\n    tmp[lastslash - dir] = _T('\\0');\n    EnsureDirectory(rootdir, tmp);\n    name++;\n  }\n  TCHAR cd[MAX_PATH];\n  _tcscpy(cd, rootdir);\n  //_tcscat(cd,name);\n  _tcscat(cd, dir); //+++1.2\n  CreateDirectory(cd, NULL);\n}\n\nZRESULT TUnzip::Unzip(int index, void *dst, unsigned int len, DWORD flags) {\n  if (flags != ZIP_MEMORY && flags != ZIP_FILENAME && flags != ZIP_HANDLE)\n    return ZR_ARGS;\n  if (flags == ZIP_MEMORY) {\n    if (index != currentfile) {\n      if (currentfile != -1)\n        unzCloseCurrentFile(uf);\n      currentfile = -1;\n      if (index >= (int)uf->gi.number_entry)\n        return ZR_ARGS;\n      if (index < (int)uf->num_file)\n        unzGoToFirstFile(uf);\n      while ((int)uf->num_file < index)\n        unzGoToNextFile(uf);\n      unzOpenCurrentFile(uf);\n      currentfile = index;\n    }\n    int res = unzReadCurrentFile(uf, dst, len);\n    if (res > 0)\n      return ZR_MORE;\n    unzCloseCurrentFile(uf);\n    currentfile = -1;\n    if (res == 0)\n      return ZR_OK;\n    else\n      return ZR_FLATE;\n  }\n\n  // otherwise we're writing to a handle or a file\n  if (currentfile != -1)\n    unzCloseCurrentFile(uf);\n  currentfile = -1;\n  if (index >= (int)uf->gi.number_entry)\n    return ZR_ARGS;\n  if (index < (int)uf->num_file)\n    unzGoToFirstFile(uf);\n  while ((int)uf->num_file < index)\n    unzGoToNextFile(uf);\n  ZIPENTRY ze;\n  Get(index, &ze);\n\n  // zipentry=directory is handled specially\n  if ((ze.attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {\n    if (flags == ZIP_HANDLE)\n      return ZR_OK; // don't do anything\n#ifdef _UNICODE\n    TCHAR uname[MAX_PATH];\n    GetUnicodeFileName(ze.name, uname, MAX_PATH - 1);\n    EnsureDirectory(rootdir, uname);\n#else\n    EnsureDirectory(rootdir, ze.name);\n#endif\n    return ZR_OK;\n  }\n\n  // otherwise, we write the zipentry to a file/handle\n  HANDLE h;\n  if (flags == ZIP_HANDLE)\n    h = dst;\n  else {\n    const TCHAR *name = (const TCHAR *)dst;\n    const TCHAR *c = name;\n    while (*c) {\n      if (*c == _T('/') || *c == _T('\\\\'))\n        name = c + 1;\n      c++;\n    }\n    // if it's a relative filename, ensure directories. We do this as a service\n    // to the caller so they can just unzip straight unto ze.name.\n    if (name != (const TCHAR *)dst) {\n      TCHAR dir[MAX_PATH];\n      _tcscpy(dir, (const TCHAR *)dst);\n      dir[name - (const TCHAR *)dst - 1] = _T('\\0');\n      bool isabsolute =\n          (dir[0] == _T('/') || dir[0] == _T('\\\\') || dir[1] == _T(':'));\n      isabsolute |=\n          (_tcsstr(dir, _T(\"../\")) != 0) | (_tcsstr(dir, _T(\"..\\\\\")) != 0);\n      if (!isabsolute)\n        EnsureDirectory(rootdir, dir);\n    }\n    h = ::CreateFile((const TCHAR *)dst, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,\n                     ze.attr, NULL);\n  }\n\n  if (h == INVALID_HANDLE_VALUE)\n    return ZR_NOFILE;\n\n  unzOpenCurrentFile(uf);\n  BYTE buf[16384];\n  bool haderr = false;\n\n  for (;;) {\n    int res = unzReadCurrentFile(uf, buf, 16384);\n    if (res < 0) {\n      haderr = true;\n      break;\n    }\n    if (res == 0)\n      break;\n    DWORD writ;\n    BOOL bres = WriteFile(h, buf, res, &writ, NULL);\n    if (!bres) {\n      haderr = true;\n      break;\n    }\n  }\n  bool settime = false;\n  DWORD type = GetFileType(h);\n  if (type == FILE_TYPE_DISK && !haderr)\n    settime = true;\n  if (settime)\n    SetFileTime(h, &ze.ctime, &ze.atime, &ze.mtime);\n  if (flags != ZIP_HANDLE)\n    CloseHandle(h);\n  unzCloseCurrentFile(uf);\n  if (haderr)\n    return ZR_WRITE;\n  return ZR_OK;\n}\n\nZRESULT TUnzip::Close() {\n  if (currentfile != -1)\n    unzCloseCurrentFile(uf);\n  currentfile = -1;\n  if (uf != 0)\n    unzClose(uf);\n  uf = 0;\n  return ZR_OK;\n}\n\nZRESULT lasterrorU = ZR_OK;\n\nunsigned int FormatZipMessageU(ZRESULT code, char *buf, unsigned int len) {\n  if (code == ZR_RECENT)\n    code = lasterrorU;\n  const char *msg = \"unknown zip result code\";\n  switch (code) {\n  case ZR_OK:\n    msg = \"Success\";\n    break;\n  case ZR_NODUPH:\n    msg = \"Culdn't duplicate handle\";\n    break;\n  case ZR_NOFILE:\n    msg = \"Couldn't create/open file\";\n    break;\n  case ZR_NOALLOC:\n    msg = \"Failed to allocate memory\";\n    break;\n  case ZR_WRITE:\n    msg = \"Error writing to file\";\n    break;\n  case ZR_NOTFOUND:\n    msg = \"File not found in the zipfile\";\n    break;\n  case ZR_MORE:\n    msg = \"Still more data to unzip\";\n    break;\n  case ZR_CORRUPT:\n    msg = \"Zipfile is corrupt or not a zipfile\";\n    break;\n  case ZR_READ:\n    msg = \"Error reading file\";\n    break;\n  case ZR_ARGS:\n    msg = \"Caller: faulty arguments\";\n    break;\n  case ZR_PARTIALUNZ:\n    msg = \"Caller: the file had already been partially unzipped\";\n    break;\n  case ZR_NOTMMAP:\n    msg = \"Caller: can only get memory of a memory zipfile\";\n    break;\n  case ZR_MEMSIZE:\n    msg = \"Caller: not enough space allocated for memory zipfile\";\n    break;\n  case ZR_FAILED:\n    msg = \"Caller: there was a previous error\";\n    break;\n  case ZR_ENDED:\n    msg = \"Caller: additions to the zip have already been ended\";\n    break;\n  case ZR_ZMODE:\n    msg = \"Caller: mixing creation and opening of zip\";\n    break;\n  case ZR_NOTINITED:\n    msg = \"Zip-bug: internal initialisation not completed\";\n    break;\n  case ZR_SEEK:\n    msg = \"Zip-bug: trying to seek the unseekable\";\n    break;\n  case ZR_MISSIZE:\n    msg = \"Zip-bug: the anticipated size turned out wrong\";\n    break;\n  case ZR_NOCHANGE:\n    msg = \"Zip-bug: tried to change mind, but not allowed\";\n    break;\n  case ZR_FLATE:\n    msg = \"Zip-bug: an internal error during flation\";\n    break;\n  }\n  unsigned int mlen = (unsigned int)strlen(msg);\n  if (buf == 0 || len == 0)\n    return mlen;\n  unsigned int n = mlen;\n  if (n + 1 > len)\n    n = len - 1;\n  strncpy(buf, msg, n);\n  buf[n] = 0;\n  return mlen;\n}\n\ntypedef struct {\n  DWORD flag;\n  TUnzip *unz;\n} TUnzipHandleData;\n\nHZIP OpenZipU(void *z, unsigned int len, DWORD flags) {\n  TUnzip *unz = new TUnzip();\n  lasterrorU = unz->Open(z, len, flags);\n  if (lasterrorU != ZR_OK) {\n    delete unz;\n    return 0;\n  }\n  TUnzipHandleData *han = new TUnzipHandleData;\n  han->flag = 1;\n  han->unz = unz;\n  return (HZIP)han;\n}\n\nZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Get(index, ze);\n  return lasterrorU;\n}\n\nZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *zew) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  ZIPENTRY ze;\n  lasterrorU = unz->Get(index, &ze);\n  if (lasterrorU == ZR_OK) {\n    zew->index = ze.index;\n    zew->attr = ze.attr;\n    zew->atime = ze.atime;\n    zew->ctime = ze.ctime;\n    zew->mtime = ze.mtime;\n    zew->comp_size = ze.comp_size;\n    zew->unc_size = ze.unc_size;\n#ifdef _UNICODE\n    GetUnicodeFileName(ze.name, zew->name, MAX_PATH - 1);\n#else\n    strcpy(zew->name, ze.name);\n#endif\n  }\n  return lasterrorU;\n}\n\nZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index,\n                     ZIPENTRY *ze) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Find(name, ic, index, ze);\n  return lasterrorU;\n}\n\nZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index,\n                     ZIPENTRYW *zew) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  ZIPENTRY ze;\n  lasterrorU = unz->Find(name, ic, index, &ze);\n  if (lasterrorU == ZR_OK) {\n    zew->index = ze.index;\n    zew->attr = ze.attr;\n    zew->atime = ze.atime;\n    zew->ctime = ze.ctime;\n    zew->mtime = ze.mtime;\n    zew->comp_size = ze.comp_size;\n    zew->unc_size = ze.unc_size;\n#ifdef _UNICODE\n    GetUnicodeFileName(ze.name, zew->name, MAX_PATH - 1);\n#else\n    strcpy(zew->name, ze.name);\n#endif\n  }\n\n  return lasterrorU;\n}\n\nZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len,\n                  DWORD flags) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Unzip(index, dst, len, flags);\n  return lasterrorU;\n}\n\nZRESULT CloseZipU(HZIP hz) {\n  if (hz == 0) {\n    lasterrorU = ZR_ARGS;\n    return ZR_ARGS;\n  }\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  if (han->flag != 1) {\n    lasterrorU = ZR_ZMODE;\n    return ZR_ZMODE;\n  }\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Close();\n  delete unz;\n  delete han;\n  return lasterrorU;\n}\n\nbool IsZipHandleU(HZIP hz) {\n  if (hz == 0)\n    return true;\n  TUnzipHandleData *han = (TUnzipHandleData *)hz;\n  return (han->flag == 1);\n}\n"
  },
  {
    "path": "common/xzip/XUnzip.h",
    "content": "// XUnzip.h  Version 1.3\n//\n// Authors:      Mark Adler et al. (see below)\n//\n// Modified by:  Lucian Wischik\n//               lu@wischik.com\n//\n// Version 1.0   - Turned C files into just a single CPP file\n//               - Made them compile cleanly as C++ files\n//               - Gave them simpler APIs\n//               - Added the ability to zip/unzip directly in memory without \n//                 any intermediate files\n// \n// Modified by:  Hans Dietrich\n//               hdietrich@gmail.com\n//\n///////////////////////////////////////////////////////////////////////////////\n//\n// Lucian Wischik's comments:\n// --------------------------\n// THIS FILE is almost entirely based upon code by info-zip.\n// It has been modified by Lucian Wischik.\n// The original code may be found at http://www.info-zip.org\n// The original copyright text follows.\n//\n///////////////////////////////////////////////////////////////////////////////\n//\n// Original authors' comments:\n// ---------------------------\n// This is version 2002-Feb-16 of the Info-ZIP copyright and license. The \n// definitive version of this document should be available at \n// ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely.\n// \n// Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.\n//\n// For the purposes of this copyright and license, \"Info-ZIP\" is defined as\n// the following set of individuals:\n//\n//   Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois,\n//   Jean-loup Gailly, Hunter Goatley, Ian Gorman, Chris Herborth, Dirk Haase,\n//   Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, \n//   David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, \n//   Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, \n//   Kai Uwe Rommel, Steve Salisbury, Dave Smith, Christian Spieler, \n//   Antoine Verheijen, Paul von Behren, Rich Wales, Mike White\n//\n// This software is provided \"as is\", without warranty of any kind, express\n// or implied.  In no event shall Info-ZIP or its contributors be held liable\n// for any direct, indirect, incidental, special or consequential damages\n// arising out of the use of or inability to use this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n//    1. Redistributions of source code must retain the above copyright notice,\n//       definition, disclaimer, and this list of conditions.\n//\n//    2. Redistributions in binary form (compiled executables) must reproduce \n//       the above copyright notice, definition, disclaimer, and this list of \n//       conditions in documentation and/or other materials provided with the \n//       distribution. The sole exception to this condition is redistribution \n//       of a standard UnZipSFX binary as part of a self-extracting archive; \n//       that is permitted without inclusion of this license, as long as the \n//       normal UnZipSFX banner has not been removed from the binary or disabled.\n//\n//    3. Altered versions--including, but not limited to, ports to new \n//       operating systems, existing ports with new graphical interfaces, and \n//       dynamic, shared, or static library versions--must be plainly marked \n//       as such and must not be misrepresented as being the original source.  \n//       Such altered versions also must not be misrepresented as being \n//       Info-ZIP releases--including, but not limited to, labeling of the \n//       altered versions with the names \"Info-ZIP\" (or any variation thereof, \n//       including, but not limited to, different capitalizations), \n//       \"Pocket UnZip\", \"WiZ\" or \"MacZip\" without the explicit permission of \n//       Info-ZIP.  Such altered versions are further prohibited from \n//       misrepresentative use of the Zip-Bugs or Info-ZIP e-mail addresses or \n//       of the Info-ZIP URL(s).\n//\n//    4. Info-ZIP retains the right to use the names \"Info-ZIP\", \"Zip\", \"UnZip\",\n//       \"UnZipSFX\", \"WiZ\", \"Pocket UnZip\", \"Pocket Zip\", and \"MacZip\" for its \n//       own source and binary releases.\n//\n///////////////////////////////////////////////////////////////////////////////\n\n#ifndef XUNZIP_H\n#define XUNZIP_H\n\n\n#ifndef XZIP_H\nDECLARE_HANDLE(HZIP);\t// An HZIP identifies a zip file that has been opened\n#endif\n\ntypedef DWORD ZRESULT;\n// return codes from any of the zip functions. Listed later.\n\n#define ZIP_HANDLE   1\n#define ZIP_FILENAME 2\n#define ZIP_MEMORY   3\n\ntypedef struct\n{ int index;                 // index of this file within the zip\n  char name[MAX_PATH];       // filename within the zip\n  DWORD attr;                // attributes, as in GetFileAttributes.\n  FILETIME atime,ctime,mtime;// access, create, modify filetimes\n  long comp_size;            // sizes of item, compressed and uncompressed. These\n  long unc_size;             // may be -1 if not yet known (e.g. being streamed in)\n} ZIPENTRY;\n\ntypedef struct\n{ int index;                 // index of this file within the zip\n  TCHAR name[MAX_PATH];      // filename within the zip\n  DWORD attr;                // attributes, as in GetFileAttributes.\n  FILETIME atime,ctime,mtime;// access, create, modify filetimes\n  long comp_size;            // sizes of item, compressed and uncompressed. These\n  long unc_size;             // may be -1 if not yet known (e.g. being streamed in)\n} ZIPENTRYW;\n\n// #ifdef _UNICODE\n// #define ZIPENTRY ZIPENTRYW\n// #else\n// #define ZIPENTRY ZIPENTRYA\n// #endif\n///////////////////////////////////////////////////////////////////////////////\n//\n// OpenZip()\n//\n// Purpose:     Open an existing zip archive file\n//\n// Parameters:  z      - archive file name if flags is ZIP_FILENAME;  for other\n//                       uses see below\n//              len    - for memory (ZIP_MEMORY) should be the buffer size;\n//                       for other uses, should be 0\n//              flags  - indicates usage, see below;  for files, this will be\n//                       ZIP_FILENAME\n//\n// Returns:     HZIP   - non-zero if zip archive opened ok, otherwise 0\n//\nHZIP OpenZip(void *z, unsigned int len, DWORD flags);\n// OpenZip - opens a zip file and returns a handle with which you can\n// subsequently examine its contents. You can open a zip file from:\n// from a pipe:             OpenZip(hpipe_read,0, ZIP_HANDLE);\n// from a file (by handle): OpenZip(hfile,0,      ZIP_HANDLE);\n// from a file (by name):   OpenZip(\"c:\\\\test.zip\",0, ZIP_FILENAME);\n// from a memory block:     OpenZip(bufstart, buflen, ZIP_MEMORY);\n// If the file is opened through a pipe, then items may only be\n// accessed in increasing order, and an item may only be unzipped once,\n// although GetZipItem can be called immediately before and after unzipping\n// it. If it's opened i\tn any other way, then full random access is possible.\n// Note: pipe input is not yet implemented.\n\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// GetZipItem()\n//\n// Purpose:     Get information about an item in an open zip archive\n//\n// Parameters:  hz      - handle of open zip archive\n//              index   - index number (0 based) of item in zip \n//              ze      - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct\n//                        (if Unicode)\n//\n// Returns:     ZRESULT - ZR_OK if success, otherwise some other value\n//\n\n#ifdef _UNICODE\n#define GetZipItem GetZipItemW\n#else\n#define GetZipItem GetZipItemA\n#endif\n\nZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze);\nZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze);\n// GetZipItem - call this to get information about an item in the zip.\n// If index is -1 and the file wasn't opened through a pipe,\n// then it returns information about the whole zipfile\n// (and in particular ze.index returns the number of index items).\n// Note: the item might be a directory (ze.attr & FILE_ATTRIBUTE_DIRECTORY)\n// See below for notes on what happens when you unzip such an item.\n// Note: if you are opening the zip through a pipe, then random access\n// is not possible and GetZipItem(-1) fails and you can't discover the number\n// of items except by calling GetZipItem on each one of them in turn,\n// starting at 0, until eventually the call fails. Also, in the event that\n// you are opening through a pipe and the zip was itself created into a pipe,\n// then then comp_size and sometimes unc_size as well may not be known until\n// after the item has been unzipped.\n\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// FindZipItem()\n//\n// Purpose:     Find item by name and return information about it\n//\n// Parameters:  hz      - handle of open zip archive\n//              name    - name of file to look for inside zip archive\n//              ic      - TRUE = case insensitive\n//              index   - pointer to index number returned, or -1\n//              ze      - pointer to a ZIPENTRY (if ANSI) or ZIPENTRYW struct\n//                        (if Unicode)\n//\n// Returns:     ZRESULT - ZR_OK if success, otherwise some other value\n//\n\n#ifdef _UNICODE\n#define FindZipItem FindZipItemW\n#else\n#define FindZipItem FindZipItemA\n#endif\n\nZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);\nZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze);\n// FindZipItem - finds an item by name. ic means 'insensitive to case'.\n// It returns the index of the item, and returns information about it.\n// If nothing was found, then index is set to -1 and the function returns\n// an error code.\n\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// UnzipItem()\n//\n// Purpose:     Find item by index and unzip it\n//\n// Parameters:  hz      - handle of open zip archive\n//              index   - index number of file to unzip\n//              dst     - target file name of unzipped file\n//              len     - for memory (ZIP_MEMORY. length of buffer;\n//                        otherwise 0\n//              flags   - indicates usage, see below;  for files, this will be\n//                        ZIP_FILENAME\n//\n// Returns:     ZRESULT - ZR_OK if success, otherwise some other value\n//\n\nZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags);\n// UnzipItem - given an index to an item, unzips it. You can unzip to:\n// to a pipe:             UnzipItem(hz,i, hpipe_write,0,ZIP_HANDLE);\n// to a file (by handle): UnzipItem(hz,i, hfile,0,ZIP_HANDLE);\n// to a file (by name):   UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);\n// to a memory block:     UnzipItem(hz,i, buf,buflen,ZIP_MEMORY);\n// In the final case, if the buffer isn't large enough to hold it all,\n// then the return code indicates that more is yet to come. If it was\n// large enough, and you want to know precisely how big, GetZipItem.\n// Note: zip files are normally stored with relative pathnames. If you\n// unzip with ZIP_FILENAME a relative pathname then the item gets created\n// relative to the current directory - it first ensures that all necessary\n// subdirectories have been created. Also, the item may itself be a directory.\n// If you unzip a directory with ZIP_FILENAME, then the directory gets created.\n// If you unzip it to a handle or a memory block, then nothing gets created\n// and it emits 0 bytes.\n\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// CloseZip()\n//\n// Purpose:     Close an open zip archive\n//\n// Parameters:  hz      - handle to an open zip archive\n//\n// Returns:     ZRESULT - ZR_OK if success, otherwise some other value\n//\nZRESULT CloseZip(HZIP hz);\n// CloseZip - the zip handle must be closed with this function.\n\nunsigned int FormatZipMessage(ZRESULT code, char *buf,unsigned int len);\n// FormatZipMessage - given an error code, formats it as a string.\n// It returns the length of the error message. If buf/len points\n// to a real buffer, then it also writes as much as possible into there.\n\n\n// These are the result codes:\n#define ZR_OK         0x00000000     // nb. the pseudo-code zr-recent is never returned,\n#define ZR_RECENT     0x00000001     // but can be passed to FormatZipMessage.\n// The following come from general system stuff (e.g. files not openable)\n#define ZR_GENMASK    0x0000FF00\n#define ZR_NODUPH     0x00000100     // couldn't duplicate the handle\n#define ZR_NOFILE     0x00000200     // couldn't create/open the file\n#define ZR_NOALLOC    0x00000300     // failed to allocate some resource\n#define ZR_WRITE      0x00000400     // a general error writing to the file\n#define ZR_NOTFOUND   0x00000500     // couldn't find that file in the zip\n#define ZR_MORE       0x00000600     // there's still more data to be unzipped\n#define ZR_CORRUPT    0x00000700     // the zipfile is corrupt or not a zipfile\n#define ZR_READ       0x00000800     // a general error reading the file\n// The following come from mistakes on the part of the caller\n#define ZR_CALLERMASK 0x00FF0000\n#define ZR_ARGS       0x00010000     // general mistake with the arguments\n#define ZR_NOTMMAP    0x00020000     // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't\n#define ZR_MEMSIZE    0x00030000     // the memory size is too small\n#define ZR_FAILED     0x00040000     // the thing was already failed when you called this function\n#define ZR_ENDED      0x00050000     // the zip creation has already been closed\n#define ZR_MISSIZE    0x00060000     // the indicated input file size turned out mistaken\n#define ZR_PARTIALUNZ 0x00070000     // the file had already been partially unzipped\n#define ZR_ZMODE      0x00080000     // tried to mix creating/opening a zip \n// The following come from bugs within the zip library itself\n#define ZR_BUGMASK    0xFF000000\n#define ZR_NOTINITED  0x01000000     // initialisation didn't work\n#define ZR_SEEK       0x02000000     // trying to seek in an unseekable file\n#define ZR_NOCHANGE   0x04000000     // changed its mind on storage, but not allowed\n#define ZR_FLATE      0x05000000     // an internal error in the de/inflation code\n\n\n\n\n\n// e.g.\n//\n// SetCurrentDirectory(\"c:\\\\docs\\\\stuff\");\n// HZIP hz = OpenZip(\"c:\\\\stuff.zip\",0,ZIP_FILENAME);\n// ZIPENTRY ze; GetZipItem(hz,-1,&ze); int numitems=ze.index;\n// for (int i=0; i<numitems; i++)\n// { GetZipItem(hz,i,&ze);\n//   UnzipItem(hz,i,ze.name,0,ZIP_FILENAME);\n// }\n// CloseZip(hz);\n//\n//\n// HRSRC hrsrc = FindResource(hInstance,MAKEINTRESOURCE(1),RT_RCDATA);\n// HANDLE hglob = LoadResource(hInstance,hrsrc);\n// void *zipbuf=LockResource(hglob);\n// unsigned int ziplen=SizeofResource(hInstance,hrsrc);\n// HZIP hz = OpenZip(zipbuf, ziplen, ZIP_MEMORY);\n//   - unzip to a membuffer -\n// ZIPENTRY ze; int i; FindZipItem(hz,\"file.dat\",&i,&ze);\n// char *ibuf = new char[ze.unc_size];\n// UnzipItem(hz,i, ibuf, ze.unc_size,ZIP_MEMORY);\n// delete[] buf;\n//   - unzip to a fixed membuff -\n// ZIPENTRY ze; int i; FindZipItem(hz,\"file.dat\",&i,&ze);\n// char ibuf[1024]; ZIPRESULT zr=ZR_MORE; unsigned long totsize=0;\n// while (zr==ZR_MORE)\n// { zr = UnzipItem(hz,i, ibuf,1024,ZIP_MEMORY);\n//   unsigned long bufsize=1024; if (zr==ZR_OK) bufsize=ze.unc_size-totsize;\n//   totsize+=bufsize;\n// }\n//   - unzip to a pipe -\n// HANDLE hthread=CreateWavReaderThread(&hread,&hwrite);\n// FindZipItem(hz,\"sound.wav\",&i,&ze);\n// UnzipItem(hz,i, hwrite,0,ZIP_HANDLE);\n// CloseHandle(hwrite);\n// WaitForSingleObject(hthread,INFINITE);\n// CloseHandle(hread); CloseHandle(hthread);\n//   - finished -\n// CloseZip(hz);\n// // note: no need to free resources obtained through Find/Load/LockResource\n//\n//\n// SetCurrentDirectory(\"c:\\\\docs\\\\pipedzipstuff\");\n// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite);\n// CreateZipWriterThread(hwrite);\n// HZIP hz = OpenZip(hread,0,ZIP_HANDLE);\n// for (int i=0; ; i++)\n// { ZIPENTRY ze; ZRESULT res = GetZipItem(hz,i,&ze);\n//   if (res!=ZE_OK) break; // no more\n//   UnzipItem(hz,i, ze.name,0,ZIP_FILENAME);\n// }\n// CloseZip(hz);\n//\n\n\n\n\n// Now we indulge in a little skullduggery so that the code works whether\n// the user has included just zip or both zip and unzip.\n// Idea: if header files for both zip and unzip are present, then presumably\n// the cpp files for zip and unzip are both present, so we will call\n// one or the other of them based on a dynamic choice. If the header file\n// for only one is present, then we will bind to that particular one.\nHZIP OpenZipU(void *z,unsigned int len,DWORD flags);\nZRESULT CloseZipU(HZIP hz);\nunsigned int FormatZipMessageU(ZRESULT code, char *buf,unsigned int len);\nbool IsZipHandleU(HZIP hz);\n#define OpenZip OpenZipU\n\n#ifdef XZIP_H\n#undef CloseZip\n#define CloseZip(hz) (IsZipHandleU(hz)?CloseZipU(hz):CloseZipZ(hz))\n#else\n#define CloseZip CloseZipU\n#define FormatZipMessage FormatZipMessageU\n#endif\n\n\n#endif //XUNZIP_H\n"
  },
  {
    "path": "src/.gitignore",
    "content": "# Compiled Static libraries\n\n.vs/\nDebug/\nRelease/\n"
  },
  {
    "path": "src/App.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"Current\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>17.0</VCProjectVersion>\r\n    <ProjectName>Downloader</ProjectName>\r\n    <ProjectGuid>{D175BBA1-8E6A-4592-8F6C-3ABA862250BB}</ProjectGuid>\r\n    <RootNamespace>Downloader</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <UseOfMfc>false</UseOfMfc>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v143</PlatformToolset>\r\n    <UseOfMfc>false</UseOfMfc>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup>\r\n    <_ProjectFileVersion>17.0.34018.303</_ProjectFileVersion>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <OutDir>.\\Release\\</OutDir>\r\n    <IntDir>.\\Release\\</IntDir>\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\r\n    <GenerateManifest>false</GenerateManifest>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <OutDir>.\\Debug\\</OutDir>\r\n    <IntDir>.\\Debug\\</IntDir>\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <GenerateManifest>false</GenerateManifest>\r\n    <EnableMicrosoftCodeAnalysis>false</EnableMicrosoftCodeAnalysis>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Midl>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MkTypLibCompatible>true</MkTypLibCompatible>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <TargetEnvironment>Win32</TargetEnvironment>\r\n      <TypeLibraryName>.\\Release\\Downloader.tlb</TypeLibraryName>\r\n      <HeaderFileName />\r\n    </Midl>\r\n    <ClCompile>\r\n      <Optimization>MinSpace</Optimization>\r\n      <InlineFunctionExpansion>Default</InlineFunctionExpansion>\r\n      <IntrinsicFunctions>false</IntrinsicFunctions>\r\n      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r\n      <EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>\r\n      <WholeProgramOptimization>false</WholeProgramOptimization>\r\n      <AdditionalIncludeDirectories>./;../common;../WTL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;UNICODE;SQLITE_HAS_CODEC;COMPILER_MSVC;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <StringPooling>true</StringPooling>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>.\\Release\\$(ProjectName).pch</PrecompiledHeaderOutputFile>\r\n      <AssemblerListingLocation>.\\Release\\</AssemblerListingLocation>\r\n      <ObjectFileName>.\\Release\\</ObjectFileName>\r\n      <ProgramDataBaseFileName>.\\Release\\</ProgramDataBaseFileName>\r\n      <WarningLevel>Level2</WarningLevel>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r\n      <LanguageStandard>stdcpp14</LanguageStandard>\r\n      <ExceptionHandling>Async</ExceptionHandling>\r\n    </ClCompile>\r\n    <ResourceCompile>\r\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <Culture>0x0804</Culture>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <AdditionalOptions>\r\n      </AdditionalOptions>\r\n      <OutputFile>.\\Release\\$(ProjectName).exe</OutputFile>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r\n      <UACUIAccess>false</UACUIAccess>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <ProgramDatabaseFile>.\\Release\\$(ProjectName).pdb</ProgramDatabaseFile>\r\n      <SubSystem>Windows</SubSystem>\r\n      <OptimizeReferences />\r\n      <EnableCOMDATFolding />\r\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r\n      <DataExecutionPrevention>false</DataExecutionPrevention>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\r\n    </Link>\r\n    <Bscmake>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <OutputFile>.\\Release\\$(ProjectName).bsc</OutputFile>\r\n    </Bscmake>\r\n    <PostBuildEvent>\r\n      <Command>del  /f /q  ..\\0utPut\\Release\r\nxcopy  /Y  $(OutDir)$(TargetFileName)  ..\\0utPut\\Release\\\r\n..\\bin\\upx-4.1.0-win32\\upx.exe  ..\\0utPut\\Release\\Downloader.exe  -o  ..\\0utPut\\Release\\CompressedDownloader.exe</Command>\r\n    </PostBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Midl>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MkTypLibCompatible>true</MkTypLibCompatible>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <TargetEnvironment>Win32</TargetEnvironment>\r\n      <TypeLibraryName>.\\Debug\\Downloader.tlb</TypeLibraryName>\r\n      <HeaderFileName />\r\n    </Midl>\r\n    <ClCompile>\r\n      <AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>\r\n      <Optimization>Disabled</Optimization>\r\n      <AdditionalIncludeDirectories>./;../common;../WTL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;UNICODE;SQLITE_HAS_CODEC;COMPILER_MSVC;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MinimalRebuild>false</MinimalRebuild>\r\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>\r\n      <PrecompiledHeader>Use</PrecompiledHeader>\r\n      <PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>\r\n      <PrecompiledHeaderOutputFile>.\\Debug\\$(ProjectName).pch</PrecompiledHeaderOutputFile>\r\n      <AssemblerListingLocation>.\\Debug\\</AssemblerListingLocation>\r\n      <ObjectFileName>.\\Debug\\</ObjectFileName>\r\n      <ProgramDataBaseFileName>.\\Debug\\</ProgramDataBaseFileName>\r\n      <BrowseInformation>true</BrowseInformation>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r\n      <LanguageStandard>stdcpp14</LanguageStandard>\r\n      <ExceptionHandling>Async</ExceptionHandling>\r\n    </ClCompile>\r\n    <ResourceCompile>\r\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <Culture>0x0804</Culture>\r\n    </ResourceCompile>\r\n    <Link>\r\n      <OutputFile>.\\Debug\\$(ProjectName).exe</OutputFile>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <ProgramDatabaseFile>.\\Debug\\$(ProjectName).pdb</ProgramDatabaseFile>\r\n      <SubSystem>Windows</SubSystem>\r\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r\n      <DataExecutionPrevention>false</DataExecutionPrevention>\r\n      <TargetMachine>MachineX86</TargetMachine>\r\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\r\n    </Link>\r\n    <Bscmake>\r\n      <SuppressStartupBanner>true</SuppressStartupBanner>\r\n      <OutputFile>.\\Debug\\$(ProjectName).bsc</OutputFile>\r\n    </Bscmake>\r\n    <PostBuildEvent>\r\n      <Command>xcopy  $(OutDir)$(TargetFileName)  ..\\0utPut\\Debug\\   /Y</Command>\r\n    </PostBuildEvent>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"res\\App.ico\" />\r\n    <Image Include=\"res\\png\\1.png\" />\r\n    <Image Include=\"res\\png\\2.png\" />\r\n    <Image Include=\"res\\png\\3.png\" />\r\n    <Image Include=\"res\\png\\4.png\" />\r\n    <Image Include=\"res\\png\\5.png\" />\r\n    <Image Include=\"res\\png\\6.png\" />\r\n    <Image Include=\"res\\png\\AboutDlg.png\" />\r\n    <Image Include=\"res\\png\\account_close.png\" />\r\n    <Image Include=\"res\\png\\backmain.png\" />\r\n    <Image Include=\"res\\png\\btn_min.png\" />\r\n    <Image Include=\"res\\png\\checkbox.png\" />\r\n    <Image Include=\"res\\png\\dialog_btn_main.png\" />\r\n    <Image Include=\"res\\png\\edit_install_back.png\" />\r\n    <Image Include=\"res\\png\\lightpoint.png\" />\r\n    <Image Include=\"res\\png\\LOGO.png\" />\r\n    <Image Include=\"res\\png\\selctpath.png\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Xml Include=\"res\\xml\\EngUIAgreement.xml\" />\r\n    <Xml Include=\"res\\xml\\EngUICannotDown.xml\" />\r\n    <Xml Include=\"res\\xml\\EngUIContent.xml\" />\r\n    <Xml Include=\"res\\xml\\EngUIMainWindow.xml\" />\r\n    <Xml Include=\"res\\xml\\UIAgreement.xml\" />\r\n    <Xml Include=\"res\\xml\\UICannotDown.xml\" />\r\n    <Xml Include=\"res\\xml\\UIContent.xml\" />\r\n    <Xml Include=\"res\\xml\\UIMainWindow.xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\reader.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\value.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\writer.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\base.cpp\" />\r\n    <ClCompile Include=\"..\\common\\util\\md5.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">NotUsing</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">NotUsing</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\system.cpp\" />\r\n    <ClCompile Include=\"..\\common\\util\\util_tools.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xml\\tinystr.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxml.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxmlerror.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxmlparser.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xml\\xmlhelper.cpp\" />\r\n    <ClCompile Include=\"..\\common\\xzip\\XUnzip.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Use</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\at_exist.cc\" />\r\n    <ClCompile Include=\"base\\common_threads.cc\" />\r\n    <ClCompile Include=\"base\\lazy_instance.cc\" />\r\n    <ClCompile Include=\"base\\MessageLoop.cc\" />\r\n    <ClCompile Include=\"base\\MessagePumpDefault.cc\" />\r\n    <ClCompile Include=\"base\\MessagePumpWin.cc\" />\r\n    <ClCompile Include=\"base\\notification_registrar.cc\" />\r\n    <ClCompile Include=\"base\\notification_service.cc\" />\r\n    <ClCompile Include=\"base\\PendingTask.cpp\" />\r\n    <ClCompile Include=\"base\\ref_counted.cc\" />\r\n    <ClCompile Include=\"base\\stringprintf.cc\" />\r\n    <ClCompile Include=\"base\\Thread.cc\" />\r\n    <ClCompile Include=\"base\\thread_local.cc\" />\r\n    <ClCompile Include=\"base\\WeakPtr.cc\" />\r\n    <ClCompile Include=\"DirectUI\\Draw.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIButton.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUICheckBox.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIElement.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIElementsMgr.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIGDIResource.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIHyperLink.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUILayeredEdit.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIOptionLine.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIPanel.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIProgress.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIRadioButton.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIStatic.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUITab.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUITabList.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUITransWindow.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUITransWindowEx.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\DUIWindowStyle.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\UpdateWindowBase.cpp\" />\r\n    <ClCompile Include=\"DirectUI\\UpdateWindowBaseEx.cpp\" />\r\n    <ClCompile Include=\"Language\\Language.cpp\" />\r\n    <ClCompile Include=\"Main.cpp\" />\r\n    <ClCompile Include=\"DownLoader\\DownloadDelegate.cpp\" />\r\n    <ClCompile Include=\"DownLoader\\fetcherurl.cpp\" />\r\n    <ClCompile Include=\"DownLoader\\fetchfile.cpp\" />\r\n    <ClCompile Include=\"Event\\WaitableEvent.cc\" />\r\n    <ClCompile Include=\"Global.cpp\" />\r\n    <ClCompile Include=\"LogAssist\\LogAssist.cpp\" />\r\n    <ClCompile Include=\"net\\url_fetcher.cc\" />\r\n    <ClCompile Include=\"StdAfx.cpp\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"time\\time.cc\">\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n      </PrecompiledHeader>\r\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n      </PrecompiledHeader>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UI\\FrameShowState.cpp\" />\r\n    <ClCompile Include=\"UI\\UIAgreement.cpp\" />\r\n    <ClCompile Include=\"UI\\UICannotDown.cpp\" />\r\n    <ClCompile Include=\"UI\\UIMainWindowEx.cpp\" />\r\n    <ClCompile Include=\"UI\\UtilityWindow.cpp\" />\r\n    <ClCompile Include=\"Util\\UtilApi.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"..\\common\\util\\base.h\" />\r\n    <ClInclude Include=\"..\\common\\util\\def.h\" />\r\n    <ClInclude Include=\"..\\common\\util\\md5.h\" />\r\n    <ClInclude Include=\"..\\common\\util\\system.h\" />\r\n    <ClInclude Include=\"..\\common\\util\\util_tools.h\" />\r\n    <ClInclude Include=\"..\\common\\xml\\tinystr.h\" />\r\n    <ClInclude Include=\"..\\common\\xml\\tinyxml.h\" />\r\n    <ClInclude Include=\"..\\common\\xml\\xmlhelper.h\" />\r\n    <ClInclude Include=\"..\\common\\xzip\\XUnzip.h\" />\r\n    <ClInclude Include=\"base.h\" />\r\n    <ClInclude Include=\"base\\aligned_memory.h\" />\r\n    <ClInclude Include=\"base\\at_exist.h\" />\r\n    <ClInclude Include=\"base\\common_threads.h\" />\r\n    <ClInclude Include=\"base\\FastDelegate.h\" />\r\n    <ClInclude Include=\"base\\FastDelegateImpl.h\" />\r\n    <ClInclude Include=\"base\\lazy_instance.h\" />\r\n    <ClInclude Include=\"base\\macros.h\" />\r\n    <ClInclude Include=\"base\\MessageLoop.h\" />\r\n    <ClInclude Include=\"base\\MessagePump.h\" />\r\n    <ClInclude Include=\"base\\MessagePumpDefault.h\" />\r\n    <ClInclude Include=\"base\\MessagePumpWin.h\" />\r\n    <ClInclude Include=\"base\\notification_details.h\" />\r\n    <ClInclude Include=\"base\\notification_observer.h\" />\r\n    <ClInclude Include=\"base\\notification_registrar.h\" />\r\n    <ClInclude Include=\"base\\notification_service.h\" />\r\n    <ClInclude Include=\"base\\notification_source.h\" />\r\n    <ClInclude Include=\"base\\notification_types.h\" />\r\n    <ClInclude Include=\"base\\observer_list.h\" />\r\n    <ClInclude Include=\"base\\PendingTask.h\" />\r\n    <ClInclude Include=\"base\\ref_counted.h\" />\r\n    <ClInclude Include=\"base\\scoped_handle.h\" />\r\n    <ClInclude Include=\"base\\stringprintf.h\" />\r\n    <ClInclude Include=\"base\\string_util_win.h\" />\r\n    <ClInclude Include=\"base\\Thread.h\" />\r\n    <ClInclude Include=\"base\\thread_local.h\" />\r\n    <ClInclude Include=\"base\\WeakPtr.h\" />\r\n    <ClInclude Include=\"base\\WrapperObj.h\" />\r\n    <ClInclude Include=\"DirectUI\\Draw.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIButton.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUICheckBox.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIDef.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIElement.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIElementsMgr.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIGDIResource.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIHyperLink.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUILayeredEdit.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIOptionLine.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIPanel.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIProgress.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIRadioButton.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIStatic.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUITab.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUITabList.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUITransWindow.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUITransWindowEx.h\" />\r\n    <ClInclude Include=\"DirectUI\\DUIWindowStyle.h\" />\r\n    <ClInclude Include=\"DirectUI\\EventHandler.h\" />\r\n    <ClInclude Include=\"DirectUI\\UpdateWindowBase.h\" />\r\n    <ClInclude Include=\"DirectUI\\UpdateWindowBaseEx.h\" />\r\n    <ClInclude Include=\"DownLoader\\DownloadDelegate.h\" />\r\n    <ClInclude Include=\"DownLoader\\fetcherurl.h\" />\r\n    <ClInclude Include=\"DownLoader\\fetchfile.h\" />\r\n    <ClInclude Include=\"Event\\WaitableEvent.h\" />\r\n    <ClInclude Include=\"Global.h\" />\r\n    <ClInclude Include=\"Language\\Language.h\" />\r\n    <ClInclude Include=\"LogAssist\\LogAssist.h\" />\r\n    <ClInclude Include=\"net\\url_fetcher.h\" />\r\n    <ClInclude Include=\"resource.h\" />\r\n    <ClInclude Include=\"StdAfx.h\" />\r\n    <ClInclude Include=\"time\\time.h\" />\r\n    <ClInclude Include=\"UI\\FrameShowState.h\" />\r\n    <ClInclude Include=\"UI\\UIAgreement.h\" />\r\n    <ClInclude Include=\"UI\\UICannotDown.h\" />\r\n    <ClInclude Include=\"UI\\UIMainWindowEx.h\" />\r\n    <ClInclude Include=\"UI\\UtilityWindow.h\" />\r\n    <ClInclude Include=\"Util\\UtilApi.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Downloader.rc\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n  <ProjectExtensions>\r\n    <VisualStudio>\r\n      <UserProperties RESOURCE_FILE=\"Downloader.rc\" />\r\n    </VisualStudio>\r\n  </ProjectExtensions>\r\n</Project>"
  },
  {
    "path": "src/App.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Resource Files\">\r\n      <UniqueIdentifier>{36f9056a-636c-40bc-96cd-25e4593e0c6c}</UniqueIdentifier>\r\n      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\\xml\">\r\n      <UniqueIdentifier>{fca6d130-8e3d-4966-9e99-c1844aef3e18}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"UI\">\r\n      <UniqueIdentifier>{2db7664e-c8fb-4e80-b5b5-6f9d455d4b20}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Event\">\r\n      <UniqueIdentifier>{c64e9972-b794-47dc-8084-1b1ff1849fdc}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Header Files\">\r\n      <UniqueIdentifier>{0bfba4d8-4763-41f4-b73e-8ca8b37d9a5f}</UniqueIdentifier>\r\n      <Extensions>h;hpp;hxx;hm;inl</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Source Files\">\r\n      <UniqueIdentifier>{2a1a6d63-56a0-44dd-9507-2b1afd266b54}</UniqueIdentifier>\r\n      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"DirectUI\">\r\n      <UniqueIdentifier>{79608960-972b-4ef6-8402-d1badcb3d89e}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"LogAssist\">\r\n      <UniqueIdentifier>{3177097e-e870-4533-839c-ff574fcea022}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Resource Files\\asset\">\r\n      <UniqueIdentifier>{02db92af-b773-4c23-8db0-69921050af59}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Base\">\r\n      <UniqueIdentifier>{f2292b24-3b2c-4df8-ad50-aa59b70f48dd}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Common\">\r\n      <UniqueIdentifier>{6d1bdfe8-e533-40c7-92f0-9f8ee843fe73}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Json\">\r\n      <UniqueIdentifier>{d7cf154b-894a-4f17-ba2c-57aa29546709}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Net\">\r\n      <UniqueIdentifier>{b1d7c97d-e37c-4702-8e4a-fea518bc67a9}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Time\">\r\n      <UniqueIdentifier>{ebeb2e1b-6ecb-42b6-850c-647eb39e0436}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Xml\">\r\n      <UniqueIdentifier>{a461547a-0e97-40c5-91a8-cbdecd80186a}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"DownLoader\">\r\n      <UniqueIdentifier>{7b4c229b-5ab9-42ae-bc7c-7736a3d3d6c4}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Language\">\r\n      <UniqueIdentifier>{c78cdafb-789f-48cc-b4cc-81126be49e04}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Uzip\">\r\n      <UniqueIdentifier>{547d1d3c-aa70-4228-9a56-63fc1d3250aa}</UniqueIdentifier>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"res\\App.ico\">\r\n      <Filter>Resource Files</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\AboutDlg.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\account_close.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\backmain.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\btn_min.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\checkbox.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\dialog_btn_main.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\edit_install_back.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\lightpoint.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\LOGO.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\selctpath.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\1.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\2.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\3.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\4.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\5.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n    <Image Include=\"res\\png\\6.png\">\r\n      <Filter>Resource Files\\asset</Filter>\r\n    </Image>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Xml Include=\"res\\xml\\EngUICannotDown.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\EngUIMainWindow.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\UIAgreement.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\UICannotDown.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\UIContent.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\UIMainWindow.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\EngUIAgreement.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n    <Xml Include=\"res\\xml\\EngUIContent.xml\">\r\n      <Filter>Resource Files\\xml</Filter>\r\n    </Xml>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"UI\\UIAgreement.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UI\\UICannotDown.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UI\\UIMainWindowEx.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Event\\WaitableEvent.cc\">\r\n      <Filter>Event</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Global.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"StdAfx.cpp\">\r\n      <Filter>Source Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\Draw.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIButton.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUICheckBox.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIElement.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIElementsMgr.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIGDIResource.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIHyperLink.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUILayeredEdit.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIOptionLine.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIPanel.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIProgress.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIRadioButton.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIStatic.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUITab.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUITabList.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUITransWindow.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUITransWindowEx.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\DUIWindowStyle.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\UpdateWindowBase.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DirectUI\\UpdateWindowBaseEx.cpp\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"time\\time.cc\">\r\n      <Filter>Time</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"net\\url_fetcher.cc\">\r\n      <Filter>Net</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\at_exist.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\common_threads.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\lazy_instance.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\MessageLoop.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\MessagePumpDefault.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\MessagePumpWin.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\PendingTask.cpp\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\ref_counted.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\stringprintf.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\Thread.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\thread_local.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\WeakPtr.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DownLoader\\DownloadDelegate.cpp\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DownLoader\\fetcherurl.cpp\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"DownLoader\\fetchfile.cpp\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"LogAssist\\LogAssist.cpp\">\r\n      <Filter>LogAssist</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Main.cpp\" />\r\n    <ClCompile Include=\"base\\notification_registrar.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"base\\notification_service.cc\">\r\n      <Filter>Base</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Language\\Language.cpp\">\r\n      <Filter>Language</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UI\\FrameShowState.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"UI\\UtilityWindow.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"Util\\UtilApi.cpp\">\r\n      <Filter>Common</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xml\\tinystr.cpp\">\r\n      <Filter>Xml</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxml.cpp\">\r\n      <Filter>Xml</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxmlerror.cpp\">\r\n      <Filter>Xml</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xml\\tinyxmlparser.cpp\">\r\n      <Filter>Xml</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xml\\xmlhelper.cpp\">\r\n      <Filter>Xml</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\xzip\\XUnzip.cpp\">\r\n      <Filter>Uzip</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\reader.cpp\">\r\n      <Filter>Json</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\value.cpp\">\r\n      <Filter>Json</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\jsoncpp\\writer.cpp\">\r\n      <Filter>Json</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\base.cpp\">\r\n      <Filter>Common</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\md5.cpp\">\r\n      <Filter>Common</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\system.cpp\">\r\n      <Filter>Common</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"..\\common\\util\\util_tools.cpp\">\r\n      <Filter>Common</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"UI\\UIAgreement.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"UI\\UICannotDown.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"UI\\UIMainWindowEx.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Event\\WaitableEvent.h\">\r\n      <Filter>Event</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"resource.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\Draw.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIButton.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUICheckBox.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIDef.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIElement.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIElementsMgr.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIGDIResource.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIHyperLink.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUILayeredEdit.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIOptionLine.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIPanel.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIProgress.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIRadioButton.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIStatic.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUITab.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUITabList.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUITransWindow.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUITransWindowEx.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\DUIWindowStyle.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\EventHandler.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\UpdateWindowBase.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DirectUI\\UpdateWindowBaseEx.h\">\r\n      <Filter>DirectUI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"time\\time.h\">\r\n      <Filter>Time</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"net\\url_fetcher.h\">\r\n      <Filter>Net</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\aligned_memory.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\at_exist.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\common_threads.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\FastDelegate.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\FastDelegateImpl.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\lazy_instance.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\macros.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\MessageLoop.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\MessagePump.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\MessagePumpDefault.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\MessagePumpWin.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\observer_list.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\PendingTask.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\ref_counted.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\scoped_handle.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\string_util_win.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\stringprintf.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\Thread.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\thread_local.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\WeakPtr.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\WrapperObj.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DownLoader\\DownloadDelegate.h\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DownLoader\\fetcherurl.h\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"DownLoader\\fetchfile.h\">\r\n      <Filter>DownLoader</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"LogAssist\\LogAssist.h\">\r\n      <Filter>LogAssist</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_details.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_observer.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_registrar.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_source.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_types.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"base\\notification_service.h\">\r\n      <Filter>Base</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Language\\Language.h\">\r\n      <Filter>Language</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"UI\\FrameShowState.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"UI\\UtilityWindow.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Util\\UtilApi.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\xml\\tinystr.h\">\r\n      <Filter>Xml</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\xml\\tinyxml.h\">\r\n      <Filter>Xml</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\xml\\xmlhelper.h\">\r\n      <Filter>Xml</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\xzip\\XUnzip.h\">\r\n      <Filter>Uzip</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\util\\base.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\util\\def.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\util\\md5.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\util\\system.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"..\\common\\util\\util_tools.h\">\r\n      <Filter>Common</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"Global.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"StdAfx.h\">\r\n      <Filter>Header Files</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"Downloader.rc\">\r\n      <Filter>Resource Files</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "src/DirectUI/DUIButton.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIButton.h\"\n\nCButtonCtl::CButtonCtl(HWND father, BOOL trans) {\n  _host = father;\n  _class = _T(\"DirectButton\");\n  _transparent = trans;\n  _tracking = FALSE;\n  _down = FALSE;\n  _state = DUI_STATE_NORMAL;\n  _bmpBtn = NULL;\n  _bmpIcon = NULL;\n  _bmpSmallIcon = NULL;\n  _colText = RGB(0, 0, 0);\n  _colHover = RGB(0, 0, 0);\n  _colDown = RGB(0, 0, 0);\n  _colDisable = RGB(0, 0, 0);\n  _vertical_flag = FALSE;\n  _nTextLimitLength = 0;\n  _textFont = NULL;\n  _hdelta = 0;\n}\n\nCButtonCtl::CButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                       LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans)\n    : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _host = father;\n  _class = _T(\"DirectButton\");\n  _transparent = trans;\n  _tracking = FALSE;\n  _down = FALSE;\n  _state = DUI_STATE_NORMAL;\n  _bmpBtn = NULL;\n  _bmpIcon = NULL;\n  _bmpSmallIcon = NULL;\n  _colText = RGB(0, 0, 0);\n  _colHover = RGB(0, 0, 0);\n  _colDown = RGB(0, 0, 0);\n  _colDisable = RGB(0, 0, 0);\n  _vertical_flag = FALSE;\n  _nTextLimitLength = 0;\n  _textFont = NULL;\n  _hdelta = 0;\n}\n\nCButtonCtl::~CButtonCtl(void) {}\n\nvoid CButtonCtl::SetColor(COLORREF colText, COLORREF colHover,\n                          COLORREF colDown) {\n  _colText = colText;\n  _colHover = colHover;\n  _colDown = colDown;\n}\n\nvoid CButtonCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n\n  _bmpBtn = GetBitmapAttribute(element, \"image\");\n  _bmpIcon = GetBitmapAttribute(element, \"icon\");\n  _bmpSmallIcon = GetBitmapAttribute(element, \"smallicon\");\n  _colText = GetRGBAttribute(element, \"textcolor\");\n  _colHover = GetRGBAttribute(element, \"hovercolor\");\n  _colDown = GetRGBAttribute(element, \"downcolor\");\n  _colDisable = GetRGBAttribute(element, \"discolor\");\n  _rcCorners = GetRectAttribute(element, \"corner\");\n  _hdelta = GetIntegerAttribute(element, \"hdelta\");\n  if (GetIntegerAttribute(element, \"bigfont\")) {\n    _textFont = CGDIResource::GetInstance().GDI_GetBiggerFont();\n  }\n}\n\nvoid CButtonCtl::SetCorner(DUI_Rect rcCorners) {\n  CopyRect(&_rcCorners, &rcCorners);\n}\nvoid CButtonCtl::Disable() {\n  _state = DUI_STATE_DISABLE;\n  Refresh(DUI_STATE_DISABLE);\n}\n\nvoid CButtonCtl::Enable(BOOL enable) {\n  DUI_BUTTON_STATE state;\n  if (enable)\n    state = DUI_STATE_NORMAL;\n  else\n    state = DUI_STATE_DISABLE;\n  if (_state != state) {\n    _state = state;\n    RaiseInvalidate(TRUE);\n  }\n}\n\nvoid CButtonCtl::SetImage(LPCTSTR lpszImageRes) {\n  _bmpBtn =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG);\n}\n\nvoid CButtonCtl::SetImage(HBITMAP bmp) { _bmpBtn = bmp; }\n\nvoid CButtonCtl::SetImageFile(LPCTSTR lpszImageFile) {\n  _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(lpszImageFile);\n}\n\nvoid CButtonCtl::SetIcon(LPCTSTR lpszImageRes) {\n  _bmpIcon =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG);\n}\n\nvoid CButtonCtl::SetIcon(HBITMAP hIcon) { _bmpIcon = hIcon; }\n\nvoid CButtonCtl::SetSmallIcon(LPCTSTR lpszImageRes) {\n  _bmpSmallIcon =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG);\n}\n\nvoid CButtonCtl::SetSmallIconFile(LPCTSTR lpszImageFile) {\n  _bmpSmallIcon = CGDIResource::GetInstance().GDI_GetBitmap(lpszImageFile);\n}\n\nvoid CButtonCtl::SetVertical() { _vertical_flag = TRUE; }\n\nvoid CButtonCtl::SetTitle(const tstring &title) { _title = title; }\n\nvoid CButtonCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n\n    BITMAP bmpInfor;\n    GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor);\n\n    DUI_Rect rcDest(_location, _size);\n    int nImageOffset = 0;\n    COLORREF col = _colText;\n    switch (_state) {\n    case DUI_STATE_NORMAL:\n      nImageOffset = 0;\n      col = _colText;\n      break;\n    case DUI_STATE_HOVER:\n      nImageOffset = 1;\n      col = _colHover;\n      break;\n    case DUI_STATE_DOWN:\n      nImageOffset = 2;\n      col = _colDown;\n      break;\n    case DUI_STATE_DISABLE:\n      nImageOffset = 3;\n      col = _colDisable;\n      break;\n    }\n\n    DUI_Rect rcSrc;\n    DUI_Size sz;\n    if (!_vertical_flag) {\n      sz.cx = bmpInfor.bmWidth / 4;\n      sz.cy = bmpInfor.bmHeight;\n\n      rcSrc.left = nImageOffset * sz.cx;\n      rcSrc.top = 0;\n      rcSrc.right = rcSrc.left + sz.cx;\n      rcSrc.bottom = rcSrc.top + sz.cy;\n    } else {\n      sz.cx = bmpInfor.bmWidth;\n      sz.cy = bmpInfor.bmHeight / 4;\n\n      rcSrc.left = 0;\n      rcSrc.top = nImageOffset * sz.cy;\n      rcSrc.right = rcSrc.left + sz.cx;\n      rcSrc.bottom = rcSrc.top + sz.cy;\n    }\n\n    if (_bmpBtn) {\n\n      if (rcDest.Width() > rcSrc.Width() || rcDest.Height() > rcSrc.Height()) {\n        if (_rcCorners.Width() == 0 && _rcCorners.Height() == 0) {\n          CopyRect(&_rcCorners, CRect(3, 6, 3, 6));\n        }\n        CGDIResource::GetInstance().GDI_DrawImageStretch(\n            hDC, _bmpBtn, rcDest, rcSrc, 255, _rcCorners);\n      } else {\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcDest, rcSrc,\n                                                  DUI_BT_ALPHA);\n      }\n    }\n\n    DUI_Rect rcIcon;\n    if (_bmpIcon) {\n      BITMAP bmpInfo;\n      GetObject(_bmpIcon, sizeof(bmpInfo), &bmpInfo);\n      DUI_Rect rcBmp;\n      sz.cx = bmpInfo.bmWidth / 4;\n      sz.cy = bmpInfo.bmHeight;\n\n      rcBmp.left = nImageOffset * sz.cx;\n      rcBmp.top = 0;\n      rcBmp.right = rcBmp.left + sz.cx;\n      rcBmp.bottom = rcBmp.top + sz.cy;\n      rcIcon.CopyRect(&rcBmp);\n\n      POINT point;\n      point.y = rcDest.top;\n      point.x = rcDest.left;\n\n      CSize size;\n      SelectObject(hDC, CGDIResource::GetInstance().GDI_GetNormalFont());\n      if (::GetTextExtentPoint32(hDC, _title.c_str(), _title.size(), &size)) {\n        if (size.cx > 0)\n          size.cx += 5;\n\n        int nLeft = (rcDest.Width() - size.cx - rcIcon.Width()) / 2;\n        point.x = nLeft > 0 ? point.x + nLeft : point.x;\n        int nTop = (rcDest.Height() - rcIcon.Height()) / 2;\n        point.y = nTop > 0 ? point.y + nTop : point.y;\n      }\n\n      rcIcon.MoveToXY(point);\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, rcIcon, rcBmp,\n                                                DUI_BT_ALPHA);\n    }\n\n    if (_bmpSmallIcon) {\n      BITMAP bmpInfo;\n      GetObject(_bmpSmallIcon, sizeof(bmpInfo), &bmpInfo);\n\n      CSize Txtsize;\n      ::GetTextExtentPoint32(hDC, _title.c_str(), _title.length(), &Txtsize);\n\n      rcIcon.left =\n          rcDest.left +\n          (rcDest.right - rcDest.left - (bmpInfo.bmWidth + Txtsize.cx + 5)) / 2;\n      rcIcon.top = rcDest.top + (rcDest.Height() - bmpInfo.bmHeight) / 2;\n      rcIcon.right = rcIcon.left + bmpInfo.bmWidth;\n      rcIcon.bottom = rcIcon.top + bmpInfo.bmHeight;\n\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpSmallIcon, rcIcon);\n    }\n\n    if (!_title.empty()) {\n      rcDest.top += _hdelta;\n      UINT nFormat = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS;\n      if (_bmpIcon || _bmpSmallIcon) {\n        rcDest.left = rcIcon.right + 5;\n        if (_nTextLimitLength > 0)\n          rcDest.right = rcDest.left + _nTextLimitLength;\n        nFormat = nFormat | DT_LEFT;\n      } else\n        nFormat = nFormat | DT_CENTER;\n\n      if (_transparent) {\n        if (!_textFont)\n          CGDIResource::GetInstance().GDI_DrawText_Trans(hDC, _title.c_str(),\n                                                         &rcDest, col, nFormat);\n        else if (DUI_STATE_DISABLE == _state)\n          CGDIResource::GetInstance().GDI_DrawText_Trans(\n              hDC, _title.c_str(), &rcDest, _textFont, col, nFormat);\n        else\n          CGDIResource::GetInstance().GDI_DrawText_Trans(\n              hDC, _title.c_str(), &rcDest, _textFont, col, nFormat);\n      } else {\n        CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcDest,\n                                                 _textFont, col, nFormat);\n      }\n    }\n  }\n}\n\nvoid CButtonCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      Refresh(DUI_STATE_HOVER);\n    }\n  }\n}\n\nvoid CButtonCtl::OnMouseLeave() {\n  _down = FALSE;\n  _tracking = FALSE;\n  if (_state != DUI_STATE_DISABLE) {\n    Refresh(DUI_STATE_NORMAL);\n  }\n}\n\nvoid CButtonCtl::Refresh(DUI_BUTTON_STATE nowstate) {\n  if (_state != nowstate) {\n    _state = nowstate;\n    RaiseInvalidate(TRUE);\n  }\n}\n\nvoid CButtonCtl::OnMouseDown(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    _down = TRUE;\n    Refresh(DUI_STATE_DOWN);\n    OnMouseDownClick();\n  }\n}\n\nvoid CButtonCtl::OnMouseUp(UINT nFlags, CPoint point) {\n  if (_visible) {\n    if (_state != DUI_STATE_DISABLE) {\n      DUI_BUTTON_STATE state = _state;\n      Refresh(DUI_STATE_HOVER);\n\n      if (_down && (state == DUI_STATE_DOWN)) {\n        OnMouseClick();\n      }\n\n      _down = FALSE;\n    }\n  }\n}\n\nvoid CButtonCtl::OnMouseDownClick() { _leftdown_event.Invoke(); }\n\nvoid CButtonCtl::SetTextLimitLength(int nLength) {\n  _nTextLimitLength = nLength;\n}\n\nvoid CButtonCtl::OnCall_LeftUp() {\n  if (_leftup_event.m_func_no_para)\n    _leftup_event.Invoke();\n\n  else if (_leftup_event.m_func_para_string)\n    _leftup_event.Invoke(_id.c_str());\n}\n\nvoid CButtonCtl::OnCall_RightUp() {\n  if (_rightup_event.m_func_no_para)\n    _rightup_event.Invoke();\n\n  else if (_rightup_event.m_func_para_string)\n    _rightup_event.Invoke(_id.c_str());\n}\n"
  },
  {
    "path": "src/DirectUI/DUIButton.h",
    "content": "#pragma once\n\n#include \"DUIDef.h\"\n#include \"DUIElement.h\"\n\nclass CButtonCtl : public CBaseElementCtl {\npublic:\n  CButtonCtl(HWND father, BOOL trans = FALSE);\n  CButtonCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip,\n             DUI_Rect rcElement, BOOL trans = FALSE);\n  ~CButtonCtl(void);\n\n  void Disable();\n  void Enable(BOOL enable);\n  void CreateElement(XmlElementPtr element);\n  void SetImage(LPCTSTR lpszImageRes);\n  void SetImage(HBITMAP bmp);\n  void SetIcon(LPCTSTR lpszImageRes);\n  virtual void SetIcon(HBITMAP hIcon);\n  void SetSmallIcon(LPCTSTR lpszImageRes);\n  void SetSmallIconFile(LPCTSTR lpszImageFile);\n  void SetImageFile(LPCTSTR lpszImageFile);\n  void SetVertical();\n  void SetTitle(const tstring &title);\n  void SetColor(COLORREF colText, COLORREF colHover, COLORREF colDown);\n  void SetTextLimitLength(int nLength);\n  void SetCorner(DUI_Rect rcCorners);\n  void OnCall_LeftUp();\n  void OnCall_RightUp();\n  void SetTextFont(HFONT font) { _textFont = font; }\n\nprotected:\n  BOOL _tracking;\n  BOOL _down;\n  DUI_BUTTON_STATE _state;\n  HBITMAP _bmpBtn;\n  HBITMAP _bmpIcon;\n  HBITMAP _bmpSmallIcon;\n  COLORREF _colText;\n  COLORREF _colHover;\n  COLORREF _colDown;\n  COLORREF _colDisable;\n  BOOL _vertical_flag;\n  int _nTextLimitLength;\n  DUI_Rect _rcCorners;\n  HFONT _textFont;\n  int _hdelta;\n\npublic:\n  void Refresh(DUI_BUTTON_STATE nowstate);\n  virtual void OnPaint(HDC hDC);\n  virtual void OnMouseHover(UINT nFlags, CPoint point);\n  virtual void OnMouseLeave();\n  virtual void OnMouseDown(UINT nFlags, CPoint point);\n  virtual void OnMouseUp(UINT nFlags, CPoint point);\n  virtual void OnMouseDownClick();\n};\n"
  },
  {
    "path": "src/DirectUI/DUICheckBox.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUICheckBox.h\"\n\nCCheckBoxCtl::CCheckBoxCtl(HWND father, BOOL trans) : CButtonCtl(father) {\n  _class = _T(\"\");\n  _transparent = trans;\n  _txtColor = RGB(67, 75, 94);\n  _bChecked = FALSE;\n  _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                      _T(\"CHECK_BOX\"), PNG);\n}\n\nCCheckBoxCtl::CCheckBoxCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                           LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _class = _T(\"\");\n  _txtColor = RGB(67, 75, 94);\n  _bChecked = FALSE;\n  _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                      _T(\"CHECK_BOX\"), PNG);\n}\n\nCCheckBoxCtl::~CCheckBoxCtl(void) {}\n\nvoid CCheckBoxCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n\n  _bmpBtn = GetBitmapAttribute(element, \"image\");\n\n  _txtColor = GetRGBAttribute(element, \"textcolor\");\n}\n\nvoid CCheckBoxCtl::Enable(BOOL enable) {\n  if (enable) {\n    switch (_state) {\n    case DUI_STATE_NORMAL_DISABLE:\n      _state = DUI_STATE_NORMAL;\n      break;\n    case DUI_STATE_DOWN_DISABLE:\n      _state = DUI_STATE_DOWN;\n      break;\n    default:\n      break;\n    }\n  } else {\n    Disable();\n  }\n}\n\nvoid CCheckBoxCtl::OnPaint(HDC hDC) {\n  BITMAP bmpInfor;\n  GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor);\n\n  int nCheckWidth = bmpInfor.bmWidth / 2;\n\n  DUI_Size szCheckImage(nCheckWidth, bmpInfor.bmHeight);\n  DUI_Point ptCheckImage(_location.x,\n                         _location.y + (_size.cy - bmpInfor.bmHeight) / 2);\n  DUI_Rect rcImage(ptCheckImage, szCheckImage);\n  int nImageOffset = 0;\n  switch (_state) {\n  case DUI_STATE_NORMAL:\n  case DUI_STATE_HOVER:\n    nImageOffset = 0;\n    break;\n  case DUI_STATE_DOWN:\n    nImageOffset = 1;\n    break;\n  case DUI_STATE_NORMAL_DISABLE:\n    nImageOffset = 2;\n    break;\n  case DUI_STATE_DOWN_DISABLE:\n    nImageOffset = 3;\n    break;\n  }\n\n  DUI_Rect rcSrc(DUI_Point(nImageOffset * nCheckWidth, 0),\n                 DUI_Size(nCheckWidth, bmpInfor.bmHeight));\n\n  CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcImage, rcSrc);\n\n  DUI_Rect rcText(DUI_Point(rcImage.right + 5, _location.y),\n                  DUI_Size(_size.cx - rcImage.Width() - 1, _size.cy));\n  if (_transparent) {\n    CGDIResource::GetInstance().GDI_DrawText_Trans(\n        hDC, _title.c_str(), &rcText, _txtColor,\n        DT_LEFT | DT_SINGLELINE | DT_VCENTER);\n  } else {\n    CGDIResource::GetInstance().GDI_DrawText(\n        hDC, _title.c_str(), &rcText, _txtColor,\n        DT_LEFT | DT_SINGLELINE | DT_VCENTER);\n  }\n}\n\nvoid CCheckBoxCtl::Disable() {\n  switch (_state) {\n  case DUI_STATE_NORMAL:\n    _state = DUI_STATE_NORMAL_DISABLE;\n    break;\n  case DUI_STATE_DOWN:\n    _state = DUI_STATE_DOWN_DISABLE;\n    break;\n  default:\n    break;\n  }\n}\n\nvoid CCheckBoxCtl::OnMouseDown(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    _down = !_down;\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n      _bChecked = TRUE;\n    } else {\n      Refresh(DUI_STATE_NORMAL);\n      _bChecked = FALSE;\n    }\n    OnMouseDClick();\n  }\n}\n\nvoid CCheckBoxCtl::OnMouseUp(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    OnMouseClick();\n  }\n}\n\nvoid CCheckBoxCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      Refresh(DUI_STATE_HOVER);\n    }\n  }\n}\n\nvoid CCheckBoxCtl::OnMouseLeave() {\n  _tracking = FALSE;\n  if (_state != DUI_STATE_DISABLE) {\n    if (!_down) {\n      Refresh(DUI_STATE_NORMAL);\n    }\n  }\n}\n\nvoid CCheckBoxCtl::SetCheck(BOOL bCheck) {\n  _bChecked = bCheck;\n\n  if (_state != DUI_STATE_DISABLE) {\n    if (_bChecked) {\n      _state = DUI_STATE_DOWN;\n      _down = TRUE;\n    } else {\n      _state = DUI_STATE_NORMAL;\n      _down = FALSE;\n    }\n  }\n}\n\nBOOL CCheckBoxCtl::GetCheck() { return _bChecked; }\n"
  },
  {
    "path": "src/DirectUI/DUICheckBox.h",
    "content": "#pragma once\n\n#include \"DUIButton.h\"\n\nclass CCheckBoxCtl : public CButtonCtl {\npublic:\n  CCheckBoxCtl(HWND father, BOOL trans = FALSE);\n  CCheckBoxCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n               LPCTSTR lpszTooptip, DUI_Rect rcElement);\n  ~CCheckBoxCtl(void);\n\n  void SetCheck(BOOL bCheck);\n  BOOL GetCheck();\n  void Disable();\n  void Enable(BOOL enable);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void OnMouseDown(UINT nFlags, CPoint point);\n  void OnMouseUp(UINT nFlags, CPoint point);\n  void OnMouseHover(UINT nFlags, CPoint point);\n  void OnMouseLeave();\n\nprotected:\n  COLORREF _txtColor;\n\n  BOOL _bChecked;\n};\n"
  },
  {
    "path": "src/DirectUI/DUIDef.h",
    "content": "#pragma once\n\n#include <algorithm>\n#include <list>\n#include <map>\n#include <set>\n#include <string>\n#include <vector>\n#include \"../resource.h\"\n#include \"xml/xmlhelper.h\"\n\ntypedef WTL::CPoint DUI_Point;\ntypedef WTL::CSize DUI_Size;\ntypedef WTL::CRect DUI_Rect;\n\ntypedef enum { DUI_BT_NORMAL = 0, DUI_BT_TRANS, DUI_BT_ALPHA } DUI_BITMAP_TYPE;\n\ntypedef enum {\n  DUI_ALIGNMENT_NONE = 0,\n  DUI_ALIGNMENT_LEFT,\n  DUI_ALIGNMENT_TOP,\n  DUI_ALIGNMENT_RIGHT,\n  DUI_ALIGNMENT_BOTTOM,\n  DUI_ALIGNMENT_CENTER\n} DUI_ALIGNMENT;\n\ntypedef enum {\n  DUI_STRETCH_NONE = 0,\n  DUI_STRETCH_SCALE,\n  DUI_STRETCH_FILL,\n  DUI_STRETCH_HORIZONTAL,\n  DUI_STRETCH_VERTICAL\n} DUI_STRETCH;\n\ntypedef enum {\n  DUI_STATE_NORMAL = 0,\n  DUI_STATE_DOWN,\n  DUI_STATE_HOVER,\n  DUI_STATE_DISABLE,\n  DUI_STATE_NORMAL_DISABLE,\n  DUI_STATE_DOWN_DISABLE,\n  DUI_STATE_HOVER_DISABLE\n} DUI_BUTTON_STATE;\n\nvoid TrackMouseLeave(HWND hWnd);\n\n#define TRANSPARENT_COLOR RGB(255, 0, 255)\n\n#define WM_MSG_TIPS WM_USER + 0x1000\n#define WM_MSG_CURSOR WM_USER + 0x1001\n#define WM_MSG_ICON_NOTIFY WM_USER + 0x1002\n#define WM_MSG_POP_MENU WM_USER + 0x1003\n#define WM_MSG_TREE_SCROLLBAR WM_USER + 0x1004\n#define WM_MSG_BEGIN_SCROLL WM_USER + 0x1005\n#define WM_MSG_ACTIVE WM_USER + 0x1006\n#define WM_ASYNC_CALL_LUP WM_USER + 0x1020\n#define WM_ASYNC_CALL_RUP WM_USER + 0x1021\n#define WM_ASYNC_CALL_DROPUP WM_USER + 0x1022\n#define WM_ASYNC_CALL_ENTERKEY WM_USER + 0x1023\n#define WM_ASYNC_CALL_TABKEY WM_USER + 0x1024\n#define WM_ASYNC_CALL_LDBCLICK WM_USER + 0x1025\n#define WM_ASYNC_CALL_LDOWN WM_USER + 0x1026\n\n#define WM_RADIOBUTTON_DOWN WM_USER + 0x2ae0\n#define WM_CONTROL_TAB WM_USER + 0x2ae1\n#define WM_PATH_ILLCHARACTER WM_USER + 0x2ae2\n\n#define MSG_UPDATE_WINDOW_INVALIDATE (WM_USER + 0x5000)\n\n#define ACTIVE_TIMER 0x200\n"
  },
  {
    "path": "src/DirectUI/DUIElement.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIElement.h\"\n\nCBaseElementCtl::CBaseElementCtl() : _editCheckPath(FALSE) {\n  _handleMouse = TRUE;\n  _handleKeyboard = FALSE;\n  _viscur = FALSE;\n  _active = FALSE;\n  _host = NULL;\n  _visible = TRUE;\n  _transparent = FALSE;\n  _id = _T(\"\");\n  _name = _T(\"\");\n  _base_pt.x = 0;\n  _base_pt.y = 0;\n  _location.x = 0;\n  _location.y = 0;\n  _size.cx = 0;\n  _size.cy = 0;\n  _cursor = LoadCursor(NULL, IDC_ARROW);\n}\n\nCBaseElementCtl::CBaseElementCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                                 LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : _editCheckPath(FALSE) {\n\n  _handleMouse = TRUE;\n  _handleKeyboard = FALSE;\n  _viscur = FALSE;\n  _active = FALSE;\n  _host = father;\n  _visible = TRUE;\n  _id = lpszID;\n  _name = lpszID;\n  _title = lpszTitle;\n  _tip = lpszTooptip;\n  _base_pt.x = 0;\n  _base_pt.y = 0;\n  _location.x = rcElement.left;\n  _location.y = rcElement.top;\n  _size.cx = rcElement.Width();\n  _size.cy = rcElement.Height();\n  _cursor = LoadCursor(NULL, IDC_ARROW);\n}\n\nCBaseElementCtl::~CBaseElementCtl(void) {}\n\nvoid CBaseElementCtl::CreateElement(XmlElementPtr element) {}\n\nvoid CBaseElementCtl::GetElementStyle(XmlElementPtr element) {\n  CXmlHelper helper;\n\n  _id = helper.GetAttributeString(element, \"id\");\n\n  _name = helper.GetAttributeString(element, \"name\");\n\n  _title = helper.GetAttributeString(element, \"title\");\n\n  _tip = helper.GetAttributeString(element, \"tip\");\n\n  _style = helper.GetAttributeInt(element, \"style\");\n\n  _ex_style = helper.GetAttributeInt(element, \"style_ex\");\n\n  _location.x = helper.GetAttributeInt(element, \"left\");\n  _location.y = helper.GetAttributeInt(element, \"top\");\n  _size.cx = helper.GetAttributeInt(element, \"width\");\n  _size.cy = helper.GetAttributeInt(element, \"height\");\n  _ori_location = _location;\n  _ori_size = _size;\n\n  LoadStyle(element);\n}\n\nvoid CBaseElementCtl::OnKeyDown(DWORD dwFlag) {}\n\nvoid CBaseElementCtl::OnKeyUp(DWORD dwFlag) {}\n\nvoid CBaseElementCtl::OnMouseClick() {\n  ::PostMessage(_host, WM_ASYNC_CALL_LUP, (WPARAM)this, 0);\n}\n\nvoid CBaseElementCtl::OnMouseDClick() {\n  ::PostMessage(_host, WM_ASYNC_CALL_LDOWN, (WPARAM)this, 0);\n}\n\nvoid CBaseElementCtl::OnCall_LeftUp() { _leftup_event.Invoke(); }\n\nvoid CBaseElementCtl::OnCall_LeftDown() { _leftdown_event.Invoke(); }\n\nvoid CBaseElementCtl::OnMove() {}\nvoid CBaseElementCtl::OnMouseDblDown(UINT nFlags, CPoint point) {\n  OnMouseDClick();\n}\n\nvoid CBaseElementCtl::OnMouseDown(UINT nFlags, CPoint point) {}\n\nvoid CBaseElementCtl::OnMouseUp(UINT nFlags, CPoint point) {}\n\nvoid CBaseElementCtl::OnMouseLDbClick(UINT nFlags, CPoint point) {}\n\nvoid CBaseElementCtl::OnMouseRUp(UINT nFlags, CPoint point) {\n  ::PostMessage(_host, WM_ASYNC_CALL_RUP, (WPARAM)this, 0);\n}\nvoid CBaseElementCtl::OnCall_RightUp() { _rightup_event.Invoke(); }\n\nvoid CBaseElementCtl::OnCall_LDbClick() {\n  if (_leftDbclick_event.m_func_no_para)\n    _leftDbclick_event.Invoke();\n  else if (_leftDbclick_event.m_func_para_string)\n    _leftDbclick_event.Invoke(_id.c_str());\n}\n\nvoid CBaseElementCtl::OnEnterKey() {\n  ::PostMessage(_host, WM_ASYNC_CALL_ENTERKEY, (WPARAM)this, 0);\n}\n\nvoid CBaseElementCtl::OnCall_EnterKey() { _enterkey_event.Invoke(); }\n\nvoid CBaseElementCtl::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled) {}\n\nvoid CBaseElementCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  _hover_event.Invoke();\n}\n\nvoid CBaseElementCtl::OnMouseLeave() { _leave_event.Invoke(); }\n\nvoid CBaseElementCtl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) {}\n\nvoid CBaseElementCtl::OnPaint(HDC hDC) {}\n\nvoid CBaseElementCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) {\n  CRect rc;\n  rc = StyleRectToWindowRect(DUI_Rect(_location, _size), _ori_location,\n                             wndChangingSize, CSize(w, h), _xAlignment,\n                             _yAlignment, _xStretch, _yStretch);\n\n  _location.x = rc.left;\n  _location.y = rc.top;\n  _size.cx = rc.Width();\n  _size.cy = rc.Height();\n}\n\nvoid CBaseElementCtl::RaiseInvalidate(BOOL forceRedraw) {\n  if (_host != NULL) {\n    if (forceRedraw) {\n      if (_transparent) {\n        ::PostMessage(_host, MSG_UPDATE_WINDOW_INVALIDATE, 0, 100);\n      } else {\n        ::InvalidateRect(_host, Rectangle(), TRUE);\n      }\n    }\n  }\n}\n\nint CBaseElementCtl::GetTextWidth(LPCTSTR lpszText, HFONT hFont) {\n  CPaintDC dc(_host);\n  HFONT hOldFont = dc.SelectFont(hFont);\n  ::SetBkMode(dc.m_hDC, TRANSPARENT);\n  CSize szText;\n  ::GetTextExtentPoint32(dc.m_hDC, lpszText, lstrlen(lpszText), &szText);\n  dc.SelectFont(hOldFont);\n\n  return szText.cx;\n}\n"
  },
  {
    "path": "src/DirectUI/DUIElement.h",
    "content": "#pragma once\n\n#include \"DUIDef.h\"\n#include \"DUIGDIResource.h\"\n#include \"DUIWindowStyle.h\"\n#include \"EventHandler.h\"\n\nclass __declspec(novtable) CBaseElementCtl : public CWindowCtlStyle {\npublic:\n  CBaseElementCtl();\n  CBaseElementCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                  LPCTSTR lpszTooptip, DUI_Rect rcElement);\n  virtual ~CBaseElementCtl(void);\n\n  virtual void CreateElement(XmlElementPtr element);\n\n  virtual tstring GetID();\n  virtual tstring GetName();\n  virtual tstring GetTitle();\n  virtual tstring GetTooltip();\n  virtual tstring &GetWndClassName();\n  virtual void SetTitle(const tstring &csName);\n  virtual void SetTooltip(const tstring &strTip);\n  virtual void SetID(const tstring &id);\n  virtual void SetName(const tstring &id);\n  virtual void SetHandleMouse(BOOL mouse);\n  virtual BOOL GetVisible();\n  virtual BOOL GetHandleMouse();\n  virtual void SetVisible(BOOL bVisible);\n  virtual void SetHandleKeyboard(BOOL keyboard);\n  virtual BOOL GetHandleKeyboard();\n  virtual void SetActive(BOOL active);\n  virtual void SetActive(CBaseElementCtl *element);\n  virtual BOOL GetActive();\n  virtual void SetVisibleCur(BOOL bVisible);\n  virtual BOOL GetVisibleCur();\n  virtual void SetPos(WTL::CPoint pt, WTL::CSize sz);\n  virtual void SetOriginPos(CPoint pt, CSize sz);\n  virtual void SetPos(WTL::CRect rc);\n  virtual void SetOriginPos(WTL::CRect rc);\n  virtual CRect Rectangle();\n  virtual CRect OriginRectangle();\n  virtual HCURSOR GetCursor();\n  virtual void SetCursor(HCURSOR cursor);\n  virtual void RegisterLButtonDownEvent(EventHandler event);\n  virtual void RegisterLButtonUpEvent(EventHandler event);\n  virtual void RegisterRButtonUpEvent(EventHandler event);\n  virtual void RegisterHoverEvent(EventHandler event);\n  virtual void RegisterLeaveEvent(EventHandler event);\n  virtual void RegisterEnterKeyEvent(EventHandler event);\n  virtual void RegisterLButtonDbCEvent(EventHandler event);\n  virtual void RaiseInvalidate(BOOL forceRedraw = TRUE);\n  virtual int GetTextWidth(LPCTSTR lpszText, HFONT hFont);\n  virtual HWND GetHost();\n  virtual void DrawCursor() { ; }\n  virtual void VerticalOffset(int i = 0) { _location.y += i; }\n\n  virtual BOOL IsPanel() { return FALSE; }\n\n  virtual void OnMove();\n  virtual void OnKeyDown(DWORD dwFlag);\n  virtual void OnKeyUp(DWORD dwFlag);\n  virtual void OnMouseDClick();\n  virtual void OnMouseClick();\n  virtual void OnMouseLDbClick(UINT nFlags, CPoint point);\n  virtual void OnMouseDown(UINT nFlags, CPoint point);\n  virtual void OnMouseDblDown(UINT nFlags, CPoint point);\n  virtual void OnMouseUp(UINT nFlags, CPoint point);\n  virtual void OnMouseRUp(UINT nFlags, CPoint point);\n  virtual void OnMouseHover(UINT nFlags, CPoint point);\n  virtual void OnMouseLeave();\n  virtual void OnPaint(HDC hDC);\n  virtual void OnSizeChanged(DUI_Size wndChangingSize, int w, int h);\n  virtual void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);\n  virtual BOOL PointInRect(CPoint pt, CRect rect);\n  virtual void OnCall_LeftUp();\n  virtual void OnCall_RightUp();\n  virtual void OnCall_EnterKey();\n  virtual void OnCall_LeftDown();\n  virtual void OnEnterKey();\n  virtual void OnTabKey() {}\n  virtual void OnCall_LDbClick();\n  virtual void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n\npublic:\n  virtual void GetElementStyle(XmlElementPtr element);\n\n  HWND _host;\n  tstring _id;\n  tstring _name;\n  tstring _title;\n  tstring _class;\n  tstring _tip;\n  DWORD _style;\n  DWORD _ex_style;\n  CPoint _location;\n  CPoint _ori_location;\n  CSize _size;\n  CSize _ori_size;\n  CPoint _base_pt;\n  BOOL _handleMouse;\n  BOOL _handleKeyboard;\n  BOOL _active;\n  BOOL _visible;\n  BOOL _viscur;\n  HCURSOR _cursor;\n  BOOL _transparent;\n  BOOL _editCheckPath;\n\n  EventHandler _leftdown_event;\n  EventHandler _leftup_event;\n  EventHandler _rightup_event;\n  EventHandler _hover_event;\n  EventHandler _leave_event;\n  EventHandler _enterkey_event;\n  EventHandler _leftDbclick_event;\n};\n\ninline HWND CBaseElementCtl::GetHost() { return _host; }\n\ninline void CBaseElementCtl::SetID(const tstring &id) { _id = id; }\ninline tstring CBaseElementCtl::GetID() { return _id; }\n\ninline tstring CBaseElementCtl::GetTitle() { return _title; }\n\ninline void CBaseElementCtl::SetTitle(const tstring &title) { _title = title; }\n\ninline void CBaseElementCtl::SetVisible(BOOL visible) {\n  if (_visible != visible) {\n    _visible = visible;\n    RaiseInvalidate(TRUE);\n  }\n}\n\ninline BOOL CBaseElementCtl::GetVisible() { return _visible; }\n\ninline tstring CBaseElementCtl::GetTooltip() { return _tip; }\n\ninline void CBaseElementCtl::SetTooltip(const tstring &csTooltip) {\n  _tip = csTooltip;\n}\n\ninline void CBaseElementCtl::SetHandleMouse(BOOL mouse) {\n  _handleMouse = mouse;\n}\n\ninline BOOL CBaseElementCtl::GetHandleMouse() { return _handleMouse; }\n\ninline void CBaseElementCtl::SetHandleKeyboard(BOOL keyboard) {\n  _handleKeyboard = keyboard;\n}\n\ninline BOOL CBaseElementCtl::GetHandleKeyboard() { return _handleKeyboard; }\n\ninline void CBaseElementCtl::SetActive(BOOL active) {\n  _active = active;\n  if (_active) {\n  }\n}\n\ninline void CBaseElementCtl::SetActive(CBaseElementCtl *element) {\n  if (element == this)\n    _active = TRUE;\n  else\n    _active = FALSE;\n}\n\ninline BOOL CBaseElementCtl::GetActive() { return _active; }\n\ninline void CBaseElementCtl::SetVisibleCur(BOOL bVisible) {\n  _viscur = bVisible;\n}\n\ninline BOOL CBaseElementCtl::GetVisibleCur() { return _viscur; }\n\ninline void CBaseElementCtl::SetName(const tstring &name) { _name = name; }\ninline tstring CBaseElementCtl::GetName() { return _name; }\n\ninline CRect CBaseElementCtl::Rectangle() {\n  CPoint pt(_base_pt.x + _location.x, _base_pt.y + _location.y);\n  return CRect(pt.x, pt.y, pt.x + _size.cx, pt.y + _size.cy);\n}\n\ninline CRect CBaseElementCtl::OriginRectangle() {\n  CPoint pt(_ori_location.x, _ori_location.y);\n  return CRect(pt.x, pt.y, pt.x + _ori_size.cx, pt.y + _ori_size.cy);\n}\n\ninline void CBaseElementCtl::SetPos(CPoint pt, CSize sz) {\n  _location.x = pt.x;\n  _location.y = pt.y;\n  _size.cx = sz.cx;\n  _size.cy = sz.cy;\n}\n\ninline void CBaseElementCtl::SetOriginPos(CPoint pt, CSize sz) {\n  _ori_location = pt;\n  _ori_size = sz;\n}\n\ninline void CBaseElementCtl::SetPos(WTL::CRect rc) {\n  _location.x = rc.left;\n  _location.y = rc.top;\n  _size.cx = rc.Width();\n  _size.cy = rc.Height();\n}\n\ninline void CBaseElementCtl::SetOriginPos(WTL::CRect rc) {\n  _ori_location.x = rc.left;\n  _ori_location.y = rc.top;\n  _ori_size.cx = rc.Width();\n  _ori_size.cy = rc.Height();\n}\n\ninline HCURSOR CBaseElementCtl::GetCursor() { return _cursor; }\n\ninline void CBaseElementCtl::SetCursor(HCURSOR cursor) { _cursor = cursor; }\n\ninline tstring &CBaseElementCtl::GetWndClassName() { return _class; }\n\ninline void CBaseElementCtl::RegisterLButtonUpEvent(EventHandler event) {\n  _leftup_event = event;\n}\n\ninline void CBaseElementCtl::RegisterRButtonUpEvent(EventHandler event) {\n  _rightup_event = event;\n}\n\ninline void CBaseElementCtl::RegisterLButtonDownEvent(EventHandler event) {\n  _leftdown_event = event;\n}\n\ninline void CBaseElementCtl::RegisterHoverEvent(EventHandler event) {\n  _hover_event = event;\n}\n\ninline void CBaseElementCtl::RegisterLeaveEvent(EventHandler event) {\n  _leave_event = event;\n}\n\ninline void CBaseElementCtl::RegisterEnterKeyEvent(EventHandler event) {\n  _enterkey_event = event;\n}\n\ninline void CBaseElementCtl::RegisterLButtonDbCEvent(EventHandler event) {\n  _leftDbclick_event = event;\n}\n\ninline BOOL CBaseElementCtl::PointInRect(CPoint pt, CRect rect) {\n  return (((pt.x >= rect.left) && (pt.x <= rect.right)) &&\n          ((pt.y >= rect.top) && (pt.y <= rect.bottom)));\n}\n"
  },
  {
    "path": "src/DirectUI/DUIElementsMgr.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIPanel.h\"\n#include \"DUIElementsMgr.h\"\n\nusing namespace std;\n\nCAnyElementsMgr::CAnyElementsMgr(void) {\n  _last_mouseon_element = NULL;\n  _owner = NULL;\n  _rearrange_element = NULL;\n}\n\nCAnyElementsMgr::~CAnyElementsMgr(void) {}\n\nvoid CAnyElementsMgr::AddElement(CBaseElementCtl *element) {\n  _controls.push_back(element);\n}\n\nvoid CAnyElementsMgr::AddElement2(CBaseElementCtl *element) {\n  if (_controls.size() == 0 || _controls.size() == 1)\n    _controls.push_back(element);\n  else {\n    list<CBaseElementCtl *>::iterator Iter;\n    Iter = _controls.begin();\n    Iter++;\n    _controls.insert(Iter, element);\n  }\n}\n\nvoid CAnyElementsMgr::OnKeyDown(DWORD dwFlag) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    element->OnKeyDown(dwFlag);\n  }\n}\n\nvoid CAnyElementsMgr::OnKeyUp(DWORD dwFlag) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    element->OnKeyUp(dwFlag);\n  }\n}\n\nvoid CAnyElementsMgr::OnMove() {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if (element->GetVisible() && element->GetHandleMouse()) {\n      element->OnMove();\n    }\n  }\n}\n\nBOOL CAnyElementsMgr::MouseOnElement(CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if ((element->GetVisible() && element->GetHandleMouse()) &&\n        PointInRect(pt, element->Rectangle())) {\n      return TRUE;\n    }\n  }\n  return FALSE;\n}\n\nvoid CAnyElementsMgr::OnMouseClick(CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if (element->GetVisible() && element->GetHandleMouse()) {\n      PointInRect(CPoint(pt.x, pt.y), element->Rectangle());\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseDown(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if ((element->GetVisible() && element->GetHandleMouse()) &&\n        PointInRect(pt, element->Rectangle())) {\n      element->OnMouseDown(nFlags, pt);\n    }\n  }\n\n  if (_rearrange_element != NULL) {\n    list<CBaseElementCtl *>::iterator ite =\n        find(_controls.begin(), _controls.end(), _rearrange_element);\n    _controls.erase(ite);\n    _controls.push_back(_rearrange_element);\n    _rearrange_element = NULL;\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseLDbClick(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  CBaseElementCtl *cur_element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    cur_element = *ite;\n    if (cur_element->GetVisible() && cur_element->GetHandleMouse()) {\n      if (PointInRect(pt, cur_element->Rectangle())) {\n        cur_element->OnMouseLDbClick(nFlags, pt);\n      }\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseUp(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  CBaseElementCtl *cur_element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (; ite != _controls.end(); ite++) {\n    cur_element = *ite;\n    if (cur_element->GetVisible() && cur_element->GetHandleMouse()) {\n      if (PointInRect(pt, cur_element->Rectangle())) {\n        cur_element->OnMouseUp(nFlags, pt);\n        if (!cur_element->GetWndClassName().compare(_T(\"DirectButton\"))) {\n          break;\n        }\n      }\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseRUp(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  CBaseElementCtl *cur_element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    cur_element = *ite;\n    if (cur_element->GetVisible() && cur_element->GetHandleMouse()) {\n      if (PointInRect(pt, cur_element->Rectangle())) {\n        cur_element->OnMouseRUp(nFlags, pt);\n      }\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseLeave() {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if ((element->GetVisible() && element->GetHandleMouse()) &&\n        (_last_mouseon_element == element)) {\n      element->OnMouseLeave();\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseMove(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  CBaseElementCtl *element2 = NULL;\n  CBaseElementCtl *element3 = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element3 = *ite;\n    if (element3->GetVisible() && element3->GetHandleMouse()) {\n      if (PointInRect(pt, element3->Rectangle())) {\n        element = element3;\n      } else if (_last_mouseon_element == element3) {\n        element2 = element3;\n      }\n    }\n  }\n  if (((element != NULL) && (_last_mouseon_element != element)) &&\n      (element2 == NULL)) {\n    element2 = _last_mouseon_element;\n  }\n  if (element2 != NULL) {\n    element2->OnMouseLeave();\n    ::SendMessage(_owner, WM_MSG_TIPS, FALSE, 0);\n    ::SendMessage(_owner, WM_MSG_CURSOR, (WPARAM)element2->GetCursor(), 0);\n  }\n\n  if ((element != NULL)) {\n    if (!lstrcmp(element->GetWndClassName().c_str(), _T(\"Panel\"))) {\n      element->OnMouseHover(nFlags, pt);\n    } else {\n      element->OnMouseHover(nFlags, pt);\n      if (_last_mouseon_element != element) {\n        ::SendMessage(_owner, WM_MSG_TIPS, TRUE,\n                      (LPARAM)element->GetTooltip().c_str());\n        ::SendMessage(_owner, WM_MSG_CURSOR, (WPARAM)element->GetCursor(), 0);\n      }\n    }\n  }\n  _last_mouseon_element = element;\n}\n\nvoid CAnyElementsMgr::DrawCursor() {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if ((element->GetVisible() && element->GetHandleKeyboard())) {\n      element->DrawCursor();\n    }\n  }\n}\n\nvoid CAnyElementsMgr::SetActive(CBaseElementCtl *element) {\n  CBaseElementCtl *ele = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    ele = *ite;\n    ele->SetActive(element);\n  }\n}\n\nvoid CAnyElementsMgr::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled) {\n  CBaseElementCtl *ele = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    ele = *ite;\n    ele->OnMsg(nMsg, wParam, lParam, bHandled);\n  }\n}\n\nvoid CAnyElementsMgr::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n  CBaseElementCtl *cur_element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    cur_element = *ite;\n    if (cur_element->GetVisible() && cur_element->GetHandleMouse()) {\n      if (PointInRect(pt, cur_element->Rectangle())) {\n        cur_element->OnMouseWheel(nFlags, zDelta, pt);\n      }\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnPaint(HDC hDC) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if (element->GetVisible()) {\n      element->OnPaint(hDC);\n    }\n  }\n}\n\nvoid CAnyElementsMgr::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    element->OnSizeChanged(wndChangingSize, w, h);\n  }\n}\n\nvoid CAnyElementsMgr::RearrangeElement(CBaseElementCtl *e) {\n  if (e != NULL) {\n    list<CBaseElementCtl *>::iterator ite =\n        find(_controls.begin(), _controls.end(), e);\n    _controls.erase(ite);\n    _controls.push_back(e);\n  }\n}\n\nCBaseElementCtl *CAnyElementsMgr::Search(const tstring id) {\n  CBaseElementCtl *filterEle = NULL;\n  CBaseElementCtl *element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n\n    if (!lstrcmp(element->GetWndClassName().c_str(), _T(\"Panel\"))) {\n      filterEle = ((CPanelCtl *)element)->_elementmgr.Search(id);\n      if (filterEle) {\n        break;\n      }\n    }\n    if (element->GetID() == id) {\n      filterEle = element;\n      break;\n    }\n  }\n\n  return filterEle;\n}\n\nvoid CAnyElementsMgr::Reset() { _cur_pos = _controls.begin(); }\n\nCBaseElementCtl *CAnyElementsMgr::GetElement() {\n  CBaseElementCtl *element = NULL;\n  while (_cur_pos != _controls.end()) {\n    element = *_cur_pos;\n    _cur_pos++;\n    return element;\n  }\n  return NULL;\n}\n\nvoid CAnyElementsMgr::Dispose() {\n\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (; ite != _controls.end(); ++ite) {\n    element = *ite;\n    if (element) {\n      delete element;\n    }\n  }\n  _controls.clear();\n\n  _last_mouseon_element = NULL;\n  _rearrange_element = NULL;\n}\n\nvoid CAnyElementsMgr::Dispose(const tstring id) {\n  CBaseElementCtl *element = NULL;\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end();) {\n    element = *ite;\n\n    if (element->GetID() == id) {\n      delete element;\n      _controls.erase(ite++);\n    } else {\n      ite++;\n    }\n  }\n  _last_mouseon_element = NULL;\n}\n\nvoid CAnyElementsMgr::OnMouseDblDown(UINT nFlags, CPoint pt) {\n  CBaseElementCtl *element = NULL;\n\n  list<CBaseElementCtl *>::iterator ite = _controls.begin();\n  for (ite; ite != _controls.end(); ite++) {\n    element = *ite;\n    if ((element->GetVisible() && element->GetHandleMouse()) &&\n        PointInRect(pt, element->Rectangle())) {\n      element->OnMouseDblDown(nFlags, pt);\n    }\n  }\n}\n\nlist<CBaseElementCtl *> *CAnyElementsMgr::GetAllElement() { return &_controls; }\n"
  },
  {
    "path": "src/DirectUI/DUIElementsMgr.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n\nclass CAnyElementsMgr {\npublic:\n  CAnyElementsMgr(void);\n  CAnyElementsMgr(HWND owner) { _owner = owner; }\n  ~CAnyElementsMgr(void);\n\n  void InitOwner(HWND hWnd) { _owner = hWnd; }\n\n  void OnMove();\n  BOOL MouseOnElement(CPoint pt);\n  void OnKeyDown(DWORD dwFlag);\n  void OnKeyUp(DWORD dwFlag);\n  void OnMouseClick(CPoint pt);\n  void OnMouseDown(UINT nFlags, CPoint pt);\n  void OnMouseDblDown(UINT nFlags, CPoint pt);\n  void OnMouseUp(UINT nFlags, CPoint pt);\n  void OnMouseRUp(UINT nFlags, CPoint pt);\n  void OnMouseLDbClick(UINT nFlags, CPoint pt);\n  void OnMouseLeave();\n  void OnMouseMove(UINT nFlags, CPoint pt);\n  void OnPaint(HDC hDC);\n  void OnSizeChanged(DUI_Size wndChangingSize, int w, int h);\n  void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);\n  void RearrangeElement(CBaseElementCtl *e);\n  void AddElement(CBaseElementCtl *element);\n  void AddElement2(CBaseElementCtl *element);\n  void DrawCursor();\n  void SetActive(CBaseElementCtl *element);\n  void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  CBaseElementCtl *Search(const tstring id);\n  CBaseElementCtl *GetElement();\n  void Reset();\n  void Dispose();\n  void Dispose(const tstring id);\n  std::list<CBaseElementCtl *> *GetAllElement();\n  DWORD EleNum() { return _controls.size(); }\n\nprivate:\n  std::list<CBaseElementCtl *> _controls;\n  CBaseElementCtl *_last_mouseon_element;\n  HWND _owner;\n  CBaseElementCtl *_rearrange_element;\n  BOOL _visible;\n  std::list<CBaseElementCtl *>::iterator _cur_pos;\n\nprotected:\n  BOOL PointInRect(CPoint pt, CRect rect);\n};\n\ninline BOOL CAnyElementsMgr::PointInRect(CPoint pt, CRect rect) {\n  return (((pt.x >= rect.left) && (pt.x <= rect.right)) &&\n          ((pt.y >= rect.top) && (pt.y <= rect.bottom)));\n}\n\n"
  },
  {
    "path": "src/DirectUI/DUIGDIResource.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Util/UtilApi.h\"\n#include \"DUIGDIResource.h\"\n\nusing namespace std;\n\nstatic constexpr LPCTSTR glpszFontName[] = { _T(\"Tahoma\"), _T(\"Microsoft Yahei\") };\n\nHFONT CGDIResource::m_hNormalFont = NULL;\nHFONT CGDIResource::m_hNormalBoldFont = NULL;\nHFONT CGDIResource::m_hBiggerBoldFont = NULL;\nHFONT CGDIResource::m_hSmallFont = NULL;\nHFONT CGDIResource::m_BiggerFont = NULL;\nHFONT CGDIResource::m_hUnderLineFont = NULL;\nULONG_PTR CGDIResource::m_Token = 0;\nmap<tstring, HBITMAP> CGDIResource::m_mapAllRes;\nint CGDIResource::m_nRef = 0;\nCriticalSection CGDIResource::m_cs;\n\nCGDIResource::CGDIResource() {}\n\nCGDIResource::~CGDIResource() {}\n\nvoid CGDIResource::Initialize(LPCTSTR lpszResPath) {\n  m_strResPath = lpszResPath;\n  m_cs.Lock();\n  if (m_nRef == 0) {\n\n    Gdiplus::GdiplusStartupInput input;\n    Gdiplus::GdiplusStartup(&m_Token, &input, NULL);\n  }\n  m_nRef = m_nRef + 1;\n  m_cs.UnLock();\n}\nvoid CGDIResource::UnInitialize() {\n  m_cs.Lock();\n  if (m_nRef > 0)\n    m_nRef = m_nRef - 1;\n  if (m_nRef == 0) {\n    Dispose();\n\n    Gdiplus::GdiplusShutdown(m_Token);\n  }\n  m_cs.UnLock();\n}\n\nvoid CGDIResource::Dispose() {\n  HBITMAP hBitmap = NULL;\n  map<tstring, HBITMAP>::iterator ite = m_mapAllRes.begin();\n  for (ite; ite != m_mapAllRes.end(); ite++) {\n    hBitmap = ite->second;\n    if (hBitmap) {\n      ::DeleteObject(hBitmap);\n    }\n  }\n  m_mapAllRes.clear();\n\n  if (m_hNormalFont) {\n    ::DeleteObject(m_hNormalFont);\n    m_hNormalFont = NULL;\n  }\n  if (m_hNormalBoldFont) {\n    ::DeleteObject(m_hNormalBoldFont);\n    m_hNormalBoldFont = NULL;\n  }\n  if (m_hBiggerBoldFont) {\n    ::DeleteObject(m_hBiggerBoldFont);\n    m_hBiggerBoldFont = NULL;\n  }\n  if (m_hSmallFont) {\n    ::DeleteObject(m_hSmallFont);\n    m_hSmallFont = NULL;\n  }\n  if (m_hUnderLineFont) {\n    ::DeleteObject(m_hUnderLineFont);\n    m_hUnderLineFont = NULL;\n  }\n}\n\nvoid CGDIResource::GDI_DrawImageStretch(HDC hDC, HBITMAP hBitmap, CRect rcDest,\n                                        CRect rcBmp, BYTE uFade,\n                                        CRect rcCorners) {\n  HDC hdcMem = CreateCompatibleDC(hDC);\n  HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap);\n\n  ATLASSERT(rcBmp.Width() > rcCorners.left + rcCorners.right);\n  ATLASSERT(rcBmp.Height() > rcCorners.top + rcCorners.bottom);\n\n  BLENDFUNCTION bf = {AC_SRC_OVER, 0, uFade, AC_SRC_ALPHA};\n\n  AlphaBlend(hDC, rcDest.left, rcDest.top, rcCorners.left, rcCorners.top,\n             hdcMem, rcBmp.left, rcBmp.top, rcCorners.left, rcCorners.top, bf);\n\n  AlphaBlend(hDC, rcDest.left + rcCorners.left, rcDest.top,\n             rcDest.Width() - rcCorners.left - rcCorners.right, rcCorners.top,\n             hdcMem, rcBmp.left + rcCorners.left, rcBmp.top,\n             rcBmp.Width() - rcCorners.left - rcCorners.right, rcCorners.top,\n             bf);\n\n  AlphaBlend(hDC, rcDest.right - rcCorners.right, rcDest.top, rcCorners.right,\n             rcCorners.top, hdcMem, rcBmp.right - rcCorners.right, rcBmp.top,\n             rcCorners.right, rcCorners.top, bf);\n\n  AlphaBlend(hDC, rcDest.left, rcDest.top + rcCorners.top, rcCorners.left,\n             rcDest.Height() - rcCorners.top - rcCorners.bottom, hdcMem,\n             rcBmp.left, rcBmp.top + rcCorners.top, rcCorners.left,\n             rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf);\n\n  AlphaBlend(hDC, rcDest.left + rcCorners.left, rcDest.top + rcCorners.top,\n             rcDest.Width() - rcCorners.left - rcCorners.right,\n             rcDest.Height() - rcCorners.top - rcCorners.bottom, hdcMem,\n             rcBmp.left + rcCorners.left, rcBmp.top + rcCorners.top,\n             rcBmp.Width() - rcCorners.left - rcCorners.right,\n             rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf);\n\n  AlphaBlend(\n      hDC, rcDest.right - rcCorners.right, rcDest.top + rcCorners.top,\n      rcCorners.right, rcDest.Height() - rcCorners.top - rcCorners.bottom,\n      hdcMem, rcBmp.right - rcCorners.right, rcBmp.top + rcCorners.top,\n      rcCorners.right, rcBmp.Height() - rcCorners.top - rcCorners.bottom, bf);\n\n  AlphaBlend(hDC, rcDest.left, rcDest.bottom - rcCorners.bottom, rcCorners.left,\n             rcCorners.bottom, hdcMem, rcBmp.left,\n             rcBmp.bottom - rcCorners.bottom, rcCorners.left, rcCorners.bottom,\n             bf);\n\n  AlphaBlend(\n      hDC, rcDest.left + rcCorners.left, rcDest.bottom - rcCorners.bottom,\n      rcDest.Width() - rcCorners.left - rcCorners.right, rcCorners.bottom,\n      hdcMem, rcBmp.left + rcCorners.left, rcBmp.bottom - rcCorners.bottom,\n      rcBmp.Width() - rcCorners.left - rcCorners.right, rcCorners.bottom, bf);\n\n  AlphaBlend(\n      hDC, rcDest.right - rcCorners.right, rcDest.bottom - rcCorners.bottom,\n      rcCorners.right, rcCorners.bottom, hdcMem, rcBmp.right - rcCorners.right,\n      rcBmp.bottom - rcCorners.bottom, rcCorners.right, rcCorners.bottom, bf);\n\n  SelectObject(hdcMem, hBmpOld);\n  DeleteDC(hdcMem);\n}\n\nvoid CGDIResource::GDI_DrawImage(HDC hDC, Bitmap *pBmp, int nLeft, int nTop,\n                                 int nWidth, int nHeight, BOOL bTransparent) {\n  Graphics g(hDC);\n  if (bTransparent) {\n    ImageAttributes imageAtt;\n    imageAtt.SetColorKey(Color(255, 0, 255), Color(255, 0, 255));\n\n    Rect rcDst(nLeft, nTop, nWidth, nHeight);\n    g.DrawImage(pBmp, rcDst, 0, 0, pBmp->GetWidth(), pBmp->GetHeight(),\n                UnitPixel, &imageAtt);\n  } else {\n    TextureBrush brush(pBmp, WrapModeTile,\n                       Rect(0, 0, pBmp->GetWidth(), pBmp->GetHeight()));\n    brush.TranslateTransform((REAL)nLeft, (REAL)nTop);\n    g.FillRectangle(&brush, nLeft, nTop, nWidth, nHeight);\n  }\n}\n\nvoid CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, int nLeft, int nTop,\n                                 int nWidth, int nHeight,\n                                 DUI_BITMAP_TYPE bmpType, DWORD trans) {\n  HDC hdcMem = CreateCompatibleDC(hDC);\n  HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap);\n\n  BITMAP bmInfor;\n  GetObject(hBitmap, sizeof(bmInfor), &bmInfor);\n\n  if (bmpType != DUI_BT_ALPHA) {\n\n    TransparentBlt(hDC, nLeft, nTop, nWidth, nHeight, hdcMem, 0, 0,\n                   bmInfor.bmWidth, bmInfor.bmHeight, TRANSPARENT_COLOR);\n  } else {\n\n    BLENDFUNCTION bf;\n    bf.BlendOp = AC_SRC_OVER;\n    bf.BlendFlags = 0;\n    if (trans < 0 || trans > 0xFF)\n      trans = 0xFF;\n    bf.SourceConstantAlpha = static_cast<BYTE>(trans);\n    bf.AlphaFormat = AC_SRC_ALPHA;\n    AlphaBlend(hDC, nLeft, nTop, nWidth, nHeight, hdcMem, 0, 0, bmInfor.bmWidth,\n               bmInfor.bmHeight, bf);\n  }\n  SelectObject(hdcMem, hBmpOld);\n  DeleteDC(hdcMem);\n}\n\nvoid CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, LPRECT rcDest,\n                                 DUI_BITMAP_TYPE bmpType, DWORD trans) {\n  GDI_DrawImage(hDC, hBitmap, rcDest->left, rcDest->top,\n                rcDest->right - rcDest->left, rcDest->bottom - rcDest->top,\n                bmpType, trans);\n}\n\nvoid CGDIResource::GDI_DrawImage(HDC hDC, HBITMAP hBitmap, DUI_Rect &rcDest,\n                                 DUI_Rect &rcSrc, DUI_BITMAP_TYPE bmpType) {\n  HDC hdcMem = CreateCompatibleDC(hDC);\n  HBITMAP hBmpOld = (HBITMAP)SelectObject(hdcMem, hBitmap);\n\n  if (bmpType != DUI_BT_ALPHA) {\n\n    TransparentBlt(hDC, rcDest.left, rcDest.top, rcDest.Width(),\n                   rcDest.Height(), hdcMem, rcSrc.left, rcSrc.top,\n                   rcSrc.Width(), rcSrc.Height(), TRANSPARENT_COLOR);\n\n  } else {\n\n    BLENDFUNCTION bf;\n    bf.BlendOp = AC_SRC_OVER;\n    bf.BlendFlags = 0;\n    bf.SourceConstantAlpha = 0xFF;\n    bf.AlphaFormat = AC_SRC_ALPHA;\n    AlphaBlend(hDC, rcDest.left, rcDest.top, rcDest.Width(), rcDest.Height(),\n               hdcMem, rcSrc.left, rcSrc.top, rcSrc.Width(), rcSrc.Height(),\n               bf);\n  }\n  SelectObject(hdcMem, hBmpOld);\n  DeleteDC(hdcMem);\n}\n\nvoid CGDIResource::GDI_DrawIcon(HDC hDC, HICON hIcon, int nLeft, int nTop) {\n  ::DrawIcon(hDC, nLeft, nTop, hIcon);\n}\n\nvoid CGDIResource::GDI_DrawIconEx(HDC hDC, HICON hIcon, int nLeft, int nTop,\n                                  int nWidth, int nHeight) {\n  ::DrawIconEx(hDC, nLeft, nTop, hIcon, nWidth, nHeight, 0, NULL,\n               DI_IMAGE | DI_MASK);\n}\n\nvoid CGDIResource::GDI_DrawLine(HDC hDC, int nBegX, int nBegY, int nEndX,\n                                int nEndY, COLORREF colLine) {\n  HPEN hPen = CreatePen(PS_SOLID, 0, colLine);\n  HPEN hPenOld = (HPEN)SelectObject(hDC, hPen);\n\n  MoveToEx(hDC, nBegX, nBegY, (LPPOINT)NULL);\n  LineTo(hDC, nEndX, nEndY);\n  SelectObject(hDC, hPenOld);\n  DeleteObject(hPen);\n}\n\nvoid CGDIResource::GDI_DrawLine_trans(HDC hDC, int nBegX, int nBegY, int nEndX,\n                                      int nEndY, COLORREF colLine) {\n  Graphics g(hDC);\n  Color col(Color::MakeARGB(254, GetRValue(colLine), GetGValue(colLine),\n                            GetBValue(colLine)));\n  Pen p(col, 1.0);\n  g.DrawLine(&p, nBegX, nBegY, nEndX, nEndY);\n}\n\nvoid CGDIResource::GDI_DrawDotLine(HDC hDC, int nBegX, int nBegY, int nEndX,\n                                   int nEndY, COLORREF colLine) {\n  HPEN hPen = CreatePen(PS_DOT, 0, colLine);\n  HPEN hPenOld = (HPEN)SelectObject(hDC, hPen);\n\n  MoveToEx(hDC, nBegX, nBegY, (LPPOINT)NULL);\n  LineTo(hDC, nEndX, nEndY);\n  SelectObject(hDC, hPenOld);\n  DeleteObject(hPen);\n}\n\nvoid CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                HFONT hFont, COLORREF colText, UINT nFormat) {\n  CDCHandle dc(hDC);\n  dc.SetBkMode(TRANSPARENT);\n  HFONT hOldFont = dc.SelectFont(hFont);\n  dc.SetTextColor(colText);\n  dc.DrawText(strText, lstrlen(strText), rcText, nFormat);\n  dc.SelectFont(hOldFont);\n}\n\nvoid CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                UINT nFormat) {\n  GDI_DrawText(hDC, strText, rcText, GDI_GetNormalFont(), RGB(0, 0, 0),\n               nFormat);\n}\n\nvoid CGDIResource::GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                COLORREF colText, UINT nFormat) {\n  GDI_DrawText(hDC, strText, rcText, GDI_GetNormalFont(), colText, nFormat);\n}\n\nvoid CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                      HFONT hFont, COLORREF colText,\n                                      UINT nFormat) {\n  Graphics g(hDC);\n  Color col(Color::MakeARGB(254, GetRValue(colText), GetGValue(colText),\n                            GetBValue(colText)));\n  SolidBrush brush(col);\n  Gdiplus::Font font(hDC, hFont);\n  RectF rf(rcText->left, rcText->top, rcText->right - rcText->left,\n           rcText->bottom - rcText->top);\n  StringFormat sf;\n  if (nFormat & DT_LEFT) {\n    sf.SetAlignment(StringAlignmentNear);\n  } else if (nFormat & DT_CENTER) {\n    sf.SetAlignment(StringAlignmentCenter);\n  } else if (nFormat & DT_RIGHT) {\n    sf.SetAlignment(StringAlignmentFar);\n  }\n  if (nFormat & DT_VCENTER) {\n    sf.SetLineAlignment(StringAlignmentCenter);\n  } else {\n    sf.SetLineAlignment(StringAlignmentNear);\n  }\n\n  if (nFormat & DT_SINGLELINE) {\n    sf.SetFormatFlags(StringFormatFlagsNoWrap);\n  }\n  if (nFormat & DT_END_ELLIPSIS) {\n    sf.SetTrimming(StringTrimmingEllipsisCharacter);\n  }\n\n  g.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);\n  g.DrawString(strText, -1, &font, rf, &sf, &brush);\n}\n\nvoid CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                      COLORREF colText, UINT nFormat) {\n  GDI_DrawText_Trans(hDC, strText, rcText, GDI_GetNormalFont(), colText,\n                     nFormat);\n}\n\nvoid CGDIResource::GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                      UINT nFormat) {\n  GDI_DrawText_Trans(hDC, strText, rcText, GDI_GetNormalFont(), RGB(0, 0, 0),\n                     nFormat);\n}\n\nvoid CGDIResource::GDI_FillRectBack(HDC hDC, LPRECT rc, COLORREF colBrush) {\n  CDCHandle dc(hDC);\n  HBRUSH hBrush = CreateSolidBrush(colBrush);\n  HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hBrush);\n  dc.FillRect(rc, hBrush);\n  ::SelectObject(hDC, hOldBrush);\n  DeleteObject(hBrush);\n}\n\nvoid CGDIResource::GDI_DrawRectangle(HDC hDC, LPRECT rc, COLORREF colBorder,\n                                     COLORREF colBrush) {\n  HPEN hPen = CreatePen(PS_SOLID, 1, colBorder);\n  HPEN hOldPen = (HPEN)SelectObject(hDC, hPen);\n  HBRUSH hBrush = CreateSolidBrush(colBrush);\n  HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);\n  Rectangle(hDC, rc->left, rc->top, rc->right, rc->bottom);\n  SelectObject(hDC, hOldPen);\n  SelectObject(hDC, hOldBrush);\n  DeleteObject(hPen);\n  DeleteObject(hBrush);\n}\n\nvoid CGDIResource::GDI_DrawRectangle_Trans(HDC hDC, LPRECT rc,\n                                           COLORREF colBorder,\n                                           COLORREF colBrush) {\n  Graphics g(hDC);\n  Color colPen(Color::MakeARGB(254, GetRValue(colBorder), GetGValue(colBorder),\n                               GetBValue(colBorder)));\n  Color colBru(Color::MakeARGB(254, GetRValue(colBrush), GetGValue(colBrush),\n                               GetBValue(colBrush)));\n  SolidBrush brush(colBru);\n  Pen pen(colPen);\n  g.FillRectangle(&brush, rc->left, rc->top, rc->right - rc->left,\n                  rc->bottom - rc->top);\n  g.DrawRectangle(&pen, rc->left, rc->top, rc->right - rc->left,\n                  rc->bottom - rc->top);\n  g.ReleaseHDC(hDC);\n}\n\nvoid CGDIResource::GDI_DrawRoundRectangle(HDC hDC, LPRECT rc,\n                                          COLORREF colBorder,\n                                          COLORREF colBrush) {\n  HPEN hPen = CreatePen(PS_SOLID, 1, colBorder);\n  HPEN hOldPen = (HPEN)SelectObject(hDC, hPen);\n  HBRUSH hBrush = CreateSolidBrush(colBrush);\n  HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);\n  RoundRect(hDC, rc->left, rc->top, rc->right, rc->bottom, 3, 3);\n  SelectObject(hDC, hOldPen);\n  SelectObject(hDC, hOldBrush);\n  DeleteObject(hPen);\n  DeleteObject(hBrush);\n}\n\nvoid CGDIResource::GDI_DrawRoundRectangle_Trans(HDC hDC, LPRECT rc,\n                                                COLORREF colBorder,\n                                                COLORREF colBrush) {\n  Graphics g(hDC);\n  Color colPen(Color::MakeARGB(254, GetRValue(colBorder), GetGValue(colBorder),\n                               GetBValue(colBorder)));\n  Color colBru(Color::MakeARGB(254, GetRValue(colBrush), GetGValue(colBrush),\n                               GetBValue(colBrush)));\n  SolidBrush brush(colBru);\n  Pen pen(colPen);\n\n  GraphicsPath *path = MakeRoundRect(rc, 6);\n  g.FillPath(&brush, path);\n  g.DrawPath(&pen, path);\n\n  delete path;\n}\n\nHBITMAP CGDIResource::GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName,\n                                    int nResType) {\n\n  map<tstring, HBITMAP>::iterator ite = m_mapAllRes.find(pszResName);\n  if (ite != m_mapAllRes.end()) {\n    return (HBITMAP)(ite->second);\n  }\n\n  HGLOBAL hGlobalReal = NULL;\n  HRSRC hRes = FindResource(hInstance, pszResName, MAKEINTRESOURCE(nResType));\n  if (hRes) {\n    HGLOBAL hGlobal = LoadResource(hInstance, hRes);\n    if (hGlobal) {\n      DWORD dwSize = SizeofResource(hInstance, hRes);\n      hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);\n\n      LPVOID pDest = ::GlobalLock(hGlobalReal);\n      LPVOID pSrc = ::LockResource(hGlobal);\n      ::CopyMemory(pDest, pSrc, dwSize);\n      ::FreeResource(hRes);\n    }\n  }\n\n  Gdiplus::Bitmap *pBitmap = NULL;\n  if (hGlobalReal) {\n    CComPtr<IStream> pStm;\n\n    HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm);\n    if (hr == S_OK && pStm)\n      pBitmap = new Gdiplus::Bitmap(pStm, FALSE);\n\n    GlobalUnlock(hGlobalReal);\n    GlobalFree(hGlobalReal);\n    hGlobalReal = NULL;\n  }\n\n  if (pBitmap == NULL)\n    return NULL;\n\n  HBITMAP hBitmap = NULL;\n  if (pBitmap->GetLastStatus() == Gdiplus::Ok)\n    pBitmap->GetHBITMAP(NULL, &hBitmap);\n\n  delete pBitmap;\n\n  m_mapAllRes[pszResName] = hBitmap;\n\n  return hBitmap;\n}\n\nHBITMAP CGDIResource::GDI_GetBitmap_NoCache(HINSTANCE hInstance,\n                                            LPCTSTR pszResName, int nResType) {\n  HGLOBAL hGlobalReal = NULL;\n  HRSRC hRes = FindResource(hInstance, pszResName, MAKEINTRESOURCE(nResType));\n  if (hRes) {\n    HGLOBAL hGlobal = LoadResource(hInstance, hRes);\n    if (hGlobal) {\n      DWORD dwSize = SizeofResource(hInstance, hRes);\n      hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);\n\n      LPVOID pDest = ::GlobalLock(hGlobalReal);\n      LPVOID pSrc = ::LockResource(hGlobal);\n      ::CopyMemory(pDest, pSrc, dwSize);\n      ::FreeResource(hRes);\n    }\n  }\n\n  Gdiplus::Bitmap *pBitmap = NULL;\n  if (hGlobalReal) {\n    CComPtr<IStream> pStm;\n\n    HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm);\n    if (hr == S_OK && pStm)\n      pBitmap = new Gdiplus::Bitmap(pStm, FALSE);\n\n    GlobalUnlock(hGlobalReal);\n    GlobalFree(hGlobalReal);\n    hGlobalReal = NULL;\n  }\n\n  if (pBitmap == NULL)\n    return NULL;\n\n  HBITMAP hBitmap = NULL;\n  if (pBitmap->GetLastStatus() == Gdiplus::Ok)\n    pBitmap->GetHBITMAP(NULL, &hBitmap);\n\n  delete pBitmap;\n\n  return hBitmap;\n}\n\nHBITMAP CGDIResource::GDI_GetBitmap_NoCache(LPCTSTR lpszFileName) {\n  if (lstrlen(lpszFileName) == 0) {\n    return NULL;\n  }\n\n  HBITMAP hBitmap = NULL;\n\n  Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromFile(lpszFileName);\n  if (pBitmap->GetLastStatus() == Gdiplus::Ok)\n    pBitmap->GetHBITMAP(NULL, &hBitmap);\n  delete pBitmap;\n\n  return hBitmap;\n}\n\nHBITMAP CGDIResource::GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName,\n                                    LPCTSTR lpszResType) {\n  map<tstring, HBITMAP>::iterator ite = m_mapAllRes.find(pszResName);\n  if (ite != m_mapAllRes.end()) {\n    return (HBITMAP)(ite->second);\n  }\n\n  HGLOBAL hGlobalReal = NULL;\n  HRSRC hRes = FindResource(hInstance, pszResName, lpszResType);\n  if (hRes) {\n    HGLOBAL hGlobal = LoadResource(hInstance, hRes);\n    if (hGlobal) {\n      DWORD dwSize = SizeofResource(hInstance, hRes);\n      hGlobalReal = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, dwSize);\n\n      LPVOID pDest = ::GlobalLock(hGlobalReal);\n      LPVOID pSrc = ::LockResource(hGlobal);\n      ::CopyMemory(pDest, pSrc, dwSize);\n      ::FreeResource(hRes);\n    }\n  }\n\n  Gdiplus::Bitmap *pBitmap = NULL;\n  if (hGlobalReal) {\n    CComPtr<IStream> pStm;\n\n    HRESULT hr = CreateStreamOnHGlobal(hGlobalReal, TRUE, &pStm);\n    if (hr == S_OK && pStm)\n      pBitmap = new Gdiplus::Bitmap(pStm, FALSE);\n\n    GlobalUnlock(hGlobalReal);\n    GlobalFree(hGlobalReal);\n    hGlobalReal = NULL;\n  }\n\n  if (pBitmap == NULL)\n    return NULL;\n\n  HBITMAP hBitmap = NULL;\n  if (pBitmap->GetLastStatus() == Gdiplus::Ok)\n    pBitmap->GetHBITMAP(NULL, &hBitmap);\n\n  delete pBitmap;\n\n  m_mapAllRes[pszResName] = hBitmap;\n\n  return hBitmap;\n}\n\nHBITMAP CGDIResource::GDI_GetBitmap(LPCTSTR lpszFileName) {\n  if (lstrlen(lpszFileName) == 0) {\n    return NULL;\n  }\n\n  map<tstring, HBITMAP>::iterator ite = m_mapAllRes.find(lpszFileName);\n  if (ite != m_mapAllRes.end()) {\n    return (HBITMAP)(ite->second);\n  }\n\n  HBITMAP hBitmap = NULL;\n\n  Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromFile(lpszFileName);\n  if (pBitmap->GetLastStatus() == Gdiplus::Ok)\n    pBitmap->GetHBITMAP(NULL, &hBitmap);\n\n  delete pBitmap;\n\n  m_mapAllRes[lpszFileName] = hBitmap;\n\n  return hBitmap;\n}\n\nHFONT CGDIResource::GDI_GetNormalFont() {\n  if (m_hNormalFont)\n    return m_hNormalFont;\n\n  LANGID lanId = GetSystemDefaultLangID();\n\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {13, 18};\n\n  if (0x804 == lanId) {\n    m_hNormalFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                               0, 0, glpszFontName[nIndex]);\n  } else {\n    m_hNormalFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                               0, 0, _T(\"Arial\"));\n  }\n  return m_hNormalFont;\n}\n\nHFONT CGDIResource::GDI_GetNormalBoldFont() {\n  if (m_hNormalBoldFont)\n    return m_hNormalBoldFont;\n\n  LANGID lanId = GetSystemDefaultLangID();\n\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {13, 18};\n\n  if (0x804 == lanId) {\n    m_hNormalBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0,\n                                   0, 0, 0, 0, 0, glpszFontName[nIndex]);\n  } else {\n    m_hNormalBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0,\n                                   0, 0, 0, 0, 0, L\"Arial\");\n  }\n  return m_hNormalBoldFont;\n}\n\nHFONT CGDIResource::GDI_GetBiggerFont() {\n  if (m_BiggerFont)\n    return m_BiggerFont;\n\n  LANGID lanId = GetSystemDefaultLangID();\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {16, 21};\n\n  if (0x804 == lanId) {\n    m_BiggerFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                              0, 0, glpszFontName[nIndex]);\n  } else {\n    m_BiggerFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n                              0, 0, L\"Arial\");\n  }\n  return m_BiggerFont;\n}\n\nHFONT CGDIResource::GDI_GetBiggerBoldFont() {\n  if (m_hBiggerBoldFont) {\n    return m_hBiggerBoldFont;\n  }\n\n  LANGID lanId = GetSystemDefaultLangID();\n\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {16, 20};\n\n  if (0x804 == lanId) {\n    m_hBiggerBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0,\n                                   0, 0, 0, 0, 0, glpszFontName[nIndex]);\n  } else {\n    m_hBiggerBoldFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0,\n                                   0, 0, 0, 0, 0, L\"Arial\");\n  }\n  return m_hBiggerBoldFont;\n}\n\nHFONT CGDIResource::GDI_GetSmallFont() {\n  if (m_hSmallFont)\n    return m_hSmallFont;\n\n  LANGID lanId = GetSystemDefaultLangID();\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {12, 14};\n\n  if (0x804 == lanId) {\n    m_hSmallFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0,\n                              0, 0, 0, 0, glpszFontName[nIndex]);\n  } else {\n    m_hSmallFont = CreateFont(nFontSize[nIndex], 0, 0, 0, FW_BOLD, 0, 0, 0, 0,\n                              0, 0, 0, 0, L\"Arial\");\n  }\n  return m_hSmallFont;\n}\n\nHFONT CGDIResource::GDI_GetUnderlineFont() {\n  if (m_hUnderLineFont)\n    return m_hUnderLineFont;\n\n  LANGID lanId = GetSystemDefaultLangID();\n  int nIndex = Util::Tools::IsWin7() ? 1 : 0;\n  int nFontSize[] = {13, 18};\n\n  if (0x804 == lanId) {\n    m_hUnderLineFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, TRUE, 0, 0,\n                                  0, 0, 0, 0, glpszFontName[nIndex]);\n  } else {\n    m_hUnderLineFont = CreateFont(nFontSize[nIndex], 0, 0, 0, 0, 0, TRUE, 0, 0,\n                                  0, 0, 0, 0, L\"Arial\");\n  }\n  return m_hUnderLineFont;\n}\n\ntstring CGDIResource::GDI_GetIconPath(LPCTSTR lpszIconFileName) {\n  TCHAR szPath[MAX_PATH] = {0};\n  _sntprintf_s(szPath, MAX_PATH, _TRUNCATE, _T(\"%s\"), m_strResPath.c_str());\n  PathAppend(szPath, lpszIconFileName);\n\n  return szPath;\n}\n\nHICON CGDIResource::GDI_GetIcon(LPCTSTR lpszIconFileName) {\n  return (HICON)LoadImage(NULL, lpszIconFileName, IMAGE_ICON, 0, 0,\n                          LR_LOADFROMFILE);\n}\n\nHICON CGDIResource::GDI_GetIcon(LPCTSTR lpszIconFileName, int cx, int cy) {\n  return (HICON)LoadImage(NULL, lpszIconFileName, IMAGE_ICON, cx, cy,\n                          LR_LOADFROMFILE);\n}\n\nHICON CGDIResource::GDI_GetIcon(UINT nResourceID) {\n  return (HICON)LoadImage(_hInstance, MAKEINTRESOURCE(nResourceID), IMAGE_ICON,\n                          0, 0, LR_LOADFROMFILE);\n}\n\nGraphicsPath *CGDIResource::MakeRoundRect(LPRECT rc, INT percentageRounded) {\n  INT left = rc->left;\n  INT right = rc->right;\n\n  INT top = rc->top;\n  INT bottom = rc->bottom;\n\n  INT offsetX = (right - left) * percentageRounded / 100;\n  INT offsetY = (bottom - top) * percentageRounded / 100;\n\n  GraphicsPath pt;\n  GraphicsPath *path = pt.Clone();\n\n  path->AddArc(right - offsetX, top, offsetX, offsetY, 270, 90);\n  path->AddArc(right - offsetX, bottom - offsetY, offsetX, offsetY, 0, 90);\n  path->AddArc(left, bottom - offsetY, offsetX, offsetY, 90, 90);\n  path->AddArc(left, top, offsetX, offsetY, 180, 90);\n  path->AddLine(left + offsetX, top, right - offsetX / 2, top);\n  return path;\n}\n"
  },
  {
    "path": "src/DirectUI/DUIGDIResource.h",
    "content": "#pragma once\n\n#include <gdiplus.h>\n#include \"util/util_tools.h\"\n#include \"DUIDef.h\"\n\nusing namespace Gdiplus;\n\nclass CGDIResource {\npublic:\n  CGDIResource();\n  virtual ~CGDIResource();\n\n  static CGDIResource &GetInstance() {\n    static CGDIResource This;\n    return This;\n  }\n\n  void Initialize(LPCTSTR lpszResPath);\n  void UnInitialize();\n\n  void Dispose();\n\n  virtual void GDI_DrawImageStretch(HDC hDC, HBITMAP hBitmap, CRect rcDest,\n                                    CRect rcBmp, BYTE uFade, CRect rcCorners);\n\n  virtual void GDI_DrawImage(HDC hDC, Bitmap *pBmp, int nLeft, int nTop,\n                             int nWidth, int nHeight, BOOL bTransparent = TRUE);\n  virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, int nLeft, int nTop,\n                             int nWidth, int nHeight,\n                             DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA,\n                             DWORD dwtrans = 0xFF);\n  virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, LPRECT rcDest,\n                             DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA,\n                             DWORD dwtrans = 0xFF);\n  virtual void GDI_DrawImage(HDC hDC, HBITMAP hBitmap, DUI_Rect &rcDest,\n                             DUI_Rect &rcSrc,\n                             DUI_BITMAP_TYPE bmpType = DUI_BT_ALPHA);\n\n  virtual void GDI_DrawIcon(HDC hDC, HICON hIcon, int nLeft, int nTop);\n  virtual void GDI_DrawIconEx(HDC hDC, HICON hIcon, int nLeft, int nTop,\n                              int nWidth, int nHeight);\n  virtual void GDI_DrawLine(HDC hDC, int nBegX, int nBegY, int nEndX, int nEndY,\n                            COLORREF colLine = RGB(0, 0, 0));\n  virtual void GDI_DrawDotLine(HDC hDC, int nBegX, int nBegY, int nEndX,\n                               int nEndY, COLORREF colLine = RGB(0, 0, 0));\n\n  virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                            HFONT hFont, COLORREF colText = RGB(0, 0, 0),\n                            UINT nFormat = DT_LEFT);\n  virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                            COLORREF colText, UINT nFormat = DT_LEFT);\n  virtual void GDI_DrawText(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                            UINT nFormat = DT_LEFT);\n\n  virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                  HFONT hFont, COLORREF colText = RGB(0, 0, 0),\n                                  UINT nFormat = DT_LEFT);\n  virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                  COLORREF colText, UINT nFormat = DT_LEFT);\n  virtual void GDI_DrawText_Trans(HDC hDC, LPCTSTR strText, LPRECT rcText,\n                                  UINT nFormat = DT_LEFT);\n\n  virtual void GDI_FillRectBack(HDC hDC, LPRECT rc, COLORREF colBrush);\n\n  virtual void GDI_DrawRectangle(HDC hDC, LPRECT rc,\n                                 COLORREF colBorder = RGB(0, 0, 0),\n                                 COLORREF colBrush = RGB(255, 255, 255));\n  virtual void GDI_DrawRectangle_Trans(HDC hDC, LPRECT rc,\n                                       COLORREF colBorder = RGB(0, 0, 0),\n                                       COLORREF colBrush = RGB(255, 255, 255));\n  virtual void GDI_DrawRoundRectangle(HDC hDC, LPRECT rc,\n                                      COLORREF colBorder = RGB(0, 0, 0),\n                                      COLORREF colBrush = RGB(255, 255, 255));\n  virtual void GDI_DrawRoundRectangle_Trans(HDC hDC, LPRECT rc,\n                                            COLORREF colBorder = RGB(0, 0, 0),\n                                            COLORREF colBrush = RGB(255, 255,\n                                                                    255));\n\n  virtual HBITMAP GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName,\n                                int nResType);\n  virtual HBITMAP GDI_GetBitmap(HINSTANCE hInstance, LPCTSTR pszResName,\n                                LPCTSTR lpszResType);\n  virtual HBITMAP GDI_GetBitmap(LPCTSTR lpszFileName);\n  virtual HBITMAP GDI_GetBitmap_NoCache(HINSTANCE hInstance, LPCTSTR pszResName,\n                                        int nResType);\n  virtual HBITMAP GDI_GetBitmap_NoCache(LPCTSTR lpszFileName);\n\n  virtual HFONT GDI_GetNormalFont();\n  virtual HFONT GDI_GetNormalBoldFont();\n  virtual HFONT GDI_GetBiggerBoldFont();\n  virtual HFONT GDI_GetBiggerFont();\n  virtual HFONT GDI_GetSmallFont();\n  virtual HFONT GDI_GetUnderlineFont();\n\n  tstring GDI_GetIconPath(LPCTSTR lpszIconFileName);\n\n  virtual HICON GDI_GetIcon(LPCTSTR lpszIconFileName);\n  virtual HICON GDI_GetIcon(LPCTSTR lpszIconFileName, int cx, int cy);\n\n  virtual HICON GDI_GetIcon(UINT nResourceID);\n\n  virtual void GDI_DrawLine_trans(HDC hDC, int nBegX, int nBegY, int nEndX,\n                                  int nEndY, COLORREF colLine = RGB(0, 0, 0));\n\nprotected:\n  GraphicsPath *MakeRoundRect(LPRECT rc, INT percentageRounded);\n\nprotected:\n  tstring m_strResPath;\n  static HFONT m_hNormalFont;\n  static HFONT m_hNormalBoldFont;\n  static HFONT m_hBiggerBoldFont;\n  static HFONT m_hSmallFont;\n  static HFONT m_BiggerFont;\n\n  static HFONT m_hUnderLineFont;\n  static ULONG_PTR m_Token;\n  static std::map<tstring, HBITMAP> m_mapAllRes;\n  static int m_nRef;\n  static CriticalSection m_cs;\n};\n"
  },
  {
    "path": "src/DirectUI/DUIHyperLink.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIHyperLink.h\"\n\nCHyperLinkCtl::CHyperLinkCtl(HWND father, BOOL trans) : CButtonCtl(father) {\n  _host = father;\n  _transparent = trans;\n  _class = _T(\"\");\n  _textFormat = DT_LEFT;\n  _bmpIcon = NULL;\n  _textFont = CGDIResource::GetInstance().GDI_GetNormalFont();\n  _textUnderLineFont = CGDIResource::GetInstance().GDI_GetUnderlineFont();\n}\n\nCHyperLinkCtl::CHyperLinkCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                             LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _host = father;\n  _class = _T(\"\");\n  _linkColor = RGB(54, 151, 242);\n  _visitedColour = RGB(54, 151, 242);\n  _hoverColor = RGB(54, 151, 242);\n  _textFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;\n  _bmpIcon = NULL;\n  _textFont = CGDIResource::GetInstance().GDI_GetNormalFont();\n  _textUnderLineFont = CGDIResource::GetInstance().GDI_GetUnderlineFont();\n}\n\nCHyperLinkCtl::~CHyperLinkCtl(void) {}\n\nvoid CHyperLinkCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n\n  _linkColor = GetRGBAttribute(element, \"linkcolor\");\n  _visitedColour = GetRGBAttribute(element, \"visitedcolor\");\n  _hoverColor = GetRGBAttribute(element, \"hovercolor\");\n}\n\nvoid CHyperLinkCtl::SetLinkColor(COLORREF colLink) { _linkColor = colLink; }\n\nvoid CHyperLinkCtl::SetHoverColor(COLORREF colHover) { _hoverColor = colHover; }\n\nvoid CHyperLinkCtl::SetIcon(LPCTSTR lpszIconRes) {\n  _bmpIcon =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszIconRes, PNG);\n}\n\nvoid CHyperLinkCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    HFONT textFont = _textFont;\n\n    DUI_Rect rcLink(_location, _size);\n\n    COLORREF color = RGB(0, 0, 0);\n    switch (_state) {\n    case DUI_STATE_NORMAL:\n      color = _linkColor;\n      break;\n    case DUI_STATE_DOWN: {\n      textFont = _textUnderLineFont;\n      color = _visitedColour;\n    } break;\n    case DUI_STATE_HOVER: {\n      textFont = _textUnderLineFont;\n      color = _hoverColor;\n    } break;\n    case DUI_STATE_DISABLE:\n      color = RGB(153, 153, 153);\n      break;\n    }\n\n    if (_bmpIcon) {\n      BITMAP bmpIconInfor;\n      GetObject(_bmpIcon, sizeof(bmpIconInfor), &bmpIconInfor);\n\n      int nY = _location.y + (_size.cy - bmpIconInfor.bmHeight) / 2;\n\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, _location.x, nY,\n                                                bmpIconInfor.bmWidth,\n                                                bmpIconInfor.bmHeight);\n\n      rcLink.left = _location.x + bmpIconInfor.bmWidth + 2;\n    }\n\n    if (_transparent) {\n      CGDIResource::GetInstance().GDI_DrawText_Trans(\n          hDC, _title.c_str(), &rcLink, textFont, color, _textFormat);\n    } else {\n      CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcLink,\n                                               textFont, color, _textFormat);\n    }\n  }\n}\nvoid CHyperLinkCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    CButtonCtl::OnMouseHover(nFlags, point);\n    _cursor = LoadCursor(NULL, IDC_HAND);\n  }\n}\n\nvoid CHyperLinkCtl::OnMouseLeave() {\n  CButtonCtl::OnMouseLeave();\n\n  _cursor = LoadCursor(NULL, IDC_ARROW);\n}\n\nvoid CHyperLinkCtl::OnCall_LeftUp() {\n  _leftup_event.Invoke();\n  _leftup_event.Invoke(m_strURL.c_str());\n}\n\nvoid CHyperLinkCtl::GotoURL() {\n\n  HINSTANCE result =\n      ShellExecute(NULL, _T(\"open\"), m_strURL.c_str(), NULL, NULL, SW_SHOW);\n\n  if ((UINT)result <= HINSTANCE_ERROR) {\n  }\n}\n\nvoid CHyperLinkCtl::SetAlignRight() {\n  _textFormat = DT_RIGHT;\n\n  int nTextWidth = GetTextWidth(\n      _title.c_str(), CGDIResource::GetInstance().GDI_GetNormalFont());\n  _location.x = Rectangle().right - nTextWidth;\n  if (_size.cx > nTextWidth) {\n    _size.cx = nTextWidth;\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUIHyperLink.h",
    "content": "#pragma once\n\n#include \"DUIButton.h\"\n\nclass CHyperLinkCtl : public CButtonCtl {\npublic:\n  CHyperLinkCtl(HWND father, BOOL trans = FALSE);\n  CHyperLinkCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                LPCTSTR lpszTooptip, DUI_Rect rcElement);\n  ~CHyperLinkCtl(void);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void SetURL(tstring strURL);\n  void SetAlignRight();\n  void SetLinkColor(COLORREF colLink);\n  void SetHoverColor(COLORREF colHover);\n  void SetIcon(LPCTSTR lpszIconRes);\n\n  virtual void OnMouseHover(UINT nFlags, CPoint point);\n  virtual void OnMouseLeave();\n\n  virtual void OnCall_LeftUp();\n\nprotected:\n  tstring m_strURL;\n  COLORREF _linkColor;\n  COLORREF _visitedColour;\n  COLORREF _hoverColor;\n  UINT _textFormat;\n  HBITMAP _bmpIcon;\n  HFONT _textFont;\n  HFONT _textUnderLineFont;\n\n  void GotoURL();\n};\n\ninline void CHyperLinkCtl::SetURL(tstring strURL) { m_strURL = strURL; }\n"
  },
  {
    "path": "src/DirectUI/DUILayeredEdit.cpp",
    "content": "#include \"StdAfx.h\"\n#include <regex>\n#include \"util/def.h\"\n#include \"../Global.h\"\n#include \"DUILayeredEdit.h\"\n\nCLayeredEditCtl::CLayeredEditCtl(HWND father) : _bmpBack(NULL) {\n  _host = father;\n  _class = _T(\"\");\n  _state = DUI_STATE_NORMAL;\n  _borderColor = RGB(60, 152, 208);\n  _bmpNormal = NULL;\n  _bmpHover = NULL;\n  _bmpIcon = NULL;\n  _readonly = FALSE;\n  _transparent = TRUE;\n  _password = FALSE;\n  _index = 0;\n  _hPopUpWnd = NULL;\n  _LimitText = 5000;\n  _brushColor = RGB(255, 255, 255);\n  _textcolor = RGB(0, 0, 0);\n}\n\nvoid CLayeredEditCtl::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n  _tab = CXmlHelper::GetInstance().GetAttributeInt(element, \"tab\");\n  _index = CXmlHelper::GetInstance().GetAttributeInt(element, \"index\");\n  _bmpNormal = GetBitmapAttribute(element, \"normalBack\");\n  _bmpHover = GetBitmapAttribute(element, \"hoverBack\");\n  _bmpBack = GetBitmapAttribute(element, \"image\");\n  _bmpIcon = GetBitmapAttribute(element, \"icon\");\n  _password = CXmlHelper::GetInstance().GetAttributeInt(element, \"pWd\");\n  _readonly = CXmlHelper::GetInstance().GetAttributeInt(element, \"readonly\");\n  _borderColor = GetRGBAttribute(element, \"bordercolor\");\n  _brushColor = GetRGBAttribute(element, \"backcolor\");\n  _textcolor = GetRGBAttribute(element, \"textcolor\");\n  _editCheckPath = GetIntegerAttribute(element, \"checkpath\");\n\n  if (!_bmpIcon) {\n    DUI_Rect rcEdit(_location, _size);\n    rcEdit.left += 10;\n    rcEdit.right -= 10;\n    rcEdit.top += 5;\n    rcEdit.bottom -= 2;\n    _rcEdit = rcEdit;\n  } else {\n    BITMAP bmpInfor;\n    GetObject(_bmpIcon, sizeof(bmpInfor), &bmpInfor);\n\n    DUI_Rect rcEdit(_location, _size);\n    rcEdit.left += bmpInfor.bmWidth + 10;\n    rcEdit.right -= 10;\n    rcEdit.top += 5;\n    rcEdit.bottom -= 2;\n    _rcEdit = rcEdit;\n  }\n}\n\nvoid CLayeredEditCtl::SetLimitText(int uMax) { _LimitText = uMax; }\n\nvoid CLayeredEditCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    DUI_Rect rc(_location, _size);\n\n    if (_bmpBack)\n      CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, _bmpBack, _location.x, _location.y, _size.cx, _size.cy);\n    else\n      CGDIResource::GetInstance().GDI_DrawRectangle_Trans(\n          hDC, &rc, _borderColor, _brushColor);\n    if (_password) {\n      const int c = _title.length();\n      int i = c;\n      WCHAR *s = new WCHAR[++i];\n      for (int k = 0; k < c; ++k) {\n        s[k] = _T('*');\n      }\n      s[c] = NULL;\n      if (c > 0) {\n        CGDIResource::GetInstance().GDI_DrawText_Trans(\n            hDC, s, &_rcEdit, _textcolor, DT_SINGLELINE);\n      }\n      delete[] s;\n      return;\n    }\n    CGDIResource::GetInstance().GDI_DrawText_Trans(\n        hDC, _title.c_str(), &_rcEdit, _textcolor, DT_SINGLELINE);\n  }\n}\n\nvoid CLayeredEditCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) {}\n\nvoid CLayeredEditCtl::OnMove() {}\n\nLRESULT EditPopWindow::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  if (::IsWindow(m_hWnd)) {\n    RECT rc;\n    GetClientRect(&rc);\n    DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL;\n    m_edit.Create(m_hWnd, rc, NULL, dwStyle, WS_EX_TOOLWINDOW);\n    if (::IsWindow(m_edit.m_hWnd)) {\n      m_edit.SetFont(CGDIResource::GetInstance().GDI_GetNormalFont(), TRUE);\n      ::SetFocus(m_edit.m_hWnd);\n    }\n  }\n  return 0;\n}\n\nLRESULT EditPopWindow::OnPaintChild(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  ::SetBkColor((HDC)wParam, RGB(69, 68, 73));\n  ::SetTextColor((HDC)wParam, RGB(255, 255, 255));\n  return (LRESULT)_hbrush;\n}\n\nLRESULT EditPopWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled) {\n  DestroyWindow();\n  return 0;\n}\n\nvoid EditPopWindow::OnFinalMessage(HWND hWnd) { delete this; }\n\nvoid CLayeredEditCtl::GetTitleIn() {\n  BSTR strText = NULL;\n  _hPopUpWnd->m_edit.GetWindowText(strText);\n  CString strRes = strText;\n  _title = (LPCTSTR)strRes;\n  SysFreeString(strText);\n}\n\nvoid CMyEditEx::DeleObj(void *p) { delete p; }\n\nLRESULT CMyEditEx::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled) {\n  WCHAR nChar = (WCHAR)wParam;\n  if (nChar == 13) {\n    if (m_pOwner) {\n      m_pOwner->OnTabKey();\n      m_pOwner->OnEnterKey();\n    }\n  }\n  if (nChar == 9) {\n    if (m_pOwner) {\n      m_pOwner->OnTabKey();\n    }\n  }\n\n  if (m_pOwner && ::IsWindow(m_pOwner->_host) && m_pOwner->_editCheckPath) {\n    ::PostMessage(m_pOwner->_host, WM_PATH_ILLCHARACTER,\n                  (WPARAM)m_pOwner->_editCheckPath, 0);\n  }\n  bHandled = FALSE;\n  return 0;\n}\n\nLRESULT CMyEditEx::OnActiving(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) {\n  if (m_pOwner) {\n    ((CLayeredEditCtl *)m_pOwner)->GetTitleIn();\n    HWND hParent = ::GetParent(m_hWnd);\n\n    ((CLayeredEditCtl *)m_pOwner)->_hPopUpWnd = NULL;\n    ::ShowWindow(hParent, SW_HIDE);\n    m_pOwner->RaiseInvalidate(TRUE);\n    ::PostMessage(global.hUitlWnd_, WM_DEL_GDI_OBJ, 0, (LPARAM)hParent);\n  }\n  return 0;\n}\n\nvoid CLayeredEditCtl::OnMouseDown(UINT nFlags, CPoint point) { ForceCreate(); }\n\nvoid CLayeredEditCtl::ForceCreate() {\n  if (NULL == _hPopUpWnd) {\n    _hPopUpWnd = new EditPopWindow;\n  }\n  if (!_hPopUpWnd) {\n    ATLASSERT(0);\n    return;\n  }\n  if (::IsWindow(_hPopUpWnd->m_hWnd)) {\n    return;\n  }\n  _hPopUpWnd->m_edit.SetOwner(this);\n  _hPopUpWnd->m_hWnd = NULL;\n  RECT src = {0};\n  DUI_Rect rcParent = src;\n  ::GetWindowRect(_host, &rcParent);\n  DUI_Rect rc(\n      DUI_Point(rcParent.left + _rcEdit.left, rcParent.top + _rcEdit.top),\n      _rcEdit.Size());\n  DWORD style = WS_POPUP | WS_VISIBLE;\n  _hPopUpWnd->Create(_host, rc, _T(\"\"), style);\n  if (::IsWindow(_hPopUpWnd->m_edit.m_hWnd)) {\n    _hPopUpWnd->m_edit.SetLimitText(_LimitText);\n    ::SetWindowText(_hPopUpWnd->m_edit.m_hWnd, _title.c_str());\n  } else {\n    ATLASSERT(0);\n  }\n}\n\nvoid CLayeredEditCtl::DestroyEditWindow() {\n  if (_hPopUpWnd && IsWindow(_hPopUpWnd->m_hWnd)) {\n    GetTitleIn();\n    void *p = _hPopUpWnd;\n    RaiseInvalidate(TRUE);\n    ::DestroyWindow(_hPopUpWnd->m_hWnd);\n    ::PostMessage(global.hUitlWnd_, WM_DEL_GDI_OBJ, 0, (LPARAM)p);\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUILayeredEdit.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n\nclass CLayeredEditCtl;\n\nclass CMyEditEx : public CWindowImpl<CMyEditEx, CEdit> {\npublic:\n  CMyEditEx() { m_pOwner = NULL; }\n  static void DeleObj(void *p);\n  BEGIN_MSG_MAP(CMyEditEx)\n  MESSAGE_HANDLER(WM_CHAR, OnChar)\n  MESSAGE_HANDLER(WM_KILLFOCUS, OnActiving)\n  END_MSG_MAP()\n\n  LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  LRESULT OnActiving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  void SetOwner(CBaseElementCtl *pOwner) { m_pOwner = pOwner; }\n  void OnFinalMessage(HWND hWnd) {}\n\nprivate:\n  CBaseElementCtl *m_pOwner;\n};\n\nclass EditPopWindow : public CWindowImpl<EditPopWindow> {\npublic:\n  EditPopWindow() { _hbrush = CreateSolidBrush(RGB(69, 68, 73)); }\n  ~EditPopWindow() {\n    if (_hbrush)\n      DeleteObject((HGDIOBJ)_hbrush);\n  }\n  BEGIN_MSG_MAP(EditPopWindow)\n\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnPaintChild)\n  MESSAGE_HANDLER(WM_CLOSE, OnClose)\n  END_MSG_MAP()\n\n  LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  LRESULT OnPaintChild(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n\n  void OnFinalMessage(HWND hWnd);\n  CMyEditEx m_edit;\n\nprivate:\n  HBRUSH _hbrush;\n};\n\nclass CLayeredEditCtl : public CBaseElementCtl {\npublic:\n  friend CMyEditEx;\n  CLayeredEditCtl(HWND father);\n  ~CLayeredEditCtl(void) {}\n  void OnMouseDown(UINT nFlags, CPoint point);\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void OnSizeChanged(DUI_Size wndChangingSize, int w, int h);\n  void OnMove();\n  void SetVisible(BOOL visible);\n  void SetPos(WTL::CRect rc);\n  void SetPos(CPoint pt, CSize sz);\n  void SetLimitText(int uMax);\n  tstring GetTitle() override;\n  void SetTitle(const tstring &csName);\n  virtual void OnTabKey();\n  EditPopWindow *_hPopUpWnd;\n  CRect _rcEdit;\n  DUI_BUTTON_STATE _state;\n  void DestroyEditWindow();\n  void ForceCreate();\n\nprotected:\n  void GetTitleIn();\n  COLORREF _borderColor;\n  COLORREF _brushColor;\n  COLORREF _textcolor;\n  HBITMAP _bmpNormal;\n  HBITMAP _bmpHover;\n  HBITMAP _bmpIcon;\n  BOOL _password;\n  BOOL _tab;\n  BOOL _readonly;\n  HBITMAP _bmpBack;\n  int _index;\n  int _LimitText;\n};\ninline void CLayeredEditCtl::OnTabKey() {\n  if (_tab) {\n    ::PostMessage(_host, WM_ASYNC_CALL_TABKEY, (WPARAM)this, _index);\n  }\n}\n\ninline void CLayeredEditCtl::SetTitle(const tstring &csName) {\n  _title = csName;\n\n  RaiseInvalidate();\n}\n\ninline void CLayeredEditCtl::SetVisible(BOOL visible) {\n  if (_visible != visible) {\n    _visible = visible;\n  }\n}\n\ninline tstring CLayeredEditCtl::GetTitle() {\n  if (_hPopUpWnd && ::IsWindow(_hPopUpWnd->m_hWnd)) {\n    BSTR strText = NULL;\n    _hPopUpWnd->m_edit.GetWindowText(strText);\n    CString strRes = strText;\n    _title = (LPCTSTR)strRes;\n    SysFreeString(strText);\n  }\n  return _title;\n}\n\ninline void CLayeredEditCtl::SetPos(CPoint pt, CSize sz) {\n  _location.x = pt.x;\n  _location.y = pt.y;\n  _size.cx = sz.cx;\n  _size.cy = sz.cy;\n\n  if (!_bmpIcon) {\n\n    DUI_Rect rcEdit(_location, _size);\n    rcEdit.left += 10;\n    rcEdit.right -= 10;\n    rcEdit.top += 5;\n    rcEdit.bottom -= 2;\n    _rcEdit = rcEdit;\n  } else {\n    BITMAP bmpInfor;\n    GetObject(_bmpIcon, sizeof(bmpInfor), &bmpInfor);\n\n    DUI_Rect rcEdit(_location, _size);\n    rcEdit.left += bmpInfor.bmWidth + 10;\n    rcEdit.right -= 10;\n    rcEdit.top += 5;\n    rcEdit.bottom -= 2;\n    _rcEdit = rcEdit;\n  }\n}\n\ninline void CLayeredEditCtl::SetPos(WTL::CRect rc) {\n  DUI_Point pt;\n  pt.x = rc.left;\n  pt.y = rc.top;\n\n  DUI_Size sz;\n  sz.cx = rc.Width();\n  sz.cy = rc.Height();\n  SetPos(pt, sz);\n}\n"
  },
  {
    "path": "src/DirectUI/DUIOptionLine.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIOptionLine.h\"\n\nCOptionLineCtl::COptionLineCtl(HWND father, BOOL trans) {\n  _host = father;\n  _class = _T(\"DUIOptionLine\");\n  _transparent = trans;\n  _textFont = NULL;\n  _textCol = RGB(0, 0, 0);\n  _lineCol = RGB(0, 0, 0);\n}\n\nCOptionLineCtl::COptionLineCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                               LPCTSTR lpszTooptip, DUI_Rect rcElement,\n                               BOOL trans)\n    : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _host = father;\n  _class = _T(\"DUIOptionLine\");\n  _transparent = trans;\n  _textFont = NULL;\n  _textCol = RGB(0, 0, 0);\n  _lineCol = RGB(0, 0, 0);\n}\n\nCOptionLineCtl::~COptionLineCtl(void) {}\n\nvoid COptionLineCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n  _textFont = CGDIResource::GetInstance().GDI_GetNormalFont();\n  _textCol = GetRGBAttribute(element, \"textcolor\");\n  _lineCol = GetRGBAttribute(element, \"linecolor\");\n}\nvoid COptionLineCtl::SetTextFont(HFONT font) { _textFont = font; }\n\nvoid COptionLineCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    UINT nTextFormat = DT_LEFT;\n    DUI_Rect rc(_location, _size);\n\n    int nWidth = 0;\n    if (_title.size() > 0) {\n      nWidth = GetTextWidth(_title.c_str(), _textFont) + 10;\n      DUI_Rect rcText;\n      CopyRect(&rcText, &rc);\n      rcText.right = rcText.left + nWidth;\n      if (_transparent) {\n        CGDIResource::GetInstance().GDI_DrawText_Trans(\n            hDC, _title.c_str(), &rcText, _textFont, _textCol, DT_LEFT);\n      } else {\n        CGDIResource::GetInstance().GDI_DrawText(hDC, _title.c_str(), &rcText,\n                                                 _textFont, _textCol, DT_LEFT);\n      }\n    }\n\n    int nMiddle = rc.top + rc.Height() / 2;\n    int nLeft = rc.left + nWidth;\n    if (_transparent) {\n      CGDIResource::GetInstance().GDI_DrawLine_trans(\n          hDC, nLeft, nMiddle, rc.right, nMiddle, _lineCol);\n    } else {\n      CGDIResource::GetInstance().GDI_DrawLine(hDC, nLeft, nMiddle, rc.right,\n                                               nMiddle, _lineCol);\n    }\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUIOptionLine.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n\nclass COptionLineCtl : public CBaseElementCtl {\npublic:\n  COptionLineCtl(HWND father, BOOL trans = FALSE);\n  COptionLineCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                 LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE);\n  ~COptionLineCtl(void);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n\n  void SetTextFont(HFONT font);\n\nprotected:\n  HFONT _textFont;\n  COLORREF _textCol;\n  COLORREF _lineCol;\n};\n"
  },
  {
    "path": "src/DirectUI/DUIPanel.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIButton.h\"\n#include \"DUICheckBox.h\"\n#include \"DUIHyperLink.h\"\n#include \"DUILayeredEdit.h\"\n#include \"DUIProgress.h\"\n#include \"DUIRadioButton.h\"\n#include \"DUIStatic.h\"\n#include \"DUITabList.h\"\n#include \"DUIPanel.h\"\n\nusing namespace std;\n\nCPanelCtl::CPanelCtl(HWND father, BOOL trans) {\n  _host = father;\n  _handleKeyboard = TRUE;\n  _class = _T(\"Panel\");\n  _transparent = trans;\n  _colBack = RGB(255, 255, 255);\n  _colBorder = RGB(255, 255, 255);\n  _bmpBackground = NULL;\n  _elementmgr.InitOwner(_host);\n  _draw_border = FALSE;\n}\n\nCPanelCtl::CPanelCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                     LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : CBaseElementCtl(hWnd, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _class = _T(\"Panel\");\n  _host = hWnd;\n  _handleKeyboard = TRUE;\n  _colBack = RGB(255, 255, 255);\n  _colBorder = RGB(255, 255, 255);\n  _bmpBackground = NULL;\n  _elementmgr.InitOwner(_host);\n  _draw_border = FALSE;\n}\n\nCPanelCtl::~CPanelCtl(void) {\n  CBaseElementCtl *pEle = NULL;\n  _elementmgr.Reset();\n  while ((pEle = _elementmgr.GetElement()) != NULL) {\n    delete pEle;\n    pEle = NULL;\n  }\n}\n\nvoid CPanelCtl::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n\n  _bmpBackground = GetBitmapAttribute(element, \"background\");\n  _colBack = GetRGBAttribute(element, \"backcolor\");\n  _colBorder = GetRGBAttribute(element, \"bordercolor\");\n  _draw_border = GetIntegerAttribute(element, \"border\") == 1 ? TRUE : FALSE;\n\n  CXmlHelper helper;\n  vector<XmlElementPtr> pAllElement = helper.GetChild(element);\n  vector<XmlElementPtr>::iterator ite = pAllElement.begin();\n  tstring strEleName;\n  CBaseElementCtl *pElement = NULL;\n  for (ite; ite != pAllElement.end(); ite++) {\n    strEleName = helper.GetElementName(*ite);\n    if (!strEleName.compare(_T(\"panel\"))) {\n      pElement = new CPanelCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"button\"))) {\n      pElement = new CButtonCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"tablist\"))) {\n      pElement = new CTabListCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"static\"))) {\n      pElement = new CStaticCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"link\"))) {\n      pElement = new CHyperLinkCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"progress\"))) {\n      pElement = new CProgressCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"checkbox\"))) {\n      pElement = new CCheckBoxCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n    if (!strEleName.compare(_T(\"radiobutton\"))) {\n      pElement = new CRadioButtonCtl(_host);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"layedit\"))) {\n      pElement = new CLayeredEditCtl(_host);\n      pElement->CreateElement(*ite);\n      AddElement(pElement);\n      continue;\n    }\n  }\n}\n\nvoid CPanelCtl::SetBackImage(LPCTSTR lpszImageRes) {\n  _bmpBackground =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG);\n}\n\nvoid CPanelCtl::AddElement(CBaseElementCtl *element) {\n  DUI_Rect rcElement = element->Rectangle();\n\n  element->SetPos(\n      DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top),\n      DUI_Size(rcElement.Width(), rcElement.Height()));\n  _elementmgr.AddElement(element);\n}\n\nvoid CPanelCtl::AddElement2(CBaseElementCtl *element) {\n  DUI_Rect rcElement = element->Rectangle();\n\n  element->SetPos(\n      DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top),\n      DUI_Size(rcElement.Width(), rcElement.Height()));\n  _elementmgr.AddElement2(element);\n}\n\nvoid CPanelCtl::OnMove() { _elementmgr.OnMove(); }\n\nvoid CPanelCtl::OnMouseDown(UINT nFlags, CPoint pt) {\n  _elementmgr.OnMouseDown(nFlags, pt);\n}\n\nvoid CPanelCtl::OnKeyDown(DWORD dwFlag) { _elementmgr.OnKeyDown(dwFlag); }\n\nvoid CPanelCtl::OnKeyUp(DWORD dwFlag) { _elementmgr.OnKeyUp(dwFlag); }\n\nvoid CPanelCtl::OnMouseDblDown(UINT nFlags, CPoint pt) {\n  _elementmgr.OnMouseDblDown(nFlags, pt);\n}\nvoid CPanelCtl::OnMouseUp(UINT nFlags, CPoint pt) {\n  _elementmgr.OnMouseUp(nFlags, pt);\n}\n\nvoid CPanelCtl::OnMouseRUp(UINT nFlags, CPoint pt) {\n  _elementmgr.OnMouseRUp(nFlags, pt);\n}\n\nvoid CPanelCtl::OnMouseLeave() { _elementmgr.OnMouseLeave(); }\n\nvoid CPanelCtl::OnMouseHover(UINT nFlags, CPoint pt) {\n  _elementmgr.OnMouseMove(nFlags, pt);\n}\n\nvoid CPanelCtl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) {\n  _elementmgr.OnMouseWheel(nFlags, zDelta, pt);\n}\n\nvoid CPanelCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    if (!_transparent) {\n      DUI_Rect rc(_location, _size);\n\n      CGDIResource::GetInstance().GDI_DrawRectangle(hDC, &rc, _colBorder,\n                                                    _colBack);\n\n      if (_bmpBackground) {\n        BITMAP bmpBackInfor;\n        GetObject(_bmpBackground, sizeof(bmpBackInfor), &bmpBackInfor);\n\n        DUI_Rect rcSrc;\n        rcSrc.left = 0;\n        rcSrc.top = 0;\n        rcSrc.right = bmpBackInfor.bmWidth;\n        rcSrc.bottom = bmpBackInfor.bmHeight;\n        CGDIResource::GetInstance().GDI_DrawImageStretch(\n            hDC, _bmpBackground, rc, rcSrc, 255, CRect(10, 10, 10, 10));\n      }\n    } else {\n      DUI_Rect rc(_location, _size);\n      if (_draw_border) {\n\n        CGDIResource::GetInstance().GDI_DrawRectangle_Trans(\n            hDC, &rc, _colBorder, _colBack);\n      }\n    }\n    _elementmgr.OnPaint(hDC);\n  }\n}\n\nvoid CPanelCtl::OnSizeChanged(DUI_Size wndChangingSize, int w, int h) {\n  _elementmgr.Reset();\n  CBaseElementCtl *element = NULL;\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n\n  DUI_Size szOldPanel = _size;\n\n  CBaseElementCtl::OnSizeChanged(wndChangingSize, w, h);\n\n  DUI_Size szNewPanel = _size;\n\n  _elementmgr.Reset();\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    element->OnSizeChanged(szOldPanel, szNewPanel.cx, szNewPanel.cy);\n\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n}\n\nvoid CPanelCtl::SetVisible(BOOL visible) {\n  if (_visible != visible) {\n    _visible = visible;\n\n    CBaseElementCtl *pEle = NULL;\n    _elementmgr.Reset();\n    while ((pEle = _elementmgr.GetElement()) != NULL) {\n      pEle->SetVisible(_visible);\n    }\n\n    RaiseInvalidate(TRUE);\n  }\n}\n\nvoid CPanelCtl::Invlidate() {\n  if (_visible) {\n\n    RaiseInvalidate(TRUE);\n\n    CBaseElementCtl *pEle = NULL;\n    _elementmgr.Reset();\n    while ((pEle = _elementmgr.GetElement()) != NULL) {\n      pEle->RaiseInvalidate(TRUE);\n    }\n  }\n}\n\nvoid CPanelCtl::Dispose() { _elementmgr.Dispose(); }\n\nvoid CPanelCtl::Dispose(LPCTSTR lpszID) { _elementmgr.Dispose(lpszID); }\n\nCBaseElementCtl *CPanelCtl::GetElement() { return _elementmgr.GetElement(); }\n\nvoid CPanelCtl::ResetElement() { _elementmgr.Reset(); }\n\nvoid CPanelCtl::DrawCursor() { _elementmgr.DrawCursor(); }\n\nvoid CPanelCtl::SetActive(CBaseElementCtl *element) {\n  _elementmgr.SetActive(element);\n}\n\nvoid CPanelCtl::OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) {\n  _elementmgr.OnMsg(nMsg, wParam, lParam, bHandled);\n}\n"
  },
  {
    "path": "src/DirectUI/DUIPanel.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n#include \"DUIElementsMgr.h\"\n\nclass CPanelCtl : public CBaseElementCtl {\npublic:\n  CPanelCtl(HWND father, BOOL trans = FALSE);\n  CPanelCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip,\n            DUI_Rect rcElement);\n  ~CPanelCtl(void);\n\n  void SetPos(CPoint pt, CSize sz);\n  void SetPos(WTL::CRect rc);\n\n  void CreateElement(XmlElementPtr element);\n  void SetBackImage(LPCTSTR lpszImageRes);\n  void AddElement(CBaseElementCtl *element);\n  void AddElement2(CBaseElementCtl *element);\n  void OnMove();\n  void OnKeyDown(DWORD dwFlag);\n  void OnKeyUp(DWORD dwFlag);\n  void OnMouseDown(UINT nFlags, CPoint pt);\n  void OnMouseDblDown(UINT nFlags, CPoint pt);\n  void OnMouseUp(UINT nFlags, CPoint pt);\n  void OnMouseRUp(UINT nFlags, CPoint pt);\n  void OnMouseLeave();\n  void OnMouseHover(UINT nFlags, CPoint pt);\n  void OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);\n  void OnPaint(HDC hDC);\n  void OnSizeChanged(DUI_Size wndChangingSize, int w, int h);\n  void SetVisible(BOOL visible);\n  void Invlidate();\n  void Dispose();\n  void Dispose(LPCTSTR lpszID);\n  void ResetElement();\n  CBaseElementCtl *GetElement();\n  void DrawCursor();\n  void SetActive(CBaseElementCtl *element);\n  void OnMsg(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  DWORD EleNum() { return _elementmgr.EleNum(); }\n\npublic:\n  CAnyElementsMgr _elementmgr;\n\nprotected:\n  HBITMAP _bmpBackground;\n  COLORREF _colBack;\n  COLORREF _colBorder;\n  BOOL _draw_border;\n};\n\ninline void CPanelCtl::SetPos(CPoint pt, CSize sz) {\n  _elementmgr.Reset();\n  CBaseElementCtl *element = NULL;\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n\n  _location.x = pt.x;\n  _location.y = pt.y;\n  _size.cx = sz.cx;\n  _size.cy = sz.cy;\n\n  _elementmgr.Reset();\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n}\n\ninline void CPanelCtl::SetPos(WTL::CRect rc) {\n  _elementmgr.Reset();\n  CBaseElementCtl *element = NULL;\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(rcElement.left - _location.x, rcElement.top - _location.y),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n\n  _location.x = rc.left;\n  _location.y = rc.top;\n  _size.cx = rc.Width();\n  _size.cy = rc.Height();\n\n  _elementmgr.Reset();\n  while ((element = _elementmgr.GetElement()) != NULL) {\n    DUI_Rect rcElement = element->Rectangle();\n\n    element->SetPos(\n        DUI_Point(_location.x + rcElement.left, _location.y + rcElement.top),\n        DUI_Size(rcElement.Width(), rcElement.Height()));\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUIProgress.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIProgress.h\"\n\nCProgressCtl::CProgressCtl(HWND father, BOOL trans)\n    : _bmpLightPoint(NULL), _nCurPos(0.0), _nActualWidth(0),\n      _lightpointdela(0) {\n  _host = father;\n  _handleMouse = FALSE;\n  _class = _T(\"\");\n  _bmpBackground = NULL;\n  _bmpProgress = NULL;\n  _backcolor = RGB(53, 53, 61);\n  _progresscolor = RGB(144, 197, 38);\n  _transparent = trans;\n}\n\nCProgressCtl::CProgressCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                           LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans)\n    : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement),\n      _bmpLightPoint(NULL), _nCurPos(0.0), _nActualWidth(0),\n      _lightpointdela(0) {\n  _host = father;\n  _handleMouse = FALSE;\n  _class = _T(\"\");\n  _bmpBackground = NULL;\n  _bmpProgress = NULL;\n  _backcolor = RGB(53, 53, 61);\n  _progresscolor = RGB(144, 197, 38);\n  _transparent = trans;\n}\n\nCProgressCtl::~CProgressCtl(void) {}\n\nvoid CProgressCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n\n  _bmpBackground = GetBitmapAttribute(element, \"background\");\n  _bmpProgress = GetBitmapAttribute(element, \"progress\");\n  _nActualWidth = GetIntegerAttribute(element, \"progress_width\");\n  _bmpLightPoint = GetBitmapAttribute(element, \"image\");\n  _lightpointdela = GetIntegerAttribute(element, \"lightpointdela\");\n}\n\nvoid CProgressCtl::SetPos(double nPos) {\n  _nCurPos = nPos;\n  RaiseInvalidate(TRUE);\n}\n\nvoid CProgressCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    if (_bmpBackground) {\n\n      int nWidth = _size.cx;\n      int nHeight = _nActualWidth;\n      CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, _bmpBackground, _location.x, _location.y, nWidth, nHeight);\n    } else {\n      DUI_Rect rcDest(_location.x, _location.y, _location.x + _nActualWidth,\n                      _location.y + _size.cy);\n      if (_transparent)\n        CGDIResource::GetInstance().GDI_DrawRectangle_Trans(\n            hDC, &rcDest, _backcolor, _backcolor);\n      else\n        CGDIResource::GetInstance().GDI_DrawRectangle(hDC, &rcDest, _backcolor,\n                                                      _backcolor);\n    }\n\n    if (_bmpProgress) {\n\n      int nDrawWidth = static_cast<int>(_nActualWidth * _nCurPos);\n\n      BITMAP bmpProgressInfor;\n      GetObject(_bmpProgress, sizeof(bmpProgressInfor), &bmpProgressInfor);\n      int nDrawLeft = _location.x + 8;\n      int nDrawTop = _location.y + 7;\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpProgress, nDrawLeft,\n                                                nDrawTop, nDrawWidth,\n                                                bmpProgressInfor.bmHeight);\n    } else {\n      int nDrawWidth = static_cast<int>(_nActualWidth * _nCurPos);\n      DUI_Rect rcDest(_location.x, _location.y, _location.x + nDrawWidth,\n                      _location.y + _size.cy);\n      if (_transparent)\n        CGDIResource::GetInstance().GDI_DrawRectangle_Trans(\n            hDC, &rcDest, _progresscolor, _progresscolor);\n      else\n        CGDIResource::GetInstance().GDI_DrawRectangle(\n            hDC, &rcDest, _progresscolor, _progresscolor);\n    }\n\n    if (_bmpLightPoint) {\n      BITMAP bmpBackInfor;\n      GetObject(_bmpLightPoint, sizeof(bmpBackInfor), &bmpBackInfor);\n      int nWidth = bmpBackInfor.bmWidth;\n      int nHeight = bmpBackInfor.bmHeight;\n      int px = _location.x + static_cast<int>(_nActualWidth * _nCurPos) -\n               nWidth / 2 + _lightpointdela;\n      int py = _location.y + _size.cy / 2 - nHeight / 2;\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpLightPoint, px, py,\n                                                nWidth, nHeight);\n    }\n\n    TCHAR szArgs[25] = {0};\n    _sntprintf_s(szArgs, 25, _TRUNCATE, _T(\"%.1f%%\"), _nCurPos * 100);\n    CRect rcText;\n    rcText.left = _nActualWidth + 30;\n    rcText.top = _location.y - 10;\n    rcText.right = rcText.left + 55;\n    rcText.bottom = rcText.top + 20;\n    UINT nFormat = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS;\n    nFormat = nFormat | DT_LEFT;\n    if (_transparent) {\n      CGDIResource::GetInstance().GDI_DrawText_Trans(\n          hDC, szArgs, &rcText, CGDIResource::GetInstance().GDI_GetSmallFont(),\n          RGB(250, 250, 250), nFormat);\n    } else {\n      CGDIResource::GetInstance().GDI_DrawText(\n          hDC, szArgs, &rcText, CGDIResource::GetInstance().GDI_GetSmallFont(),\n          RGB(250, 250, 250), nFormat);\n    }\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUIProgress.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n\nclass CProgressCtl : public CBaseElementCtl {\npublic:\n  CProgressCtl(HWND father, BOOL trans = FALSE);\n  CProgressCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n               LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE);\n  ~CProgressCtl(void);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void SetPos(double nPos);\n\nprotected:\n  HBITMAP _bmpBackground;\n  HBITMAP _bmpProgress;\n  HBITMAP _bmpLightPoint;\n  COLORREF _backcolor;\n  COLORREF _progresscolor;\n  int _lightpointdela;\n  int _nActualWidth;\n  double _nCurPos;\n};\n"
  },
  {
    "path": "src/DirectUI/DUIRadioButton.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIRadioButton.h\"\n\nCRadioButtonCtl::CRadioButtonCtl(HWND father, BOOL trans) : CButtonCtl(father) {\n  _class = _T(\"\");\n  _transparent = trans;\n  _txtColor = RGB(67, 75, 94);\n  _bChecked = FALSE;\n  _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                      _T(\"RadioButton\"), PNG);\n}\n\nCRadioButtonCtl::CRadioButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                                 LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : CButtonCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _class = _T(\"\");\n  _txtColor = RGB(67, 75, 94);\n  _bChecked = FALSE;\n  _bmpBtn = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                      _T(\"RadioButton\"), PNG);\n}\n\nCRadioButtonCtl::~CRadioButtonCtl(void) {}\n\nvoid CRadioButtonCtl::CreateElement(XmlElementPtr element) {\n\n  GetElementStyle(element);\n\n  _bmpBtn = GetBitmapAttribute(element, \"image\");\n}\n\nvoid CRadioButtonCtl::Enable(BOOL enable) {\n  if (enable) {\n    switch (_state) {\n    case DUI_STATE_NORMAL_DISABLE:\n      _state = DUI_STATE_NORMAL;\n      break;\n    case DUI_STATE_DOWN_DISABLE:\n      _state = DUI_STATE_DOWN;\n      break;\n    default:\n      break;\n    }\n  } else {\n    Disable();\n  }\n}\n\nvoid CRadioButtonCtl::OnPaint(HDC hDC) {\n  BITMAP bmpInfor;\n  GetObject(_bmpBtn, sizeof(bmpInfor), &bmpInfor);\n\n  int nCheckWidth = bmpInfor.bmWidth / 2;\n\n  DUI_Size szCheckImage(nCheckWidth, bmpInfor.bmHeight);\n  DUI_Point ptCheckImage(_location.x,\n                         _location.y + (_size.cy - bmpInfor.bmHeight) / 2);\n  DUI_Rect rcImage(ptCheckImage, szCheckImage);\n  int nImageOffset = 0;\n  switch (_state) {\n  case DUI_STATE_NORMAL:\n  case DUI_STATE_HOVER:\n    nImageOffset = 0;\n    break;\n  case DUI_STATE_DOWN:\n    nImageOffset = 1;\n    break;\n  case DUI_STATE_NORMAL_DISABLE:\n    nImageOffset = 2;\n    break;\n  case DUI_STATE_DOWN_DISABLE:\n    nImageOffset = 3;\n    break;\n  }\n\n  DUI_Rect rcSrc(DUI_Point(nImageOffset * nCheckWidth, 0),\n                 DUI_Size(nCheckWidth, bmpInfor.bmHeight));\n\n  CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpBtn, rcImage, rcSrc);\n\n  DUI_Rect rcText(DUI_Point(rcImage.right + 5, _location.y),\n                  DUI_Size(_size.cx - rcImage.Width() - 1, _size.cy));\n  if (_transparent) {\n    CGDIResource::GetInstance().GDI_DrawText_Trans(\n        hDC, _title.c_str(), &rcText, _txtColor,\n        DT_LEFT | DT_SINGLELINE | DT_VCENTER);\n  } else {\n    CGDIResource::GetInstance().GDI_DrawText(\n        hDC, _title.c_str(), &rcText, _txtColor,\n        DT_LEFT | DT_SINGLELINE | DT_VCENTER);\n  }\n}\n\nvoid CRadioButtonCtl::Disable() {\n  switch (_state) {\n  case DUI_STATE_NORMAL:\n    _state = DUI_STATE_NORMAL_DISABLE;\n    break;\n  case DUI_STATE_DOWN:\n    _state = DUI_STATE_DOWN_DISABLE;\n    break;\n  default:\n    break;\n  }\n}\n\nvoid CRadioButtonCtl::OnMouseDown(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    if (_bChecked == FALSE) {\n      _down = TRUE;\n      if (_down) {\n\n        Refresh(DUI_STATE_DOWN);\n        _bChecked = TRUE;\n        ::SendMessageW(_host, WM_RADIOBUTTON_DOWN, (WPARAM)this, 0);\n      } else {\n        Refresh(DUI_STATE_NORMAL);\n        _bChecked = FALSE;\n      }\n    }\n  }\n}\n\nvoid CRadioButtonCtl::OnMouseUp(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    OnMouseClick();\n  }\n}\n\nvoid CRadioButtonCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      Refresh(DUI_STATE_HOVER);\n    }\n  }\n}\n\nvoid CRadioButtonCtl::OnMouseLeave() {\n  _tracking = FALSE;\n  if (_state != DUI_STATE_DISABLE) {\n    if (!_down) {\n      Refresh(DUI_STATE_NORMAL);\n    }\n  }\n}\n\nvoid CRadioButtonCtl::SetCheck(BOOL bCheck) {\n  _bChecked = bCheck;\n\n  if (_state != DUI_STATE_DISABLE) {\n    if (_bChecked) {\n      _state = DUI_STATE_DOWN;\n      _down = TRUE;\n    } else {\n      _state = DUI_STATE_NORMAL;\n      _down = FALSE;\n    }\n    RaiseInvalidate(TRUE);\n  }\n}\n\nBOOL CRadioButtonCtl::GetCheck() { return _bChecked; }\n"
  },
  {
    "path": "src/DirectUI/DUIRadioButton.h",
    "content": "#pragma once\n\n#include \"DUIButton.h\"\n\nclass CRadioButtonCtl : public CButtonCtl {\npublic:\n  CRadioButtonCtl(HWND father, BOOL trans = FALSE);\n  CRadioButtonCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                  LPCTSTR lpszTooptip, DUI_Rect rcElement);\n  ~CRadioButtonCtl(void);\n\n  void SetCheck(BOOL bCheck);\n  BOOL GetCheck();\n  void Disable();\n  void Enable(BOOL enable);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void OnMouseDown(UINT nFlags, CPoint point);\n  void OnMouseUp(UINT nFlags, CPoint point);\n  void OnMouseHover(UINT nFlags, CPoint point);\n  void OnMouseLeave();\n\nprotected:\n  COLORREF _txtColor;\n  BOOL _bChecked;\n};\n"
  },
  {
    "path": "src/DirectUI/DUIStatic.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUIStatic.h\"\n\nCStaticCtl::CStaticCtl(HWND father, BOOL trans) {\n  _host = father;\n\n  _down = FALSE;\n  _class = _T(\"\");\n  _transparent = trans;\n  _bmpBackground = NULL;\n  _bmpIcon = NULL;\n  _textFont = CGDIResource::GetInstance().GDI_GetNormalFont();\n  _textCol = RGB(0, 0, 0);\n  _textFormat = DT_LEFT;\n  _viewport = 0;\n  _scrollDelta = 0;\n}\n\nCStaticCtl::CStaticCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                       LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans)\n    : CBaseElementCtl(father, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _host = father;\n\n  _class = _T(\"\");\n  _bmpBackground = NULL;\n  _bmpIcon = NULL;\n  _textFont = CGDIResource::GetInstance().GDI_GetNormalFont();\n  _textCol = RGB(0, 0, 0);\n  _textFormat = DT_LEFT;\n  _transparent = trans;\n  _viewport = 0;\n  _scrollDelta = 0;\n}\n\nCStaticCtl::~CStaticCtl(void) {}\n\nvoid CStaticCtl::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n\n  _bmpBackground = GetBitmapAttribute(element, \"background\");\n  _textCol = GetRGBAttribute(element, \"color\");\n  _bmpIcon = GetBitmapAttribute(element, \"icon\");\n  if (GetIntegerAttribute(element, \"bigfont\")) {\n    _textFont = CGDIResource::GetInstance().GDI_GetBiggerFont();\n  }\n  if (GetIntegerAttribute(element, \"samllfont\")) {\n    _textFont = CGDIResource::GetInstance().GDI_GetSmallFont();\n  }\n  _viewport = GetIntegerAttribute(element, \"viewport\");\n}\nvoid CStaticCtl::SetTextFont(HFONT font) { _textFont = font; }\n\nvoid CStaticCtl::SetTextColor(COLORREF colText) { _textCol = colText; }\n\nvoid CStaticCtl::SetImage(LPCTSTR lpszImageRes) {\n  _bmpBackground =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszImageRes, PNG);\n}\n\nvoid CStaticCtl::SetIcon(LPCTSTR lpszIconRes) {\n  _bmpIcon =\n      CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, lpszIconRes, PNG);\n}\n\nvoid CStaticCtl::SetTextFormat(UINT nTextFormat) { _textFormat = nTextFormat; }\n\nvoid CStaticCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    UINT nTextFormat = DT_LEFT;\n    DUI_Rect rcText(_location, _size);\n    if (_bmpIcon) {\n      BITMAP bmpIconInfor;\n      GetObject(_bmpIcon, sizeof(bmpIconInfor), &bmpIconInfor);\n\n      int nY = _location.y + (_size.cy - bmpIconInfor.bmHeight) / 2;\n\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, _bmpIcon, _location.x, nY,\n                                                bmpIconInfor.bmWidth,\n                                                bmpIconInfor.bmHeight);\n\n      rcText.left = _location.x + bmpIconInfor.bmWidth + 2;\n      nTextFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS;\n    }\n    if (_title.size() > 0) {\n      if (_viewport) {\n        ::SetWindowOrgEx(hDC, 0, _scrollDelta, NULL);\n        rcText.bottom += _scrollDelta;\n      }\n      if (_textFormat != 0) {\n        nTextFormat = _textFormat;\n      }\n\n      if (_transparent) {\n        CGDIResource::GetInstance().GDI_DrawText_Trans(\n            hDC, _title.c_str(), &rcText, _textFont, _textCol, nTextFormat);\n      } else {\n        CGDIResource::GetInstance().GDI_DrawText(\n            hDC, _title.c_str(), &rcText, _textFont, _textCol, nTextFormat);\n      }\n      if (_viewport) {\n        ::SetWindowOrgEx(hDC, 0, 0, NULL);\n      }\n    }\n\n    if (_bmpBackground) {\n\n      int nWidth = _size.cx;\n\n      int nHeight = _size.cy;\n      CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, _bmpBackground, _location.x, _location.y, nWidth, nHeight);\n    }\n  }\n}\n\nvoid CStaticCtl::OnMouseDown(UINT nFlags, CPoint point) {\n  if (_visible) {\n    _down = TRUE;\n  }\n}\n\nvoid CStaticCtl::OnMouseUp(UINT nFlags, CPoint point) {\n  if (_visible) {\n    if (_down) {\n      OnMouseClick();\n    }\n    _down = FALSE;\n  }\n}\n\nvoid CStaticCtl::OnCall_LeftUp() {\n  if (_leftup_event.m_func_no_para)\n    _leftup_event.Invoke();\n}\n"
  },
  {
    "path": "src/DirectUI/DUIStatic.h",
    "content": "#pragma once\n\n#include \"DUIElement.h\"\n\nclass CStaticCtl : public CBaseElementCtl {\npublic:\n  CStaticCtl(HWND father, BOOL trans = FALSE);\n  CStaticCtl(HWND father, LPCTSTR lpszID, LPCTSTR lpszTitle,\n             LPCTSTR lpszTooptip, DUI_Rect rcElement, BOOL trans = FALSE);\n  ~CStaticCtl(void);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void OnMouseDown(UINT nFlags, CPoint point);\n  void OnMouseUp(UINT nFlags, CPoint point);\n  void OnCall_LeftUp();\n\n  void SetTextFont(HFONT font);\n  void SetTextColor(COLORREF colText);\n  void SetImage(LPCTSTR lpszImageRes);\n  void SetIcon(LPCTSTR lpszIconRes);\n  void SetTextFormat(UINT nTextFormat);\n\nprotected:\n  HBITMAP _bmpBackground;\n  HBITMAP _bmpIcon;\n  HFONT _textFont;\n  COLORREF _textCol;\n  BOOL _down;\n  UINT _textFormat;\n  BOOL _viewport;\n\npublic:\n  int _scrollDelta;\n};\n"
  },
  {
    "path": "src/DirectUI/DUITab.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUITab.h\"\n#include \"DUITabList.h\"\n\nCTabCtl::CTabCtl(HWND father, CTabListCtl *pList, BOOL trans)\n    : CButtonCtl(father, trans) {\n  _class = _T(\"\");\n  _tab_list = pList;\n  _bSel = FALSE;\n  _bmpUpdate = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                         _T(\"TABUPDATE\"), PNG);\n  _nCount = 0;\n  _transparent = trans;\n}\n\nCTabCtl::CTabCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle,\n                 LPCTSTR lpszTooptip, DUI_Rect rcElement)\n    : CButtonCtl(hWnd, lpszID, lpszTitle, lpszTooptip, rcElement) {\n  _class = _T(\"\");\n  _bSel = FALSE;\n  _bmpUpdate = CGDIResource::GetInstance().GDI_GetBitmap(\n      _hInstance, _T(\"CHANNELUPDATE\"), PNG);\n  _nCount = 0;\n}\n\nCTabCtl::~CTabCtl(void) {}\n\nvoid CTabCtl::OnPaint(HDC hDC) { CButtonCtl::OnPaint(hDC); }\n\nvoid CTabCtl::OnMouseHover(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      Refresh(DUI_STATE_HOVER);\n    }\n  }\n}\n\nvoid CTabCtl::OnMouseLeave() {\n  _tracking = FALSE;\n  if (_state != DUI_STATE_DISABLE) {\n    if (_down) {\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      Refresh(DUI_STATE_NORMAL);\n    }\n  }\n}\n\nvoid CTabCtl::OnMouseUp(UINT nFlags, CPoint point) {\n  if (_state != DUI_STATE_DISABLE) {\n    DUI_BUTTON_STATE state = _state;\n\n    if (_down && (state == DUI_STATE_DOWN)) {\n\n      OnMouseClick();\n\n      if (_tab_list)\n        _tab_list->SelTab(_id);\n    }\n  }\n}\nvoid CTabCtl::SetSel(BOOL bSel) {\n  _bSel = bSel;\n\n  if (_state != DUI_STATE_DISABLE) {\n    if (_bSel) {\n      _down = TRUE;\n\n      Refresh(DUI_STATE_DOWN);\n    } else {\n      _down = FALSE;\n\n      Refresh(DUI_STATE_NORMAL);\n    }\n  }\n}\n\nBOOL CTabCtl::GetSel() { return _bSel; }\n\nvoid CTabCtl::SetUpdate(int nCount) {\n  _nCount = nCount;\n  RaiseInvalidate(TRUE);\n}\n\nvoid CTabCtl::RaiseInvalidate(BOOL forceRedraw) {\n  if (_host != NULL) {\n    if (forceRedraw) {\n      DUI_Rect rcTab = Rectangle();\n      rcTab.top -= 2;\n      rcTab.right += 2;\n      ::InvalidateRect(_host, rcTab, TRUE);\n    }\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUITab.h",
    "content": "#pragma once\n\n#include \"DUIButton.h\"\n\nclass CTabListCtl;\nclass CTabCtl : public CButtonCtl {\npublic:\n  CTabCtl(HWND father, CTabListCtl *pList = NULL, BOOL trans = FALSE);\n  CTabCtl(HWND hWnd, LPCTSTR lpszID, LPCTSTR lpszTitle, LPCTSTR lpszTooptip,\n          DUI_Rect rcElement);\n  ~CTabCtl(void);\n\npublic:\n  void SetUpdate(int nCount);\n  void SetSel(BOOL bSel);\n  BOOL GetSel();\n  void OnPaint(HDC hDC);\n  virtual void OnMouseHover(UINT nFlags, CPoint point);\n  virtual void OnMouseLeave();\n  virtual void OnMouseUp(UINT nFlags, CPoint point);\n\n  void RaiseInvalidate(BOOL forceRedraw);\n\nprotected:\n  HBITMAP _bmpUpdate;\n\n  BOOL _bSel;\n\n  int _nCount;\n\n  CTabListCtl *_tab_list;\n};\n"
  },
  {
    "path": "src/DirectUI/DUITabList.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DUITabList.h\"\n\nusing namespace std;\n\nCTabListCtl::CTabListCtl(HWND father, BOOL trans) : CPanelCtl(father) {\n  _host = father;\n  _class = _T(\"\");\n  _transparent = trans;\n}\n\nCTabListCtl::~CTabListCtl(void) {}\n\nvoid CTabListCtl::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n\n  CXmlHelper helper;\n  vector<XmlElementPtr> pAllElement = helper.GetChild(element);\n  vector<XmlElementPtr>::iterator ite = pAllElement.begin();\n  tstring strEleName;\n  CBaseElementCtl *pElement = NULL;\n  for (ite; ite != pAllElement.end(); ite++) {\n\n    strEleName = helper.GetElementName(*ite);\n\n    if (!strEleName.compare(_T(\"tab\"))) {\n      pElement = new CTabCtl(_host, this, _transparent);\n      pElement->CreateElement(*ite);\n      _elementmgr.AddElement(pElement);\n    }\n  }\n}\n\nvoid CTabListCtl::AddPage(const tstring &strTabID, CBaseElementCtl *pElement) {\n  if (strTabID.empty())\n    return;\n\n  _mapTabPage[strTabID] = pElement;\n}\n\nvoid CTabListCtl::SelTab(const tstring &strTabID) {\n  CTabCtl *pTab = NULL;\n  ResetElement();\n  while ((pTab = (CTabCtl *)GetElement()) != NULL) {\n    if (pTab->GetID() == strTabID) {\n      pTab->SetSel(TRUE);\n    } else {\n      pTab->SetSel(FALSE);\n    }\n  }\n\n  map<tstring, CBaseElementCtl *>::iterator ite = _mapTabPage.begin();\n  for (ite; ite != _mapTabPage.end(); ite++) {\n    if (ite->first == strTabID) {\n      ite->second->SetVisible(TRUE);\n    } else {\n      ite->second->SetVisible(FALSE);\n    }\n  }\n}\n\nvoid CTabListCtl::UnSelTab(void) {\n  CTabCtl *pTab = NULL;\n  ResetElement();\n  while ((pTab = (CTabCtl *)GetElement()) != NULL) {\n    pTab->SetSel(FALSE);\n  }\n\n  map<tstring, CBaseElementCtl *>::iterator ite = _mapTabPage.begin();\n  for (ite; ite != _mapTabPage.end(); ite++) {\n    ite->second->SetVisible(FALSE);\n  }\n}\n\nvoid CTabListCtl::OnPaint(HDC hDC) {\n  if (_visible) {\n    _elementmgr.OnPaint(hDC);\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/DUITabList.h",
    "content": "#pragma once\n\n#include \"DUIPanel.h\"\n#include \"DUITab.h\"\n\nclass CTabListCtl : public CPanelCtl {\npublic:\n  CTabListCtl(HWND father, BOOL trans = FALSE);\n  ~CTabListCtl(void);\n\n  void CreateElement(XmlElementPtr element);\n  void OnPaint(HDC hDC);\n  void AddPage(const tstring &strTabID, CBaseElementCtl *pElement);\n  void SelTab(const tstring &strID);\n  void UnSelTab(void);\n\nprotected:\n  std::map<tstring, CBaseElementCtl *> _mapTabPage;\n};\n"
  },
  {
    "path": "src/DirectUI/DUITransWindow.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"util/util_tools.h\"\n#include \"../base/Thread.h\"\n#include \"../base/common_threads.h\"\n#include \"DUITransWindow.h\"\n\nusing namespace std;\n\nconst int WINDOW_WIDTH = 960;\nconst int WINDOW_HEIGHT = 600;\n\nCTransWindow::CTransWindow() : _bRoundCorner(0) {\n  _bIsWin7 = FALSE;\n  _bActived = FALSE;\n  _nTimerID = 0;\n  _transparent = TRUE;\n  _nMinWidth = 307;\n  _nMinHeight = 451;\n  _nTitleHeight = 20;\n  _bmpFrame = NULL;\n  _bmpFrameBack = NULL;\n  _bmpResize = NULL;\n  _bmpTitle = NULL;\n  _bmpLogo = NULL;\n  _bIsCenter = FALSE;\n  m_ptips = NULL;\n  _bSupportChangeSize = FALSE;\n  _bSupportDblTitle = FALSE;\n  _bOK = FALSE;\n}\n\nCTransWindow::~CTransWindow() { Detach(); }\n\nBOOL CTransWindow::DUICreateW(HWND hParentWnd, WCHAR *lpszXml) {\n  CXmlHelper helper;\n  helper.LoadStringW(lpszXml);\n\n  m_pXmlWindow = helper.GetRoot();\n  if (m_pXmlWindow == NULL) {\n    return FALSE;\n  }\n  if (helper.GetElementName(m_pXmlWindow).compare(_T(\"window\"))) {\n    return FALSE;\n  }\n\n  CreateElement(m_pXmlWindow);\n\n  SetWndPos(_location, _size);\n\n  SetWndStyle();\n\n  DUI_Rect rcWnd(_location, _size);\n\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;\n\n  HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style);\n\n  if (hWnd == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  ::SetForegroundWindow(m_hWnd);\n\n  OnLoaded();\n  return TRUE;\n}\n\nBOOL CTransWindow::DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow) {\n  _strXmlWindow = lpszXmlWidow;\n\n  CXmlHelper helper;\n  helper.loadResFile(_hInstance, _strXmlWindow.c_str(), _T(\"xml\"));\n\n  m_pXmlWindow = helper.GetRoot();\n  if (m_pXmlWindow == NULL) {\n    return FALSE;\n  }\n  if (helper.GetElementName(m_pXmlWindow).compare(_T(\"window\"))) {\n    return FALSE;\n  }\n\n  CreateElement(m_pXmlWindow);\n\n  SetWndPos(_location, _size);\n\n  SetWndStyle();\n\n  DUI_Rect rcWnd(_location, _size);\n\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;\n\n  HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style);\n\n  if (hWnd == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  ::SetForegroundWindow(m_hWnd);\n\n  OnLoaded();\n\n  return TRUE;\n}\n\nBOOL CTransWindow::DUICreate(HWND hParentWnd, DWORD dwExStyle) {\n  SetWndPos(_location, _size);\n\n  DUI_Rect rcWnd(_location, _size);\n\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP;\n\n  if (Create(hParentWnd, rcWnd, _T(\"\"), dwStyle, dwExStyle) == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  ::SetForegroundWindow(m_hWnd);\n\n  return TRUE;\n}\n\nvoid CTransWindow::SetWndPos(DUI_Point &pt, DUI_Size &sz) {}\n\nBOOL CTransWindow::DoModal() {\n  HWND hWndParent = ::GetWindow(m_hWnd, GW_OWNER);\n  ::ShowWindow(m_hWnd, SW_SHOWNORMAL);\n  ::EnableWindow(hWndParent, FALSE);\n\n  std::auto_ptr<base::MessageLoop::LayerLoop> message_loop;\n  message_loop.reset(\n      new base::MessageLoop::LayerLoop(base::MessageLoop::TYPE_UI));\n  CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current());\n  (static_cast<base::MessagePumpForUI *>(message_loop->pump_win()))\n      ->upPumpLayer(static_cast<base::MessagePumpForUI *>(\n          base::Threads::Get(Threads::UI)->pump_win()));\n\n  base::MessageLoop::LayerLoop::PushBackLoop(message_loop.get());\n\n  message_loop->Run();\n\n  base::MessageLoop::LayerLoop::PopBackLoop();\n\n  ::EnableWindow(hWndParent, TRUE);\n  ::SetFocus(hWndParent);\n\n  return _bOK;\n}\n\nLRESULT CTransWindow::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled) {\n  _host = m_hWnd;\n\n  if (_bIsCenter)\n    CenterWindow();\n\n  _elementManager.InitOwner(m_hWnd);\n\n  OnDynamicCreate();\n\n  if (!m_ptips)\n    m_ptips = new CToolTipCtrl;\n\n  m_ptips->Create(m_hWnd);\n  m_ptips->Activate(FALSE);\n  m_ptips->AddTool(m_hWnd);\n  m_ptips->SetMaxTipWidth(260);\n\n  OnLoad();\n\n  SetWindowText(_title.c_str());\n\n  OnLoadIcon();\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  if (m_ptips) {\n    if (::IsWindow((m_ptips->m_hWnd))) {\n      m_ptips->DestroyWindow();\n    }\n    delete m_ptips;\n    m_ptips = NULL;\n  }\n  return 0;\n}\n\nvoid CTransWindow::OnLoadIcon() {\n  static HICON hIcon = (HICON)::LoadImage(\n      _Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON,\n      ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON),\n      LR_DEFAULTCOLOR);\n  if (hIcon) {\n    SetIcon(hIcon, TRUE);\n    SetIcon(hIcon, FALSE);\n  }\n}\n\nvoid CTransWindow::OnDynamicCreate() {\n  CXmlHelper helper;\n  vector<XmlElementPtr> pAllElement = helper.GetChild(m_pXmlWindow);\n  vector<XmlElementPtr>::iterator ite = pAllElement.begin();\n  tstring strEleName;\n  CBaseElementCtl *pElement = NULL;\n  for (ite; ite != pAllElement.end(); ite++) {\n\n    CXmlHelper helper;\n    strEleName = helper.GetElementName(*ite);\n\n    if (!strEleName.compare(_T(\"button\"))) {\n      pElement = new CButtonCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"static\"))) {\n      pElement = new CStaticCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"tablist\"))) {\n      pElement = new CTabListCtl(_host, _transparent);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"link\"))) {\n      pElement = new CHyperLinkCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"layedit\"))) {\n      pElement = new CLayeredEditCtl(m_hWnd);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"panel\"))) {\n      pElement = new CPanelCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"progress\"))) {\n      pElement = new CProgressCtl(m_hWnd);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"checkbox\"))) {\n      pElement = new CCheckBoxCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n  }\n}\n\nvoid CTransWindow::SetWndStyle() {}\n\nvoid CTransWindow::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n\n  _nMinWidth = GetIntegerAttribute(element, \"minWidth\");\n  _nMinHeight = GetIntegerAttribute(element, \"minHeight\");\n  _nTitleHeight = GetIntegerAttribute(element, \"titleHeight\");\n  _strIconFile = GetStringAttribute(element, \"icon\");\n  _bmpFrame = GetBitmapAttribute(element, \"frame\");\n  _rcFrameCorner = GetRectAttribute(element, \"frameCorner\");\n  _bmpFrameBack = GetBitmapAttribute(element, \"frameBack\");\n  _rcFrameBackCorner = GetRectAttribute(element, \"frameBackCorner\");\n  _rcFrameBackPos = GetRectAttribute(element, \"frameBackPos\");\n  _bIsCenter = GetIntegerAttribute(element, \"center\") == 1 ? TRUE : FALSE;\n\n  _bmpResize = GetBitmapAttribute(element, \"resize\");\n  _bmpTitle = GetBitmapAttribute(element, \"title\");\n  _bmpLogo = GetBitmapAttribute(element, \"logo\");\n  _bRoundCorner = GetIntegerAttribute(element, \"roundcorner\");\n}\n\nHRESULT CTransWindow::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  bHandled = TRUE;\n  return 0;\n}\n\nvoid CTransWindow::DrawBg(HDC hDC) {\n  DrawBorder(hDC);\n  DrawTitle(hDC);\n}\n\nvoid CTransWindow::OnDraw(HDC hDC) { _elementManager.OnPaint(hDC); }\n\nvoid CTransWindow::DrawFrame(CDCHandle dc) {\n  RECT rcClient;\n  GetClientRect(&rcClient);\n\n  HDC hDC = dc.m_hDC;\n\n  CGDIResource::GetInstance().GDI_DrawRectangle(\n      hDC, &rcClient, RGB(110, 150, 177), RGB(182, 234, 253));\n}\n\nvoid CTransWindow::DrawBorder(CDCHandle dc) {\n  DUI_Rect wndRect;\n  GetClientRect(&wndRect);\n\n  HDC hDC = dc.m_hDC;\n\n  BITMAP bmpFrameData;\n  GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData);\n\n  if (_bmpFrame) {\n    CGDIResource::GetInstance().GDI_DrawImageStretch(\n        hDC, _bmpFrame, wndRect,\n        DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255,\n        _rcFrameCorner);\n  }\n\n  if (_bmpFrameBack) {\n    BITMAP bmpBackData;\n    GetObject(_bmpFrameBack, sizeof(bmpBackData), &bmpBackData);\n    CGDIResource::GetInstance().GDI_DrawImageStretch(\n        hDC, _bmpFrameBack, _rcFrameBackPos,\n        DUI_Rect(0, 0, bmpBackData.bmWidth, bmpBackData.bmHeight), 255,\n        _rcFrameBackCorner);\n  }\n}\n\nvoid CTransWindow::DrawTitle(CDCHandle dc) {\n  BITMAP bmpLogoInfor;\n  if (_bmpLogo) {\n    GetObject(_bmpLogo, sizeof(bmpLogoInfor), &bmpLogoInfor);\n\n    int nLeft = 10;\n    int nTop = 10;\n\n    CGDIResource::GetInstance().GDI_DrawImage(\n        dc.m_hDC, _bmpLogo, nLeft, nTop, bmpLogoInfor.bmWidth,\n        bmpLogoInfor.bmHeight, DUI_BT_ALPHA);\n  }\n\n  if (_title.size() > 0) {\n    RECT rcClient;\n    GetClientRect(&rcClient);\n\n    RECT rcText;\n    rcText.left = _bmpLogo != NULL ? 10 + bmpLogoInfor.bmWidth + 7 : 18;\n    rcText.right = rcClient.right - 1;\n    rcText.top = 9;\n    rcText.bottom = _nTitleHeight > 0 ? _nTitleHeight : rcText.top + 20;\n\n    CGDIResource::GetInstance().GDI_DrawText_Trans(\n        dc.m_hDC, _title.c_str(), &rcText,\n        CGDIResource::GetInstance().GDI_GetNormalFont(), RGB(255, 255, 255));\n  }\n}\n\nLRESULT CTransWindow::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  RECT rect;\n  GetWindowRect(&rect);\n  int x = GET_X_LPARAM(lParam);\n  int y = GET_Y_LPARAM(lParam);\n\n  DUI_Point pt(x, y);\n  ScreenToClient(&pt);\n\n  if (_elementManager.MouseOnElement(pt))\n    return HTCLIENT;\n\n  UINT nFlags = 0;\n  _elementManager.OnMouseMove(nFlags, pt);\n\n  int nTop = 4;\n  int nLeft = 4;\n  int nRight = 4;\n  int nBottom = 4;\n\n  if (IsZoomed()) {\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n    return HTCLIENT;\n  }\n\n  if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n    return HTCAPTION;\n\n  if (_bSupportChangeSize) {\n    if (x >= rect.left && x <= rect.left + nLeft) {\n      if (y < rect.top + nTop)\n        return HTTOPLEFT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMLEFT;\n\n      return HTLEFT;\n    }\n\n    if (x <= rect.right && x >= rect.right - nRight) {\n      if (y < rect.top + nTop)\n        return HTTOPRIGHT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMRIGHT;\n\n      return HTRIGHT;\n    }\n\n    if (y >= rect.top && y <= rect.top + nTop)\n      return HTTOP;\n\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n\n    if (y <= rect.bottom && y >= rect.bottom - nBottom) {\n      return HTBOTTOM;\n    }\n  }\n  return HTCLIENT;\n}\n\nLRESULT CTransWindow::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled) {\n  int cx = GET_X_LPARAM(lParam);\n  int cy = GET_Y_LPARAM(lParam);\n\n  _elementManager.OnSizeChanged(_size, cx, cy);\n  _size.cx = cx;\n  _size.cy = cy;\n\n  SetSkinedWindowRgn(_bRoundCorner);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  _elementManager.OnKeyDown((DWORD)wParam);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) {\n  _elementManager.OnKeyUp((DWORD)wParam);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n\n  _elementManager.OnKeyDown((DWORD)wParam);\n  return 0;\n}\n\nLRESULT CTransWindow::OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled) {\n  _elementManager.OnKeyUp((DWORD)wParam);\n  return 0;\n}\n\nLRESULT CTransWindow::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled) {\n  MINMAXINFO *lpMMI = (MINMAXINFO *)lParam;\n  lpMMI->ptMinTrackSize.x = _nMinWidth;\n  lpMMI->ptMinTrackSize.y = _nMinHeight;\n\n  RECT rt;\n  SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rt, 0);\n\n  lpMMI->ptMaxPosition.x = rt.left;\n  lpMMI->ptMaxPosition.y = rt.top;\n\n  lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x = rt.right - rt.left;\n  lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y = rt.bottom - rt.top;\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                        BOOL &bHandled) {\n  if (_bSupportDblTitle) {\n    if (IsZoomed())\n      ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);\n    else\n      ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);\n  }\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  if (IsZoomed() && !_bIsWin7) {\n    ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0);\n  } else {\n    ModifyStyle(WS_SYSMENU, 0, 0);\n  }\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0);\n  bHandled = FALSE;\n  return 0;\n}\n\nLRESULT CTransWindow::OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  return 0;\n}\n\nLRESULT CTransWindow::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseDown(uMsg, pt);\n  return 0;\n}\nLRESULT CTransWindow::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseUp(uMsg, pt);\n  return 0;\n}\n\nLRESULT CTransWindow::OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  return 0;\n}\n\nLRESULT CTransWindow::OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseRUp(uMsg, pt);\n  return 0;\n}\n\nLRESULT CTransWindow::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  MSG msg;\n  msg.hwnd = m_hWnd;\n  msg.message = WM_MOUSEMOVE;\n  msg.wParam = 0;\n  msg.lParam = GetMessagePos();\n  if (m_ptips)\n    m_ptips->RelayEvent(&msg);\n\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseMove(uMsg, pt);\n\n  TrackMouseLeave(m_hWnd);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseMove(uMsg, pt);\n  return 0;\n}\n\nLRESULT CTransWindow::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled) {\n  return 0;\n}\n\nLRESULT CTransWindow::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled) {\n  if (!IsWindow()) {\n    return 0;\n  }\n\n  UINT nState = (UINT)wParam;\n  if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) {\n    _bActived = TRUE;\n  } else {\n    _bActived = FALSE;\n  }\n\n  RECT rcClient;\n  GetClientRect(&rcClient);\n  rcClient.bottom = rcClient.top + _nTitleHeight;\n  InvalidateRect(&rcClient);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) {\n  ShowWindow(SW_HIDE);\n\n  OnExit();\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled) {\n  _elementManager.OnMove();\n  return 0;\n}\n\nLRESULT CTransWindow::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) {\n  if (wParam == ACTIVE_TIMER) {\n    _elementManager.DrawCursor();\n  }\n\n  return 0;\n}\n\nvoid CTransWindow::SetSkinedWindowRgn(BOOL bRound) {\n  if (!bRound) {\n    ::SetWindowRgn(m_hWnd, NULL, TRUE);\n  } else {\n    RECT rect;\n    GetWindowRect(&rect);\n    OffsetRect(&rect, -rect.left, -rect.top);\n    const int nRgnCornerSize = 5;\n    HRGN hRgn1 =\n        CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom,\n                           nRgnCornerSize, nRgnCornerSize);\n    HRGN hRgn2 = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right,\n                               rect.bottom);\n    HRGN hRgn = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right,\n                              rect.bottom);\n\n    CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR);\n    DeleteObject(hRgn1);\n    DeleteObject(hRgn2);\n\n    ::SetWindowRgn(m_hWnd, hRgn, TRUE);\n  }\n}\n\nBOOL CTransWindow::PreTranslateMessage(MSG *pMsg) {\n  if (m_ptips && ::IsWindow(m_ptips->m_hWnd)) {\n    m_ptips->RelayEvent(pMsg);\n  }\n  return FALSE;\n}\n\nLRESULT CTransWindow::OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled) {\n  if (!m_ptips)\n    return 0;\n  BOOL bTips = (BOOL)wParam;\n  if (bTips) {\n    LPCTSTR lpszText = (LPCTSTR)lParam;\n    m_ptips->UpdateTipText(lpszText, m_hWnd);\n    m_ptips->Activate(TRUE);\n  } else {\n    m_ptips->Activate(FALSE);\n  }\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  _elementManager.SetActive(pOwner);\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnChainMsg(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled) {\n  _elementManager.OnMsg(nMsg, wParam, lParam, bHandled);\n  return 0;\n}\n\nLRESULT CTransWindow::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  HCURSOR hCur = (HCURSOR)wParam;\n  if (hCur == LoadCursor(NULL, IDC_HAND)) {\n    ::SetClassLong(m_hWnd, GCL_HCURSOR,\n                   (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND)));\n  } else if (hCur == LoadCursor(NULL, IDC_IBEAM)) {\n    ::SetClassLong(m_hWnd, GCL_HCURSOR,\n                   (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_IBEAM)));\n  } else {\n    ::SetClassLong(m_hWnd, GCL_HCURSOR,\n                   (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));\n  }\n\n  return 0;\n}\n\nLRESULT CTransWindow::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  UINT fwKeys = LOWORD(wParam); /* key flags */\n  short zDelta = (short)HIWORD(wParam);\n  /* wheel rotation */\n  int xPos = (short)LOWORD(lParam);\n  /* horizontal position of pointer */\n  int yPos = (short)HIWORD(lParam);\n  /* vertical position of pointer */\n  CPoint pt(xPos, yPos);\n  ScreenToClient(&pt);\n  _elementManager.OnMouseWheel(fwKeys, zDelta, pt);\n  return 0;\n}\n\nvoid CTransWindow::OnLoad() {}\n\nvoid CTransWindow::OnLoaded() {}\n\nvoid CTransWindow::OnExit() { _elementManager.Dispose(); }\n\nDWORD CTransWindow::OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_NOTIFYITEMDRAW;\n}\n\nDWORD CTransWindow::OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_DODEFAULT;\n}\n\nDWORD CTransWindow::OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_DODEFAULT;\n}\n"
  },
  {
    "path": "src/DirectUI/DUITransWindow.h",
    "content": "#pragma once\n\n#include \"DUIButton.h\"\n#include \"DUICheckBox.h\"\n#include \"DUIElement.h\"\n#include \"DUIElementsMgr.h\"\n#include \"DUIHyperLink.h\"\n#include \"DUILayeredEdit.h\"\n#include \"DUIPanel.h\"\n#include \"DUIProgress.h\"\n#include \"DUIStatic.h\"\n#include \"DUITab.h\"\n#include \"DUITabList.h\"\n#include \"UpdateWindowBase.h\"\n\n#define CHAIN_ALL_MSG(func)                                                    \\\n  {                                                                            \\\n    if (func(uMsg, wParam, lParam, bHandled))                                  \\\n      return TRUE;                                                             \\\n  }\n\nclass __declspec(novtable) CTransWindow : public CMessageFilter,\n                                          public CBaseElementCtl,\n                                          public CUpdateWindowBase {\npublic:\n  CTransWindow();\n  virtual ~CTransWindow();\n\n  DECLARE_WND_CLASS(NULL)\n\n  BEGIN_MSG_MAP(CTransWindow)\n  CHAIN_MSG_MAP(CUpdateWindowBase)\n  CHAIN_ALL_MSG(OnChainMsg)\n\n  MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n  MESSAGE_HANDLER(WM_SIZE, OnSize)\n  MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n  MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)\n  MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)\n  MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)\n  MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)\n  MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNcMouseMove)\n  MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n  MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)\n  MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)\n  MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUP)\n  MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n  MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)\n  MESSAGE_HANDLER(WM_COMMAND, OnCommand)\n\n  MESSAGE_HANDLER(WM_MOVE, OnMove)\n  MESSAGE_HANDLER(WM_CLOSE, OnClose)\n  MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)\n  MESSAGE_HANDLER(WM_GETICON, OnGetIcon)\n\n  MESSAGE_HANDLER(WM_MSG_TIPS, OnTips)\n  MESSAGE_HANDLER(WM_MSG_CURSOR, OnSetCursor)\n  MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseWheel)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_LUP, OnAsynCall_LUp)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_RUP, OnAsynCall_RUp)\n  MESSAGE_HANDLER(WM_MSG_ACTIVE, OnElementActive)\n\n  END_MSG_MAP()\n\n  BOOL DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow);\n  BOOL DUICreateW(HWND hParentWnd, WCHAR *lpszXml);\n  BOOL DUICreate(HWND hParentWnd, DWORD dwExStyle = 0);\n  BOOL DoModal();\n\n  virtual void DrawBg(HDC hDC);\n  virtual void OnDraw(HDC hDC);\n\n  virtual void DrawFrame(CDCHandle dc);\n\n  virtual void DrawBorder(CDCHandle dc);\n\n  virtual void DrawTitle(CDCHandle dc);\n\n  virtual LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                           BOOL &bHandled);\n  virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled);\n  virtual LRESULT OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled);\n  virtual LRESULT OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled);\n  virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled);\n  virtual LRESULT OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled);\n  virtual LRESULT OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled);\n  virtual LRESULT OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled);\n  virtual LRESULT OnChainMsg(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled);\n  virtual BOOL PreTranslateMessage(MSG *pMsg);\n\n  virtual void SetWndPos(DUI_Point &pt, DUI_Size &sz);\n\n  virtual void OnLoad();\n  virtual void OnLoaded();\n\n  virtual void OnExit();\n  virtual void OnLoadIcon();\n\n  virtual DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n  virtual DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n  virtual DWORD OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n\n  BOOL _bOK;\n\nprotected:\n  virtual void OnDynamicCreate();\n\n  virtual void SetSkinedWindowRgn(BOOL bZoomed);\n  virtual void CreateElement(XmlElementPtr element);\n  virtual void SetWndStyle();\n\n  BOOL _bIsWin7;\n\n  BOOL _bActived;\n\n  int _nTimerID;\n\n  CAnyElementsMgr _elementManager;\n\n  CToolTipCtrl *m_ptips;\n\n  BOOL _bSupportDblTitle;\n\n  BOOL _bSupportChangeSize;\n\n  int _nMinWidth;\n  int _nMinHeight;\n  int _nTitleHeight;\n  BOOL _bIsCenter;\n  BOOL _bRoundCorner;\n\n  tstring _strXmlWindow;\n\n  tstring _strIconFile;\n\n  HBITMAP _bmpSingleBack;\n\n  HBITMAP _bmpArrow;\n\n  HBITMAP _bmpBackgroundTL;\n  HBITMAP _bmpBackgroundT;\n  HBITMAP _bmpBackgroundTR;\n  HBITMAP _bmpBackgroundL;\n  HBITMAP _bmpBackgroundC;\n  HBITMAP _bmpBackgroundR;\n  HBITMAP _bmpBackgroundBL;\n  HBITMAP _bmpBackgroundB;\n  HBITMAP _bmpBackgroundBR;\n\n  HBITMAP _bmpFrame;\n  DUI_Rect _rcFrameCorner;\n  HBITMAP _bmpFrameBack;\n  DUI_Rect _rcFrameBackCorner;\n  DUI_Rect _rcFrameBackPos;\n\n  HBITMAP _bmpResize;\n\n  HBITMAP _bmpTitle;\n\n  HBITMAP _bmpLogo;\n\n  XmlElementPtr m_pXmlWindow;\n};\n\ninline LRESULT CTransWindow::OnAsynCall_LUp(UINT nMsg, WPARAM wParam,\n                                            LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_LeftUp();\n\n  return S_OK;\n}\n\ninline LRESULT CTransWindow::OnAsynCall_RUp(UINT nMsg, WPARAM wParam,\n                                            LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_RightUp();\n\n  return S_OK;\n}\n"
  },
  {
    "path": "src/DirectUI/DUITransWindowEx.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DUITransWindowEx.h\"\n"
  },
  {
    "path": "src/DirectUI/DUITransWindowEx.h",
    "content": "#pragma once\n\n#include \"util/system.h\"\n#include \"DUIButton.h\"\n#include \"DUICheckBox.h\"\n#include \"DUIElement.h\"\n#include \"DUIElementsMgr.h\"\n#include \"DUIHyperLink.h\"\n#include \"DUILayeredEdit.h\"\n#include \"DUIOptionLine.h\"\n#include \"DUIPanel.h\"\n#include \"DUIProgress.h\"\n#include \"DUIStatic.h\"\n#include \"DUITab.h\"\n#include \"DUITabList.h\"\n#include \"UpdateWindowBaseEx.h\"\n\nenum enumShakeWindow { SHAKEWINDOW_ERROR = 0 };\n\n#define SHAKEWINDOW 0x10\n\ntemplate <class T>\nclass __declspec(novtable) CTransWindowEx : public CMessageFilter,\n                                            public CBaseElementCtl,\n                                            public CUpdateWindowBaseEx<T> {\npublic:\n  CTransWindowEx();\n  virtual ~CTransWindowEx();\n  BEGIN_MSG_MAP(CTransWindowEx)\n  CHAIN_MSG_MAP(CUpdateWindowBaseEx<T>)\n  MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(WM_DESTROY, OnDestroy)\n  MESSAGE_HANDLER(WM_SIZE, OnSize)\n  MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)\n  MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)\n  MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)\n  MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)\n  MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)\n  MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnNcMouseMove)\n  MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\n  MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)\n  MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)\n  MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUP)\n  MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\n  MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)\n  MESSAGE_HANDLER(WM_COMMAND, OnCommand)\n  MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)\n  MESSAGE_HANDLER(WM_MOVE, OnMove)\n  MESSAGE_HANDLER(WM_CLOSE, OnClose)\n  MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)\n  MESSAGE_HANDLER(WM_GETICON, OnGetIcon)\n  MESSAGE_HANDLER(WM_TIMER, OnTimer)\n  MESSAGE_HANDLER(WM_MSG_TIPS, OnTips)\n  MESSAGE_HANDLER(WM_MSG_CURSOR, OnSetCursor)\n  MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseWheel)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_LUP, OnAsynCall_LUp)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_RUP, OnAsynCall_RUp)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_ENTERKEY, OnAsynCall_EnterKey)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_TABKEY, OnAsynCall_TabKey)\n  MESSAGE_HANDLER(WM_ASYNC_CALL_LDOWN, OnAsynCall_LDown)\n  MESSAGE_HANDLER(WM_MSG_ACTIVE, OnElementActive)\n  MESSAGE_HANDLER(WM_PATH_ILLCHARACTER, OnPathIllCharacter)\n  END_MSG_MAP()\n\n  BOOL DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow);\n  BOOL DUICreateW(HWND hParentWnd, WCHAR *lpszXml);\n  BOOL DUICreate(HWND hParentWnd, DWORD dwExStyle = 0);\n  BOOL DoModal();\n  virtual void DrawBg(HDC hDC);\n  virtual void OnDraw(HDC hDC);\n\n  virtual void DrawFrame(CDCHandle dc);\n\n  virtual void DrawBorder(CDCHandle dc);\n\n  virtual void DrawTitle(CDCHandle dc);\n\n  virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                           BOOL &bHandled);\n  virtual LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled);\n  virtual LRESULT OnNcLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled);\n  virtual LRESULT OnNcMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                BOOL &bHandled);\n  virtual LRESULT OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled);\n  virtual LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled);\n  virtual LRESULT OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  virtual LRESULT OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled);\n  virtual LRESULT OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                         BOOL &bHandled);\n  virtual LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                               BOOL &bHandled);\n  virtual LRESULT OnAsynCall_LUp(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled);\n  virtual LRESULT OnAsynCall_RUp(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                 BOOL &bHandled);\n  virtual LRESULT OnAsynCall_EnterKey(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled);\n  virtual LRESULT OnAsynCall_TabKey(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled);\n  virtual LRESULT OnAsynCall_LDown(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled);\n  virtual LRESULT OnElementActive(UINT nMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled);\n  virtual LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                            BOOL &bHandled);\n  virtual LRESULT OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled);\n  virtual BOOL PreTranslateMessage(MSG *pMsg);\n\n  virtual void SetWndPos(DUI_Point &pt, DUI_Size &sz);\n\n  virtual void OnLoad();\n  virtual void OnLoaded();\n\n  virtual void OnExit();\n  virtual void OnLoadIcon();\n\n  virtual DWORD OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n  virtual DWORD OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n  virtual DWORD OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD);\n\n  void ChangeSize(int w, int h);\n\nprotected:\n  virtual void OnDynamicCreate();\n\n  virtual void SetSkinedWindowRgn(BOOL bZoomed);\n  virtual void CreateElement(XmlElementPtr element);\n  virtual void SetWndStyle();\n\n  BOOL _bIsWin7;\n\n  BOOL _bActived;\n\n  int _nTimerID;\n\n  CAnyElementsMgr _elementManager;\n\n  CToolTipCtrl m_tips;\n\n  BOOL _bSupportDblTitle;\n\n  BOOL _bSupportChangeSize;\n\n  int _nMinWidth;\n  int _nMinHeight;\n  int _nTitleHeight;\n  BOOL _bIsCenter;\n\n  tstring _strXmlWindow;\n\n  tstring _strIconFile;\n\n  HBITMAP _bmpSingleBack;\n\n  HBITMAP _bmpArrow;\n\n  HBITMAP _bmpBackgroundTL;\n  HBITMAP _bmpBackgroundT;\n  HBITMAP _bmpBackgroundTR;\n  HBITMAP _bmpBackgroundL;\n  HBITMAP _bmpBackgroundC;\n  HBITMAP _bmpBackgroundR;\n  HBITMAP _bmpBackgroundBL;\n  HBITMAP _bmpBackgroundB;\n  HBITMAP _bmpBackgroundBR;\n\n  HBITMAP _bmpFrame;\n  DUI_Rect _rcFrameCorner;\n  HBITMAP _bmpFrameBack;\n  DUI_Rect _rcFrameBackCorner;\n  DUI_Rect _rcFrameBackPos;\n\n  HBITMAP _bmpResize;\n\n  HBITMAP _bmpTitle;\n\n  HBITMAP _bmpLogo;\n\n  XmlElementPtr m_pXmlWindow;\n\n  BOOL _bOK;\n\n  bool bshaking_;\n\nprotected:\n  virtual void StartShake() {}\n  virtual void Shaked() {}\n\npublic:\n  void ShakeWindow(int reason = 0);\n  RECT m_WindowRect;\n  int m_count;\n  int m_Lrud;\n  void LmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) {\n    o_rc = i_rc;\n    o_rc.left -= delta;\n    o_rc.right -= delta;\n  }\n  void UmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) {\n    o_rc = i_rc;\n    o_rc.top -= delta;\n    o_rc.bottom -= delta;\n  }\n  void RmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) {\n    o_rc = i_rc;\n    o_rc.left += delta;\n    o_rc.right += delta;\n  }\n  void DmoveRect(/*_In_*/ const RECT &i_rc, long delta, /*_Out_*/ RECT &o_rc) {\n    o_rc = i_rc;\n    o_rc.top += delta;\n    o_rc.bottom += delta;\n  }\n};\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnAsynCall_LUp(UINT nMsg, WPARAM wParam,\n                                          LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_LeftUp();\n  return S_OK;\n}\n\ntemplate <typename T>\nLRESULT CTransWindowEx<T>::OnAsynCall_LDown(UINT nMsg, WPARAM wParam,\n                                            LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_LeftDown();\n  return S_OK;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnAsynCall_RUp(UINT nMsg, WPARAM wParam,\n                                          LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_RightUp();\n\n  return S_OK;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnAsynCall_EnterKey(UINT nMsg, WPARAM wParam,\n                                               LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  pOwner->OnCall_EnterKey();\n  return S_OK;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnAsynCall_TabKey(UINT nMsg, WPARAM wParam,\n                                             LPARAM lParam, BOOL &bHandled) {\n  return S_OK;\n}\n\ntemplate <class T> CTransWindowEx<T>::CTransWindowEx() : bshaking_(false) {\n  _bIsWin7 = FALSE;\n  _bActived = FALSE;\n  _nTimerID = 0;\n  _transparent = TRUE;\n  _nMinWidth = 307;\n  _nMinHeight = 451;\n  _nTitleHeight = 20;\n  _bmpArrow = NULL;\n  _bmpFrame = NULL;\n  _bmpFrameBack = NULL;\n  _bmpResize = NULL;\n  _bmpTitle = NULL;\n  _bmpLogo = NULL;\n  _bIsCenter = FALSE;\n  _bSupportChangeSize = FALSE;\n  _bSupportDblTitle = FALSE;\n  _bOK = FALSE;\n  m_count = 0;\n  m_Lrud = 0;\n}\n\ntemplate <class T> CTransWindowEx<T>::~CTransWindowEx() { Detach(); }\n\ntemplate <class T>\nBOOL CTransWindowEx<T>::DUICreateW(HWND hParentWnd, WCHAR *lpszXml) {\n\n  CXmlHelper helper;\n  helper.LoadStringW(lpszXml);\n\n  m_pXmlWindow = helper.GetRoot();\n  if (m_pXmlWindow == NULL) {\n    return FALSE;\n  }\n  if (helper.GetElementName(m_pXmlWindow).compare(_T(\"window\"))) {\n    return FALSE;\n  }\n\n  CreateElement(m_pXmlWindow);\n\n  SetWndPos(_location, _size);\n\n  SetWndStyle();\n\n  DUI_Rect rcWnd(_location, _size);\n  _CUpdateWindowBaseEx_WndRect_con = rcWnd;\n\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME;\n  _style |= DS_MODALFRAME;\n  HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style);\n\n  if (hWnd == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  ::SetForegroundWindow(m_hWnd);\n\n  OnLoaded();\n  return TRUE;\n}\n\ntemplate <class T>\nBOOL CTransWindowEx<T>::DUICreate(HWND hParentWnd, LPCTSTR lpszXmlWidow) {\n  _strXmlWindow = lpszXmlWidow;\n\n  CXmlHelper helper;\n  helper.loadResFile(_hInstance, _strXmlWindow.c_str(), _T(\"xml\"));\n\n  m_pXmlWindow = helper.GetRoot();\n  if (m_pXmlWindow == NULL) {\n    return FALSE;\n  }\n  if (helper.GetElementName(m_pXmlWindow).compare(_T(\"window\"))) {\n    return FALSE;\n  }\n\n  CreateElement(m_pXmlWindow);\n\n  SetWndPos(_location, _size);\n\n  SetWndStyle();\n\n  DUI_Rect rcWnd(_location, _size);\n  _CUpdateWindowBaseEx_WndRect_con = rcWnd;\n\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME;\n  _style |= DS_MODALFRAME;\n  HWND hWnd = Create(hParentWnd, rcWnd, _title.c_str(), _style, _ex_style);\n\n  if (hWnd == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  ::SetForegroundWindow(m_hWnd);\n\n  OnLoaded();\n\n  return TRUE;\n}\n\ntemplate <class T>\nBOOL CTransWindowEx<T>::DUICreate(HWND hParentWnd, DWORD dwExStyle) {\n  SetWndPos(_location, _size);\n\n  DUI_Rect rcWnd(_location, _size);\n  _CUpdateWindowBaseEx_WndRect_con = rcWnd;\n  DWORD dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP | DS_MODALFRAME;\n\n  if (Create(hParentWnd, rcWnd, _T(\"\"), dwStyle, dwExStyle) == NULL) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return FALSE;\n  }\n\n  if (dwExStyle & WS_EX_TOOLWINDOW) {\n    ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);\n  } else {\n    ::SetForegroundWindow(m_hWnd);\n  }\n\n  return TRUE;\n}\n\ntemplate <class T>\nvoid CTransWindowEx<T>::SetWndPos(DUI_Point &pt, DUI_Size &sz) {}\n\ntemplate <class T> BOOL CTransWindowEx<T>::DoModal() {\n  // todo\n  return _bOK;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  _host = m_hWnd;\n\n  if (_bIsCenter) {\n    CenterWindow();\n    GetWindowRect(&_CUpdateWindowBaseEx_WndRect_con);\n  }\n\n  _elementManager.InitOwner(m_hWnd);\n\n  OnDynamicCreate();\n\n  m_tips.Create(m_hWnd);\n  m_tips.Activate(FALSE);\n  m_tips.AddTool(m_hWnd);\n  m_tips.SetMaxTipWidth(260);\n\n  OnLoad();\n\n  OnLoadIcon();\n\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::OnLoadIcon() {\n  static HICON hIcon = (HICON)::LoadImage(\n      _Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON,\n      ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON),\n      LR_DEFAULTCOLOR);\n  if (hIcon) {\n    SetIcon(hIcon, TRUE);\n    SetIcon(hIcon, FALSE);\n  }\n}\n\ntemplate <class T> void CTransWindowEx<T>::OnDynamicCreate() {\n  CXmlHelper helper;\n  std::vector<XmlElementPtr> pAllElement = helper.GetChild(m_pXmlWindow);\n  std::vector<XmlElementPtr>::iterator ite = pAllElement.begin();\n  tstring strEleName;\n  CBaseElementCtl *pElement = NULL;\n  for (ite; ite != pAllElement.end(); ite++) {\n\n    CXmlHelper helper;\n    strEleName = helper.GetElementName(*ite);\n\n    if (!strEleName.compare(_T(\"button\"))) {\n      pElement = new CButtonCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n    if (!strEleName.compare(_T(\"tab\"))) {\n      pElement = new CTabCtl(m_hWnd);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"static\"))) {\n      pElement = new CStaticCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"link\"))) {\n      pElement = new CHyperLinkCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"layedit\"))) {\n      pElement = new CLayeredEditCtl(m_hWnd);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"panel\"))) {\n      pElement = new CPanelCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n    if (!strEleName.compare(_T(\"progress\"))) {\n      pElement = new CProgressCtl(m_hWnd);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n    }\n\n    if (!strEleName.compare(_T(\"checkbox\"))) {\n      pElement = new CCheckBoxCtl(m_hWnd, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n\n    if (!strEleName.compare(_T(\"tablist\"))) {\n      pElement = new CTabListCtl(_host, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n      continue;\n    }\n    if (!strEleName.compare(_T(\"optionline\"))) {\n      pElement = new COptionLineCtl(_host, TRUE);\n      pElement->CreateElement(*ite);\n      _elementManager.AddElement(pElement);\n    }\n  }\n}\n\ntemplate <class T>\nvoid CTransWindowEx<T>::CreateElement(XmlElementPtr element) {\n  GetElementStyle(element);\n\n  _nMinWidth = GetIntegerAttribute(element, \"minWidth\");\n  _nMinHeight = GetIntegerAttribute(element, \"minHeight\");\n  _nTitleHeight = GetIntegerAttribute(element, \"titleHeight\");\n  _strIconFile = GetStringAttribute(element, \"icon\");\n  _bmpFrame = GetBitmapAttribute(element, \"frame\");\n  _rcFrameCorner = GetRectAttribute(element, \"frameCorner\");\n  _bmpFrameBack = GetBitmapAttribute(element, \"frameBack\");\n  _rcFrameBackCorner = GetRectAttribute(element, \"frameBackCorner\");\n  _rcFrameBackPos = GetRectAttribute(element, \"frameBackPos\");\n  _bIsCenter = GetIntegerAttribute(element, \"center\") == 1 ? TRUE : FALSE;\n\n  GetIntegerAttribute(element, \"topmost\") ? (_ex_style |= WS_EX_TOPMOST)\n                                          : _ex_style;\n\n  _bmpResize = GetBitmapAttribute(element, \"resize\");\n  _bmpTitle = GetBitmapAttribute(element, \"title\");\n  _bmpLogo = GetBitmapAttribute(element, \"logo\");\n}\n\ntemplate <class T> void CTransWindowEx<T>::DrawBg(HDC hDC) {\n  DrawBorder(hDC);\n  DrawTitle(hDC);\n}\n\ntemplate <class T> void CTransWindowEx<T>::OnDraw(HDC hDC) {\n  _elementManager.OnPaint(hDC);\n}\n\ntemplate <class T> void CTransWindowEx<T>::DrawFrame(CDCHandle dc) {\n  RECT rcClient;\n  GetClientRect(&rcClient);\n\n  HDC hDC = dc.m_hDC;\n\n  CGDIResource::GetInstance().GDI_DrawRectangle(\n      hDC, &rcClient, RGB(110, 150, 177), RGB(182, 234, 253));\n}\n\ntemplate <class T> void CTransWindowEx<T>::DrawBorder(CDCHandle dc) {\n  if (!_bmpFrame)\n    return;\n\n  DUI_Rect wndRect(0, 0, 0, 0);\n\n  if (_bCUpdateWindowBaseEx_TransShow) {\n    HDC hDC = dc.m_hDC;\n\n    BITMAP bmpFrameData;\n    GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData);\n\n    wndRect.right = _CUpdateWindowBaseEx_WndRect_con.Width();\n    wndRect.bottom = _CUpdateWindowBaseEx_WndRect_con.Height();\n\n    CGDIResource::GetInstance().GDI_DrawImageStretch(\n        hDC, _bmpFrame, wndRect,\n        DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255,\n        _rcFrameCorner);\n  } else {\n    GetClientRect(&wndRect);\n\n    HDC hDC = dc.m_hDC;\n\n    BITMAP bmpFrameData;\n    GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData);\n\n    CGDIResource::GetInstance().GDI_DrawImageStretch(\n        hDC, _bmpFrame, wndRect,\n        DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 255,\n        _rcFrameCorner);\n  }\n}\n\ntemplate <class T> void CTransWindowEx<T>::DrawTitle(CDCHandle dc) {\n  BITMAP bmpLogoInfor;\n  if (_bmpLogo) {\n    GetObject(_bmpLogo, sizeof(bmpLogoInfor), &bmpLogoInfor);\n\n    int nLeft = 12;\n    int nTop = 10;\n    if (nTop < 0)\n      nTop = 0;\n    CGDIResource::GetInstance().GDI_DrawImage(\n        dc.m_hDC, _bmpLogo, nLeft, nTop, bmpLogoInfor.bmWidth,\n        bmpLogoInfor.bmHeight, DUI_BT_ALPHA);\n  }\n\n  if (_title.size() > 0) {\n    RECT rcClient = {0, 0, 0, 0};\n    if (_bCUpdateWindowBaseEx_TransShow) {\n      rcClient.right = _CUpdateWindowBaseEx_WndRect_con.Width();\n      rcClient.bottom = _CUpdateWindowBaseEx_WndRect_con.Height();\n    } else\n      GetClientRect(&rcClient);\n\n    RECT rcText;\n    rcText.left = _bmpLogo != NULL ? 8 + bmpLogoInfor.bmWidth + 8 : 14;\n    rcText.right = rcClient.right - 1;\n    rcText.top = 9;\n    rcText.bottom = _nTitleHeight > 0 ? _nTitleHeight : rcText.top + 20;\n    if (1) {\n      CGDIResource::GetInstance().GDI_DrawText_Trans(\n          dc.m_hDC, _title.c_str(), &rcText, RGB(255, 255, 255));\n    }\n  }\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  if (bshaking_) {\n    bHandled = TRUE;\n    return S_OK;\n  }\n  RECT rect;\n  GetWindowRect(&rect);\n  int x = GET_X_LPARAM(lParam);\n  int y = GET_Y_LPARAM(lParam);\n\n  DUI_Point pt(x, y);\n  ScreenToClient(&pt);\n\n  if (_elementManager.MouseOnElement(pt))\n    return HTCLIENT;\n\n  UINT nFlags = 0;\n  _elementManager.OnMouseMove(nFlags, pt);\n\n  int nTop = 4;\n  int nLeft = 4;\n  int nRight = 4;\n  int nBottom = 4;\n\n  if (IsZoomed()) {\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n    return HTCLIENT;\n  }\n\n  if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n    return HTCAPTION;\n\n  if (_bSupportChangeSize) {\n    if (x >= rect.left && x <= rect.left + nLeft) {\n      if (y < rect.top + nTop)\n        return HTTOPLEFT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMLEFT;\n\n      return HTLEFT;\n    }\n\n    if (x <= rect.right && x >= rect.right - nRight) {\n      if (y < rect.top + nTop)\n        return HTTOPRIGHT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMRIGHT;\n\n      return HTRIGHT;\n    }\n\n    if (y >= rect.top && y <= rect.top + nTop)\n      return HTTOP;\n\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n\n    if (y <= rect.bottom && y >= rect.bottom - nBottom) {\n      return HTBOTTOM;\n    }\n  }\n  return HTCLIENT;\n\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  if (_bCUpdateWindowBaseEx_TransShow)\n    return 0;\n\n  int cx = GET_X_LPARAM(lParam);\n  int cy = GET_Y_LPARAM(lParam);\n\n  _elementManager.OnSizeChanged(_size, cx, cy);\n  _size.cx = cx;\n  _size.cy = cy;\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::ChangeSize(int a, int b) {\n  _size.cx = a;\n  _size.cy = b;\n  _elementManager.OnSizeChanged(_size, a, b);\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) {\n  _elementManager.OnKeyDown((DWORD)wParam);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  _elementManager.OnKeyUp((DWORD)wParam);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnSysKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                        BOOL &bHandled) {\n\n  _elementManager.OnKeyDown((DWORD)wParam);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnSysKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled) {\n  _elementManager.OnKeyUp((DWORD)wParam);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnGetMinMaxInfo(UINT uMsg, WPARAM wParam,\n                                           LPARAM lParam, BOOL &bHandled) {\n  MINMAXINFO *lpMMI = (MINMAXINFO *)lParam;\n  lpMMI->ptMinTrackSize.x = _nMinWidth;\n  lpMMI->ptMinTrackSize.y = _nMinHeight;\n\n  RECT rt;\n  SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rt, 0);\n\n  lpMMI->ptMaxPosition.x = rt.left;\n  lpMMI->ptMaxPosition.y = rt.top;\n\n  lpMMI->ptMaxTrackSize.x = lpMMI->ptMaxSize.x = rt.right - rt.left;\n  lpMMI->ptMaxTrackSize.y = lpMMI->ptMaxSize.y = rt.bottom - rt.top;\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnNcLButtonDblClk(UINT uMsg, WPARAM wParam,\n                                             LPARAM lParam, BOOL &bHandled) {\n  if (_bSupportDblTitle) {\n    if (IsZoomed())\n      ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);\n    else\n      ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);\n  }\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnNcMouseMove(UINT uMsg, WPARAM wParam,\n                                         LPARAM lParam, BOOL &bHandled) {\n  if (IsZoomed() && !_bIsWin7) {\n    ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0);\n  } else {\n    ModifyStyle(WS_SYSMENU, 0, 0);\n  }\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnGetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) {\n  ModifyStyle(0, WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0);\n  bHandled = FALSE;\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) {\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnLButtonDown(UINT uMsg, WPARAM wParam,\n                                         LPARAM lParam, BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseDown(uMsg, pt);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseUp(uMsg, pt);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnRButtonDown(UINT uMsg, WPARAM wParam,\n                                         LPARAM lParam, BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnRButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseRUp(uMsg, pt);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  MSG msg;\n  msg.hwnd = m_hWnd;\n  msg.message = WM_MOUSEMOVE;\n  msg.wParam = 0;\n  msg.lParam = GetMessagePos();\n  if (IsWindow())\n    m_tips.RelayEvent(&msg);\n\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseMove(uMsg, pt);\n\n  TrackMouseLeave(m_hWnd);\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                        BOOL &bHandled) {\n  bHandled = TRUE;\n  DUI_Point pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));\n  _elementManager.OnMouseMove(uMsg, pt);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) {\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled) {\n  if (!IsWindow()) {\n    return 0;\n  }\n  UINT nState = (UINT)wParam;\n  if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) {\n    _bActived = TRUE;\n  } else {\n    _bActived = FALSE;\n  }\n\n  RECT rcClient;\n  GetClientRect(&rcClient);\n  rcClient.bottom = rcClient.top + _nTitleHeight;\n  InvalidateRect(&rcClient);\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  this->OnExit();\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) {\n  if (::IsWindow((m_tips.m_hWnd))) {\n    m_tips.DestroyWindow();\n  }\n  m_tips.m_hWnd = NULL;\n  KillTimer(SHAKEWINDOW);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnPathIllCharacter(UINT uMsg, WPARAM wParam,\n                                              LPARAM lParam, BOOL &bHandled) {\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::OnExit() {\n  _elementManager.Dispose();\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnMove(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  _elementManager.OnMove();\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::SetSkinedWindowRgn(BOOL bZoomed) {\n  if (bZoomed) {\n    ::SetWindowRgn(m_hWnd, NULL, TRUE);\n  } else {\n    RECT rect;\n    GetWindowRect(&rect);\n    OffsetRect(&rect, -rect.left, -rect.top);\n    const int nRgnCornerSize = 5;\n    HRGN hRgn1 =\n        CreateRoundRectRgn(rect.left, rect.top, rect.right + 1, rect.bottom,\n                           nRgnCornerSize, nRgnCornerSize);\n    HRGN hRgn2 = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right,\n                               rect.bottom);\n    HRGN hRgn = CreateRectRgn(rect.left, rect.top + nRgnCornerSize, rect.right,\n                              rect.bottom);\n\n    CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR);\n    DeleteObject(hRgn1);\n    DeleteObject(hRgn2);\n\n    ::SetWindowRgn(m_hWnd, hRgn, TRUE);\n  }\n}\n\ntemplate <class T> BOOL CTransWindowEx<T>::PreTranslateMessage(MSG *pMsg) {\n  if (::IsWindow(m_tips.m_hWnd)) {\n    m_tips.RelayEvent(pMsg);\n  }\n\n  return FALSE;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnTips(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  BOOL bTips = (BOOL)wParam;\n  if (bTips) {\n    LPCTSTR lpszText = (LPCTSTR)lParam;\n\n    m_tips.UpdateTipText(lpszText, m_hWnd);\n    m_tips.Activate(TRUE);\n  } else {\n    m_tips.Activate(FALSE);\n  }\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnElementActive(UINT nMsg, WPARAM wParam,\n                                           LPARAM lParam, BOOL &bHandled) {\n  CBaseElementCtl *pOwner = (CBaseElementCtl *)wParam;\n  _elementManager.SetActive(pOwner);\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnSetCursor(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  HCURSOR hCur = (HCURSOR)wParam;\n  if (hCur == LoadCursor(NULL, IDC_HAND)) {\n    ::SetClassLong(m_hWnd, GCL_HCURSOR,\n                   (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND)));\n  } else {\n    ::SetClassLong(m_hWnd, GCL_HCURSOR,\n                   (long)LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));\n  }\n\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                        BOOL &bHandled) {\n  UINT fwKeys = LOWORD(wParam); /* key flags */\n  short zDelta = (short)HIWORD(wParam);\n  /* wheel rotation */\n  int xPos = (short)LOWORD(lParam);\n  /* horizontal position of pointer */\n  int yPos = (short)HIWORD(lParam);\n  /* vertical position of pointer */\n  CPoint pt(xPos, yPos);\n  ScreenToClient(&pt);\n  _elementManager.OnMouseWheel(fwKeys, zDelta, pt);\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::OnLoad() {}\n\ntemplate <class T> void CTransWindowEx<T>::OnLoaded() {}\n\ntemplate <class T>\nDWORD CTransWindowEx<T>::OnPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_NOTIFYITEMDRAW;\n}\n\ntemplate <class T>\nDWORD CTransWindowEx<T>::OnItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_DODEFAULT;\n}\n\ntemplate <class T>\nDWORD CTransWindowEx<T>::OnSubItemPrePaint(int idCtrl, LPNMCUSTOMDRAW lpNMCD) {\n  return CDRF_DODEFAULT;\n}\n\ntemplate <class T> void CTransWindowEx<T>::ShakeWindow(int reason) {\n  SystemCommon::Window::StretchForegroundWindow(m_hWnd);\n  ::SetFocus(m_hWnd);\n  if (reason == SHAKEWINDOW_ERROR) {\n    StartShake();\n    bshaking_ = true;\n    GetWindowRect(&m_WindowRect);\n    KillTimer(SHAKEWINDOW);\n    m_count = 11;\n    m_Lrud = 0;\n    SetTimer(SHAKEWINDOW, 45, NULL);\n    return;\n  }\n}\n\ntemplate <class T>\nLRESULT CTransWindowEx<T>::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  switch (wParam) {\n  case ACTIVE_TIMER: {\n    _elementManager.DrawCursor();\n  } break;\n  case SHAKEWINDOW: {\n    if (m_count <= 0) {\n      Shaked();\n      bshaking_ = false;\n      KillTimer(SHAKEWINDOW);\n      m_count = 0;\n      SetWindowPos(0, &m_WindowRect, SWP_NOZORDER | SWP_NOSIZE);\n    } else {\n      m_count--;\n      RECT rc;\n      int delta = 2;\n      if (m_Lrud == 0) {\n        m_Lrud++;\n        LmoveRect(m_WindowRect, delta, rc);\n        SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE);\n      } else if (m_Lrud == 1) {\n        m_Lrud++;\n        UmoveRect(m_WindowRect, delta, rc);\n        SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE);\n      } else if (m_Lrud == 2) {\n        m_Lrud++;\n        RmoveRect(m_WindowRect, delta, rc);\n        SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE);\n      } else if (m_Lrud == 3) {\n        m_Lrud = 0;\n        DmoveRect(m_WindowRect, delta, rc);\n        SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE);\n      }\n    }\n  } break;\n  }\n  return 0;\n}\n\ntemplate <class T> void CTransWindowEx<T>::SetWndStyle() {}\n"
  },
  {
    "path": "src/DirectUI/DUIWindowStyle.cpp",
    "content": "#include \"stdafx.h\"\n#include \"DUIWindowStyle.h\"\n#include \"DUIGDIResource.h\"\n\nCWindowCtlStyle::CWindowCtlStyle()\n    : _xAlignment(DUI_ALIGNMENT_NONE), _yAlignment(DUI_ALIGNMENT_NONE),\n      _xStretch(DUI_STRETCH_NONE), _yStretch(DUI_STRETCH_NONE) {}\n\nCWindowCtlStyle::~CWindowCtlStyle() {}\n\nvoid CWindowCtlStyle::LoadStyle(XmlElementPtr element) {\n  CXmlHelper helper;\n  _xAlignment = AlignmentStringToValue(\n      helper.GetAttributeString(element, \"xAlignment\").c_str(),\n      DUI_ALIGNMENT_LEFT);\n  _yAlignment = AlignmentStringToValue(\n      helper.GetAttributeString(element, \"yAlignment\").c_str(),\n      DUI_ALIGNMENT_TOP);\n  _xStretch = StretchStringToValue(\n      helper.GetAttributeString(element, \"xStretch\").c_str(), DUI_STRETCH_NONE);\n  _yStretch = StretchStringToValue(\n      helper.GetAttributeString(element, \"yStretch\").c_str(), DUI_STRETCH_NONE);\n}\n\ntstring CWindowCtlStyle::GetStringAttribute(XmlElementPtr element,\n                                            string attrName) {\n  CXmlHelper helper;\n  return helper.GetAttributeString(element, attrName.c_str());\n}\n\nHBITMAP CWindowCtlStyle::GetBitmapAttribute(XmlElementPtr element,\n                                            string attrName,\n                                            string key_mid_string) {\n  HBITMAP hBitmap = NULL;\n  CXmlHelper helper;\n  tstring attrValue = helper.GetAttributeString(element, attrName);\n  if (attrValue != _T(\"\")) {\n    hBitmap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                        attrValue.c_str(), PNG);\n  }\n\n  return hBitmap;\n}\n\nint CWindowCtlStyle::GetIntegerAttribute(XmlElementPtr element,\n                                         string attrName) {\n  CXmlHelper helper;\n  return helper.GetAttributeInt(element, attrName);\n}\n\nCOLORREF CWindowCtlStyle::GetColorAttribute(XmlElementPtr element,\n                                            string attrName) {\n  COLORREF color_ret;\n  tstring s_value = GetStringAttribute(element, attrName);\n  if (!s_value.empty()) {\n    color_ret = _tcstol(s_value.c_str(), NULL, 16);\n  }\n  return color_ret;\n}\n\nstd::vector<tstring> CWindowCtlStyle::split(const tstring src, tstring delimit,\n                                       tstring null_subst) {\n  std::vector<tstring> v;\n  int npos = -1;\n  if (src.empty() || delimit.empty())\n    return v;\n\n  int deli_len = delimit.size();\n  long index = npos, last_search_position = 0;\n  while ((index = src.find(delimit, last_search_position)) != npos) {\n    if (index == last_search_position)\n      v.push_back(null_subst);\n    else\n      v.push_back(\n          src.substr(last_search_position, index - last_search_position));\n    last_search_position = index + deli_len;\n  }\n  tstring last_one = src.substr(last_search_position);\n  v.push_back(last_one.empty() ? null_subst : last_one);\n  return v;\n}\n\nCOLORREF CWindowCtlStyle::GetRGBAttribute(XmlElementPtr element,\n                                          string attrName) {\n  COLORREF colour_ret = 0;\n  tstring s_value = GetStringAttribute(element, attrName);\n  if (!s_value.empty()) {\n    tstring src_value = s_value.c_str();\n    std::vector<tstring> v = split(src_value, _T(\",\"));\n    if (v.size() == 3) {\n      int r = _ttoi(v[0].c_str());\n      int g = _ttoi(v[1].c_str());\n      int b = _ttoi(v[2].c_str());\n      colour_ret = RGB(r, g, b);\n    }\n  }\n  return colour_ret;\n}\n\nDUI_Rect CWindowCtlStyle::GetRectAttribute(XmlElementPtr element,\n                                           string attrName) {\n  DUI_Rect rect_ret;\n  tstring s_value = GetStringAttribute(element, attrName);\n  if (!s_value.empty()) {\n    tstring src_value = s_value.c_str();\n    std::vector<tstring> v = split(src_value, _T(\",\"));\n    if (v.size() == 4) {\n      rect_ret.left = _ttoi(v[0].c_str());\n      rect_ret.top = _ttoi(v[1].c_str());\n      rect_ret.right = _ttoi(v[2].c_str());\n      rect_ret.bottom = _ttoi(v[3].c_str());\n    }\n  }\n  return rect_ret;\n}\n\nDUI_Size CWindowCtlStyle::StyleSizeToWindowSize(DUI_Size &eleSize,\n                                                DUI_Size &wndChangingSize,\n                                                DUI_Size &wndChangedSize,\n                                                DUI_STRETCH xFlag,\n                                                DUI_STRETCH yFlag) {\n  DUI_Size newSize(eleSize.cx, eleSize.cy);\n  switch (xFlag) {\n  case DUI_STRETCH_FILL:\n    newSize.cx = eleSize.cx + wndChangedSize.cx - wndChangingSize.cx;\n    break;\n  case DUI_STRETCH_SCALE:\n    newSize.cx = (int)((double)(eleSize.cx * wndChangedSize.cx) /\n                       (double)wndChangingSize.cx);\n    break;\n  default:\n    break;\n  }\n\n  switch (yFlag) {\n  case DUI_STRETCH_FILL:\n    newSize.cy = eleSize.cy + wndChangedSize.cy - wndChangingSize.cy;\n    break;\n  case DUI_STRETCH_SCALE:\n    newSize.cy = (int)((double)(eleSize.cy * wndChangedSize.cy) /\n                       (double)wndChangingSize.cy);\n    break;\n  default:\n    break;\n  }\n\n  return newSize;\n}\n\nDUI_Point CWindowCtlStyle::StyleLocationToWindowLocation(DUI_Rect &rc,\n                                                         DUI_Point fixPt,\n                                                         int alignX, int alignY,\n                                                         DUI_Size &windowSize) {\n  DUI_Point point(rc.left, rc.top);\n  DUI_Size size(rc.Width(), rc.Height());\n\n  if (alignX == DUI_ALIGNMENT_LEFT)\n    point.x = point.x;\n  else if (alignX == DUI_ALIGNMENT_RIGHT)\n    point.x = windowSize.cx - fixPt.x;\n  if (alignY == DUI_ALIGNMENT_TOP)\n    point.y = point.y;\n  else if (alignY == DUI_ALIGNMENT_BOTTOM)\n    point.y = windowSize.cy - fixPt.y;\n  if (alignX == DUI_ALIGNMENT_CENTER)\n    point.x = (windowSize.cx - size.cx) / 2;\n  if (alignY == DUI_ALIGNMENT_CENTER)\n    point.y = (windowSize.cy - size.cy) / 2;\n\n  return DUI_Point(point.x, point.y);\n}\n\nDUI_Rect CWindowCtlStyle::StyleRectToWindowRect(\n    DUI_Rect rc, DUI_Point oriPt, DUI_Size &wndChangingSize,\n    DUI_Size &wndChangedSize, DUI_ALIGNMENT alignX, DUI_ALIGNMENT alignY,\n    DUI_STRETCH stretchHor, DUI_STRETCH stretchVer) {\n\n  DUI_Point newPos =\n      StyleLocationToWindowLocation(rc, oriPt, alignX, alignY, wndChangedSize);\n\n  SIZE newSize =\n      StyleSizeToWindowSize(DUI_Size(rc.Width(), rc.Height()), wndChangingSize,\n                            wndChangedSize, stretchHor, stretchVer);\n\n  return DUI_Rect(newPos, newSize);\n}\n\nDUI_STRETCH CWindowCtlStyle::StretchStringToValue(tstring s,\n                                                  DUI_STRETCH stretch) {\n  if (s == _T(\"none\")) {\n    return DUI_STRETCH_NONE;\n  } else if (s == _T(\"fill\")) {\n    return DUI_STRETCH_FILL;\n  } else if (s == _T(\"scale\")) {\n    return DUI_STRETCH_SCALE;\n  } else {\n    return DUI_STRETCH_NONE;\n  }\n\n  return stretch;\n}\nDUI_ALIGNMENT CWindowCtlStyle::AlignmentStringToValue(tstring s,\n                                                      DUI_ALIGNMENT align) {\n  if (s.empty()) {\n    return align;\n  }\n  std::map<tstring, DUI_ALIGNMENT> dict1;\n  dict1[_T(\"left\")] = DUI_ALIGNMENT_LEFT;\n  dict1[_T(\"top\")] = DUI_ALIGNMENT_TOP;\n  dict1[_T(\"right\")] = DUI_ALIGNMENT_RIGHT;\n  dict1[_T(\"bottom\")] = DUI_ALIGNMENT_BOTTOM;\n  dict1[_T(\"center\")] = DUI_ALIGNMENT_CENTER;\n\n  if (dict1.find(s) != dict1.end()) {\n    return dict1[s];\n  }\n  return align;\n}\n\nHCURSOR CWindowCtlStyle::NameToCursor(tstring name) {\n  HCURSOR default_cursor = LoadCursor(NULL, IDC_ARROW);\n\n  std::map<tstring, HCURSOR> dict1;\n  dict1[_T(\"AppStarting\")] = LoadCursor(NULL, IDC_APPSTARTING);\n  dict1[_T(\"Arrow\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"Cross\")] = LoadCursor(NULL, IDC_CROSS);\n  dict1[_T(\"Default\")] = LoadCursor(NULL, IDC_ARROW);\n\n  dict1[_T(\"Help\")] = LoadCursor(NULL, IDC_HELP);\n  dict1[_T(\"HSplit\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"IBeam\")] = LoadCursor(NULL, IDC_IBEAM);\n  dict1[_T(\"No\")] = LoadCursor(NULL, IDC_NO);\n  dict1[_T(\"NoMove2D\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"NoMoveHoriz\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"NoMoveVert\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanEast\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanNE\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanNorth\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanNW\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanSE\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanSouth\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanSW\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"PanWest\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"SizeAll\")] = LoadCursor(NULL, IDC_SIZEALL);\n  dict1[_T(\"SizeNESW\")] = LoadCursor(NULL, IDC_SIZENESW);\n  dict1[_T(\"SizeNS\")] = LoadCursor(NULL, IDC_SIZENS);\n  dict1[_T(\"SizeNWSE\")] = LoadCursor(NULL, IDC_SIZENWSE);\n  dict1[_T(\"SizeWE\")] = LoadCursor(NULL, IDC_SIZEWE);\n  dict1[_T(\"UpArrow\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"VSplit\")] = LoadCursor(NULL, IDC_ARROW);\n  dict1[_T(\"WaitCursor\")] = LoadCursor(NULL, IDC_WAIT);\n  tstring key = name.c_str();\n  if (dict1.find(key) != dict1.end()) {\n    return HCURSOR(dict1[key]);\n  }\n  return default_cursor;\n}\n"
  },
  {
    "path": "src/DirectUI/DUIWindowStyle.h",
    "content": "#pragma once\n\n#include <vector>\n#include \"DUIDef.h\"\n\nclass __declspec(novtable) CWindowCtlStyle {\n  using string = std::string;\npublic:\n  CWindowCtlStyle();\n  virtual ~CWindowCtlStyle();\n\npublic:\n  virtual void LoadStyle(XmlElementPtr element);\n  tstring GetStringAttribute(XmlElementPtr element, string attrName);\n  HBITMAP GetBitmapAttribute(XmlElementPtr element, string attrName,\n                             string key_mid_string = \"\");\n  int GetIntegerAttribute(XmlElementPtr element, string attrName);\n  COLORREF GetColorAttribute(XmlElementPtr element, string attrName);\n  COLORREF GetRGBAttribute(XmlElementPtr element, string attrName);\n  DUI_Rect GetRectAttribute(XmlElementPtr element, string attrName);\n  DUI_Size StyleSizeToWindowSize(DUI_Size &eleSize, DUI_Size &wndChangingSize,\n                                 DUI_Size &wndChangedSize, DUI_STRETCH xFlag,\n                                 DUI_STRETCH yFlag);\n  DUI_Point StyleLocationToWindowLocation(DUI_Rect &rc, DUI_Point oriPt,\n                                          int alignX, int alignY,\n                                          DUI_Size &windowSize);\n  DUI_Rect StyleRectToWindowRect(DUI_Rect rc, DUI_Point oriPt,\n                                 DUI_Size &wndChangingSize,\n                                 DUI_Size &wndChangedSize, DUI_ALIGNMENT alignX,\n                                 DUI_ALIGNMENT alignY, DUI_STRETCH stretchHor,\n                                 DUI_STRETCH stretchVer);\n  DUI_ALIGNMENT AlignmentStringToValue(tstring s, DUI_ALIGNMENT align);\n  DUI_STRETCH StretchStringToValue(tstring s, DUI_STRETCH stretch);\n  HCURSOR NameToCursor(tstring name);\n  std::vector<tstring> split(const tstring src, tstring delimit,\n                        tstring null_subst = _T(\"\"));\n\npublic:\n  tstring _NameID;\n\n  DUI_ALIGNMENT _xAlignment;\n  DUI_ALIGNMENT _yAlignment;\n  DUI_STRETCH _xStretch;\n  DUI_STRETCH _yStretch;\n};\n"
  },
  {
    "path": "src/DirectUI/Draw.cpp",
    "content": "#include \"stdafx.h\"\n#include \"Draw.h\"\n\n#define KEYDOWN(Key) ((GetKeyState(Key) & 0x8000) != 0)\n\nclass CClientRect : public CRect {\npublic:\n  CClientRect(HWND hWnd) { ::GetClientRect(hWnd, this); };\n  CClientRect(const CWindow *pWnd) { ::GetClientRect(pWnd->m_hWnd, this); };\n};\n\nclass CWindowRect : public CRect {\npublic:\n  CWindowRect(HWND hWnd) { ::GetWindowRect(hWnd, this); };\n  CWindowRect(const CWindow *pWnd) { ::GetWindowRect(pWnd->m_hWnd, this); };\n};\n\nHLSCOLOR RGB2HLS(COLORREF rgb) {\n  unsigned char minval =\n      min(GetRValue(rgb), min(GetGValue(rgb), GetBValue(rgb)));\n  unsigned char maxval =\n      max(GetRValue(rgb), max(GetGValue(rgb), GetBValue(rgb)));\n  float mdiff = float(maxval) - float(minval);\n  float msum = float(maxval) + float(minval);\n\n  float luminance = msum / 510.0f;\n  float saturation = 0.0f;\n  float hue = 0.0f;\n\n  if (maxval != minval) {\n    float rnorm = (maxval - GetRValue(rgb)) / mdiff;\n    float gnorm = (maxval - GetGValue(rgb)) / mdiff;\n    float bnorm = (maxval - GetBValue(rgb)) / mdiff;\n\n    saturation =\n        (luminance <= 0.5f) ? (mdiff / msum) : (mdiff / (510.0f - msum));\n\n    if (GetRValue(rgb) == maxval)\n      hue = 60.0f * (6.0f + bnorm - gnorm);\n    if (GetGValue(rgb) == maxval)\n      hue = 60.0f * (2.0f + rnorm - bnorm);\n    if (GetBValue(rgb) == maxval)\n      hue = 60.0f * (4.0f + gnorm - rnorm);\n    if (hue > 360.0f)\n      hue = hue - 360.0f;\n  }\n  return HLS((hue * 255) / 360, luminance * 255, saturation * 255);\n}\n\nstatic BYTE _ToRGB(float rm1, float rm2, float rh) {\n  if (rh > 360.0f)\n    rh -= 360.0f;\n  else if (rh < 0.0f)\n    rh += 360.0f;\n\n  if (rh < 60.0f)\n    rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;\n  else if (rh < 180.0f)\n    rm1 = rm2;\n  else if (rh < 240.0f)\n    rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;\n\n  return (BYTE)(rm1 * 255);\n}\n\nCOLORREF HLS2RGB(HLSCOLOR hls) {\n  float hue = ((int)HLS_H(hls) * 360) / 255.0f;\n  float luminance = HLS_L(hls) / 255.0f;\n  float saturation = HLS_S(hls) / 255.0f;\n\n  if (saturation == 0.0f) {\n    return RGB(HLS_L(hls), HLS_L(hls), HLS_L(hls));\n  }\n  float rm1, rm2;\n\n  if (luminance <= 0.5f)\n    rm2 = luminance + luminance * saturation;\n  else\n    rm2 = luminance + saturation - luminance * saturation;\n  rm1 = 2.0f * luminance - rm2;\n  BYTE red = _ToRGB(rm1, rm2, hue + 120.0f);\n  BYTE green = _ToRGB(rm1, rm2, hue);\n  BYTE blue = _ToRGB(rm1, rm2, hue - 120.0f);\n\n  return RGB(red, green, blue);\n}\n\nCOLORREF HLS_TRANSFORM(COLORREF rgb, int percent_L, int percent_S) {\n  HLSCOLOR hls = RGB2HLS(rgb);\n  BYTE h = HLS_H(hls);\n  BYTE l = HLS_L(hls);\n  BYTE s = HLS_S(hls);\n\n  if (percent_L > 0) {\n    l = BYTE(l + ((255 - l) * percent_L) / 100);\n  } else if (percent_L < 0) {\n    l = BYTE((l * (100 + percent_L)) / 100);\n  }\n  if (percent_S > 0) {\n    s = BYTE(s + ((255 - s) * percent_S) / 100);\n  } else if (percent_S < 0) {\n    s = BYTE((s * (100 + percent_S)) / 100);\n  }\n  return HLS2RGB(HLS(h, l, s));\n}\n\nCBufferDC::CBufferDC(HDC hDestDC, const CRect &rcPaint) : m_hDestDC(hDestDC) {\n  if (rcPaint.IsRectEmpty()) {\n    ::GetClipBox(m_hDestDC, m_rect);\n  } else {\n    m_rect = rcPaint;\n  }\n  Attach(::CreateCompatibleDC(m_hDestDC));\n  m_bitmap.Attach(\n      ::CreateCompatibleBitmap(m_hDestDC, m_rect.right, m_rect.bottom));\n  m_hOldBitmap = ::SelectObject(m_hDC, m_bitmap);\n\n  if (m_rect.top > 0) {\n    ExcludeClipRect(0, 0, m_rect.right, m_rect.top);\n  }\n  if (m_rect.left > 0) {\n    ExcludeClipRect(0, m_rect.top, m_rect.left, m_rect.bottom);\n  }\n}\n\nCBufferDC::~CBufferDC() {\n  ::BitBlt(m_hDestDC, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),\n           m_hDC, m_rect.left, m_rect.top, SRCCOPY);\n  ::SelectObject(m_hDC, m_hOldBitmap);\n}\n\nCPenDC::CPenDC(HDC hDC, COLORREF crColor) : m_hDC(hDC) {\n  m_pen.CreatePen(PS_SOLID, 1, crColor);\n  m_hOldPen = (HPEN)::SelectObject(m_hDC, m_pen);\n}\n\nCPenDC::~CPenDC() { ::SelectObject(m_hDC, m_hOldPen); }\n\nvoid CPenDC::Color(COLORREF crColor) {\n  ::SelectObject(m_hDC, m_hOldPen);\n  m_pen.DeleteObject();\n  m_pen.CreatePen(PS_SOLID, 1, crColor);\n  m_hOldPen = (HPEN)::SelectObject(m_hDC, m_pen);\n}\n\nCOLORREF CPenDC::Color() const {\n  LOGPEN logPen;\n\n  ((CPenDC *)this)->m_pen.GetLogPen(&logPen);\n\n  return logPen.lopnColor;\n}\n\nCBrushDC::CBrushDC(HDC hDC, COLORREF crColor) : m_hDC(hDC) {\n  if (crColor == CLR_NONE)\n    m_brush.Attach((HBRUSH)::GetStockObject(NULL_BRUSH));\n  else\n    m_brush.CreateSolidBrush(crColor);\n  m_hOldBrush = (HBRUSH)::SelectObject(m_hDC, m_brush);\n}\n\nCBrushDC::~CBrushDC() { ::SelectObject(m_hDC, m_hOldBrush); }\n\nvoid CBrushDC::Color(COLORREF crColor) {\n  ::SelectObject(m_hDC, m_hOldBrush);\n  m_brush.DeleteObject();\n  if (crColor == CLR_NONE)\n    m_brush.Attach((HBRUSH)::GetStockObject(NULL_BRUSH));\n  else\n    m_brush.CreateSolidBrush(crColor);\n  m_hOldBrush = (HBRUSH)::SelectObject(m_hDC, m_brush);\n}\n\nCOLORREF CBrushDC::Color() const {\n  LOGBRUSH logBrush;\n\n  ((CBrushDC *)this)->m_brush.GetLogBrush(&logBrush);\n\n  return logBrush.lbColor;\n}\n\nCBoldDC::CBoldDC(HDC hDC, bool bBold) : m_hDC(hDC), m_hDefFont(NULL) {\n  LOGFONT lf;\n\n  CFontHandle((HFONT)::GetCurrentObject(m_hDC, OBJ_FONT)).GetLogFont(&lf);\n\n  if ((bBold && lf.lfWeight != FW_BOLD) || (!bBold && lf.lfWeight == FW_BOLD)) {\n    lf.lfWeight = bBold ? FW_BOLD : FW_NORMAL;\n\n    m_fontBold.CreateFontIndirect(&lf);\n    m_hDefFont = (HFONT)::SelectObject(m_hDC, m_fontBold);\n  }\n}\n\nCBoldDC::~CBoldDC() {\n  if (m_hDefFont != NULL) {\n    ::SelectObject(m_hDC, m_hDefFont);\n  }\n}\n"
  },
  {
    "path": "src/DirectUI/Draw.h",
    "content": "#pragma once\n\ntypedef DWORD HLSCOLOR;\n#define HLS(h, l, s)                                                           \\\n  ((HLSCOLOR)(((BYTE)(h) | ((WORD)((BYTE)(l)) << 8)) |                         \\\n              (((DWORD)(BYTE)(s)) << 16)))\n\n#define HLS_H(hls) ((BYTE)(hls))\n#define HLS_L(hls) ((BYTE)(((WORD)(hls)) >> 8))\n#define HLS_S(hls) ((BYTE)((hls) >> 16))\n\nHLSCOLOR RGB2HLS(COLORREF rgb);\nCOLORREF HLS2RGB(HLSCOLOR hls);\n\nCOLORREF HLS_TRANSFORM(COLORREF rgb, int percent_L, int percent_S);\n\nclass CBufferDC : public CDCHandle {\n  HDC m_hDestDC;\n  CBitmap m_bitmap;\n  CRect m_rect;\n  HGDIOBJ m_hOldBitmap;\n\npublic:\n  CBufferDC(HDC hDestDC, const CRect &rcPaint = CRect(0, 0, 0, 0));\n  ~CBufferDC();\n};\n\nclass CPenDC {\nprotected:\n  CPen m_pen;\n  HDC m_hDC;\n  HPEN m_hOldPen;\n\npublic:\n  CPenDC(HDC hDC, COLORREF crColor = CLR_NONE);\n  ~CPenDC();\n\n  void Color(COLORREF crColor);\n  COLORREF Color() const;\n};\n\nclass CBrushDC {\nprotected:\n  CBrush m_brush;\n  HDC m_hDC;\n  HBRUSH m_hOldBrush;\n\npublic:\n  CBrushDC(HDC hDC, COLORREF crColor = CLR_NONE);\n  ~CBrushDC();\n\n  void Color(COLORREF crColor);\n  COLORREF Color() const;\n};\n\nclass CBoldDC {\nprotected:\n  CFont m_fontBold;\n  HDC m_hDC;\n  HFONT m_hDefFont;\n\npublic:\n  CBoldDC(HDC hDC, bool bBold);\n  ~CBoldDC();\n};\n"
  },
  {
    "path": "src/DirectUI/EventHandler.h",
    "content": "#pragma once\n\n#include \"../base/FastDelegate.h\"\n\nusing namespace fastdelegate;\n\n#define BIND(c, f) MakeDelegate(&c, &f)\n\ntypedef FastDelegate0<> Delegate0;\ntypedef FastDelegate1<LPCTSTR> Delegate1_string;\ntypedef FastDelegate1<UINT> Delegate1_UINT;\n\nclass EventHandler {\npublic:\n  EventHandler() {}\n  EventHandler(Delegate0 func) : m_func_no_para(func) {}\n  EventHandler(Delegate1_string func) : m_func_para_string(func) {}\n  EventHandler(Delegate1_UINT func) : m_func_para_int(func) {}\n\n  void Invoke() {\n    if (m_func_no_para) {\n      m_func_no_para();\n    }\n  }\n\n  void Invoke(LPCTSTR strPara) {\n    if (m_func_para_string) {\n      m_func_para_string(strPara);\n    }\n  }\n\n  void Invoke(UINT nPara) {\n    if (m_func_para_int) {\n      m_func_para_int(nPara);\n    }\n  }\n\npublic:\n  Delegate0 m_func_no_para;\n  Delegate1_string m_func_para_string;\n  Delegate1_UINT m_func_para_int;\n};\n"
  },
  {
    "path": "src/DirectUI/UpdateWindowBase.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"UpdateWindowBase.h\"\n\nCUpdateWindowBase::CUpdateWindowBase() { m_hFuncInst = NULL; }\n\nCUpdateWindowBase::~CUpdateWindowBase() {\n  if (m_hFuncInst)\n    FreeLibrary(m_hFuncInst);\n}\n\nLRESULT CUpdateWindowBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  m_Blend.BlendOp = 0;\n  m_Blend.BlendFlags = 0;\n  m_Blend.AlphaFormat = 1;\n  m_Blend.SourceConstantAlpha = 255;\n\n  if (IsBits32()) {\n    m_hFuncInst = LoadLibrary(_T(\"User32.DLL\"));\n    BOOL bRet = FALSE;\n    if (m_hFuncInst)\n      UpdateLayeredWindow = (UPDATELAYERWINDOWPTR)GetProcAddress(\n          m_hFuncInst, \"UpdateLayeredWindow\");\n    else\n      assert(0);\n\n    PostMessage(MSG_UPDATE_WINDOW_INVALIDATE, 0, 100);\n  }\n\n  bHandled = FALSE;\n\n  return 0;\n}\n\nLRESULT CUpdateWindowBase::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  CPaintDC dc(m_hWnd);\n  DrawBg(dc);\n  OnDraw(dc);\n  return 0;\n}\n\nLRESULT CUpdateWindowBase::UpdateTranslate(UINT uMsg, WPARAM wParam,\n                                           LPARAM lParam, BOOL &bHandled) {\n  UpdateTransDisplay(lParam);\n  return 0;\n}\n\nBOOL CUpdateWindowBase::UpdateTransDisplay(int Transparent) {\n\n  if (!IsBits32()) {\n    Invalidate(TRUE);\n    return FALSE;\n  }\n\n  CRect rcWindow;\n  GetWindowRect(rcWindow);\n  POINT ptWinPos = {rcWindow.left, rcWindow.top};\n\n  HDC hdcTemp = GetDC();\n  HDC m_hdcMemory = CreateCompatibleDC(hdcTemp);\n  HBITMAP hBitMap =\n      CreateCompatibleBitmap(hdcTemp, rcWindow.Width(), rcWindow.Height());\n  SelectObject(m_hdcMemory, hBitMap);\n  if (Transparent < 0 || Transparent > 100)\n    Transparent = 100;\n\n  m_Blend.SourceConstantAlpha = int(Transparent * 2.55);\n  HDC hdcScreen = ::GetDC(m_hWnd);\n\n  DrawBg(m_hdcMemory);\n  OnDraw(m_hdcMemory);\n\n  SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()};\n\n  POINT ptSrc = {0, 0};\n  DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);\n  if ((dwExStyle & 0x80000) != 0x80000)\n    ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000);\n\n  BOOL bRet = FALSE;\n  bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow,\n                             m_hdcMemory, &ptSrc, 0, &m_Blend, 2);\n\n  ::ReleaseDC(m_hWnd, hdcScreen);\n  hdcScreen = NULL;\n  ::ReleaseDC(m_hWnd, hdcTemp);\n  hdcTemp = NULL;\n  DeleteObject(hBitMap);\n  DeleteDC(m_hdcMemory);\n  m_hdcMemory = NULL;\n\n  return bRet;\n}\n\nbool CUpdateWindowBase::IsBits32() {\n  DEVMODE lpDevMode;\n  BOOL Result = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode);\n  if (Result) {\n    if (lpDevMode.dmBitsPerPel == 32)\n      return true;\n  }\n\n  return false;\n}\n"
  },
  {
    "path": "src/DirectUI/UpdateWindowBase.h",
    "content": "#pragma once\n\n#include <atlapp.h>\n#include <atlwinx.h>\n#include \"DUIDef.h\"\n\nclass __declspec(novtable) CUpdateWindowBase\n    : public CWindowImpl<CUpdateWindowBase> {\npublic:\n  CUpdateWindowBase();\n  ~CUpdateWindowBase();\n\npublic:\n  BEGIN_MSG_MAP_EX(CUpdateWindowBase)\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(MSG_UPDATE_WINDOW_INVALIDATE, UpdateTranslate)\n  MESSAGE_HANDLER(WM_PAINT, OnPaint)\n  END_MSG_MAP()\n\n  LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  LRESULT UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n\nprotected:\n  typedef BOOL(WINAPI *UPDATELAYERWINDOWPTR)(HWND, HDC, POINT *, SIZE *, HDC,\n                                             POINT *, COLORREF, BLENDFUNCTION *,\n                                             DWORD);\n  UPDATELAYERWINDOWPTR UpdateLayeredWindow;\n\n  BLENDFUNCTION m_Blend;\n\n  HINSTANCE m_hFuncInst;\n\nprotected:\n  BOOL UpdateTransDisplay(int Transparent);\n\n  virtual void DrawBg(HDC hDC) = 0;\n\n  virtual void OnDraw(HDC hDC) = 0;\n\n  bool IsBits32();\n};\n"
  },
  {
    "path": "src/DirectUI/UpdateWindowBaseEx.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"UpdateWindowBaseEx.h\"\n"
  },
  {
    "path": "src/DirectUI/UpdateWindowBaseEx.h",
    "content": "#pragma once\n\n#include <atlapp.h>\n#include <atlwinx.h>\n#include \"DUIDef.h\"\n\nconstexpr int TIMER_ID1 = 0x1110;\nconstexpr int TIMER_ID2 = 0x1111;\nconstexpr int COUNT_END_CONST = -3;\n\ntemplate <typename T>\nclass __declspec(novtable) CUpdateWindowBaseEx : public CWindowImpl<T> {\npublic:\n  CUpdateWindowBaseEx();\n  virtual ~CUpdateWindowBaseEx();\n\npublic:\n  BEGIN_MSG_MAP_EX(CUpdateWindowBaseEx<T>)\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(WM_TIMER, CUpdateWindowBaseEx_OnTimer)\n  MESSAGE_HANDLER(MSG_UPDATE_WINDOW_INVALIDATE, UpdateTranslate)\n  MESSAGE_HANDLER(WM_PAINT, OnPaint)\n  END_MSG_MAP()\n\n  LRESULT CUpdateWindowBaseEx_OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled);\n  LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  LRESULT UpdateTranslate(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                          BOOL &bHandled);\n  LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n\nprotected:\n  typedef BOOL(WINAPI *UPDATELAYERWINDOWPTR)(HWND, HDC, POINT *, SIZE *, HDC,\n                                             POINT *, COLORREF, BLENDFUNCTION *,\n                                             DWORD);\n  UPDATELAYERWINDOWPTR UpdateLayeredWindow;\n\n  BLENDFUNCTION m_Blend;\n  HINSTANCE m_hFuncInst;\n\npublic:\n  BOOL UpdateTransDisplay(int Transparent);\n\nprotected:\n  BOOL UpdateTransDisplay2(int Transparent);\n  BOOL UpdateTransDisplay3(int Transparent);\n\n  virtual void DrawBg(HDC hDC) = 0;\n\n  virtual void OnDraw(HDC hDC) = 0;\n\n  virtual void IsWindowShowed() {}\n\n  bool IsBits32();\n\npublic:\n  void ClearOBJ();\n  CRect _CUpdateWindowBaseEx_WndRect_con;\n  CRect _CUpdateWindowBaseEx_WndRect_var;\n  BOOL _bCUpdateWindowBaseEx_TransShow;\n  void TransShowWindow(int SW = SW_SHOWNORMAL);\n  int _CUpdateWindowBaseEx_Count;\n  void TransBeginShow();\n  void StretchRect(const RECT &i_rc, float percent, RECT &o_rc);\n  void AnimateRect(const RECT &i_rc, int x, int y, RECT &o_rc);\n  float _CUpdateWindowBaseEx_percent;\n\n  void StretchShow(int, int);\n\n  void StretchShowSim(int, int);\n  HDC _hdcTemp;\n  HDC _hdcMemory;\n  HBITMAP _hBitMap;\n  HGDIOBJ _oldOBJ;\n};\n\ntemplate <class T>\nCUpdateWindowBaseEx<T>::CUpdateWindowBaseEx()\n    : _CUpdateWindowBaseEx_WndRect_con(0, 0, 0, 0) {\n  m_hFuncInst = NULL;\n  _bCUpdateWindowBaseEx_TransShow = FALSE;\n  _CUpdateWindowBaseEx_Count = 10;\n  _CUpdateWindowBaseEx_percent = 0.0;\n  _hdcTemp = NULL;\n  _hdcMemory = NULL;\n  _hBitMap = NULL;\n  _oldOBJ = NULL;\n}\ntemplate <class T> CUpdateWindowBaseEx<T>::~CUpdateWindowBaseEx() {\n  if (m_hFuncInst)\n    FreeLibrary(m_hFuncInst);\n}\n\ntemplate <class T>\nLRESULT CUpdateWindowBaseEx<T>::OnCreate(UINT uMsg, WPARAM wParam,\n                                         LPARAM lParam, BOOL &bHandled) {\n  m_Blend.BlendOp = 0;\n  m_Blend.BlendFlags = 0;\n  m_Blend.AlphaFormat = 1;\n  m_Blend.SourceConstantAlpha = 255;\n\n  if (IsBits32()) {\n    m_hFuncInst = LoadLibrary(_T(\"User32.DLL\"));\n    BOOL bRet = FALSE;\n    if (m_hFuncInst)\n      UpdateLayeredWindow = (UPDATELAYERWINDOWPTR)GetProcAddress(\n          m_hFuncInst, \"UpdateLayeredWindow\");\n    else\n      assert(0);\n    PostMessage(MSG_UPDATE_WINDOW_INVALIDATE, 0, 100);\n  }\n  bHandled = FALSE;\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CUpdateWindowBaseEx<T>::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                        BOOL &bHandled) {\n  CPaintDC dc(m_hWnd);\n  DrawBg(dc);\n  OnDraw(dc);\n  return 0;\n}\n\ntemplate <class T>\nLRESULT CUpdateWindowBaseEx<T>::UpdateTranslate(UINT uMsg, WPARAM wParam,\n                                                LPARAM lParam, BOOL &bHandled) {\n  UpdateTransDisplay(lParam);\n  return 0;\n}\n\ntemplate <class T>\nBOOL CUpdateWindowBaseEx<T>::UpdateTransDisplay(int Transparent) {\n\n  if (!IsBits32()) {\n    Invalidate(TRUE);\n    return FALSE;\n  }\n  if (_bCUpdateWindowBaseEx_TransShow)\n    return FALSE;\n\n  CRect rcWindow;\n  GetWindowRect(&rcWindow);\n  POINT ptWinPos = {rcWindow.left, rcWindow.top};\n\n  HDC hdcTemp = GetDC();\n  HDC m_hdcMemory = CreateCompatibleDC(hdcTemp);\n  HBITMAP hBitMap =\n      CreateCompatibleBitmap(hdcTemp, rcWindow.Width(), rcWindow.Height());\n  HGDIOBJ m_oldbj = SelectObject(m_hdcMemory, hBitMap);\n  if (Transparent < 0 || Transparent > 100)\n    Transparent = 100;\n\n  m_Blend.SourceConstantAlpha = int(Transparent * 2.55);\n  HDC hdcScreen = ::GetDC(m_hWnd);\n\n  DrawBg(m_hdcMemory);\n  OnDraw(m_hdcMemory);\n\n  SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()};\n\n  POINT ptSrc = {0, 0};\n  DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);\n  if ((dwExStyle & 0x80000) != 0x80000)\n    ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000);\n\n  BOOL bRet = FALSE;\n  bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow,\n                             m_hdcMemory, &ptSrc, 0, &m_Blend, 2);\n\n  ::ReleaseDC(m_hWnd, hdcScreen);\n  hdcScreen = NULL;\n  ::ReleaseDC(m_hWnd, hdcTemp);\n  SelectObject(m_hdcMemory, m_oldbj);\n  DeleteObject(hBitMap);\n  DeleteDC(m_hdcMemory);\n\n  return bRet;\n}\n\ntemplate <class T> bool CUpdateWindowBaseEx<T>::IsBits32() {\n  DEVMODE lpDevMode;\n  BOOL Result = EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &lpDevMode);\n  if (Result) {\n    if (lpDevMode.dmBitsPerPel == 32)\n      return true;\n  }\n  return false;\n}\n\ntemplate <class T>\nvoid CUpdateWindowBaseEx<T>::StretchShow(int a, int b) {\n  AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100 + a, -100 + a,\n              _CUpdateWindowBaseEx_WndRect_var);\n  SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_var, SWP_NOZORDER);\n  UpdateTransDisplay2(b);\n}\n\ntemplate <class T>\nvoid CUpdateWindowBaseEx<T>::StretchShowSim(int a, int b) {\n  AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100 + a, -100 + a,\n              _CUpdateWindowBaseEx_WndRect_var);\n\n  UpdateTransDisplay3(b);\n}\n\ntemplate <class T>\nLRESULT CUpdateWindowBaseEx<T>::CUpdateWindowBaseEx_OnTimer(UINT uMsg,\n                                                            WPARAM wParam,\n                                                            LPARAM lParam,\n                                                            BOOL &bHandled) {\n  if (TIMER_ID1 == wParam) {\n    --_CUpdateWindowBaseEx_Count;\n    if (_CUpdateWindowBaseEx_Count < COUNT_END_CONST) {\n      KillTimer(TIMER_ID1);\n      _bCUpdateWindowBaseEx_TransShow = FALSE;\n      return 0;\n    }\n    switch (_CUpdateWindowBaseEx_Count) {\n    case 9: {\n      StretchShowSim(6, 40);\n    } break;\n    case 8: {\n      StretchShowSim(23, 45);\n    } break;\n    case 7: {\n      StretchShowSim(51, 55);\n    } break;\n    case 6: {\n      StretchShowSim(90, 60);\n    } break;\n    case 5: {\n      KillTimer(TIMER_ID1);\n      StretchShowSim(140, 65);\n      SetTimer(TIMER_ID2, 30, NULL);\n    } break;\n    default: {\n      KillTimer(TIMER_ID1);\n      SetTimer(TIMER_ID2, 30, NULL);\n    }\n    }\n    return 0;\n  }\n  if (wParam == TIMER_ID2) {\n    --_CUpdateWindowBaseEx_Count;\n    if (_bCUpdateWindowBaseEx_TransShow == FALSE) {\n      KillTimer(TIMER_ID2);\n      UpdateTransDisplay(100);\n      ClearOBJ();\n      IsWindowShowed();\n      return 0;\n    }\n    if (_CUpdateWindowBaseEx_Count < COUNT_END_CONST) {\n      _bCUpdateWindowBaseEx_TransShow = FALSE;\n      return 0;\n    }\n    switch (_CUpdateWindowBaseEx_Count) {\n    case 4: {\n      StretchShow(126, 70);\n    } break;\n    case 3: {\n      StretchShow(114, 75);\n    } break;\n    case 2: {\n      StretchShow(106, 80);\n    } break;\n    case 1: {\n      StretchShow(102, 90);\n    } break;\n    case 0: {\n      SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_con, SWP_NOZORDER);\n      UpdateTransDisplay(100);\n      _bCUpdateWindowBaseEx_TransShow = FALSE;\n    } break;\n    default: {\n      SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_con, SWP_NOZORDER);\n      UpdateTransDisplay(100);\n      _bCUpdateWindowBaseEx_TransShow = FALSE;\n    }\n    }\n    return 0;\n  }\n  bHandled = FALSE;\n  return 0;\n}\n\ntemplate <typename T> void CUpdateWindowBaseEx<T>::TransBeginShow() {\n  if (!IsBits32()) {\n    _bCUpdateWindowBaseEx_TransShow = FALSE;\n    return;\n  }\n  _bCUpdateWindowBaseEx_TransShow = TRUE;\n}\n\ntemplate <class T>\nvoid CUpdateWindowBaseEx<T>::StretchRect(/*_In_*/ const RECT &i_rc,\n                                         float percent, /*_Out_*/ RECT &o_rc) {\n  int x;\n  int y;\n  x = (i_rc.right - i_rc.left) * percent;\n  y = (i_rc.bottom - i_rc.top) * percent;\n  o_rc.left = i_rc.left + ((i_rc.right - i_rc.left) - x) / 2;\n  o_rc.right = (o_rc.left + x);\n  o_rc.top = i_rc.top + ((i_rc.bottom - i_rc.top) - y) / 2;\n  o_rc.bottom = (o_rc.top + y);\n}\n\ntemplate <class T>\nBOOL CUpdateWindowBaseEx<T>::UpdateTransDisplay2(int Transparent) {\n  CRect rcWindow;\n  rcWindow = _CUpdateWindowBaseEx_WndRect_var;\n  POINT ptWinPos = {rcWindow.left, rcWindow.top};\n  if (Transparent < 0 || Transparent > 100)\n    Transparent = 100;\n\n  m_Blend.SourceConstantAlpha = int(Transparent * 2.55);\n  HDC hdcScreen = ::GetDC(m_hWnd);\n  SIZE sizeWindow = {rcWindow.Width(), rcWindow.Height()};\n  HDC yyhdcTemp = GetDC();\n  HDC m_yyhdcMemory = CreateCompatibleDC(yyhdcTemp);\n  HBITMAP yyhBitMap = CreateCompatibleBitmap(\n      yyhdcTemp, _CUpdateWindowBaseEx_WndRect_var.Width(),\n      _CUpdateWindowBaseEx_WndRect_var.Height());\n  HGDIOBJ m_oldbj2 = SelectObject(m_yyhdcMemory, yyhBitMap);\n  ::StretchBlt(m_yyhdcMemory, 0, 0, sizeWindow.cx, sizeWindow.cy, _hdcMemory, 0,\n               0, _CUpdateWindowBaseEx_WndRect_con.Width(),\n               _CUpdateWindowBaseEx_WndRect_con.Height(), SRCCOPY);\n  POINT ptSrc = {0, 0};\n  DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);\n  if ((dwExStyle & 0x80000) != 0x80000)\n    ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000);\n  BOOL bRet = FALSE;\n\n  bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow,\n                             m_yyhdcMemory, &ptSrc, 0, &m_Blend, 2);\n  ::ReleaseDC(m_hWnd, hdcScreen);\n  ::ReleaseDC(m_hWnd, yyhdcTemp);\n  SelectObject(m_yyhdcMemory, m_oldbj2);\n  DeleteDC(m_yyhdcMemory);\n  DeleteObject(yyhBitMap);\n  return bRet;\n}\n\ntemplate <class T>\nBOOL CUpdateWindowBaseEx<T>::UpdateTransDisplay3(int Transparent) {\n  CRect rcWindow;\n  rcWindow = _CUpdateWindowBaseEx_WndRect_con;\n  POINT ptWinPos = {rcWindow.left - 20, rcWindow.top - 20};\n  if (Transparent < 0 || Transparent > 100)\n    Transparent = 100;\n\n  m_Blend.SourceConstantAlpha = int(Transparent * 2.55);\n  HDC hdcScreen = ::GetDC(m_hWnd);\n  SIZE sizeWindow = {rcWindow.Width() + 40, rcWindow.Height() + 40};\n  HDC yyhdcTemp = GetDC();\n  HDC m_yyhdcMemory = CreateCompatibleDC(yyhdcTemp);\n  HBITMAP yyhBitMap = CreateCompatibleBitmap(\n      yyhdcTemp, _CUpdateWindowBaseEx_WndRect_con.Width() + 40,\n      _CUpdateWindowBaseEx_WndRect_con.Height() + 40);\n  HGDIOBJ m_oldbj2 = SelectObject(m_yyhdcMemory, yyhBitMap);\n  int delta_x = _CUpdateWindowBaseEx_WndRect_con.Width() + 40 -\n                _CUpdateWindowBaseEx_WndRect_var.Width();\n  delta_x = delta_x / 2;\n  int delta_y = _CUpdateWindowBaseEx_WndRect_con.Height() + 40 -\n                _CUpdateWindowBaseEx_WndRect_var.Height();\n  delta_y = delta_y / 2;\n  ::StretchBlt(m_yyhdcMemory, delta_x, delta_y,\n               _CUpdateWindowBaseEx_WndRect_var.Width(),\n               _CUpdateWindowBaseEx_WndRect_var.Height(), _hdcMemory, 0, 0,\n               _CUpdateWindowBaseEx_WndRect_con.Width(),\n               _CUpdateWindowBaseEx_WndRect_con.Height(), SRCCOPY);\n  POINT ptSrc = {0, 0};\n  DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);\n  if ((dwExStyle & 0x80000) != 0x80000)\n    ::SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle ^ 0x80000);\n  BOOL bRet = FALSE;\n\n  bRet = UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow,\n                             m_yyhdcMemory, &ptSrc, 0, &m_Blend, 2);\n\n  ::ReleaseDC(m_hWnd, hdcScreen);\n  ::ReleaseDC(m_hWnd, yyhdcTemp);\n  SelectObject(m_yyhdcMemory, m_oldbj2);\n  DeleteDC(m_yyhdcMemory);\n  DeleteObject(yyhBitMap);\n  return bRet;\n}\n\ntemplate <class T> void CUpdateWindowBaseEx<T>::ClearOBJ() {\n  if (_hdcTemp && _hdcMemory) {\n    ::ReleaseDC(m_hWnd, _hdcTemp);\n    SelectObject(_hdcMemory, _oldOBJ);\n    DeleteDC(_hdcMemory);\n    DeleteObject(_hBitMap);\n    _hdcTemp = NULL;\n    _hdcMemory = NULL;\n    _hBitMap = NULL;\n    _oldOBJ = NULL;\n  }\n}\n\ntemplate <class T> void CUpdateWindowBaseEx<T>::TransShowWindow(int SW) {\n  if (_bCUpdateWindowBaseEx_TransShow) {\n    ATLASSERT(_CUpdateWindowBaseEx_Count == 10);\n    int cx, cy;\n    cx = _CUpdateWindowBaseEx_WndRect_con.Width();\n    cy = _CUpdateWindowBaseEx_WndRect_con.Height();\n    if (cx >= 150 && cy >= 110) {\n\n      MSG msg;\n      while (::PeekMessage(&msg, m_hWnd, MSG_UPDATE_WINDOW_INVALIDATE,\n                           MSG_UPDATE_WINDOW_INVALIDATE, PM_REMOVE))\n        ;\n      ((T *)this)->ChangeSize(cx, cy);\n      if (!_hdcTemp) {\n        _hdcTemp = GetDC();\n      }\n      if (!_hdcMemory) {\n        _hdcMemory = CreateCompatibleDC(_hdcTemp);\n      }\n      if (!_hBitMap) {\n        _hBitMap = CreateCompatibleBitmap(\n            _hdcTemp, _CUpdateWindowBaseEx_WndRect_con.Width(),\n            _CUpdateWindowBaseEx_WndRect_con.Height());\n      }\n      _oldOBJ = SelectObject(_hdcMemory, _hBitMap);\n      DrawBg(_hdcMemory);\n      OnDraw(_hdcMemory);\n\n      AnimateRect(_CUpdateWindowBaseEx_WndRect_con, 40, 40,\n                  _CUpdateWindowBaseEx_WndRect_var);\n      SetWindowPos(0, &_CUpdateWindowBaseEx_WndRect_var, SWP_NOZORDER);\n\n      AnimateRect(_CUpdateWindowBaseEx_WndRect_con, -100, -100,\n                  _CUpdateWindowBaseEx_WndRect_var);\n      UpdateTransDisplay3(35);\n      ShowWindow(SW_SHOWNORMAL);\n      _CUpdateWindowBaseEx_Count = 10;\n      SetTimer(TIMER_ID1, 30, NULL);\n    } else {\n      _bCUpdateWindowBaseEx_TransShow = FALSE;\n      ShowWindow(SW);\n    }\n  } else {\n    ShowWindow(SW);\n  }\n}\n\ntemplate <class T>\nvoid CUpdateWindowBaseEx<T>::AnimateRect(/*_In_*/ const RECT &i_rc, int x,\n                                         int y, /*_Out_*/ RECT &o_rc) {\n  y = x * (i_rc.bottom - i_rc.top) / (i_rc.bottom - i_rc.top);\n  x = -x;\n  o_rc.left = i_rc.left + x / 2;\n  o_rc.right = (i_rc.right - x / 2);\n  y = -y;\n  o_rc.top = i_rc.top + y / 2;\n  o_rc.bottom = (i_rc.bottom - y / 2);\n}\n"
  },
  {
    "path": "src/DownLoader/DownloadDelegate.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"DownloadDelegate.h\"\n\nDownCompleteInfo::DownCompleteInfo(net::URLFetcher::ErrorType reason)\n    : reason_(reason) {}\n"
  },
  {
    "path": "src/DownLoader/DownloadDelegate.h",
    "content": "#pragma once\n\n#include \"../net/url_fetcher.h\"\n\nstruct DownCompleteInfo {\n  explicit DownCompleteInfo(net::URLFetcher::ErrorType reason);\n  net::URLFetcher::ErrorType reason_;\n  union {\n    DWORD file_totle_size_;\n    struct {\n      DWORD already_byte_infile_;\n      DWORD endoffset_;\n      DWORD original_begin_offset_;\n    } mutDownParam;\n  };\n};\n\nclass FetchURLDelegate {\npublic:\n  virtual void FetchURLComplete(std::string res) = 0;\n};\n\nclass FetchFileDelegate {\npublic:\n  virtual void FetchFileComplete(bool status, DownCompleteInfo &info) = 0;\n  virtual void FetchFileProgress(double cur) = 0;\n};\n"
  },
  {
    "path": "src/DownLoader/fetcherurl.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"fetcherurl.h\"\n\nusing namespace net;\n\nCFetchUrl::CFetchUrl(FetchURLDelegate *delegate, std::string downurl) {\n  assert(delegate);\n  delegate_ = delegate;\n  fetcher_ = URLFetcher::Create(URLFetcher::Params(downurl), this);\n}\n\nCFetchUrl::~CFetchUrl() {\n  if (fetcher_.get())\n    fetcher_->Stop();\n}\n\nvoid CFetchUrl::OnURLFetchComplete(const net::URLFetcher *source) {\n  std::string content;\n  if (source->status()) {\n    content = const_cast<net::URLFetcher *>(source)->data();\n  }\n  if (delegate_)\n    delegate_->FetchURLComplete(content);\n}\n"
  },
  {
    "path": "src/DownLoader/fetcherurl.h",
    "content": "#pragma once\n\n#include \"../net/url_fetcher.h\"\n#include \"../base.h\"\n#include \"util/def.h\"\n#include \"DownloadDelegate.h\"\n\nclass CFetchUrl : public net::URLFetcher::URLFetcherDelegate {\npublic:\n  explicit CFetchUrl(FetchURLDelegate *delegate, std::string downurl);\n  ~CFetchUrl();\n  virtual void OnURLFetchComplete(const net::URLFetcher *source) override;\n  scoped_refptr<net::URLFetcher> fetcher_;\n\nprivate:\n  FetchURLDelegate *delegate_;\n};\n"
  },
  {
    "path": "src/DownLoader/fetchfile.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"fetchfile.h\"\n\nusing namespace net;\n\nCFetchFile::CFetchFile(FetchFileDelegate *delegate, std::string downurl,\n                       std::wstring downtopath)\n    : retrycount_(0) {\n  assert(delegate);\n  delegate_ = delegate;\n  fetcher_ = URLFetcher::Create(URLFetcher::Params(downurl, downtopath), this);\n}\n\nCFetchFile::~CFetchFile() {\n  if (fetcher_.get())\n    fetcher_->Stop();\n}\n\nvoid CFetchFile::OnURLFetchComplete(const net::URLFetcher *source) {\n  if (delegate_) {\n    DownCompleteInfo info(source->error_type_);\n    delegate_->FetchFileComplete(source->status(), info);\n  }\n}\n\nvoid CFetchFile::OnURLFetchDownloadProgress(const net::URLFetcher *source,\n                                            double cur) {\n  if (delegate_)\n    delegate_->FetchFileProgress(cur);\n}\n"
  },
  {
    "path": "src/DownLoader/fetchfile.h",
    "content": "#pragma once\n\n#include \"../net/url_fetcher.h\"\n#include \"../base.h\"\n#include \"util/def.h\"\n#include \"DownloadDelegate.h\"\n\nclass CFetchFile : public net::URLFetcher::URLFetcherDelegate {\npublic:\n  explicit CFetchFile(FetchFileDelegate *delegate, std::string downurl,\n                      std::wstring downtopath);\n  ~CFetchFile();\n  virtual void OnURLFetchComplete(const net::URLFetcher *source) override;\n  virtual void OnURLFetchDownloadProgress(const net::URLFetcher *source,\n                                          double cur) override;\n  scoped_refptr<net::URLFetcher> fetcher_;\n  char retrycount_;\n\nprivate:\n  FetchFileDelegate *delegate_;\n  \n};\n"
  },
  {
    "path": "src/Downloader.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#define APSTUDIO_HIDDEN_SYMBOLS\n#include \"windows.h\"\n#undef APSTUDIO_HIDDEN_SYMBOLS\n#include \"resource.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// (壬й) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\nLANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\n#pragma code_page(936)\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n2 TEXTINCLUDE \nBEGIN\n    \"#define APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\n    \"#include \"\"windows.h\"\"\\r\\n\"\n    \"#undef APSTUDIO_HIDDEN_SYMBOLS\\r\\n\"\n    \"#include \"\"resource.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// XML\n//\n\nUIMAINWINDOW            XML                     \"res\\\\xml\\\\UIMainWindow.xml\"\n\nUICANNOTDOWN            XML                     \"res\\\\xml\\\\UICannotDown.xml\"\n\nUIAGREEMENT             XML                     \"res\\\\xml\\\\UIAgreement.xml\"\n\nUICONTENT               XML                     \"res\\\\xml\\\\UIContent.xml\"\n\nENGUIMAINWINDOW         XML                     \"res\\\\xml\\\\EngUIMainWindow.xml\"\n\nENGUICANNOTDOWN         XML                     \"res\\\\xml\\\\EngUICannotDown.xml\"\n\nENGUIAGREEMENT          XML                     \"res\\\\xml\\\\EngUIAgreement.xml\"\n\nENGUICONTENT            XML                     \"res\\\\xml\\\\EngUIContent.xml\"\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// 6000\n//\n\nAPP1                    6000                    \"res\\\\png\\\\1.png\"\n\nAPP2                    6000                    \"res\\\\png\\\\2.png\"\n\nAPP3                    6000                    \"res\\\\png\\\\3.png\"\n\nAPP4                    6000                    \"res\\\\png\\\\4.png\"\n\nAPP5                    6000                    \"res\\\\png\\\\5.png\"\n\nAPP6                    6000                    \"res\\\\png\\\\6.png\"\n\nABOUTDIALOG             6000                    \"res\\\\png\\\\AboutDlg.png\"\n\nDLG_BTN_CLOSE           6000                    \"res\\\\png\\\\account_close.png\"\n\nDLG_BTN_MIN             6000                    \"res\\\\png\\\\btn_min.png\"\n\nDLG_BTN_INSTALL         6000                    \"res\\\\png\\\\dialog_btn_main.png\"\n\nCHECK_BOX               6000                    \"res\\\\png\\\\checkbox.png\"\n\nAPPLOGO                 6000                    \"res\\\\png\\\\logo.png\"\n\nSELECTPATH              6000                    \"res\\\\png\\\\selctpath.png\"\n\nBACKMAIN                6000                    \"res\\\\png\\\\backmain.png\"\n\nEDIT_INSTALL_BACK       6000                    \"res\\\\png\\\\edit_install_back.png\"\n\nLIGHTPOINT              6000                    \"res\\\\png\\\\lightpoint.png\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION 1,0,0,0\n PRODUCTVERSION 1,0,0,0\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x40004L\n FILETYPE 0x1L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904e4\"\n        BEGIN\n            VALUE \"FileVersion\", \"1.0.0.0\"\n            VALUE \"ProductVersion\", \"1.0.0.0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n\n#endif    // (壬й) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n/////////////////////////////////////////////////////////////////////////////\n// Ӣ() resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n#pragma code_page(1252)\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDR_MAINFRAME           ICON                    \"res\\\\App.ico\"\n\n#endif    // Ӣ() resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n\n"
  },
  {
    "path": "src/Event/WaitableEvent.cc",
    "content": "#include \"stdafx.h\"\n#include \"WaitableEvent.h\"\n\nnamespace base {\nWaitableEvent::WaitableEvent(bool manual_reset, bool signaled)\n    : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {\n\n  assert(handle_);\n}\n\nWaitableEvent::WaitableEvent(HANDLE event_handle) : handle_(event_handle) {\n  assert(handle_ != INVALID_HANDLE_VALUE);\n}\n\nHANDLE WaitableEvent::Release() {\n  HANDLE rv = handle_;\n  handle_ = NULL;\n  return rv;\n}\n\nWaitableEvent::~WaitableEvent() {\n  assert(handle_);\n  CloseHandle(handle_);\n  handle_ = NULL;\n}\n\nvoid WaitableEvent::Reset() { ResetEvent(handle_); }\n\nvoid WaitableEvent::Signal() { SetEvent(handle_); }\n\nvoid WaitableEvent::Wait() {\n  DWORD result = WaitForSingleObject(handle_, INFINITE);\n}\n\nbool WaitableEvent::TimedWait(const TimeDelta &max_time) {\n  double timeout = ceil(max_time.InMillisecondsF());\n  DWORD result = WaitForSingleObject(handle_, static_cast<DWORD>(timeout));\n  switch (result) {\n  case WAIT_OBJECT_0:\n    return true;\n  case WAIT_TIMEOUT:\n    return false;\n  }\n\n  assert(0);\n  return false;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/Event/WaitableEvent.h",
    "content": "#pragma once\n\n#include <assert.h>\n#include <math.h>\n#include <stdlib.h>\n#include \"../time/time.h\"\n\nnamespace base {\nclass TimeDelta;\n\nclass WaitableEvent {\npublic:\n  WaitableEvent(bool manual_reset, bool initially_signaled);\n\n  explicit WaitableEvent(HANDLE event_handle);\n  HANDLE Release();\n\n  ~WaitableEvent();\n\n  void Reset();\n\n  void Signal();\n\n  void Wait();\n\n  bool TimedWait(const TimeDelta &max_time);\n\n  HANDLE handle() const { return handle_; }\n\nprivate:\n  HANDLE handle_;\n\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/Global.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util/system.h\"\n#include \"Global.h\"\n\n\n/// <configuration>\n/// Set the following string and then compile\n\n// Query zip download link\nstd::string CGlobal::downloadurl_ = \"http://127.0.0.1:5001/download-url\";\n// directory name\nstd::string CGlobal::appDirName_ = \"MyeXeAppDir\";\n// Exe file name such as eXeScope.exe or a relative path such as bin\\\\eXeScope.exe\nstd::string CGlobal::appname_ = \"eXeScope.exe\";\n// shortcut file name\nstd::string CGlobal::shortcutname_ = \"eXeScope\";\n// Link to open after installation\nstd::string CGlobal::openurl_ = \"https://github.com/sinajia/Downloader\";\n\n/// </configuration>\n\n\nITaskbarList4* CGlobal::pTaskbar_ = nullptr;\n\nCGlobal::CGlobal(): hUitlWnd_(NULL), lanId_(0), m_zh(false) {\n  m_macAddress = SystemCommon::Device::GetTheFirstMac();\n  m_platform = Util::Base::GetOSVersion();\n}\nCGlobal::~CGlobal() {}\n\nCGlobal global;\n"
  },
  {
    "path": "src/Global.h",
    "content": "#pragma once\n\n#include \"util/util_tools.h\"\n\nclass CGlobal {\npublic:\n  // configuration value\n  static std::string downloadurl_;\n  static std::string appDirName_;\n  static std::string appname_;\n  static std::string shortcutname_;\n  static std::string openurl_;\n\n  CGlobal();\n  virtual ~CGlobal();\n\n  HWND hUitlWnd_ = NULL;\n  LANGID lanId_;\n\n  bool m_zh;\n  std::string m_filedownurl;\n  std::string m_downloadfileLen;\n  std::string m_macAddress;\n  std::string m_platform;\n  std::wstring m_packPath;\n  std::wstring m_strInstallPath;\n\n  static ITaskbarList4* pTaskbar_;\n\n  constexpr static TCHAR* szUtilityClassName_ = _T(\"AppInstallerWindow\");\n  constexpr static TCHAR* szGlobalString_ = _T(\"65E6B66785CEC64B329\");\n  constexpr static LONG UitlWndPrivacyCode_ = 0x746A04DE;\n\n};\n\nextern CGlobal global;\n"
  },
  {
    "path": "src/Language/Language.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"../Global.h\"\n#include \"Language.h\"\n\nnamespace lan {\nSentence AppLanguage::s_lanArr[] = {\n    {L\"Installing...Please wait!~\", L\"Server error, Try again!\",\n     L\"Install directly\", L\"Disk space not enough\",\n     L\"Downloading ... Please wait\"},\n};\nDWORD AppLanguage::lanIndex_ = 0;\n\nvoid AppLanguage::SysLanguage() {\n  global.lanId_ = GetSystemDefaultLangID();\n  switch (global.lanId_) {\n  case 0x804: {\n    global.m_zh = true;\n  } break;\n  default:\n    break;\n  }\n}\n\n} // namespace lan\n"
  },
  {
    "path": "src/Language/Language.h",
    "content": "#pragma once\n\nnamespace lan {\nstruct Sentence {\n  LPCWSTR pstrInstalling;\n  LPCWSTR pstrServiceError;\n  LPCWSTR pstrRepair;\n  LPCWSTR pstrDiskSpace;\n  LPCWSTR pstrApkInstalling;\n};\n\nclass AppLanguage {\npublic:\n  static Sentence s_lanArr[];\n  static DWORD lanIndex_;\n  static void SysLanguage();\n};\n} // namespace lan\n"
  },
  {
    "path": "src/LogAssist/LogAssist.cpp",
    "content": "#include \"StdAfx.h\"\n#include <assert.h>\n#include <io.h>\n#include <Shlwapi.h>\n#include \"LogAssist.h\"\n#include \"util/system.h\"\n\n#pragma comment(lib, \"shlwapi\")\n\napplog::LogAssist DebugSet;\n\nnamespace applog {\nbase::LazyInstance<LogThread> log_entity_ = LAZY_INSTANCE_INITIALIZER;\n\nLogThread::LogThread() : thread_() {}\n\nLogThread::~LogThread() {\n  if (thread_.IsRunning()) {\n    thread_.Stop();\n  }\n}\n\nSTRU_LOG_DATA::STRU_LOG_DATA() {\n  mlDataLen = 0;\n  ZeroMemory(&mszPrintBuff, sizeof(STRU_LOG_DATA::mszPrintBuff));\n};\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(char acCharVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 1) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 2, \"%c\", acCharVal);\n    StringCchLengthA(lpWritePtr, 2, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(bool abBoolVal) {\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 5) {\n    char *lpWritePtr = (mszPrintBuff) + mlDataLen;\n    unsigned int len = 0;\n    if (abBoolVal) {\n      StringCchPrintfA(lpWritePtr, 6, \"true\");\n      StringCchLengthA(lpWritePtr, 6, &len);\n    } else {\n      StringCchPrintfA(lpWritePtr, 6, \"%s\", \"false\");\n      StringCchLengthA(lpWritePtr, 6, &len);\n    }\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(short asShortVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 6) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 7, \"%d\", asShortVal);\n    StringCchLengthA(lpWritePtr, 7, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(int aiIntVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 11) {\n    char *lpWritePtr = (char *)mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 12, \"%d\", aiIntVal);\n    StringCchLengthA(lpWritePtr, 12, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(unsigned int aiIntVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 11) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 12, \"%u\", aiIntVal);\n    StringCchLengthA(lpWritePtr, 12, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(float afFloatVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 20) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 21, \"%f\", afFloatVal);\n    StringCchLengthA(lpWritePtr, 21, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(double afdoubleVal) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 25) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 26, \"%lf\", afdoubleVal);\n    StringCchLengthA(lpWritePtr, 26, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(__int64 aiInt64Val) {\n  unsigned int len = 0;\n  if (mlDataLen < DEF_MAX_BUFF_LEN - 20) {\n    char *lpWritePtr = mszPrintBuff + mlDataLen;\n    StringCchPrintfA(lpWritePtr, 21, \"%I64d\", aiInt64Val);\n    StringCchLengthA(lpWritePtr, 21, &len);\n    mlDataLen += len;\n  }\n  return *this;\n}\n\nSTRU_LOG_DATA &STRU_LOG_DATA::operator<<(const char *apStrVal) {\n  unsigned int len = 0;\n  char *lpWritePtr = mszPrintBuff + mlDataLen;\n  if (!apStrVal) {\n    if (mlDataLen < DEF_MAX_BUFF_LEN - 4) {\n      StringCchPrintfA(lpWritePtr, 5, \"%s\", \"NULL\");\n      StringCchLengthA(lpWritePtr, 5, &len);\n      mlDataLen += len;\n    }\n  } else {\n    int iLen = static_cast<int>(strlen(apStrVal));\n    if (mlDataLen < DEF_MAX_BUFF_LEN - iLen) {\n      StringCchPrintfA(lpWritePtr, iLen + 1, \"%s\", apStrVal);\n      StringCchLengthA(lpWritePtr, iLen + 1, &len);\n      mlDataLen += len;\n    } else if (DEF_MAX_BUFF_LEN - mlDataLen > 1) {\n      StringCchCopyA(lpWritePtr, DEF_MAX_BUFF_LEN - mlDataLen, apStrVal);\n      mlDataLen += (DEF_MAX_BUFF_LEN - mlDataLen - 1);\n    }\n  }\n  return *this;\n}\n\nLogAssist::LogAssist()\n    : mbIsOpen(false), mbInitial(false), mnLogLevel(3),\n      muTraceOptions(LogAssist::Timestamp | LogAssist::AppendToFile |\n                     LogAssist::FileAndLine | LogAssist::PrintThreadID) {}\n\nLogAssist::~LogAssist() {}\n\nvoid LogAssist::OpenLog(int anLogLevel, const tstring &strDirectory) {\n  CHECK(strDirectory.length());\n  base::Threads::Get(base::Threads::UI)\n      ->PostTask(base::Bind(base::Unretained(this), &LogAssist::InitDebug,\n                            anLogLevel, strDirectory));\n}\n\nvoid LogAssist::CloseLog() { mbIsOpen = false; }\n\nvoid LogAssist::SetOptions(unsigned options) {\n  base::Threads::Get(base::Threads::UI)\n      ->PostTask(base::Bind(base::Unretained(this), &LogAssist::SetTraceOptions,\n                            options));\n}\n\nvoid LogAssist::LogString(const std::string &strFile, int aiLine,\n                          int aiLogLevel, const std::string &strContent) {\n  base::Threads::Get(base::Threads::UI)\n      ->PostTask(base::Bind(base::Unretained(this), &LogAssist::PrintLogInUI,\n                            strFile, aiLine, aiLogLevel, strContent));\n}\n\nstd::string LogAssist::Print(const char *pFmt, ...) {\n  char lstrPrintBuff[DEF_MAX_BUFF_LEN] = {0};\n  va_list argptr;\n  va_start(argptr, pFmt);\n  StringCchVPrintfA(lstrPrintBuff, ARRAYSIZE(lstrPrintBuff) - 1, pFmt, argptr);\n  va_end(argptr);\n  std::string strBuffer = lstrPrintBuff;\n  return strBuffer;\n}\n\nvoid LogAssist::InitDebug(int anLogLevel, const tstring &strDirectory) {\n#ifdef NDEBUG\n  return;\n#endif\n\n  CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current());\n  if (0 == strDirectory.length()) {\n    return;\n  }\n\n  if (mbInitial) {\n    return;\n  }\n\n  char szVariable[100] = { 0 };\n\n  SetTraceLevel(anLogLevel);\n  if (&log_entity_.Get()) {\n    if (!log_entity_.Get().Thread().IsRunning()) {\n      log_entity_.Get().Thread().set_thread_name(\"LogThread\");\n      log_entity_.Get().Thread().StartWithOptions(base::Thread::Options());\n    }\n    if (!log_entity_.Get().Thread().IsRunning()) {\n      return;\n    }\n\n    mbInitial = true;\n    mbIsOpen = true;\n\n    log_entity_.Get().Thread().message_loop()->PostTask(\n        base::Bind(base::Unretained(this), &LogAssist::InitLog, strDirectory));\n  }\n}\n\nvoid LogAssist::PrintLogInUI(const std::string &strFile, int aiLine,\n                             int aiLogLevel, const std::string &strContent) {\n  if (!CanTrace(aiLogLevel) || !mbInitial)\n    return;\n\n  if (&log_entity_.Get()) {\n    if (!log_entity_.Get().Thread().IsRunning() ||\n        !log_entity_.Get().Thread().message_loop())\n      return;\n    log_entity_.Get().Thread().message_loop()->PostTask(\n        base::Bind(base::Unretained(this), &LogAssist::DoPrintLog, strFile,\n                   aiLine, aiLogLevel, strContent));\n  }\n}\n\nvoid LogAssist::DoPrintLog(const std::string &strFile, int aiLine,\n                           int aiLogLevel, const std::string &strContent) {\n  STRU_LOG_DATA loDebugData;\n\n  OptionTrace(loDebugData, aiLogLevel);\n\n  loDebugData << strContent.c_str();\n\n  char *lszSrcFile = PathFindFileNameA(strFile.c_str());\n  FileLineTrace(loDebugData, lszSrcFile, aiLine);\n\n  EndTrace(loDebugData);\n}\n\ntstring LogAssist::CreateLogFile(LPCTSTR szDirectory) {\n  tstring strReturn;\n  tstring strFileName;\n\n  tstring filename0;\n  tstring filename1;\n  FILETIME fileTime0 = {0};\n  FILETIME fileTime1 = {0};\n\n  TCHAR szAppData[MAX_PATH + 1] = {0};\n  GetModuleFileName(NULL, szAppData, MAX_PATH);\n  strFileName = szAppData;\n  strFileName = SystemCommon::FilePathHelper::GetPath(strFileName);\n  PathCombine(szAppData, strFileName.c_str(), szDirectory);\n  strFileName = szAppData;\n  SystemCommon::FilePathHelper::CreateDir(strFileName.c_str());\n  if (PathFileExists(strFileName.c_str())) {\n    int i = 0;\n    for (; i < 2; ++i) {\n      TCHAR lszFileName[MAX_PATH] = {0};\n      StringCchPrintf(lszFileName, MAX_PATH, _T(\"%d.log\"), i);\n      PathAppend(szAppData, lszFileName);\n\n      tstring &filename = (0 == i) ? filename0 : filename1;\n      filename = szAppData;\n\n      HANDLE file = ::CreateFile(filename.c_str(), GENERIC_READ, NULL, NULL,\n                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n      if (file != INVALID_HANDLE_VALUE) {\n        FILETIME &filetime = i ? fileTime1 : fileTime0;\n        GetFileTime(file, NULL, NULL, &filetime);\n        CloseHandle(file);\n      }\n\n      long size = SystemCommon::FilePathHelper::GetFileSize(szAppData);\n      if (size < DEF_MAX_FILE_SIZE) {\n        strReturn = filename;\n        break;\n      }\n      PathRemoveFileSpec(szAppData);\n    }\n    if (2 == i) {\n      strReturn =\n          (CompareFileTime(&fileTime0, &fileTime1) > 0) ? filename1 : filename0;\n      DeleteFile(strReturn.c_str());\n    }\n  }\n  return strReturn;\n}\n\nvoid LogAssist::InitLog(const tstring &strDirectory) {\n  mszLogFileName = CreateLogFile(strDirectory.c_str());\n}\n\nvoid LogAssist::SetTraceLevel(int aiTraceLevel) { mnLogLevel = aiTraceLevel; }\n\nvoid LogAssist::SetTraceOptions(unsigned options) { muTraceOptions = options; }\n\nunsigned LogAssist::GetTraceOptions(void) { return muTraceOptions; }\n\nbool LogAssist::CanTrace(int aiLogLevel) {\n  return mbIsOpen && (aiLogLevel <= mnLogLevel);\n}\n\nvoid LogAssist::OptionTrace(STRU_LOG_DATA &astruDebugData, int aiLogLevel) {\n  astruDebugData.mlDataLen = 0;\n\n  if (muTraceOptions & Timestamp) {\n    SYSTEMTIME loSystemTime;\n    GetLocalTime(&loSystemTime);\n\n    char lszTraceBuff[MAX_PATH] = {0};\n    StringCchPrintfA(lszTraceBuff, ARRAYSIZE(lszTraceBuff) - 1,\n                     \"%d.%d.%d %02d:%02d:%02d:%03d \", loSystemTime.wYear,\n                     loSystemTime.wMonth, loSystemTime.wDay, loSystemTime.wHour,\n                     loSystemTime.wMinute, loSystemTime.wSecond,\n                     loSystemTime.wMilliseconds);\n\n    astruDebugData << lszTraceBuff;\n  }\n  if (muTraceOptions & LogLevel) {\n    astruDebugData << aiLogLevel << ' ';\n  }\n  return;\n}\n\nvoid LogAssist::TraceFormat(STRU_LOG_DATA &astruDebugData, const char *pFmt,\n                            ...) {\n  char szTempContent[DEF_MAX_BUFF_LEN] = {0};\n  va_list argptr;\n  va_start(argptr, pFmt);\n  int liLen = StringCchVPrintfA(szTempContent, ARRAYSIZE(szTempContent) - 1,\n                                pFmt, argptr);\n  va_end(argptr);\n\n  astruDebugData << szTempContent;\n}\n\nvoid LogAssist::FileLineTrace(STRU_LOG_DATA &astruDebugData, char *apSrcFile,\n                              int aiSrcLine) {\n  if (muTraceOptions & FileAndLine) {\n    astruDebugData << \"  \" << apSrcFile << \"[\" << aiSrcLine << \"]\";\n  }\n  return;\n}\n\nvoid LogAssist::EndTrace(STRU_LOG_DATA &astruDebugData) {\n  try {\n    astruDebugData.mszPrintBuff[astruDebugData.mlDataLen] = '\\n';\n\n    if (muTraceOptions & PrintToConsole) {\n      printf(\"%s\", astruDebugData.mszPrintBuff);\n    }\n\n    if ((muTraceOptions & AppendToFile) && mszLogFileName.length()) {\n      FILE *lfpTraceFile = NULL;\n      lfpTraceFile = _tfopen(mszLogFileName.c_str(), _T(\"a\"));\n      if (NULL != lfpTraceFile) {\n        fprintf(lfpTraceFile, \"%s\", astruDebugData.mszPrintBuff);\n        fclose(lfpTraceFile);\n      }\n    }\n  } catch (...) {\n  }\n}\n\n} // namespace applog\n"
  },
  {
    "path": "src/LogAssist/LogAssist.h",
    "content": "#pragma once\n\n#include <Fcntl.h>\n#include <shlwapi.h>\n#include <strsafe.h>\n#include <sys/stat.h>\n#include \"../base/macros.h\"\n#include \"../base.h\"\n\n#define FORMAT(x) applog::LogAssist::Print##x\n#define INIT_LOG(obj, szDirectory) obj.OpenLog(3, szDirectory);\n#define PRT_LOG(obj, alevel, y)  obj.LogString(__FILE__, __LINE__, alevel, FORMAT(y));\n#define PRT_LOG3(obj, y) PRT_LOG(obj, 3, y)\n\nnamespace applog {\nconstexpr int DEF_MAX_BUFF_LEN = 2048;\nconstexpr int DEF_MAX_FILE_SIZE = 1024 * 1024 * 2;\n\nclass STRU_LOG_DATA {\npublic:\n  STRU_LOG_DATA();\n  STRU_LOG_DATA &operator<<(char acCharVal);\n  STRU_LOG_DATA &operator<<(bool abBoolVal);\n  STRU_LOG_DATA &operator<<(short asShortVal);\n  STRU_LOG_DATA &operator<<(int aiIntVal);\n  STRU_LOG_DATA &operator<<(unsigned int aiIntVal);\n  STRU_LOG_DATA &operator<<(float afFloatVal);\n  STRU_LOG_DATA &operator<<(double afdoubleVal);\n  STRU_LOG_DATA &operator<<(__int64 aiInt64Val);\n  STRU_LOG_DATA &operator<<(const char *apStrVal);\n\n  char mszPrintBuff[DEF_MAX_BUFF_LEN + sizeof(short)];\n  int mlDataLen = 0;\n};\n\nclass LogThread {\npublic:\n  base::Thread &Thread() { return thread_; }\n  DISALLOW_COPY_AND_ASSIGN(LogThread);\n\nprivate:\n  friend class base::LazyInstance<LogThread>;\n  friend class base::DefaultLazyInstanceTraits<LogThread>;\n  LogThread();\n  ~LogThread();\n  base::Thread thread_;\n};\n\nclass LogAssist {\npublic:\n  LogAssist();\n  ~LogAssist();\n\n  enum Options {\n    Timestamp = 1,\n\n    LogLevel = 2,\n\n    FileAndLine = 4,\n\n    AppendToFile = 8,\n\n    PrintToConsole = 16,\n\n    PrintThreadID = 32\n  };\n\npublic:\n  void OpenLog(int anLogLevel, const tstring &strDirectory);\n\n  void CloseLog();\n\n  void SetOptions(unsigned options);\n\n  void LogString(const std::string &strFile, int aiLine, int aiLogLevel,\n                 const std::string &strContent);\n  static std::string Print(const char *pFmt, ...);\n\nprivate:\n  void DoPrintLog(const std::string &strFile, int aiLine, int aiLogLevel,\n                  const std::string &strContent);\n  void PrintLogInUI(const std::string &strFile, int aiLine, int aiLogLevel,\n                    const std::string &strContent);\n  void InitDebug(int anLogLevel, const tstring &strDirectory);\n  void InitLog(const tstring &strDirectory);\n  bool CanTrace(int aiLogLevel);\n  void SetTraceLevel(int aiTraceLevel);\n  void SetTraceOptions(unsigned options);\n  unsigned GetTraceOptions(void);\n  void OptionTrace(STRU_LOG_DATA &astruDebugData, int aiLogLevel);\n  void TraceFormat(STRU_LOG_DATA &astruDebugData, const char *pFmt, ...);\n  void FileLineTrace(STRU_LOG_DATA &astruDebugData, char *apSrcFile,\n                     int aiSrcLine);\n  void EndTrace(STRU_LOG_DATA &astruDebugData);\n\n  static tstring CreateLogFile(LPCTSTR szDirectory);\n\nprivate:\n  tstring mszLogFileName;\n\n  unsigned muTraceOptions;\n  long mnLogLevel = 3;\n  bool mbIsOpen = false;\n  bool mbInitial = false;\n};\n\nextern base::LazyInstance<LogThread> log_entity_;\n\n} // namespace applog\n\nextern applog::LogAssist DebugSet;\n"
  },
  {
    "path": "src/Main.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util/base.h\"\n#include \"util/util_tools.h\"\n#include \"util/system.h\"\n#include \"Global.h\"\n#include \"Language/Language.h\"\n#include \"LogAssist/LogAssist.h\"\n#include \"UI/UtilityWindow.h\"\n\nHINSTANCE _hInstance = nullptr;\nCAppModule _Module;\n\nUINT WM_TASKBARBUTTONCREATED = 0x1000;\n\nstatic HRESULT Initialize();\nstatic HRESULT UnInitialize();\n\nbase::LazyInstance<base::Thread> io_thread_ LAZY_INSTANCE_INITIALIZER;\nbase::LazyInstance<base::Thread> file_thread_ LAZY_INSTANCE_INITIALIZER;\n\nvoid InstallCommonThread() {\n  if (!file_thread_.Get().IsRunning()) {\n    file_thread_.Get().set_thread_name(\"file_thread\");\n    file_thread_.Get().StartWithOptions(base::Thread::Options());\n    base::Threads::Set(base::Threads::FILE, file_thread_.Get().message_loop());\n  }\n\n  if (!io_thread_.Get().IsRunning()) {\n    io_thread_.Get().set_thread_name(\"io_thread\");\n    io_thread_.Get().StartWithOptions(\n        base::Thread::Options(base::MessageLoop::TYPE_IO));\n    base::Threads::Set(base::Threads::IO, io_thread_.Get().message_loop());\n  }\n}\n\nvoid InitGlobalPath() {\n  if (Util::Base::GetAccurateOSVersion() <= WINDOWS_2003)\n    global.m_strInstallPath = L\"C:\\\\Program Files\";\n  else {\n    global.m_strInstallPath =\n        SystemCommon::FilePathHelper::GetAssignPath(CSIDL_APPDATA, FALSE);\n  }\n\n  global.m_packPath =\n      SystemCommon::FilePathHelper::GetAssignPath(CSIDL_LOCAL_APPDATA, TRUE);\n}\n\nvoid UnstallCommonThread() {\n  io_thread_.Get().Stop();\n  file_thread_.Get().Stop();\n  applog::log_entity_.Get().Thread().Stop();\n}\n\nint Run(int nCmdShow = SW_SHOWDEFAULT) {\n  InstallCommonThread();\n\n  InitGlobalPath();\n\n  std::auto_ptr<base::MessageLoop> message_loop;\n  message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));\n  message_loop->set_thread_name(\"ui_thread\");\n  base::Threads::Set(Threads::UI, message_loop.get());\n\n  INIT_LOG(DebugSet, _T(\"LOGINIT\\\\\"))\n  PRT_LOG3(DebugSet, (\"sys lang: %d\", global.lanId_));\n\n  do {\n    TCHAR szPath[MAX_PATH + 1] = {0};\n    GetModuleFileName(NULL, szPath, MAX_PATH);\n    TCHAR szFileVersion[200] = {0};\n    SystemCommon::FileVersionHelper::GetFileVersion(szPath, szFileVersion, 200);\n    std::string verNum = Util::Base::WChar2Ansi(szFileVersion);\n    PRT_LOG3(DebugSet, (\"app started %s\", verNum.c_str()))\n  } while (false);\n\n  if (!CUtilityWindow::GetInstance().Initialize()) {\n    goto RETURN;\n  }\n  message_loop->Run();\n\n  CUtilityWindow::GetInstance().UnInitialize();\n\nRETURN:\n  UnstallCommonThread();\n  return TRUE;\n}\n\nvoid CheckIsRunning() {\n  HWND hWnd = ::FindWindow(CGlobal::szUtilityClassName_, CGlobal::szGlobalString_);\n  if (hWnd && ::IsWindow(hWnd) &&\n      GetWindowLongPtr(hWnd, GWLP_USERDATA) == CGlobal::UitlWndPrivacyCode_) {\n\n    ::PostMessage(hWnd, WM_IS_EXIST, 0, 0);\n    ExitProcess(0);\n  }\n}\n\nint APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,\n                     LPSTR lpCmdLine, int nCmdShow) {\n  CheckIsRunning();\n\n  base::AtExitManager atmgr;\n\n  _hInstance = hInstance;\n\n  WM_TASKBARBUTTONCREATED = ::RegisterWindowMessage(L\"TaskbarButtonCreated\");\n\n  HRESULT hRes = S_OK;\n\n  BOOL bSuccess = AtlInitCommonControls(ICC_BAR_CLASSES);\n  ::DefWindowProc(NULL, 0, 0, 0L);\n\n  int nRet = -1;\n\n  if (S_OK == Initialize()) {\n    hRes = _Module.Init(NULL, hInstance);\n\n    ATLASSERT(SUCCEEDED(hRes));\n\n    nRet = Run(nCmdShow);\n\n    _Module.Term();\n  }\n\n  UnInitialize();\n\n  return nRet;\n}\n\nHRESULT Initialize() {\n  LPCTSTR lpCommandLine = GetCommandLine();\n  int nArgs = 0;\n  LPTSTR *lpArgList = CommandLineToArgvW(lpCommandLine, &nArgs);\n  LPCTSTR lpParaVal = nullptr;\n  TCHAR szUrl[MAX_URL_LEN + 1] = {0};\n\n  lan::AppLanguage::SysLanguage();\n\n  return S_OK;\n}\n\nHRESULT UnInitialize() { return S_OK; }\n"
  },
  {
    "path": "src/StdAfx.cpp",
    "content": "#include \"StdAfx.h\"\n\n#pragma comment(lib, \"netapi32.lib\")\n#pragma comment(lib, \"version.lib\")\n#pragma comment(lib, \"Shell32.lib\")\n#pragma comment(lib, \"gdiplus.lib\")\n#pragma comment(lib, \"strsafe.lib\")\n\nvoid TrackMouseLeave(HWND hWnd) {\n  TRACKMOUSEEVENT tme;\n  memset(&tme, 0, sizeof(tme));\n  tme.cbSize = sizeof(tme);\n  tme.dwFlags = TME_LEAVE;\n  tme.hwndTrack = hWnd;\n  tme.dwHoverTime = 0;\n  TrackMouseEvent(&tme);\n}\n"
  },
  {
    "path": "src/StdAfx.h",
    "content": "#pragma once\n#pragma warning(disable: 4302)\n#pragma warning(disable: 4244)\n\n#define WIN32_LEAN_AND_MEAN\n#define _CRT_SECURE_NO_WARNINGS\n\n#define WINVER 0x0501\n#define _WIN32_WINNT 0x0501\n\n#include <windows.h>\n#include <CommDlg.h>\n#include <Shlwapi.h>\n#include <malloc.h>\n#include <memory>\n#include <stdlib.h>\n#include <tchar.h>\n#include <assert.h>\n#include <shlobj.h>\n#include <shellapi.h>\n#include <atlconv.h>\n#include <atlbase.h>\n#include <atlapp.h>\n#include <ExDispid.h>\n#include <MsHtmdid.h>\n#include <WinInet.h>\n#include <atlcrack.h>\n#include <atlctrls.h>\n#include <atlctrlx.h>\n#include <atlframe.h>\n#include <atlmisc.h>\n#include <atlwin.h>\n#include <comdef.h>\n#include <mshtmhst.h>\n#include <shellapi.h>\n#include <strsafe.h>\n#include <algorithm>\n#include <deque>\n#include <list>\n#include <map>\n#include <string>\n#include <vector>\n#include <new>\n\nextern CAppModule _Module;\nextern HINSTANCE _hInstance;\n\n#ifndef tstring\n#ifdef _UNICODE\n#define tstring std::wstring\n#else\n#define tstring std::string\n#endif\n#endif\n\n#define SIZEOF(A) (sizeof(A) / sizeof((A)[0]))\n\n#ifndef MAX_URL_LEN\n#define MAX_URL_LEN INTERNET_MAX_URL_LENGTH\n#endif\n\n#include \"util/base.h\"\n\n#define MAX_WINDOW_WIDTH 800\n#define MAX_WINDOW_HEIGHT 600\n"
  },
  {
    "path": "src/UI/FrameShowState.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"FrameShowState.h\"\n\nShowState::ShowState() : bPending_(false), step_(APP1), degree_(DETEN) {}\n"
  },
  {
    "path": "src/UI/FrameShowState.h",
    "content": "#pragma once\n\nclass ShowState {\npublic:\n  explicit ShowState();\n  enum PngType {\n    PNG_BEGIN = 0,\n    APP1,\n    APP2,\n    APP3,\n    APP4,\n    APP5,\n    APP6,\n  };\n\n  enum TransDegree {\n    DETEN = 20,\n    DEFIF = 50,\n    DESIX = 100,\n    DESEVN = 150,\n    DEEIGHT = 180,\n    DENIGHT = 220,\n    DEALL = 255,\n  };\n\n  bool bPending_;\n  PngType step_;\n  DWORD degree_;\n};\n"
  },
  {
    "path": "src/UI/UIAgreement.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util/util_tools.h\"\n#include \"../base/Thread.h\"\n#include \"../base/WeakPtr.h\"\n#include \"../base/WrapperObj.h\"\n#include \"../base/common_threads.h\"\n#include \"../base/lazy_instance.h\"\n#include \"../Global.h\"\n#include \"UIAgreement.h\"\n\nstatic constexpr int BEGINSCROLL = 0x101;\nstatic constexpr int SCROLLING = 0x102;\nstatic constexpr int HEIGHT = 300;\nstatic constexpr int ENHEIGHT = 400;\n\nCUIContents::CUIContents() : _parent(NULL), _scrollDelta(0) {}\n\nCUIContents::~CUIContents() { ATLTRACE(\"delete CUIContents\\n\"); }\n\nvoid CUIContents::OnWheel(WPARAM wParam) {\n  const int zDelta = (int)(short)HIWORD(wParam);\n  const int height = global.m_zh ? HEIGHT : ENHEIGHT;\n  if (zDelta < 0) {\n    _scrollDelta += 20;\n    if (_scrollDelta > height) {\n      _scrollDelta = height;\n    }\n  }\n  if (zDelta > 0) {\n    _scrollDelta -= 20;\n    if (_scrollDelta < 0) {\n      _scrollDelta = 0;\n    }\n  }\n  tstring strID = _T(\"id_static_tip2\");\n  CBaseElementCtl *pEle = _elementManager.Search(strID);\n  if (pEle) {\n    static_cast<CStaticCtl *>(pEle)->_scrollDelta = _scrollDelta;\n    RaiseInvalidate(TRUE);\n  }\n}\n\nLRESULT CUIContents::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                             BOOL &bHandled) {\n  const int height = global.m_zh ? HEIGHT : ENHEIGHT;\n  if (wParam == BEGINSCROLL) {\n    KillTimer(BEGINSCROLL);\n    SetTimer(SCROLLING, 100, NULL);\n  }\n  if (wParam == SCROLLING) {\n    _scrollDelta += 4;\n    if (_scrollDelta > height) {\n      KillTimer(SCROLLING);\n    } else {\n      tstring strID = _T(\"id_static_tip2\");\n      CBaseElementCtl *pEle = _elementManager.Search(strID);\n      if (pEle) {\n        static_cast<CStaticCtl *>(pEle)->_scrollDelta = _scrollDelta;\n        RaiseInvalidate(TRUE);\n      }\n    }\n  }\n  return S_OK;\n}\n\nLRESULT CUIContents::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                   BOOL &bHandled) {\n  if (_parent && ::IsWindow(_parent)) {\n    ::PostMessage(_parent, WM_CLOSE, 0, 0);\n  }\n  return S_OK;\n}\n\nvoid CUIContents::CreateWnd(HWND hWnd) {\n  _parent = hWnd;\n  std::wstring strXMLSource;\n  switch (global.lanId_) {\n  case 0x804: {\n    strXMLSource = L\"UICONTENT\";\n  } break;\n  default:\n    strXMLSource = L\"ENGUICONTENT\";\n  }\n\n  CTransWindow::DUICreate(hWnd, strXMLSource.c_str());\n  ::ShowWindow(m_hWnd, SW_SHOW);\n}\n\nvoid CUIContents::OnFinalMessage(HWND) {\n  _elementManager.Dispose();\n  delete this;\n}\n\nvoid CUIContents::OnLoad() {\n  RECT rc;\n  ::GetWindowRect(_parent, &rc);\n  rc.left += 20;\n  rc.top += 47;\n\n  SetWindowPos(0, &rc, SWP_NOZORDER | SWP_NOSIZE);\n}\n\nvoid CUIContents::OnLoaded() { SetTimer(BEGINSCROLL, 600, NULL); }\n\nCUIAgreement::CUIAgreement() : _obj(NULL) {}\n\nCUIAgreement::~CUIAgreement() {}\n\nvoid CUIAgreement::CreateWnd(HWND hpWnd) {\n  std::wstring strXMLSource;\n  switch (global.lanId_) {\n  case 0x804: {\n    strXMLSource = L\"UIAGREEMENT\";\n  } break;\n  default:\n    strXMLSource = L\"ENGUIAGREEMENT\";\n  }\n\n  CTransWindow::DUICreate(hpWnd, strXMLSource.c_str());\n}\n\nvoid CUIAgreement::DestroyWnd() {\n  _elementManager.Dispose();\n  DestroyWindow();\n}\n\nLRESULT CUIAgreement::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                    BOOL &bHandled) {\n  CTransWindow::OnLButtonDown(uMsg, wParam, lParam, bHandled);\n  PostMessage(WM_CLOSE, 0, 0);\n  return S_OK;\n}\n\nvoid CUIAgreement::OnLoad() {\n  _obj = new CUIContents();\n  _obj->CreateWnd(m_hWnd);\n}\n\nvoid CUIAgreement::OnLoaded() { SetFocus(); }\n\nvoid CUIAgreement::OnExit() {\n  _elementManager.Dispose();\n  DestroyWnd();\n\n  (static_cast<base::MessagePumpForUI *>(\n       base::MessageLoop::LayerLoop::Back()->pump_win()))\n      ->Quit();\n}\n\nvoid CUIAgreement::OnFinalMessage(HWND) { m_hWnd = NULL; }\n\nvoid CUIAgreement::DrawBorder(CDCHandle dc) {\n  DUI_Rect wndRect;\n  GetClientRect(&wndRect);\n\n  HDC hDC = dc.m_hDC;\n\n  BITMAP bmpFrameData;\n  GetObject(_bmpFrame, sizeof(bmpFrameData), &bmpFrameData);\n\n  if (_bmpFrame) {\n    CGDIResource::GetInstance().GDI_DrawImageStretch(\n        hDC, _bmpFrame, wndRect,\n        DUI_Rect(0, 0, bmpFrameData.bmWidth, bmpFrameData.bmHeight), 210,\n        _rcFrameCorner);\n  }\n}\n\nLRESULT CUIAgreement::OnWheel(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) {\n  if (_obj && ::IsWindow(_obj->m_hWnd)) {\n    _obj->OnWheel(wParam);\n  }\n  return S_OK;\n}\n"
  },
  {
    "path": "src/UI/UICannotDown.cpp",
    "content": "#include \"stdafx.h\"\n#include \"util/util_tools.h\"\n#include \"../Global.h\"\n#include \"../base/Thread.h\"\n#include \"../base/WeakPtr.h\"\n#include \"../base/WrapperObj.h\"\n#include \"../base/common_threads.h\"\n#include \"../base/lazy_instance.h\"\n#include \"UICannotDown.h\"\n\nCUIUpDate::CUIUpDate() : infostyle_(QUIT) {}\n\nCUIUpDate::~CUIUpDate() {}\n\nvoid CUIUpDate::CreateWnd(HWND hpWnd) {\n  std::wstring strXMLSource;\n  switch (global.lanId_) {\n  case 0x804: {\n    strXMLSource = L\"UICANNOTDOWN\";\n  } break;\n  default:\n    strXMLSource = L\"ENGUICANNOTDOWN\";\n  }\n  CTransWindow::DUICreate(hpWnd, strXMLSource.c_str());\n}\n\nvoid CUIUpDate::DestroyWnd() {\n  _elementManager.Dispose();\n  DestroyWindow();\n}\n\nvoid CUIUpDate::OnLoad() {\n  tstring strID = _T(\"id_btn_close\");\n  CBaseElementCtl *pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnCancal));\n  }\n  strID = _T(\"id_btn_ok\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnYes));\n  }\n  strID = _T(\"id_btn_cancal\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnCancal));\n  }\n  strID = _T(\"id_btn_quit\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIUpDate::OnYes));\n  }\n  if (infostyle_ == QUIT) {\n    strID = _T(\"id_btn_quit\");\n    pEle = _elementManager.Search(strID);\n    if (pEle) {\n      pEle->SetVisible(FALSE);\n    }\n    strID = _T(\"id_static_tip2\");\n    pEle = _elementManager.Search(strID);\n    if (pEle) {\n      pEle->SetVisible(FALSE);\n    }\n  } else if (infostyle_ == CHECKSYSTEM) {\n    strID = _T(\"id_btn_ok\");\n    pEle = _elementManager.Search(strID);\n    if (pEle) {\n      pEle->SetVisible(FALSE);\n    }\n    strID = _T(\"id_btn_cancal\");\n    pEle = _elementManager.Search(strID);\n    if (pEle) {\n      pEle->SetVisible(FALSE);\n    }\n    strID = _T(\"id_static_tip1\");\n    pEle = _elementManager.Search(strID);\n    if (pEle)\n      pEle->SetVisible(FALSE);\n    strID = _T(\"id_btn_close\");\n    pEle = _elementManager.Search(strID);\n    if (pEle)\n      pEle->SetVisible(FALSE);\n  }\n}\n\nvoid CUIUpDate::OnLoaded() {}\n\nvoid CUIUpDate::OnExit() {\n  _elementManager.Dispose();\n  DestroyWnd();\n\n  (static_cast<base::MessagePumpForUI *>(\n       base::MessageLoop::LayerLoop::Back()->pump_win()))\n      ->Quit();\n}\n\nvoid CUIUpDate::OnFinalMessage(HWND) { m_hWnd = NULL; }\n\nvoid CUIUpDate::OnYes() {\n  _bOK = TRUE;\n  PostMessage(WM_CLOSE, 0, 0);\n}\n\nvoid CUIUpDate::OnCancal() {\n  _bOK = FALSE;\n  PostMessage(WM_CLOSE, 0, 0);\n}\n\nvoid CUIUpDate::DrawBorder(CDCHandle dc) {\n  CTransWindow::DrawBorder(dc);\n  {\n    HBITMAP hBitMap = NULL;\n    hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n                                                        _T(\"APPLOGO\"), PNG);\n    if (hBitMap) {\n      BITMAP bmpFrameData;\n      GetObject(hBitMap, sizeof(bmpFrameData), &bmpFrameData);\n      DUI_Rect rRect(22, 20, 22 + bmpFrameData.bmWidth,\n                     20 + bmpFrameData.bmHeight);\n      HDC hDC = dc.m_hDC;\n      CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n    }\n  }\n}\n\nvoid CUIUpDate::SetCustomTitle(std::wstring &title) {\n  tstring strID = _T(\"id_static_tip2\");\n  CBaseElementCtl *pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetTitle(title);\n  }\n}\n"
  },
  {
    "path": "src/UI/UIMainWindowEx.cpp",
    "content": "#include \"stdafx.h\"\n#include <mmsystem.h>\n#include <regex>\n#include <math.h>\n#include \"jsoncpp/json/json.h\"\n#include \"util/util_tools.h\"\n#include \"util/system.h\"\n#include \"../base/Thread.h\"\n#include \"../base/common_threads.h\"\n#include \"../Global.h\"\n#include \"../LogAssist/LogAssist.h\"\n#include \"../Language/Language.h\"\n#include \"../Util/UtilApi.h\"\n#include \"UtilityWindow.h\"\n#include \"UICannotDown.h\"\n#include \"UIAgreement.h\"\n#include \"UIMainWindowEx.h\"\n\n#define PELEMENT (pEle = _elementManager.Search(strID))\n\nCUIMainWindowEx::CUIMainWindowEx(): \n  instep_(BEFOREDOWN),\n  installtype_(DEFAULT),\n  downloadway_(SINGLE),\n  showstate_(),\n  time_download_(0), \n  time_install_(0),\n  b_user_quit_(false),\n  window_showing_(true),\n  is_pack_complete_(false),\n  f_down_process_(0.0),\n  urldownloader_(this, global.downloadurl_),\n  filedownloader_(this, global.downloadurl_, global.m_packPath) {}\n\nCUIMainWindowEx::~CUIMainWindowEx() {\n}\n\nLRESULT CUIMainWindowEx::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                       BOOL &bHandled) {\n  if (wParam != SC_MAXIMIZE) {\n    bHandled = FALSE;\n  }\n  if (wParam == SC_RESTORE) {\n    RaiseInvalidate(TRUE);\n  }\n  if (SC_CLOSE == wParam) {\n    if (instep_ < INSTALLING) {\n      CUIUpDate obj;\n      obj.CreateWnd(m_hWnd);\n      if (obj.DoModal()) {\n        DownLoadingAUserQuit();\n        b_user_quit_ = true;\n      } else {\n        bHandled = TRUE;\n        base::Threads::Get(Threads::UI)\n            ->PostTask(Bind(this, &CUIMainWindowEx::DoInstall));\n      }\n    } else if (instep_ == INSTALLING) {\n      bHandled = TRUE;\n      ShakeWindow();\n    } else {\n      bHandled = TRUE;\n      base::Threads::Get(Threads::UI)\n          ->PostTask(Bind(this, &CUIMainWindowEx::OnInstallComplete));\n    }\n  }\n  return 0;\n}\n\nLRESULT CUIMainWindowEx::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                      BOOL &bHandled) {\n  if (bshaking_ || _bCUpdateWindowBaseEx_TransShow) {\n    bHandled = TRUE;\n    return S_OK;\n  }\n  RECT rect;\n  GetWindowRect(&rect);\n  int x = GET_X_LPARAM(lParam);\n  int y = GET_Y_LPARAM(lParam);\n\n  DUI_Point pt(x, y);\n  ScreenToClient(&pt);\n\n  if (_elementManager.MouseOnElement(pt))\n    return HTCLIENT;\n\n  UINT nFlags = 0;\n  _elementManager.OnMouseMove(nFlags, pt);\n\n  int nTop = 0;\n  int nLeft = 0;\n  int nRight = 0;\n  int nBottom = 0;\n\n  if (IsZoomed()) {\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n    return HTCLIENT;\n  }\n\n  if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n    return HTCAPTION;\n\n  if (_bSupportChangeSize) {\n    if (x >= rect.left && x <= rect.left + nLeft) {\n      if (y < rect.top + nTop)\n        return HTTOPLEFT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMLEFT;\n\n      return HTLEFT;\n    }\n\n    if (x <= rect.right && x >= rect.right - nRight) {\n      if (y < rect.top + nTop)\n        return HTTOPRIGHT;\n      else if (y > rect.bottom - nBottom)\n        return HTBOTTOMRIGHT;\n\n      return HTRIGHT;\n    }\n\n    if (y >= rect.top && y <= rect.top + nTop)\n      return HTTOP;\n\n    if ((y > rect.top + nTop) && (y <= rect.top + _nTitleHeight))\n      return HTCAPTION;\n\n    if (y <= rect.bottom && y >= rect.bottom - nBottom) {\n      return HTBOTTOM;\n    }\n  }\n\n  return HTCLIENT;\n}\n\nLRESULT CUIMainWindowEx::OnPathIllCharacter(UINT uMsg, WPARAM wParam,\n  LPARAM lParam, BOOL& bHandled) {\n  CBaseElementCtl* pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_panel_userdef\");\n  pEle = _elementManager.Search(strID);\n  if (pEle && pEle->GetVisible()) {\n  }\n  else\n    return 0;\n  strID = _T(\"id_edit_installpath\");\n  pEle = _elementManager.Search(strID);\n  if (!pEle)\n    return 0;\n  std::wstring title = pEle->GetTitle();\n  std::wregex p(\n    L\"^[a-zA-Z]:\\\\\\\\{1}(?:[^/:*?\\\"<>|])*[^./:*?\\\"<>|]{1}$|[a-zA-Z]:\\\\\\\\\");\n  bool ism = std::regex_match(title, p);\n  BOOL tipshow = FALSE;\n  if (ism) {\n    if (!(-1 == title.find(L\"\\\\\\\\\") && -1 == title.find(L\".\\\\\") && -1 == title.find(L\"\\\\.\"))) {\n      tipshow = TRUE;\n    }\n  } else {\n    tipshow = TRUE;\n  }\n  strID = _T(\"id_static_patherror\");\n  pEle = _elementManager.Search(strID);\n  if (pEle)\n    pEle->SetVisible(tipshow);\n  strID = _T(\"id_btn_installnow\");\n  PELEMENT;\n  if (pEle) {\n    ((CButtonCtl*)pEle)->Enable(!tipshow);\n  }\n  return 0;\n}\n\nLRESULT CUIMainWindowEx::OnTaskBarCreated(UINT uMsg, WPARAM wParam,\n  LPARAM lParam, BOOL& bHandled) {\n  if (CGlobal::pTaskbar_)\n    return S_OK;\n\n  if (S_OK == ::CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER,\n    IID_PPV_ARGS(&CGlobal::pTaskbar_))) {\n    CGlobal::pTaskbar_->HrInit();\n    CGlobal::pTaskbar_->SetProgressState(m_hWnd, TBPF_NORMAL);\n  }\n  return S_OK;\n}\n\nHWND CUIMainWindowEx::CreateWnd(HWND hParent, const WCHAR *wstr) {\n  CTransWindowEx<CUIMainWindowEx>::DUICreate(hParent, wstr);\n  TransBeginShow();\n  TransShowWindow();\n  return m_hWnd;\n}\n\nvoid CUIMainWindowEx::DestroyWnd() {\n  if (::IsWindow(m_hWnd)) {\n    DestroyWindow();\n  }\n}\n\nvoid CUIMainWindowEx::RestoreWindow() {\n  if (::IsIconic(m_hWnd))\n    ::ShowWindow(m_hWnd, SW_RESTORE);\n  RaiseInvalidate();\n}\n\nvoid CUIMainWindowEx::OnLoad() {\n  CBaseElementCtl *pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_close\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnClose));\n  }\n  strID = _T(\"id_install\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnInstall));\n  }\n\n  strID = _T(\"id_checkbox\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    ((CCheckBoxCtl *)pEle)->SetCheck(TRUE);\n    pEle->RegisterLButtonDownEvent(BIND(*this, CUIMainWindowEx::OnCheck));\n  }\n  strID = _T(\"id_openurl\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnAgreement));\n  }\n  strID = _T(\"id_userinstall\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnSelected));\n  }\n  strID = _T(\"id_btn_min\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnMin));\n  }\n  strID = _T(\"id_panel_userdef\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  strID = _T(\"id_btn_backmain\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnBackMain));\n  }\n  strID = _T(\"id_btn_installdir\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OpenInstallDir));\n  }\n  strID = _T(\"id_checkbox_shortcut\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    ((CCheckBoxCtl *)pEle)->SetCheck(TRUE);\n  }\n  strID = _T(\"id_checkbox_easymenu\");\n  pEle = _elementManager.Search(strID);\n  if (pEle)\n    ((CCheckBoxCtl *)pEle)->SetCheck(TRUE);\n  strID = _T(\"id_checkbox_autorun\");\n  pEle = _elementManager.Search(strID);\n  if (pEle)\n    ((CCheckBoxCtl *)pEle)->SetCheck(FALSE);\n  strID = _T(\"id_edit_installpath\");\n  PELEMENT;\n  if (pEle)\n    pEle->SetTitle(global.m_strInstallPath);\n  strID = _T(\"id_btn_installnow\");\n  pEle = _elementManager.Search(strID);\n  PELEMENT;\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnInstallSelected));\n  }\n  strID = _T(\"id_panel_download\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  strID = _T(\"id_panel_complete\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  strID = _T(\"id_btn_usenow\");\n  PELEMENT;\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(BIND(*this, CUIMainWindowEx::OnUseNow));\n  }\n  strID = _T(\"id_btn_complete\");\n  PELEMENT;\n  if (pEle) {\n    pEle->RegisterLButtonUpEvent(\n        BIND(*this, CUIMainWindowEx::OnInstallComplete));\n  }\n  strID = _T(\"id_static_tryshutdown\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n}\n\nvoid CUIMainWindowEx::OnLoaded() {}\n\nvoid CUIMainWindowEx::IsWindowShowed() {\n  window_showing_ = false;\n  if (CheckCanInstall()) {\n    base::Threads::Get(base::Threads::FILE)\n      ->PostTask(base::Bind(this, &CUIMainWindowEx::FileInit));\n    base::MessageLoop::current()->PostDelayedTask(\n      base::Bind(this, &CUIMainWindowEx::Rotational),\n      base::TimeDelta::FromMilliseconds(1000));\n  } else {\n    CUIUpDate obj;\n    obj.infostyle_ = CUIUpDate::CHECKSYSTEM;\n    obj.CreateWnd(m_hWnd);\n    obj.DoModal();\n    PostMessage(WM_CLOSE, 0, 0);\n  }\n}\n\nvoid CUIMainWindowEx::StartShake() {\n  tstring strID;\n  CBaseElementCtl* pEle = NULL;\n  strID = _T(\"id_static_tryshutdown\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(TRUE);\n  }\n}\n\nvoid CUIMainWindowEx::Shaked() {\n  tstring strID;\n  CBaseElementCtl* pEle = NULL;\n  strID = _T(\"id_static_tryshutdown\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n}\n\nvoid CUIMainWindowEx::DrawBorder(CDCHandle dc) {\n  CTransWindowEx<CUIMainWindowEx>::DrawBorder(dc);\n  if (showstate_.bPending_) {\n    HBITMAP hBitMap = NULL;\n    switch (showstate_.step_) {\n    case ShowState::APP1: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP6\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap =\n        CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T(\"APP1\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    case ShowState::APP2: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP1\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP2\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    case ShowState::APP3: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP2\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP3\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    case ShowState::APP4: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP3\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP4\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    case ShowState::APP5: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP4\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP5\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    case ShowState::APP6: {\n      DUI_Rect rRect(6, 6, 486, 246);\n      hBitMap =\n        CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n          _T(\"APP5\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP6\"), PNG);\n      if (hBitMap) {\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(\n          hDC, hBitMap, rRect, DUI_BT_ALPHA, showstate_.degree_);\n      }\n    } break;\n    default:\n      break;\n    }\n  }\n  else {\n    HBITMAP hBitMap = NULL;\n    switch (showstate_.step_) {\n    case ShowState::APP1: {\n      hBitMap =\n        CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T(\"APP1\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    case ShowState::APP2: {\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP2\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    case ShowState::APP3: {\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP3\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    case ShowState::APP4: {\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP4\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    case ShowState::APP5: {\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP5\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    case ShowState::APP6: {\n      hBitMap = CGDIResource::GetInstance().GDI_GetBitmap(_hInstance,\n        _T(\"APP6\"), PNG);\n      if (hBitMap) {\n        DUI_Rect rRect(6, 6, 486, 246);\n        HDC hDC = dc.m_hDC;\n        CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n      }\n    } break;\n    default:\n      break;\n    }\n  }\n\n  HBITMAP hBitMap =\n    CGDIResource::GetInstance().GDI_GetBitmap(_hInstance, _T(\"APPLOGO\"), PNG);\n  if (hBitMap) {\n    BITMAP bmpFrameData;\n    GetObject(hBitMap, sizeof(bmpFrameData), &bmpFrameData);\n    DUI_Rect rRect(20 - 4, 20 - 6, 20 - 4 + bmpFrameData.bmWidth,\n      20 - 6 + bmpFrameData.bmHeight);\n    HDC hDC = dc.m_hDC;\n    CGDIResource::GetInstance().GDI_DrawImage(hDC, hBitMap, rRect);\n  }\n}\n\nvoid CUIMainWindowEx::FetchURLComplete(std::string res) {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  if (b_user_quit_) {\n    return;\n  }\n  do {\n    instep_ = DOWNLOADING;\n\n    std::wstring errorNotice =\n      lan::AppLanguage::s_lanArr[lan::AppLanguage::lanIndex_]\n      .pstrServiceError;\n\n    std::string fileurl;\n\n    do {\n      std::map<std::string, std::string> map_token;\n      bool bret = GetJsonTokenByDownLoadUrl(res, map_token);\n      if (!bret) {\n        CUIUpDate obj;\n        obj.infostyle_ = CUIUpDate::NOTICE;\n        obj.CreateWnd(m_hWnd);\n        obj.SetCustomTitle(errorNotice);\n        obj.DoModal();\n        PostMessage(WM_CLOSE, 0, 0);\n        return;\n      }\n      std::map<std::string, std::string>::iterator ite;\n\n      ite = map_token.find(std::string(\"downloadUrl\"));\n      if (ite != map_token.end() && ite->second.length() &&\n        (0 == ite->second.find(\"http\"))) {\n        fileurl = ite->second;\n      } else {\n        CUIUpDate obj;\n        obj.infostyle_ = CUIUpDate::NOTICE;\n        obj.CreateWnd(m_hWnd);\n        obj.SetCustomTitle(errorNotice);\n        obj.DoModal();\n        PostMessage(WM_CLOSE, 0, 0);\n        return;\n      }\n\n    } while (false);\n\n    global.m_filedownurl = fileurl;\n\n    break;\n  } while (false);\n}\n\nvoid CUIMainWindowEx::FetchFileComplete(bool status, DownCompleteInfo& rest) {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  if (b_user_quit_) {\n    return;\n  }\n  const net::URLFetcher::ErrorType reason = rest.reason_;\n  if (!status) {\n    if (reason == net::URLFetcher::DISK_NO_SPACE) {\n      CUIUpDate obj;\n      obj.infostyle_ = CUIUpDate::NOTICE;\n      obj.CreateWnd(m_hWnd);\n      obj.SetCustomTitle(std::wstring(L\"Not enough disk space\"));\n      obj.DoModal();\n      base::Threads::Get(Threads::FILE)\n        ->PostTask(\n          Bind(this, &CUIMainWindowEx::ClearDownloads, global.m_packPath));\n      PostMessage(WM_CLOSE, 0, 0);\n    }\n    else {\n      if (filedownloader_.retrycount_++ != static_cast<char>(-1)) {\n        base::Threads::Get(Threads::FILE)\n          ->PostTask(Bind(this, &CUIMainWindowEx::ClearDownloads,\n            global.m_packPath));\n        base::MessageLoop::current()->PostDelayedTask(\n          Bind(this, &CUIMainWindowEx::RetryDownLoadAgain),\n          base::TimeDelta::FromMilliseconds(1000));\n      } else {\n        CUIUpDate obj;\n        obj.infostyle_ = CUIUpDate::NOTICE;\n        obj.CreateWnd(m_hWnd);\n        obj.SetCustomTitle(std::wstring(L\"Unable connect to server\"));\n        obj.DoModal();\n        base::Threads::Get(Threads::FILE)\n          ->PostTask(Bind(this, &CUIMainWindowEx::ClearDownloads,\n            global.m_packPath));\n        PostMessage(WM_CLOSE, 0, 0);\n      }\n    }\n    return;\n  }\n\n  time_download_ = timeGetTime() - time_download_;\n  is_pack_complete_ = true;\n  if (IsWindowEnabled()) {\n    instep_ = INSTALLING;\n    DoInstall();\n  }\n}\n\nvoid CUIMainWindowEx::FetchFileProgress(double cur) {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  if (b_user_quit_) {\n    return;\n  }\n\n  CBaseElementCtl* pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_progress_download\");\n  PELEMENT;\n  if (pEle) {\n    ((CProgressCtl*)pEle)->SetPos(cur * 0.8);\n  }\n  DWORD now = static_cast<DWORD>(100 * cur * 0.8);\n  SetProgressTaskBar(now, 100);\n}\n\nvoid CUIMainWindowEx::DeletePack(const std::wstring& str_path) {\n  SystemCommon::FilePathHelper::DeepDeleteFile(str_path);\n}\n\nvoid CUIMainWindowEx::OnMin() {\n  ::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);\n}\n\nvoid CUIMainWindowEx::OnClose() {\n  if (instep_ < INSTALLING) {\n    CUIUpDate obj;\n    obj.CreateWnd(m_hWnd);\n    if (obj.DoModal()) {\n      DownLoadingAUserQuit();\n      b_user_quit_ = true;\n      PostMessage(WM_CLOSE, 0, 0);\n    }\n    else {\n      base::Threads::Get(Threads::UI)\n        ->PostTask(Bind(this, &CUIMainWindowEx::DoInstall));\n    }\n  }\n  else if (instep_ == INSTALLING) {\n\n    ShakeWindow();\n  }\n  else {\n    OnInstallComplete();\n  }\n}\n\nvoid CUIMainWindowEx::OnInstall() {\n  if (window_showing_)\n    return;\n\n  tstring strID = _T(\"id_panel_main\");\n  CBaseElementCtl *pEle = NULL;\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n\n  installtype_ = DEFAULT;\n  Ready2DownloadZip();\n}\n\nvoid CUIMainWindowEx::OnInstallSelected() {\n  tstring strID = _T(\"id_edit_installpath\");\n  CBaseElementCtl *pEle = NULL;\n  int deskcut = 1;\n  int barcut = 1;\n  int autorun = 1;\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    global.m_strInstallPath = pEle->GetTitle();\n    if (global.m_strInstallPath[global.m_strInstallPath.length() - 1] == L'\\\\') {\n      std::wstring strtemp = global.m_strInstallPath.c_str();\n      strtemp[strtemp.length() - 1] = L'\\0';\n      global.m_strInstallPath = strtemp.c_str();\n    }\n  }\n  strID = _T(\"id_checkbox_shortcut\");\n  PELEMENT;\n  if (pEle) {\n    deskcut = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0;\n  }\n  strID = _T(\"id_checkbox_easymenu\");\n  PELEMENT;\n  if (pEle) {\n    barcut = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0;\n  }\n  strID = _T(\"id_checkbox_autorun\");\n  PELEMENT;\n  if (pEle) {\n    autorun = ((CCheckBoxCtl *)pEle)->GetCheck() ? 1 : 0;\n  }\n  strID = _T(\"id_panel_userdef\");\n  PELEMENT;\n  if (!pEle)\n    return;\n  pEle->SetVisible(FALSE);\n  installtype_ = SELECT;\n  Ready2DownloadZip();\n}\n\nvoid CUIMainWindowEx::OnAgreement() {\n  CUIAgreement obj;\n  obj.CreateWnd(m_hWnd);\n  if (obj.DoModal()) {\n  }\n}\n\nvoid CUIMainWindowEx::OnCheck() {\n  if (window_showing_)\n    return;\n\n  bool bCheck = false;\n  tstring strID = _T(\"id_checkbox\");\n  CBaseElementCtl* pEle = _elementManager.Search(strID);\n  if (pEle) {\n    bCheck = ((CCheckBoxCtl*)pEle)->GetCheck();\n  }\n  strID = _T(\"id_install\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    if (bCheck) {\n      ((CButtonCtl*)pEle)->Enable(TRUE);\n    }\n    else {\n      ((CButtonCtl*)pEle)->Enable(FALSE);\n    }\n  }\n  strID = _T(\"id_userinstall\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    if (bCheck) {\n      ((CButtonCtl*)pEle)->Enable(TRUE);\n    }\n    else {\n      ((CButtonCtl*)pEle)->Enable(FALSE);\n    }\n  }\n}\n\nvoid CUIMainWindowEx::OpenInstallDir() {\n  BROWSEINFO bi;\n  bi.hwndOwner = this->GetHost();\n  bi.pidlRoot = NULL;\n  bi.pszDisplayName = NULL;\n  bi.lpszTitle = TEXT(\"Please select a folder\");\n  bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;\n  bi.lpfn = NULL;\n  bi.lParam = 0;\n  bi.iImage = 0;\n  LPITEMIDLIST pidl = SHBrowseForFolder(&bi);\n  if (pidl == NULL) {\n    return;\n  }\n  WCHAR szPath[MAX_PATH + 1] = {0};\n  if (!SHGetPathFromIDListW(pidl, szPath)) {\n    return;\n  }\n\n  tstring strID;\n  strID = _T(\"id_edit_installpath\");\n  CBaseElementCtl *pEle = _elementManager.Search(strID);\n  if (pEle) {\n    std::wstring strPath = szPath;\n    static_cast<CLayeredEditCtl *>(pEle)->SetTitle(strPath);\n  }\n  strID = _T(\"id_static_patherror\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  strID = _T(\"id_btn_installnow\");\n  PELEMENT;\n  if (pEle) {\n    static_cast<CButtonCtl *>(pEle)->Enable(TRUE);\n  }\n}\n\nvoid CUIMainWindowEx::OnSelected() {\n  if (window_showing_)\n    return;\n\n  CBaseElementCtl *pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_panel_main\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 472, SWP_NOZORDER | SWP_NOMOVE);\n  ChangeSize(492, 472);\n  strID = _T(\"id_panel_userdef\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(TRUE);\n    if (GetPathEditError())\n      ;\n    else {\n      strID = _T(\"id_static_patherror\");\n      pEle = _elementManager.Search(strID);\n      if (pEle)\n        pEle->SetVisible(FALSE);\n    }\n  }\n}\n\nvoid CUIMainWindowEx::OnBackMain() {\n  CBaseElementCtl *pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_panel_userdef\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  ChangeSize(492, 402);\n  strID = _T(\"id_panel_main\");\n  pEle = _elementManager.Search(strID);\n  if (pEle) {\n    pEle->SetVisible(TRUE);\n  }\n  ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 402, SWP_NOZORDER | SWP_NOMOVE);\n}\n\nvoid CUIMainWindowEx::OnUseNow() {\n  b_user_quit_ = true;\n\n  std::wstring app = global.m_strInstallPath + L\"\\\\\" + Util::Base::s2ws(global.appname_);\n\n  STARTUPINFO si = { 0 };\n  PROCESS_INFORMATION pi = { 0 };\n  WCHAR szProcessCmd[MAX_PATH + 1 + MAX_URL_LEN + MAX_PATH] = { 0 };\n  _snwprintf(szProcessCmd, MAX_PATH + MAX_URL_LEN + MAX_PATH, L\"\\\"%s\\\"\",\n    app.c_str());\n  do {\n    std::wstring wstrtmp = szProcessCmd;\n    std::string stemstr = Util::Base::ws2s(wstrtmp);\n\n  } while (false);\n\n  bool ProcessCreated = true;\n\n  do {\n    if (!SystemCommon::OS::CreateLowIntegrityProcess(szProcessCmd)) {\n      ProcessCreated = false;\n      break;\n    }\n  } while (false);\n  if (false == ProcessCreated) {\n    CreateProcessW(NULL, szProcessCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si,\n      &pi);\n  }\n  PostMessage(WM_CLOSE, 0, 0);\n}\n\nvoid CUIMainWindowEx::OnInstallComplete() {\n  b_user_quit_ = true;\n  PostMessage(WM_CLOSE, 0, 0);\n}\n\nvoid CUIMainWindowEx::CreateShortCut(LPCTSTR szExePath,\n  const ShortCutType Stype) {\n  ::CoInitialize(NULL);\n\n  IShellLink* psl;\n  LPITEMIDLIST pidl;\n  LPMALLOC pShellMalloc;\n  std::wstring strDesktopPath;\n  std::wstring strStartMenuPath;\n\n  const int nFolder[2] = { CSIDL_DESKTOPDIRECTORY, CSIDL_STARTMENU };\n\n  if (SUCCEEDED(SHGetMalloc(&pShellMalloc))) {\n    TCHAR Path[MAX_PATH + 1];\n    for (int i = 0; i < 2; ++i) {\n      if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, nFolder[i], &pidl))) {\n        if (SHGetPathFromIDList(pidl, Path)) {\n          if (i == 0)\n            strDesktopPath = Path;\n          else\n            strStartMenuPath = Path;\n        }\n        pShellMalloc->Free(pidl);\n      }\n    }\n    pShellMalloc->Release();\n  }\n\n  std::wstring str;\n\n  switch (Stype) {\n  case DESK: {\n    str = strDesktopPath;\n  } break;\n  case STARTMENU: {\n    str = strStartMenuPath;\n  } break;\n  case TASKBAR: {\n    std::wstring strTaskBarPath =\n      SystemCommon::FilePathHelper::GetAssignPath(CSIDL_APPDATA, TRUE);\n    strTaskBarPath +=\n      L\"\\\\Microsoft\\\\Internet Explorer\\\\Quick Launch\\\\User Pinned\\\\TaskBar\";\n    str = strTaskBarPath;\n  } break;\n  default: {\n    return;\n  } break;\n  }\n  str += _T(\"\\\\\");\n  str += Util::Base::s2ws(global.shortcutname_);\n  str += _T(\".lnk\");\n\n  do {\n    HRESULT hr = CoCreateInstance(CLSID_ShellLink,\n      NULL, CLSCTX_INPROC_SERVER,\n      IID_IShellLink,\n      (LPVOID*)&psl);\n    if (SUCCEEDED(hr)) {\n      IPersistFile* ppf;\n      psl->SetPath(szExePath);\n      psl->SetArguments(_T(\"\"));\n      psl->SetShowCmd(SW_SHOW);\n      psl->SetIconLocation(szExePath, 0);\n      if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) {\n        if (SUCCEEDED(ppf->Save(str.c_str(), TRUE)))\n          ;\n        ppf->Release();\n      }\n      psl->Release();\n    }\n  } while (false);\n\n  ::CoUninitialize();\n\n}\n\nvoid CUIMainWindowEx::SetProgressTaskBar(DWORD now, DWORD total) {\n  if (CGlobal::pTaskbar_) {\n    CGlobal::pTaskbar_->SetProgressValue(m_hWnd, now, total);\n  }\n}\n\nvoid CUIMainWindowEx::Rotational() {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  do {\n    if (showstate_.bPending_ == false) {\n      showstate_.bPending_ = true;\n      switch (showstate_.step_) {\n      case ShowState::APP1: {\n        showstate_.step_ = ShowState::APP2;\n      } break;\n      case ShowState::APP2: {\n        showstate_.step_ = ShowState::APP3;\n      } break;\n      case ShowState::APP3: {\n        showstate_.step_ = ShowState::APP4;\n      } break;\n      case ShowState::APP4: {\n        showstate_.step_ = ShowState::APP5;\n      } break;\n      case ShowState::APP5: {\n        showstate_.step_ = ShowState::APP6;\n      } break;\n      case ShowState::APP6: {\n        showstate_.step_ = ShowState::APP1;\n      } break;\n      default:\n        break;\n      }\n      showstate_.degree_ = ShowState::DETEN;\n      break;\n    }\n    if (showstate_.degree_ == ShowState::DEALL) {\n      showstate_.bPending_ = false;\n      RaiseInvalidate(TRUE);\n      base::MessageLoop::current()->PostDelayedTask(\n        base::Bind(this, &CUIMainWindowEx::Rotational),\n        base::TimeDelta::FromMilliseconds(4000));\n      return;\n    }\n    switch (showstate_.degree_) {\n    case ShowState::DETEN: {\n      showstate_.degree_ = ShowState::DEFIF;\n    } break;\n    case ShowState::DEFIF: {\n      showstate_.degree_ = ShowState::DESIX;\n    } break;\n    case ShowState::DESIX: {\n      showstate_.degree_ = ShowState::DESEVN;\n    } break;\n    case ShowState::DESEVN: {\n      showstate_.degree_ = ShowState::DEEIGHT;\n    } break;\n    case ShowState::DEEIGHT: {\n      showstate_.degree_ = ShowState::DENIGHT;\n    } break;\n    case ShowState::DENIGHT: {\n      showstate_.degree_ = ShowState::DEALL;\n    } break;\n    case ShowState::DEALL: {\n\n    } break;\n    default:\n      break;\n    }\n\n  } while (false);\n  RaiseInvalidate(TRUE);\n  base::MessageLoop::current()->PostDelayedTask(\n    base::Bind(this, &CUIMainWindowEx::Rotational),\n    base::TimeDelta::FromMilliseconds(100));\n}\n\nvoid CUIMainWindowEx::Ready2DownloadZip() {\n  CBaseElementCtl *pEle = NULL;\n  tstring strID;\n  ChangeSize(492, 402);\n  ::SetWindowPos(m_hWnd, NULL, 0, 0, 492, 402, SWP_NOZORDER | SWP_NOMOVE);\n  strID = _T(\"id_panel_download\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(TRUE);\n  }\n  if (global.m_filedownurl.empty()) {\n    base::MessageLoop::current()->PostDelayedTask(\n        base::Bind(this, &CUIMainWindowEx::CheckIFTureWillDownLoad),\n        base::TimeDelta::FromMilliseconds(200));\n  } else {\n    CombineRealInstallPath();\n    DownLoadingFileUrl();\n  }\n}\n\nvoid CUIMainWindowEx::ClearDownloads(const std::wstring str_path) {\n  CUIMainWindowEx::DeletePack(str_path);\n}\n\nvoid CUIMainWindowEx::FileInit() {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(base::Threads::FILE));\n  global.m_packPath += L\"\\\\AppInsPackFileDir\\\\\";\n  SystemCommon::FilePathHelper::ForceCreateDir(global.m_packPath.c_str());\n  global.m_packPath += L\"AppPackZip\";\n  global.m_packPath += Util::Base::longtocharw(time(nullptr));\n  base::Threads::Get(Threads::UI)\n    ->PostTask(base::Bind(this, &CUIMainWindowEx::QueryDownLoadUrl));\n}\n\nvoid CUIMainWindowEx::QueryDownLoadUrl() {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  global.downloadurl_ =\n    global.downloadurl_ +\n    std::string(\"?version=\") +\n    Util::Base::ws2s(\n      SystemCommon::FileVersionHelper::GetFileVersion(_hInstance)) +\n    std::string(\"&mac_address=\") +\n    global.m_macAddress +\n    std::string(\"&platform=\") +\n    global.m_platform;\n\n  urldownloader_.fetcher_->set_download_url(global.downloadurl_);\n  urldownloader_.fetcher_->Start();\n}\n\nvoid CUIMainWindowEx::DoInstall() {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  if (is_pack_complete_ && IsWindowEnabled()) {\n    instep_ = INSTALLING;\n\n    CBaseElementCtl* pEle = NULL;\n    tstring strID;\n    strID = _T(\"id_static_downing\");\n    PELEMENT;\n    if (pEle) {\n      std::wstring strTitle =\n        lan::AppLanguage::s_lanArr[lan::AppLanguage::lanIndex_]\n        .pstrInstalling;\n      pEle->SetTitle(strTitle);\n      pEle->RaiseInvalidate(TRUE);\n    }\n    strID = _T(\"id_static_downing_size\");\n    PELEMENT;\n    if (pEle) {\n\n      pEle->SetVisible(FALSE);\n      pEle->RaiseInvalidate(TRUE);\n    }\n\n    InstallIng();\n  }\n}\n\nvoid CUIMainWindowEx::InstallIng() {\n  if (base::MessageLoop::current() != base::Threads::Get(Threads::FILE)) {\n    base::Threads::Get(Threads::FILE)\n      ->PostTask(base::Bind(this, &CUIMainWindowEx::InstallIng));\n    return;\n  }\n  do {\n    bool bIs = false;\n    std::wstring exename = Util::Base::s2ws(global.appname_);\n    exename = SystemCommon::FilePathHelper::GetFileName(exename);\n    DWORD dwPid = SystemCommon::OS::ProcesstoPid(exename.c_str());\n    if (dwPid) {\n      char szArgs[50] = { 0 };\n      _snprintf_s(szArgs, 50, _TRUNCATE, \"TASKKILL /F /PID %u\", dwPid);\n      system(szArgs);\n      bIs = true;\n    }\n    if (bIs) {\n      Sleep(100);\n    }\n  } while (false);\n  time_install_ = timeGetTime();\n  BOOL res = SystemCommon::FilePathHelper::UnzipFileToPath(global.m_packPath.c_str(),\n    global.m_strInstallPath.c_str());\n  base::Threads::Get(Threads::UI)\n    ->PostTask(base::Bind(this, &CUIMainWindowEx::UnZipComplete, res));\n}\n\nvoid CUIMainWindowEx::CheckIFTureWillDownLoad() {\n  if (b_user_quit_) {\n    return;\n  }\n  if (global.m_filedownurl.empty()) {\n    base::MessageLoop::current()->PostDelayedTask(\n      base::Bind(this, &CUIMainWindowEx::CheckIFTureWillDownLoad),\n      base::TimeDelta::FromMilliseconds(200));\n  } else {\n    CombineRealInstallPath();\n    DownLoadingFileUrl();\n  }\n}\n\nvoid CUIMainWindowEx::DownLoadingAUserQuit() {\n  CHECK(base::Threads::Get(Threads::UI) == base::MessageLoop::current());\n  urldownloader_.fetcher_->Stop();\n  filedownloader_.fetcher_->Stop();\n}\n\nvoid CUIMainWindowEx::CombineRealInstallPath() {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  global.m_strInstallPath = global.m_strInstallPath + L\"\\\\\" + Util::Base::s2ws(CGlobal::appDirName_);\n  base::Threads::Get(Threads::FILE)\n      ->PostTask(base::Bind(this, &CUIMainWindowEx::ForceCreateInstallPath,\n                            global.m_strInstallPath));\n}\n\nvoid CUIMainWindowEx::ForceCreateInstallPath(std::wstring path) {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::FILE));\n  path += L\"\\\\\";\n  SystemCommon::FilePathHelper::ForceCreateDir(path.c_str());\n}\n\nbool CUIMainWindowEx::CheckCanInstall() {\n  const DWORD c_memsize = 200;\n  const DWORD c_freeharddisk = 1000;\n  const DWORD c_cpu_type = PROCESSOR_INTEL_486;\n  SYSTEM_INFO si;\n  GetSystemInfo(&si);\n  DWORD cpu_type = si.dwProcessorType;\n  DWORD cpu_core_num = si.dwNumberOfProcessors;\n\n  MEMORYSTATUSEX statex;\n  statex.dwLength = sizeof(statex);\n  GlobalMemoryStatusEx(&statex);\n  DWORD memsize = (DWORDLONG)statex.ullTotalPhys / (1000 * 1000);\n\n  ULARGE_INTEGER uli_free_bytes_available;\n  ULARGE_INTEGER uli_total_bytes;\n  ULARGE_INTEGER uli_total_free_bytes;\n  GetDiskFreeSpaceExW(global.m_packPath.c_str(), &uli_free_bytes_available,\n    &uli_total_bytes, &uli_total_free_bytes);\n  DWORD freedisksize = uli_total_free_bytes.QuadPart / (1024 * 1024);\n  if (memsize >= c_memsize && cpu_type >= c_cpu_type &&\n    freedisksize >= c_freeharddisk && cpu_core_num >= 2)\n    return true;\n  else\n    return false;\n}\n\nvoid CUIMainWindowEx::RetryDownLoadAgain() {\n  if (b_user_quit_) {\n    return;\n  }\n  global.m_packPath = SystemCommon::FilePathHelper::GetPath(global.m_packPath);\n  global.m_packPath += L\"AppPackZip\";\n  global.m_packPath += Util::Base::longtocharw(time(NULL));\n  filedownloader_.fetcher_ = net::URLFetcher::Create(\n    net::URLFetcher::Params(global.m_filedownurl, global.m_packPath), &filedownloader_);\n  filedownloader_.fetcher_->Start();\n}\n\nbool CUIMainWindowEx::GetPathEditError() {\n  CBaseElementCtl* pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_edit_installpath\");\n  pEle = _elementManager.Search(strID);\n  if (!pEle)\n    return false;\n  std::wstring title = pEle->GetTitle();\n  std::wregex p(\n    L\"^[a-zA-Z]:\\\\\\\\{1}(?:[^/:*?\\\"<>|])*[^./:*?\\\"<>|]{1}$|[a-zA-Z]:\\\\\\\\\");\n  bool ism = std::regex_match(title, p);\n  bool tipshow = false;\n  if (ism) {\n    if (!(-1 == title.find(L\"\\\\\\\\\") && -1 == title.find(L\".\\\\\") && -1 == title.find(L\"\\\\.\"))) {\n      tipshow = true;\n    }\n  } else {\n    tipshow = true;\n  }\n  return tipshow;\n}\n\nvoid CUIMainWindowEx::DownLoadingFileUrl() {\n  if (UNKNOW == downloadway_) {\n    base::MessageLoop::current()->PostDelayedTask(\n      base::Bind(this, &CUIMainWindowEx::DownLoadingFileUrl),\n      base::TimeDelta::FromMilliseconds(200));\n    return;\n  }\n  time_download_ = timeGetTime();\n  if (downloadway_ == SINGLE) {\n    filedownloader_.fetcher_->set_download_url(global.m_filedownurl);\n    filedownloader_.fetcher_->set_file_loadpath(global.m_packPath);\n    filedownloader_.fetcher_->Start();\n  }\n}\n\nvoid CUIMainWindowEx::UnZipComplete(BOOL res) {\n  CHECK(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  time_install_ = timeGetTime() - time_install_;\n  if (FALSE == res) {\n    base::MessageLoop::current()->PostQuitTask(\n      base::Bind(CUIMainWindowEx::DeletePack, global.m_packPath));\n    CUIUpDate obj;\n    obj.infostyle_ = CUIUpDate::NOTICE;\n    obj.CreateWnd(m_hWnd);\n    obj.SetCustomTitle(std::wstring(L\"File is occupied\"));\n    obj.DoModal();\n    PostMessage(WM_CLOSE, 0, 0);\n    return;\n  }\n  CBaseElementCtl* pEle = NULL;\n  tstring strID;\n  strID = _T(\"id_progress_download\");\n  PELEMENT;\n  if (pEle) {\n    ((CProgressCtl*)pEle)->SetPos((0.95));\n    SetProgressTaskBar(95, 100);\n  }\n  strID = _T(\"id_panel_download\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  strID = _T(\"id_panel_complete\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(TRUE);\n  }\n  if (CGlobal::pTaskbar_) {\n    CGlobal::pTaskbar_->SetProgressState(m_hWnd, TBPF_NOPROGRESS);\n  }\n  strID = _T(\"id_static_tryshutdown\");\n  PELEMENT;\n  if (pEle) {\n    pEle->SetVisible(FALSE);\n  }\n  std::wstring app_path = global.m_strInstallPath + L\"\\\\\" + Util::Base::s2ws(global.appname_);\n  strID = _T(\"id_checkbox_shortcut\");\n  PELEMENT;\n  if (pEle) {\n    if (((CCheckBoxCtl*)pEle)->GetCheck()) {\n      CreateShortCut(app_path.c_str(), DESK);\n    }\n  }\n  strID = _T(\"id_checkbox_autorun\");\n  PELEMENT;\n  if (pEle) {\n    if (((CCheckBoxCtl*)pEle)->GetCheck()) {\n      const std::wstring appName = Util::Base::s2ws(global.appDirName_);\n      std::wstring regKey = L\"Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run\";\n      if (SystemCommon::OS::IsWow64()) {\n        SystemCommon::OS::SetRegValue(HKEY_CURRENT_USER, regKey.c_str(),\n          appName.c_str(), app_path);\n      } else {\n        SystemCommon::OS::SetRegValue(HKEY_CURRENT_USER, regKey.c_str(),\n          appName.c_str(), app_path);\n      }\n    }\n  }\n  if (Util::Base::GetAccurateOSVersion() >= WINDOWS_7) {\n    strID = _T(\"id_checkbox_easymenu\");\n    PELEMENT;\n    if (pEle) {\n      if (((CCheckBoxCtl*)pEle)->GetCheck()) {\n        CreateShortCut(app_path.c_str(), TASKBAR);\n      }\n    }\n  }\n  //start memu\n  CreateShortCut(app_path.c_str(), STARTMENU);\n  instep_ = INSTALLED;\n\n  if (CGlobal::openurl_.length() > 0) {\n    ShellExecuteA(NULL, \"open\", CGlobal::openurl_.c_str(), NULL, NULL, SW_SHOWNORMAL);\n  }\n\n}\n\nbool CUIMainWindowEx::GetJsonTokenByDownLoadUrl(\n    const std::string &res, std::map<std::string, std::string> &map_token) {\n\n  if (res.length() == 0 || res[0] == 0)\n    return false;\n\n  Json::Features features = Json::Features::strictMode();\n  Json::Reader reader(features);\n  Json::Value root;\n  bool parsingSuccessful = false;\n\n  parsingSuccessful = reader.parse(res, root, true);\n\n  if (parsingSuccessful && root.isObject()) {\n    Json::Value::Members keys = root.getMemberNames();\n    Json::Value::Members::iterator it = keys.begin();\n    std::string strItem;\n    for (; it != keys.end(); ++it) {\n      Json::Value valDefault(\"\");\n      std::string &strKey = *it;\n      Json::Value item = root.get(strKey, valDefault);\n\n      strItem = \"downloadUrl\";\n\n      if (strKey == strItem) {\n        if (item.isString()) {\n          map_token.insert(make_pair(strItem, item.asString()));\n        }\n        continue;\n      }\n    }\n    return true;\n  }\n  return false;\n}\n"
  },
  {
    "path": "src/UI/UIMainWindowEx.h",
    "content": "#pragma once\n\n#include \"util/def.h\"\n#include \"../DirectUI/DUITransWindowEx.h\"\n#include \"../DownLoader/DownloadDelegate.h\"\n#include \"../DownLoader/fetcherurl.h\"\n#include \"../DownLoader/fetchfile.h\"\n#include \"../Event/WaitableEvent.h\"\n#include \"../base/MessageLoop.h\"\n#include \"../base/MessagePumpWin.h\"\n#include \"../base/macros.h\"\n#include \"../base/notification_observer.h\"\n#include \"../base/notification_registrar.h\"\n#include \"FrameShowState.h\"\n\nclass CUIMainWindowEx : public CTransWindowEx<CUIMainWindowEx>,\n                         public base::RefCountedThreadSafe<CUIMainWindowEx>,\n                         public FetchURLDelegate,\n                         public FetchFileDelegate {\npublic:\n  enum InstallStep {\n    BEFOREDOWN = 0,\n    DOWNLOADING,\n    INSTALLING,\n    INSTALLED,\n  };\n\n  enum ShortCutType {\n    SHORTCUTBEGIN = 0,\n    DESK,\n    STARTMENU,\n    TASKBAR,\n  };\n\n  enum UserInstallType {\n    DEFAULT = 0,\n    SELECT,\n  };\n\n  enum DownLoadWay {\n    UNKNOW = 0,\n    SINGLE,\n    MULTI,\n  };\n\n  enum DownLoadFail {\n    NO_SPACE = 0,\n    CONNECT_ERROR,\n  };\n\n  BEGIN_MSG_MAP(CUIMainWindowEx)\n  MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)\n  CHAIN_MSG_MAP(CTransWindowEx<CUIMainWindowEx>)\n  MESSAGE_HANDLER(WM_TASKBARBUTTONCREATED, OnTaskBarCreated)\n  END_MSG_MAP()\n\n  CUIMainWindowEx();\n  virtual ~CUIMainWindowEx();\n\n  LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);\n  virtual LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                              BOOL &bHandled) override;\n  virtual LRESULT OnPathIllCharacter(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                     BOOL &bHandled) override;\n  LRESULT OnTaskBarCreated(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                           BOOL &bHandled);\n\n  HWND CreateWnd(HWND hParent, const WCHAR* wstr);\n  void DestroyWnd();\n  void RestoreWindow();\n\n  virtual void OnLoad() override;\n  virtual void OnLoaded() override;\n  virtual void OnExit() override {\n    _elementManager.Dispose();\n    DestroyWnd();\n    ::PostQuitMessage(0);\n  }\n\n  virtual void IsWindowShowed() override;\n\n  virtual void StartShake() override;\n\n  virtual void Shaked() override;\n\n  virtual void DrawBorder(CDCHandle dc) override;\n\n  virtual void FetchURLComplete(std::string res) override;\n\n  virtual void FetchFileComplete(bool status, DownCompleteInfo &rest) override;\n\n  virtual void FetchFileProgress(double cur) override;\n\nprivate:\n  static void DeletePack(const std::wstring& str_path);\n\n  void OnMin();\n  void OnClose();\n  void OnInstall();\n  void OnInstallSelected();\n  void OnAgreement();\n  void OnCheck();\n  void OpenInstallDir();\n  void OnSelected();\n  void OnBackMain();\n  void OnUseNow();\n  void OnInstallComplete();\n\n  void CreateShortCut(LPCTSTR strPath, const ShortCutType Stype = DESK);\n  void SetProgressTaskBar(DWORD now, DWORD total);\n  void Rotational();\n  void Ready2DownloadZip();\n  void ClearDownloads(const std::wstring str_path);\n  void FileInit();\n  void QueryDownLoadUrl();\n  void DoInstall();\n  void InstallIng();\n  void CheckIFTureWillDownLoad();\n  void DownLoadingAUserQuit();\n  void CombineRealInstallPath();\n  void ForceCreateInstallPath(std::wstring path);\n  bool CheckCanInstall();\n  void RetryDownLoadAgain();\n  bool GetPathEditError();\n  void DownLoadingFileUrl();\n  void UnZipComplete(BOOL res);\n  bool GetJsonTokenByDownLoadUrl(const std::string &res,\n                                 std::map<std::string, std::string> &map_token);\n\n  CFetchUrl urldownloader_;\n  CFetchFile filedownloader_;\n\n  InstallStep instep_;\n  UserInstallType installtype_;\n  DownLoadWay downloadway_;\n  ShowState showstate_;\n\n  DWORD time_download_;\n  DWORD time_install_;\n\n  bool b_user_quit_;\n  bool window_showing_;\n  bool is_pack_complete_;\n  double f_down_process_;\n\n};\n"
  },
  {
    "path": "src/UI/UtilityWindow.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"UtilityWindow.h\"\n\nCUtilityWindow::CUtilityWindow() {}\n\nCUtilityWindow::~CUtilityWindow() {}\n\nCUtilityWindow& CUtilityWindow::GetInstance() {\n  static CUtilityWindow* pThis = new CUtilityWindow();\n  return *pThis;\n}\n\nBOOL CUtilityWindow::Initialize() {\n  CGDIResource::GetInstance().Initialize(_T(\"\"));\n\n  RECT rcPos = {0, 0, 1, 1};\n\n  HWND hwnd = NULL;\n\n  hwnd = Create(HWND_MESSAGE, rcPos, CGlobal::szGlobalString_, WS_POPUP);\n\n  if (!hwnd)\n    return FALSE;\n\n  SetWindowLongPtr(GWLP_USERDATA, CGlobal::UitlWndPrivacyCode_);\n  return TRUE;\n}\n\nvoid CUtilityWindow::UnInitialize() {\n  DestroyWindow();\n\n  pUIMainWindow_ = NULL;\n\n  CGDIResource::GetInstance().Dispose();\n\n  CGDIResource::GetInstance().UnInitialize();\n}\n\nLRESULT CUtilityWindow::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/,\n                                 LPARAM /*lParam*/, BOOL & /*bHandled*/) {\n\n  global.hUitlWnd_ = m_hWnd;\n  pUIMainWindow_ = new CUIMainWindowEx();\n\n  if (NULL == pUIMainWindow_.get()) {\n    return -1;\n  }\n  std::wstring strXMLSource;\n  switch (global.lanId_) {\n  case 0x804: {\n    strXMLSource = L\"UIMAINWINDOW\";\n  } break;\n  default:\n    strXMLSource = L\"ENGUIMAINWINDOW\";\n  }\n\n  if (!pUIMainWindow_->CreateWnd(NULL, strXMLSource.c_str())) {\n    ATLTRACE(_T(\"Main window creation failed!\\n\"));\n    return -1;\n  }\n  return 0;\n}\n\nLRESULT CUtilityWindow::OnDelGdi(UINT uMsg, WPARAM wParam, LPARAM lParam,\n                                  BOOL &bHandled) {\n  HWND hwnd = (HWND)lParam;\n  if (::IsWindow(hwnd)) {\n    ::DestroyWindow(hwnd);\n  }\n  return 0;\n}\n\nLRESULT CUtilityWindow::OnRestore(UINT /*uMsg*/, WPARAM /*wParam*/,\n                                  LPARAM /*lParam*/, BOOL & /*bHandled*/) {\n  pUIMainWindow_->RestoreWindow();\n  return 0;\n}\n"
  },
  {
    "path": "src/UI/UtilityWindow.h",
    "content": "#pragma once\n\n#include <Mmsystem.h>\n#include <strsafe.h>\n#include \"util/def.h\"\n#include \"../Util/UtilApi.h\"\n#include \"../base/ref_counted.h\"\n#include \"../Global.h\"\n#include \"UIMainWindowEx.h\"\n\nclass CUtilityWindow : public CWindowImpl<CUtilityWindow> {\npublic:\n  DECLARE_WND_CLASS(CGlobal::szUtilityClassName_)\n  CUtilityWindow();\n  virtual ~CUtilityWindow();\n  BEGIN_MSG_MAP(CUtilityWindow)\n  MESSAGE_HANDLER(WM_CREATE, OnCreate)\n  MESSAGE_HANDLER(WM_DEL_GDI_OBJ, OnDelGdi)\n  MESSAGE_HANDLER(WM_IS_EXIST, OnRestore)\n  END_MSG_MAP()\n\n  static CUtilityWindow &GetInstance();\n  BOOL Initialize();\n  void UnInitialize();\n\nprivate:\n  LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/,\n                   BOOL & /*bHandled*/);\n  LRESULT OnDelGdi(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);\n  LRESULT OnRestore(UINT, WPARAM, LPARAM, BOOL &);\n\n  scoped_refptr<CUIMainWindowEx> pUIMainWindow_;\n};\n"
  },
  {
    "path": "src/Util/UtilApi.cpp",
    "content": "#include \"stdafx.h\"\r\n#include <Tlhelp32.h>\r\n#include <shlobj.h>\r\n#include <util/md5.h>\r\n#include <fstream>\r\n#include <mmsystem.h>\r\n#include \"util/base.h\"\r\n#include \"util/util_tools.h\"\r\n#include \"UtilApi.h\"\r\n\r\n#pragma comment(lib, \"winmm.lib\")\r\n\r\nnamespace Util {\r\nnamespace Tools {\r\nint GetTextWidth(HWND hWnd, LPCTSTR lpszText, HFONT hFont) {\r\n  CPaintDC dc(hWnd);\r\n  HFONT hOldFont = dc.SelectFont(hFont);\r\n  ::SetBkMode(dc.m_hDC, TRANSPARENT);\r\n  CSize szText;\r\n  ::GetTextExtentPoint32(dc.m_hDC, lpszText, lstrlen(lpszText), &szText);\r\n  dc.SelectFont(hOldFont);\r\n\r\n  return szText.cx;\r\n}\r\n\r\nint GetStringMd5(LPCTSTR lpSrc, TCHAR *lpDest, DWORD dwSize) {\r\n  char *pBuf = new char[MAX_PATH];\r\n  memset(pBuf, 0, MAX_PATH * sizeof(char));\r\n\r\n  USES_CONVERSION;\r\n\r\n  StringCchCopyA(pBuf, MAX_PATH, T2A(lpSrc));\r\n  MD5 md5((BYTE *)pBuf, strlen(pBuf));\r\n  string strMd5 = md5.toString();\r\n  StringCchCopyA(pBuf, MAX_PATH, strMd5.c_str());\r\n  StringCchCopy(lpDest, dwSize, A2T(pBuf));\r\n  delete[] pBuf;\r\n  return strMd5.size();\r\n}\r\n\r\nint GetStringMd5A(const char *lpSrc, char *lpDest, DWORD dwSize) {\r\n  char *pBuf = new char[MAX_PATH];\r\n  memset(pBuf, 0, MAX_PATH * sizeof(char));\r\n  StringCchCopyA(pBuf, MAX_PATH, (lpSrc));\r\n  MD5 md5((BYTE *)pBuf, strlen(pBuf));\r\n  string strMd5 = md5.toString();\r\n  StringCchCopyA(pBuf, MAX_PATH, strMd5.c_str());\r\n  StringCchCopyA(lpDest, dwSize, (pBuf));\r\n  delete[] pBuf;\r\n  return strMd5.size();\r\n}\r\n\r\nBOOL IsWin7() {\r\n  return Util::Base::GetAccurateOSVersion() >= WINDOWS_VISTA_NO_SP ? TRUE\r\n    : FALSE;\r\n}\r\n\r\n\r\n} // namespace Tools\r\n\r\n} // namespace Util\r\n"
  },
  {
    "path": "src/Util/UtilApi.h",
    "content": "#pragma once\r\n\r\nnamespace Util {\r\nnamespace Tools {\r\nint GetTextWidth(HWND hWnd, LPCTSTR lpszText, HFONT hFont);\r\n\r\nint GetStringMd5(LPCTSTR lpSrc, TCHAR *lpDest, DWORD dwSize);\r\n\r\nint GetStringMd5A(const char *lpSrc, char *lpDest, DWORD dwSize);\r\n\r\nBOOL IsWin7();\r\n\r\n} // namespace Tools\r\n\r\n} // namespace Util\r\n"
  },
  {
    "path": "src/base/FastDelegate.h",
    "content": "//                        FastDelegate.h\n//    Efficient delegates in C++ that generate only two lines of asm code!\n//  Documentation is found at http://www.codeproject.com/cpp/FastDelegate.asp\n//\n//                        - Don Clugston, Mar 2004.\n//        Major contributions were made by Jody Hagins.\n// History:\n// 24-Apr-04 1.0  * Submitted to CodeProject.\n// 28-Apr-04 1.1  * Prevent most unsafe uses of evil static function hack.\n//                  * Improved syntax for horrible_cast (thanks Paul Bludov).\n//                  * Tested on Metrowerks MWCC and Intel ICL (IA32)\n//                  * Compiled, but not run, on Comeau C++ and Intel Itanium\n//                  ICL.\n//    27-Jun-04 1.2 * Now works on Borland C++ Builder 5.5\n//                  * Now works on /clr \"managed C++\" code on VC7, VC7.1\n//                  * Comeau C++ now compiles without warnings.\n//                  * Prevent the virtual inheritance case from being used on\n//                      VC6 and earlier, which generate incorrect code.\n//                  * Improved warning and error messages. Non-standard hacks\n//                     now have compile-time checks to make them safer.\n//                  * implicit_cast used instead of static_cast in many cases.\n//                  * If calling a const member function, a const class pointer\n//                  can be used.\n//                  * MakeDelegate() global helper function added to simplify\n//                  pass-by-value.\n//                  * Added fastdelegate.clear()\n// 16-Jul-04 1.2.1* Workaround for gcc bug (const member function pointers in\n// templates) 30-Oct-04 1.3  * Support for (non-void) return values.\n//                  * No more workarounds in client code!\n//                     MSVC and Intel now use a clever hack invented by John\n//                     Dlugosz:\n//                     - The FASTDELEGATEDECLARE workaround is no longer\n//                     necessary.\n//                     - No more warning messages for VC6\n//                  * Less use of macros. Error messages should be more\n//                  comprehensible.\n//                  * Added include guards\n//                  * Added FastDelegate::empty() to test if invocation is safe\n//                  (Thanks Neville Franks).\n//                  * Now tested on VS 2005 Express Beta, PGI C++\n// 24-Dec-04 1.4  * Added DelegateMemento, to allow collections of disparate\n// delegates.\n//                * <,>,<=,>= comparison operators to allow storage in ordered\n//                containers.\n//                  * Substantial reduction of code size, especially the\n//                  'Closure' class.\n//                  * Standardised all the compiler-specific workarounds.\n//                * MFP conversion now works for CodePlay (but not yet supported\n//                in the full code).\n//                * Now compiles without warnings on _any_ supported compiler,\n//                including BCC 5.5.1\n//                  * New syntax: FastDelegate< int (char *, double) >.\n// 14-Feb-05 1.4.1* Now treats =0 as equivalent to .clear(), ==0 as equivalent\n// to .empty(). (Thanks elfric).\n//                  * Now tested on Intel ICL for AMD64, VS2005 Beta for AMD64\n//                  and Itanium.\n// 30-Mar-05 1.5  * Safebool idiom: \"if (dg)\" is now equivalent to \"if\n// (!dg.empty())\"\n//                  * Fully supported by CodePlay VectorC\n//                * Bugfix for Metrowerks: empty() was buggy because a valid MFP\n//                can be 0 on MWCC!\n//                * More optimal assignment,== and != operators for static\n//                function pointers.\n#pragma once\n\n#include <memory.h> // to allow <,> comparisons\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Configuration options\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Uncomment the following #define for optimally-sized delegates.\n// In this case, the generated asm code is almost identical to the code you'd\n// get if the compiler had native support for delegates. It will not work on\n// systems where sizeof(dataptr) < sizeof(codeptr). Thus, it will not work for\n// DOS compilers using the medium model. It will also probably fail on some DSP\n// systems.\n#define FASTDELEGATE_USESTATICFUNCTIONHACK\n\n// Uncomment the next line to allow function declarator syntax.\n// It is automatically enabled for those compilers where it is known to work.\n// #define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Compiler identification for workarounds\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Compiler identification. It's not easy to identify Visual C++ because\n// many vendors fraudulently define Microsoft's identifiers.\n#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__VECTOR_C) &&       \\\n    !defined(__ICL) && !defined(__BORLANDC__)\n#define FASTDLGT_ISMSVC\n\n#if (_MSC_VER < 1300) // Many workarounds are required for VC6.\n#define FASTDLGT_VC6\n#pragma warning(disable : 4786) // disable this ridiculous warning\n#endif\n\n#endif\n\n// Does the compiler uses Microsoft's member function pointer structure?\n// If so, it needs special treatment.\n// Metrowerks CodeWarrior, Intel, and CodePlay fraudulently define Microsoft's\n// identifier, _MSC_VER. We need to filter Metrowerks out.\n#if defined(_MSC_VER) && !defined(__MWERKS__)\n#define FASTDLGT_MICROSOFT_MFP\n\n#if !defined(__VECTOR_C)\n// CodePlay doesn't have the __single/multi/virtual_inheritance keywords\n#define FASTDLGT_HASINHERITANCE_KEYWORDS\n#endif\n#endif\n\n// Does it allow function declarator syntax? The following compilers are known\n// to work:\n#if defined(FASTDLGT_ISMSVC) && (_MSC_VER >= 1310) // VC 7.1\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n// Gcc(2.95+), and versions of Digital Mars, Intel and Comeau in common use.\n#if defined(__DMC__) || defined(__GNUC__) || defined(__ICL) || defined(__COMO__)\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n// It works on Metrowerks MWCC 3.2.2. From boost.Config it should work on\n// earlier ones too.\n#if defined(__MWERKS__)\n#define FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n#endif\n\n#ifdef __GNUC__ // Workaround GCC bug #8271\n// At present, GCC doesn't recognize constness of MFPs in templates\n#define FASTDELEGATE_GCC_BUG_8271\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n//                        General tricks used in this code\n//\n// (a) Error messages are generated by typdefing an array of negative size to\n//     generate compile-time errors.\n// (b) Warning messages on MSVC are generated by declaring unused variables, and\n//        enabling the \"variable XXX is never used\" warning.\n// (c) Unions are used in a few compiler-specific cases to perform illegal\n// casts. (d) For Microsoft and Intel, when adjusting the 'this' pointer, it's\n// cast to\n//     (char *) first to ensure that the correct number of *bytes* are added.\n//\n////////////////////////////////////////////////////////////////////////////////\n//                        Helper templates\n//\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace fastdelegate {\nnamespace detail { // we'll hide the implementation details in a nested\n                   // namespace.\n\n//        implicit_cast< >\n// I believe this was originally going to be in the C++ standard but\n// was left out by accident. It's even milder than static_cast.\n// I use it instead of static_cast<> to emphasize that I'm not doing\n// anything nasty.\n// Usage is identical to static_cast<>\ntemplate <class OutputClass, class InputClass>\ninline OutputClass implicit_cast(InputClass input) {\n  return input;\n}\n\n//        horrible_cast< >\n// This is truly evil. It completely subverts C++'s type system, allowing you\n// to cast from any class to any other class. Technically, using a union\n// to perform the cast is undefined behaviour (even in C). But we can see if\n// it is OK by checking that the union is the same size as each of its members.\n// horrible_cast<> should only be used for compiler-specific workarounds.\n// Usage is identical to reinterpret_cast<>.\n\n// This union is declared outside the horrible_cast because BCC 5.5.1\n// can't inline a function with a nested class, and gives a warning.\ntemplate <class OutputClass, class InputClass> union horrible_union {\n  OutputClass out;\n  InputClass in;\n};\n\ntemplate <class OutputClass, class InputClass>\ninline OutputClass horrible_cast(const InputClass input) {\n  horrible_union<OutputClass, InputClass> u;\n  // Cause a compile-time error if in, out and u are not the same size.\n  // If the compile fails here, it means the compiler has peculiar\n  // unions which would prevent the cast from working.\n  typedef int ERROR_CantUseHorrible_cast[sizeof(InputClass) == sizeof(u) &&\n                                                 sizeof(InputClass) ==\n                                                     sizeof(OutputClass)\n                                             ? 1\n                                             : -1];\n  u.in = input;\n  return u.out;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Workarounds\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Backwards compatibility: This macro used to be necessary in the virtual\n// inheritance case for Intel and Microsoft. Now it just forward-declares the\n// class.\n#define FASTDELEGATEDECLARE(CLASSNAME) class CLASSNAME;\n\n// Prevent use of the static function hack with the DOS medium model.\n#ifdef __MEDIUM__\n#undef FASTDELEGATE_USESTATICFUNCTIONHACK\n#endif\n\n//            DefaultVoid - a workaround for 'void' templates in VC6.\n//\n//  (1) VC6 and earlier do not allow 'void' as a default template argument.\n//  (2) They also doesn't allow you to return 'void' from a function.\n//\n// Workaround for (1): Declare a dummy type 'DefaultVoid' which we use\n//   when we'd like to use 'void'. We convert it into 'void' and back\n//   using the templates DefaultVoidToVoid<> and VoidToDefaultVoid<>.\n// Workaround for (2): On VC6, the code for calling a void function is\n//   identical to the code for calling a non-void function in which the\n//   return value is never used, provided the return value is returned\n//   in the EAX register, rather than on the stack.\n//   This is true for most fundamental types such as int, enum, void *.\n//   Const void * is the safest option since it doesn't participate\n//   in any automatic conversions. But on a 16-bit compiler it might\n//   cause extra code to be generated, so we disable it for all compilers\n//   except for VC6 (and VC5).\n#ifdef FASTDLGT_VC6\n// VC6 workaround\ntypedef const void *DefaultVoid;\n#else\n// On any other compiler, just use a normal void.\ntypedef void DefaultVoid;\n#endif\n\n// Translate from 'DefaultVoid' to 'void'.\n// Everything else is unchanged\ntemplate <class T> struct DefaultVoidToVoid {\n  typedef T type;\n};\n\ntemplate <> struct DefaultVoidToVoid<DefaultVoid> {\n  typedef void type;\n};\n\n// Translate from 'void' into 'DefaultVoid'\n// Everything else is unchanged\ntemplate <class T> struct VoidToDefaultVoid {\n  typedef T type;\n};\n\ntemplate <> struct VoidToDefaultVoid<void> {\n  typedef DefaultVoid type;\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 1:\n//\n//        Conversion of member function pointer to a standard form\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// GenericClass is a fake class, ONLY used to provide a type.\n// It is vitally important that it is never defined, so that the compiler\n// doesn't think it can optimize the invocation. For example, Borland generates\n// simpler code if it knows the class only uses single inheritance.\n\n// Compilers using Microsoft's structure need to be treated as a special case.\n#ifdef FASTDLGT_MICROSOFT_MFP\n\n#ifdef FASTDLGT_HASINHERITANCE_KEYWORDS\n// For Microsoft and Intel, we want to ensure that it's the most efficient type\n// of MFP (4 bytes), even when the /vmg option is used. Declaring an empty class\n// would give 16 byte pointers in this case....\nclass __single_inheritance GenericClass;\n#endif\n// ...but for Codeplay, an empty class *always* gives 4 byte pointers.\n// If compiled with the /clr option (\"managed C++\"), the JIT compiler thinks\n// it needs to load GenericClass before it can call any of its functions,\n// (compiles OK but crashes at runtime!), so we need to declare an\n// empty class to make it happy.\n// Codeplay and VC4 can't cope with the unknown_inheritance case either.\nclass GenericClass {};\n#else\nclass GenericClass;\n#endif\n\n// The size of a single inheritance member function pointer.\nconst int SINGLE_MEMFUNCPTR_SIZE = sizeof(void(GenericClass::*)());\n\n//                        SimplifyMemFunc< >::Convert()\n//\n//    A template function that converts an arbitrary member function pointer\n//    into the simplest possible form of member function pointer, using a\n//    supplied 'this' pointer.\n//  According to the standard, this can be done legally with reinterpret_cast<>.\n//    For (non-standard) compilers which use member function pointers which vary\n//    in size\n//  depending on the class, we need to use    knowledge of the internal\n//  structure of a member function pointer, as used by the compiler. Template\n//  specialization is used to distinguish between the sizes. Because some\n//  compilers don't support partial\n//    template specialisation, I use full specialisation of a wrapper struct.\n\n// general case -- don't know how to convert it. Force a compile failure\ntemplate <int N> struct SimplifyMemFunc {\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n    // Unsupported member function type -- force a compile failure.\n    // (it's illegal to have a array with negative size).\n    typedef char\n        ERROR_Unsupported_member_function_pointer_on_this_compiler[N - 100];\n    return 0;\n  }\n};\n\n// For compilers where all member func ptrs are the same size, everything goes\n// here. For non-standard compilers, only single_inheritance classes go here.\ntemplate <> struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE> {\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n#if defined __DMC__\n    // Digital Mars doesn't allow you to cast between abitrary PMF's,\n    // even though the standard says you can. The 32-bit compiler lets you\n    // static_cast through an int, but the DOS compiler doesn't.\n    bound_func = horrible_cast<GenericMemFuncType>(function_to_bind);\n#else\n    bound_func = reinterpret_cast<GenericMemFuncType>(function_to_bind);\n#endif\n    return reinterpret_cast<GenericClass *>(pthis);\n  }\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 1b:\n//\n//                    Workarounds for Microsoft and Intel\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Compilers with member function pointers which violate the standard (MSVC,\n// Intel, Codeplay), need to be treated as a special case.\n#ifdef FASTDLGT_MICROSOFT_MFP\n\n// We use unions to perform horrible_casts. I would like to use #pragma\n// pack(push, 1) at the start of each function for extra safety, but VC6 seems\n// to ICE intermittently if you do this inside a template.\n\n// __multiple_inheritance classes go here\n// Nasty hack for Microsoft and Intel (IA32 and Itanium)\ntemplate <> struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + sizeof(int)> {\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n    // We need to use a horrible_cast to do this conversion.\n    // In MSVC, a multiple inheritance member pointer is internally defined as:\n    union {\n      XFuncType func;\n      struct {\n        GenericMemFuncType funcaddress; // points to the actual member function\n        int delta; // #BYTES to be added to the 'this' pointer\n      } s;\n    } u;\n    // Check that the horrible_cast will work\n    typedef int ERROR_CantUsehorrible_cast\n        [sizeof(function_to_bind) == sizeof(u.s) ? 1 : -1];\n    u.func = function_to_bind;\n    bound_func = u.s.funcaddress;\n    return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) +\n                                            u.s.delta);\n  }\n};\n\n// virtual inheritance is a real nuisance. It's inefficient and complicated.\n// On MSVC and Intel, there isn't enough information in the pointer itself to\n// enable conversion to a closure pointer. Earlier versions of this code didn't\n// work for all cases, and generated a compile-time error instead.\n// But a very clever hack invented by John M. Dlugosz solves this problem.\n// My code is somewhat different to his: I have no asm code, and I make no\n// assumptions about the calling convention that is used.\n\n// In VC++ and ICL, a virtual_inheritance member pointer\n// is internally defined as:\nstruct MicrosoftVirtualMFP {\n  void (GenericClass::*codeptr)(); // points to the actual member function\n  int delta;                       // #bytes to be added to the 'this' pointer\n  int vtable_index;                // or 0 if no virtual inheritance\n};\n// The CRUCIAL feature of Microsoft/Intel MFPs which we exploit is that the\n// m_codeptr member is *always* called, regardless of the values of the other\n// members. (This is *not* true for other compilers, eg GCC, which obtain the\n// function address from the vtable if a virtual function is being called).\n// Dlugosz's trick is to make the codeptr point to a probe function which\n// returns the 'this' pointer that was used.\n\n// Define a generic class that uses virtual inheritance.\n// It has a trival member function that returns the value of the 'this' pointer.\nstruct GenericVirtualClass : virtual public GenericClass {\n  typedef GenericVirtualClass *(GenericVirtualClass::*ProbePtrType)();\n  GenericVirtualClass *GetThis() { return this; }\n};\n\n// __virtual_inheritance classes go here\ntemplate <> struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 2 * sizeof(int)> {\n\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n    union {\n      XFuncType func;\n      GenericClass *(X::*ProbeFunc)();\n      MicrosoftVirtualMFP s;\n    } u;\n    u.func = function_to_bind;\n    bound_func = reinterpret_cast<GenericMemFuncType>(u.s.codeptr);\n    union {\n      GenericVirtualClass::ProbePtrType virtfunc;\n      MicrosoftVirtualMFP s;\n    } u2;\n    // Check that the horrible_cast<>s will work\n    typedef int\n        ERROR_CantUsehorrible_cast[sizeof(function_to_bind) == sizeof(u.s) &&\n                                           sizeof(function_to_bind) ==\n                                               sizeof(u.ProbeFunc) &&\n                                           sizeof(u2.virtfunc) == sizeof(u2.s)\n                                       ? 1\n                                       : -1];\n    // Unfortunately, taking the address of a MF prevents it from being inlined,\n    // so this next line can't be completely optimised away by the compiler.\n    u2.virtfunc = &GenericVirtualClass::GetThis;\n    u.s.codeptr = u2.s.codeptr;\n    return (pthis->*u.ProbeFunc)();\n  }\n};\n\n#if (_MSC_VER < 1300)\n\n// Nasty hack for Microsoft Visual C++ 6.0\n// unknown_inheritance classes go here\n// There is a compiler bug in MSVC6 which generates incorrect code in this\n// case!!\ntemplate <> struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3 * sizeof(int)> {\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n    // There is an apalling but obscure compiler bug in MSVC6 and earlier:\n    // vtable_index and 'vtordisp' are always set to 0 in the\n    // unknown_inheritance case!\n    // This means that an incorrect function could be called!!!\n    // Compiling with the /vmg option leads to potentially incorrect code.\n    // This is probably the reason that the IDE has a user interface for\n    // specifying the /vmg option, but it is disabled -  you can only specify\n    // /vmg on the command line. In VC1.5 and earlier, the compiler would ICE if\n    // it ever encountered this situation. It is OK to use the /vmg option if\n    // /vmm or /vms is specified.\n\n    // Fortunately, the wrong function is only called in very obscure cases.\n    // It only occurs when a derived class overrides a virtual function declared\n    // in a virtual base class, and the member function\n    // points to the *Derived* version of that function. The problem can be\n    // completely averted in 100% of cases by using the *Base class* for the\n    // member fpointer. Ie, if you use the base class as an interface, you'll\n    // stay out of trouble.\n    // Occasionally, you might want to point directly to a derived class\n    // function that isn't an override of a base class. In this case, both\n    // vtable_index and 'vtordisp' are zero, but a virtual_inheritance pointer\n    // will be generated. We can generate correct code in this case. To prevent\n    // an incorrect call from ever being made, on MSVC6 we generate a warning,\n    // and call a function to make the program crash instantly.\n    typedef char ERROR_VC6CompilerBug[-100];\n    return 0;\n  }\n};\n\n#else\n\n// Nasty hack for Microsoft and Intel (IA32 and Itanium)\n// unknown_inheritance classes go here\n// This is probably the ugliest bit of code I've ever written. Look at the\n// casts! There is a compiler bug in MSVC6 which prevents it from using this\n// code.\ntemplate <> struct SimplifyMemFunc<SINGLE_MEMFUNCPTR_SIZE + 3 * sizeof(int)> {\n  template <class X, class XFuncType, class GenericMemFuncType>\n  inline static GenericClass *Convert(X *pthis, XFuncType function_to_bind,\n                                      GenericMemFuncType &bound_func) {\n    // The member function pointer is 16 bytes long. We can't use a normal cast,\n    // but we can use a union to do the conversion.\n    union {\n      XFuncType func;\n      // In VC++ and ICL, an unknown_inheritance member pointer\n      // is internally defined as:\n      struct {\n        GenericMemFuncType\n            m_funcaddress; // points to the actual member function\n        int delta;         // #bytes to be added to the 'this' pointer\n        int vtordisp;      // #bytes to add to 'this' to find the vtable\n        int vtable_index;  // or 0 if no virtual inheritance\n      } s;\n    } u;\n    // Check that the horrible_cast will work\n    typedef int\n        ERROR_CantUsehorrible_cast[sizeof(XFuncType) == sizeof(u.s) ? 1 : -1];\n    u.func = function_to_bind;\n    bound_func = u.s.funcaddress;\n    int virtual_delta = 0;\n    if (u.s.vtable_index) { // Virtual inheritance is used\n      // First, get to the vtable.\n      // It is 'vtordisp' bytes from the start of the class.\n      const int *vtable = *reinterpret_cast<const int *const *>(\n          reinterpret_cast<const char *>(pthis) + u.s.vtordisp);\n\n      // 'vtable_index' tells us where in the table we should be looking.\n      virtual_delta =\n          u.s.vtordisp +\n          *reinterpret_cast<const int *>(\n              reinterpret_cast<const char *>(vtable) + u.s.vtable_index);\n    }\n    // The int at 'virtual_delta' gives us the amount to add to 'this'.\n    // Finally we can add the three components together. Phew!\n    return reinterpret_cast<GenericClass *>(reinterpret_cast<char *>(pthis) +\n                                            u.s.delta + virtual_delta);\n  };\n};\n#endif // MSVC 7 and greater\n\n#endif // MS/Intel hacks\n\n} // namespace detail\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 2:\n//\n//    Define the delegate storage, and cope with static functions\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// DelegateMemento -- an opaque structure which can hold an arbitary delegate.\n// It knows nothing about the calling convention or number of arguments used by\n// the function pointed to.\n// It supplies comparison operators so that it can be stored in STL collections.\n// It cannot be set to anything other than null, nor invoked directly:\n//   it must be converted to a specific delegate.\n\n// Implementation:\n// There are two possible implementations: the Safe method and the Evil method.\n//                DelegateMemento - Safe version\n//\n// This implementation is standard-compliant, but a bit tricky.\n// A static function pointer is stored inside the class.\n// Here are the valid values:\n// +-- Static pointer --+--pThis --+-- pMemFunc-+-- Meaning------+\n// |   0                |  0       |   0        | Empty          |\n// |   !=0              |(dontcare)|  Invoker   | Static function|\n// |   0                |  !=0     |  !=0*      | Method call    |\n// +--------------------+----------+------------+----------------+\n//  * For Metrowerks, this can be 0. (first virtual function in a\n//       single_inheritance class).\n// When stored stored inside a specific delegate, the 'dontcare' entries are\n// replaced with a reference to the delegate itself. This complicates the = and\n// == operators for the delegate class.\n\n//                DelegateMemento - Evil version\n//\n// For compilers where data pointers are at least as big as code pointers, it is\n// possible to store the function pointer in the this pointer, using another\n// horrible_cast. In this case the DelegateMemento implementation is simple:\n// +--pThis --+-- pMemFunc-+-- Meaning---------------------+\n// |    0     |  0         | Empty                         |\n// |  !=0     |  !=0*      | Static function or method call|\n// +----------+------------+-------------------------------+\n//  * For Metrowerks, this can be 0. (first virtual function in a\n//       single_inheritance class).\n// Note that the Sun C++ and MSVC documentation explicitly state that they\n// support static_cast between void * and function pointers.\n\nclass DelegateMemento {\nprotected:\n  // the data is protected, not private, because many\n  // compilers have problems with template friends.\n  typedef void (detail::GenericClass::*GenericMemFuncType)(); // arbitrary MFP.\n  detail::GenericClass *m_pthis;\n  GenericMemFuncType m_pFunction;\n\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n  typedef void (*GenericFuncPtr)(); // arbitrary code pointer\n  GenericFuncPtr m_pStaticFunction;\n#endif\n\npublic:\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n  DelegateMemento() : m_pthis(0), m_pFunction(0), m_pStaticFunction(0){};\n  void clear() {\n    m_pthis = 0;\n    m_pFunction = 0;\n    m_pStaticFunction = 0;\n  }\n#else\n  DelegateMemento() : m_pthis(0), m_pFunction(0){};\n  void clear() {\n    m_pthis = 0;\n    m_pFunction = 0;\n  }\n#endif\npublic:\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n  inline bool IsEqual(const DelegateMemento &x) const {\n    // We have to cope with the static function pointers as a special case\n    if (m_pFunction != x.m_pFunction)\n      return false;\n    // the static function ptrs must either both be equal, or both be 0.\n    if (m_pStaticFunction != x.m_pStaticFunction)\n      return false;\n    if (m_pStaticFunction != 0)\n      return m_pthis == x.m_pthis;\n    else\n      return true;\n  }\n#else // Evil Method\n  inline bool IsEqual(const DelegateMemento &x) const {\n    return m_pthis == x.m_pthis && m_pFunction == x.m_pFunction;\n  }\n#endif\n  // Provide a strict weak ordering for DelegateMementos.\n  inline bool IsLess(const DelegateMemento &right) const {\n    // deal with static function pointers first\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n    if (m_pStaticFunction != 0 || right.m_pStaticFunction != 0)\n      return m_pStaticFunction < right.m_pStaticFunction;\n#endif\n    if (m_pthis != right.m_pthis)\n      return m_pthis < right.m_pthis;\n    // There are no ordering operators for member function pointers,\n    // but we can fake one by comparing each byte. The resulting ordering is\n    // arbitrary (and compiler-dependent), but it permits storage in ordered STL\n    // containers.\n    return memcmp(&m_pFunction, &right.m_pFunction, sizeof(m_pFunction)) < 0;\n  }\n  // BUGFIX (Mar 2005):\n  // We can't just compare m_pFunction because on Metrowerks,\n  // m_pFunction can be zero even if the delegate is not empty!\n  inline bool operator!() const // Is it bound to anything?\n  {\n    return m_pthis == 0 && m_pFunction == 0;\n  }\n  inline bool empty() const // Is it bound to anything?\n  {\n    return m_pthis == 0 && m_pFunction == 0;\n  }\n\npublic:\n  DelegateMemento &operator=(const DelegateMemento &right) {\n    SetMementoFrom(right);\n    return *this;\n  }\n  inline bool operator<(const DelegateMemento &right) { return IsLess(right); }\n  inline bool operator>(const DelegateMemento &right) {\n    return right.IsLess(*this);\n  }\n  DelegateMemento(const DelegateMemento &right)\n      : m_pFunction(right.m_pFunction), m_pthis(right.m_pthis)\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n        ,\n        m_pStaticFunction(right.m_pStaticFunction)\n#endif\n  {\n  }\n\nprotected:\n  void SetMementoFrom(const DelegateMemento &right) {\n    m_pFunction = right.m_pFunction;\n    m_pthis = right.m_pthis;\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n    m_pStaticFunction = right.m_pStaticFunction;\n#endif\n  }\n};\n\n//                        ClosurePtr<>\n//\n// A private wrapper class that adds function signatures to DelegateMemento.\n// It's the class that does most of the actual work.\n// The signatures are specified by:\n// GenericMemFunc: must be a type of GenericClass member function pointer.\n// StaticFuncPtr:  must be a type of function pointer with the same signature\n//                 as GenericMemFunc.\n// UnvoidStaticFuncPtr: is the same as StaticFuncPtr, except on VC6\n//                 where it never returns void (returns DefaultVoid instead).\n\n// An outer class, FastDelegateN<>, handles the invoking and creates the\n// necessary typedefs.\n// This class does everything else.\n\nnamespace detail {\n\ntemplate <class GenericMemFunc, class StaticFuncPtr, class UnvoidStaticFuncPtr>\nclass ClosurePtr : public DelegateMemento {\npublic:\n  // These functions are for setting the delegate to a member function.\n\n  // Here's the clever bit: we convert an arbitrary member function into a\n  // standard form. XMemFunc should be a member function of class X, but I can't\n  // enforce that here. It needs to be enforced by the wrapper class.\n  template <class X, class XMemFunc>\n  inline void bindmemfunc(X *pthis, XMemFunc function_to_bind) {\n    m_pthis = SimplifyMemFunc<sizeof(function_to_bind)>::Convert(\n        pthis, function_to_bind, m_pFunction);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n    m_pStaticFunction = 0;\n#endif\n  }\n  // For const member functions, we only need a const class pointer.\n  // Since we know that the member function is const, it's safe to\n  // remove the const qualifier from the 'this' pointer with a const_cast.\n  // VC6 has problems if we just overload 'bindmemfunc', so we give it a\n  // different name.\n  template <class X, class XMemFunc>\n  inline void bindconstmemfunc(const X *pthis, XMemFunc function_to_bind) {\n    m_pthis = SimplifyMemFunc<sizeof(function_to_bind)>::Convert(\n        const_cast<X *>(pthis), function_to_bind, m_pFunction);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n    m_pStaticFunction = 0;\n#endif\n  }\n#ifdef FASTDELEGATE_GCC_BUG_8271 // At present, GCC doesn't recognize constness\n                                 // of MFPs in templates\n  template <class X, class XMemFunc>\n  inline void bindmemfunc(const X *pthis, XMemFunc function_to_bind) {\n    bindconstmemfunc(pthis, function_to_bind);\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n    m_pStaticFunction = 0;\n#endif\n  }\n#endif\n  // These functions are required for invoking the stored function\n  inline GenericClass *GetClosureThis() const { return m_pthis; }\n  inline GenericMemFunc GetClosureMemPtr() const {\n    return reinterpret_cast<GenericMemFunc>(m_pFunction);\n  }\n\n  // There are a few ways of dealing with static function pointers.\n  // There's a standard-compliant, but tricky method.\n  // There's also a straightforward hack, that won't work on DOS compilers using\n  // the medium memory model. It's so evil that I can't recommend it, but I've\n  // implemented it anyway because it produces very nice asm code.\n\n#if !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\n  //                ClosurePtr<> - Safe version\n  //\n  // This implementation is standard-compliant, but a bit tricky.\n  // I store the function pointer inside the class, and the delegate then\n  // points to itself. Whenever the delegate is copied, these self-references\n  // must be transformed, and this complicates the = and == operators.\npublic:\n  // The next two functions are for operator ==, =, and the copy constructor.\n  // We may need to convert the m_pthis pointers, so that\n  // they remain as self-references.\n  template <class DerivedClass>\n  inline void CopyFrom(DerivedClass *pParent, const DelegateMemento &x) {\n    SetMementoFrom(x);\n    if (m_pStaticFunction != 0) {\n      // transform self references...\n      m_pthis = reinterpret_cast<GenericClass *>(pParent);\n    }\n  }\n  // For static functions, the 'static_function_invoker' class in the parent\n  // will be called. The parent then needs to call GetStaticFunction() to find\n  // out the actual function to invoke.\n  template <class DerivedClass, class ParentInvokerSig>\n  inline void bindstaticfunc(DerivedClass *pParent,\n                             ParentInvokerSig static_function_invoker,\n                             StaticFuncPtr function_to_bind) {\n    if (function_to_bind == 0) { // cope with assignment to 0\n      m_pFunction = 0;\n    } else {\n      bindmemfunc(pParent, static_function_invoker);\n    }\n    m_pStaticFunction = reinterpret_cast<GenericFuncPtr>(function_to_bind);\n  }\n  inline UnvoidStaticFuncPtr GetStaticFunction() const {\n    return reinterpret_cast<UnvoidStaticFuncPtr>(m_pStaticFunction);\n  }\n#else\n\n  //                ClosurePtr<> - Evil version\n  //\n  // For compilers where data pointers are at least as big as code pointers, it\n  // is possible to store the function pointer in the this pointer, using\n  // another horrible_cast. Invocation isn't any faster, but it saves 4 bytes,\n  // and speeds up comparison and assignment. If C++ provided direct language\n  // support for delegates, they would produce asm code that was almost\n  // identical to this. Note that the Sun C++ and MSVC documentation explicitly\n  // state that they support static_cast between void * and function pointers.\n\n  template <class DerivedClass>\n  inline void CopyFrom(DerivedClass *pParent, const DelegateMemento &right) {\n    SetMementoFrom(right);\n  }\n  // For static functions, the 'static_function_invoker' class in the parent\n  // will be called. The parent then needs to call GetStaticFunction() to find\n  // out the actual function to invoke.\n  // ******** EVIL, EVIL CODE! *******\n  template <class DerivedClass, class ParentInvokerSig>\n  inline void bindstaticfunc(DerivedClass *pParent,\n                             ParentInvokerSig static_function_invoker,\n                             StaticFuncPtr function_to_bind) {\n    if (function_to_bind == 0) { // cope with assignment to 0\n      m_pFunction = 0;\n    } else {\n      // We'll be ignoring the 'this' pointer, but we need to make sure we pass\n      // a valid value to bindmemfunc().\n      bindmemfunc(pParent, static_function_invoker);\n    }\n\n    // WARNING! Evil hack. We store the function in the 'this' pointer!\n    // Ensure that there's a compilation failure if function pointers\n    // and data pointers have different sizes.\n    // If you get this error, you need to #undef\n    // FASTDELEGATE_USESTATICFUNCTIONHACK.\n    typedef int ERROR_CantUseEvilMethod\n        [sizeof(GenericClass *) == sizeof(function_to_bind) ? 1 : -1];\n    m_pthis = horrible_cast<GenericClass *>(function_to_bind);\n    // MSVC, SunC++ and DMC accept the following (non-standard) code:\n    //        m_pthis = static_cast<GenericClass *>(static_cast<void\n    //        *>(function_to_bind));\n    // BCC32, Comeau and DMC accept this method. MSVC7.1 needs __int64 instead\n    // of long\n    //        m_pthis = reinterpret_cast<GenericClass\n    //        *>(reinterpret_cast<long>(function_to_bind));\n  }\n  // ******** EVIL, EVIL CODE! *******\n  // This function will be called with an invalid 'this' pointer!!\n  // We're just returning the 'this' pointer, converted into\n  // a function pointer!\n  inline UnvoidStaticFuncPtr GetStaticFunction() const {\n    // Ensure that there's a compilation failure if function pointers\n    // and data pointers have different sizes.\n    // If you get this error, you need to #undef\n    // FASTDELEGATE_USESTATICFUNCTIONHACK.\n    typedef int ERROR_CantUseEvilMethod\n        [sizeof(UnvoidStaticFuncPtr) == sizeof(this) ? 1 : -1];\n    return horrible_cast<UnvoidStaticFuncPtr>(this);\n  }\n#endif // !defined(FASTDELEGATE_USESTATICFUNCTIONHACK)\n\n  // Does the closure contain this static function?\n  inline bool IsEqualToStaticFuncPtr(StaticFuncPtr funcptr) {\n    if (funcptr == 0)\n      return empty();\n    // For the Evil method, if it doesn't actually contain a static function,\n    // this will return an arbitrary value that is not equal to any valid\n    // function pointer.\n    else\n      return funcptr == reinterpret_cast<StaticFuncPtr>(GetStaticFunction());\n  }\n};\n\n} // namespace detail\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 3:\n//\n//                Wrapper classes to ensure type safety\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Once we have the member function conversion templates, it's easy to make the\n// wrapper classes. So that they will work with as many compilers as possible,\n// the classes are of the form\n//   FastDelegate3<int, char *, double>\n// They can cope with any combination of parameters. The max number of\n// parameters allowed is 8, but it is trivial to increase this limit. Note that\n// we need to treat const member functions seperately. All this class does is to\n// enforce type safety, and invoke the delegate with the correct list of\n// parameters.\n\n// Because of the weird rule about the class of derived member function\n// pointers, you sometimes need to apply a downcast to the 'this' pointer. This\n// is the reason for the use of \"implicit_cast<X*>(pthis)\" in the code below. If\n// CDerivedClass is derived from CBaseClass, but doesn't override\n// SimpleVirtualFunction, without this trick you'd need to write:\n//        MyDelegate(static_cast<CBaseClass *>(&d),\n//        &CDerivedClass::SimpleVirtualFunction);\n// but with the trick you can write\n//        MyDelegate(&d, &CDerivedClass::SimpleVirtualFunction);\n\n// RetType is the type the compiler uses in compiling the template. For VC6,\n// it cannot be void. DesiredRetType is the real type which is returned from\n// all of the functions. It can be void.\n\n// Implicit conversion to \"bool\" is achieved using the safe_bool idiom,\n// using member data pointers (MDP). This allows \"if (dg)...\" syntax\n// Because some compilers (eg codeplay) don't have a unique value for a zero\n// MDP, an extra padding member is added to the SafeBool struct.\n// Some compilers (eg VC6) won't implicitly convert from 0 to an MDP, so\n// in that case the static function constructor is not made explicit; this\n// allows \"if (dg==0) ...\" to compile.\n\n// default\ntemplate <class RetType = detail::DefaultVoid> class Function {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)();\n  typedef RetType (*UnvoidStaticFunctionPtr)();\n  typedef RetType (detail::GenericClass::*GenericMemFn)();\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef Function type;\n\n  // Construction and comparison functions\n  Function() { clear(); }\n  Function(const Function &x) { m_Closure.CopyFrom(this, x.m_Closure); }\n  void operator=(const Function &x) { m_Closure.CopyFrom(this, x.m_Closure); }\n  bool operator==(const Function &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const Function &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const Function &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const Function &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  Function(Y *pthis, DesiredRetType (X::*function_to_bind)()) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)()) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  Function(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)() const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  Function(DesiredRetType (*function_to_bind)()) { bind(function_to_bind); }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)()) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)()) {\n    m_Closure.bindstaticfunc(this, &Function::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()() const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))();\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction() const {\n    // bugfix remove p1\n    return (*(m_Closure.GetStaticFunction()))();\n  }\n};\n\n// N=0\ntemplate <class RetType = detail::DefaultVoid> class FastDelegate0 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)();\n  typedef RetType (*UnvoidStaticFunctionPtr)();\n  typedef RetType (detail::GenericClass::*GenericMemFn)();\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate0 type;\n\n  // Construction and comparison functions\n  FastDelegate0() { clear(); }\n  FastDelegate0(const FastDelegate0 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate0 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate0 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate0 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate0 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate0 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate0(Y *pthis, DesiredRetType (X::*function_to_bind)()) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)()) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate0(const Y *pthis, DesiredRetType (X::*function_to_bind)() const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)() const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate0(DesiredRetType (*function_to_bind)()) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)()) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)()) {\n    m_Closure.bindstaticfunc(this, &FastDelegate0::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()() const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))();\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction() const {\n    return (*(m_Closure.GetStaticFunction()))();\n  }\n};\n\n// N=1\ntemplate <class Param1, class RetType = detail::DefaultVoid>\nclass FastDelegate1 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate1 type;\n\n  // Construction and comparison functions\n  FastDelegate1() { clear(); }\n  FastDelegate1(const FastDelegate1 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate1 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate1 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate1 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate1 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate1 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate1(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate1(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate1(DesiredRetType (*function_to_bind)(Param1 p1)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate1::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1) const {\n    return (*(m_Closure.GetStaticFunction()))(p1);\n  }\n};\n\n// N=2\ntemplate <class Param1, class Param2, class RetType = detail::DefaultVoid>\nclass FastDelegate2 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate2 type;\n\n  // Construction and comparison functions\n  FastDelegate2() { clear(); }\n  FastDelegate2(const FastDelegate2 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate2 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate2 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate2 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate2 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate2 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate2(Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1,\n                                                                   Param2 p2)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate2(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2)\n                    const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2)\n                       const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate2(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate2::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1,\n                                                                         p2);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2);\n  }\n};\n\n// N=3\ntemplate <class Param1, class Param2, class Param3,\n          class RetType = detail::DefaultVoid>\nclass FastDelegate3 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate3 type;\n\n  // Construction and comparison functions\n  FastDelegate3() { clear(); }\n  FastDelegate3(const FastDelegate3 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate3 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate3 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate3 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate3 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate3 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate3(Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate3(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate3(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate3::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(p1, p2,\n                                                                         p3);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3);\n  }\n};\n\n// N=4\ntemplate <class Param1, class Param2, class Param3, class Param4,\n          class RetType = detail::DefaultVoid>\nclass FastDelegate4 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                              Param4 p4);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3, Param4 p4);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate4 type;\n\n  // Construction and comparison functions\n  FastDelegate4() { clear(); }\n  FastDelegate4(const FastDelegate4 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate4 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate4 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate4 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate4 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate4 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate4(Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void\n  bind(Y *pthis, DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                       Param3 p3, Param4 p4)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate4(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4)\n                    const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3, Param4 p4)\n                       const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate4(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3, Param4 p4)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3, Param4 p4)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate4::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(\n        p1, p2, p3, p4);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3,\n                               Param4 p4) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4);\n  }\n};\n\n// N=5\ntemplate <class Param1, class Param2, class Param3, class Param4, class Param5,\n          class RetType = detail::DefaultVoid>\nclass FastDelegate5 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                              Param4 p4, Param5 p5);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3, Param4 p4,\n                                                        Param5 p5);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate5 type;\n\n  // Construction and comparison functions\n  FastDelegate5() { clear(); }\n  FastDelegate5(const FastDelegate5 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate5 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate5 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate5 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate5 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate5 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate5(Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3, Param4 p4,\n                                                         Param5 p5)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate5(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3, Param4 p4,\n                                                         Param5 p5) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate5(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3, Param4 p4,\n                                                   Param5 p5)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3, Param4 p4,\n                                                    Param5 p5)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate5::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                     Param5 p5) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(\n        p1, p2, p3, p4, p5);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                               Param5 p5) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5);\n  }\n};\n\n// N=6\ntemplate <class Param1, class Param2, class Param3, class Param4, class Param5,\n          class Param6, class RetType = detail::DefaultVoid>\nclass FastDelegate6 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                              Param4 p4, Param5 p5, Param6 p6);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5, Param6 p6);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3, Param4 p4,\n                                                        Param5 p5, Param6 p6);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate6 type;\n\n  // Construction and comparison functions\n  FastDelegate6() { clear(); }\n  FastDelegate6(const FastDelegate6 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate6 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate6 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate6 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate6 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate6 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate6(Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void\n  bind(Y *pthis,\n       DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5, Param6 p6)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate6(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6)\n                    const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3, Param4 p4,\n                                                         Param5 p5, Param6 p6)\n                       const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate6(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3, Param4 p4,\n                                                   Param5 p5, Param6 p6)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3, Param4 p4,\n                                                    Param5 p5, Param6 p6)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate6::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5,\n                     Param6 p6) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(\n        p1, p2, p3, p4, p5, p6);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                               Param5 p5, Param6 p6) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6);\n  }\n};\n\n// N=7\ntemplate <class Param1, class Param2, class Param3, class Param4, class Param5,\n          class Param6, class Param7, class RetType = detail::DefaultVoid>\nclass FastDelegate7 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                              Param4 p4, Param5 p5, Param6 p6,\n                                              Param7 p7);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5, Param6 p6,\n                                             Param7 p7);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3, Param4 p4,\n                                                        Param5 p5, Param6 p6,\n                                                        Param7 p7);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate7 type;\n\n  // Construction and comparison functions\n  FastDelegate7() { clear(); }\n  FastDelegate7(const FastDelegate7 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate7 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate7 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate7 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate7 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate7 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate7(Y *pthis, DesiredRetType (X::*function_to_bind)(\n                              Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                              Param5 p5, Param6 p6, Param7 p7)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(\n                                 Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                 Param5 p5, Param6 p6, Param7 p7)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate7(const Y *pthis, DesiredRetType (X::*function_to_bind)(\n                                    Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                    Param5 p5, Param6 p6, Param7 p7) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(const Y *pthis,\n                   DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                         Param3 p3, Param4 p4,\n                                                         Param5 p5, Param6 p6,\n                                                         Param7 p7) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate7(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3, Param4 p4,\n                                                   Param5 p5, Param6 p6,\n                                                   Param7 p7)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3, Param4 p4,\n                                                    Param5 p5, Param6 p6,\n                                                    Param7 p7)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6,\n                                                      Param7 p7)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate7::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5,\n                     Param6 p6, Param7 p7) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(\n        p1, p2, p3, p4, p5, p6, p7);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                               Param5 p5, Param6 p6, Param7 p7) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7);\n  }\n};\n\n// N=8\ntemplate <class Param1, class Param2, class Param3, class Param4, class Param5,\n          class Param6, class Param7, class Param8,\n          class RetType = detail::DefaultVoid>\nclass FastDelegate8 {\nprivate:\n  typedef typename detail::DefaultVoidToVoid<RetType>::type DesiredRetType;\n  typedef DesiredRetType (*StaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                              Param4 p4, Param5 p5, Param6 p6,\n                                              Param7 p7, Param8 p8);\n  typedef RetType (*UnvoidStaticFunctionPtr)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5, Param6 p6,\n                                             Param7 p7, Param8 p8);\n  typedef RetType (detail::GenericClass::*GenericMemFn)(Param1 p1, Param2 p2,\n                                                        Param3 p3, Param4 p4,\n                                                        Param5 p5, Param6 p6,\n                                                        Param7 p7, Param8 p8);\n  typedef detail::ClosurePtr<GenericMemFn, StaticFunctionPtr,\n                             UnvoidStaticFunctionPtr>\n      ClosureType;\n  ClosureType m_Closure;\n\npublic:\n  // Typedefs to aid generic programming\n  typedef FastDelegate8 type;\n\n  // Construction and comparison functions\n  FastDelegate8() { clear(); }\n  FastDelegate8(const FastDelegate8 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  void operator=(const FastDelegate8 &x) {\n    m_Closure.CopyFrom(this, x.m_Closure);\n  }\n  bool operator==(const FastDelegate8 &x) const {\n    return m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator!=(const FastDelegate8 &x) const {\n    return !m_Closure.IsEqual(x.m_Closure);\n  }\n  bool operator<(const FastDelegate8 &x) const {\n    return m_Closure.IsLess(x.m_Closure);\n  }\n  bool operator>(const FastDelegate8 &x) const {\n    return x.m_Closure.IsLess(m_Closure);\n  }\n  // Binding to non-const member functions\n  template <class X, class Y>\n  FastDelegate8(Y *pthis, DesiredRetType (X::*function_to_bind)(\n                              Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                              Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  template <class X, class Y>\n  inline void bind(Y *pthis, DesiredRetType (X::*function_to_bind)(\n                                 Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                 Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {\n    m_Closure.bindmemfunc(detail::implicit_cast<X *>(pthis), function_to_bind);\n  }\n  // Binding to const member functions.\n  template <class X, class Y>\n  FastDelegate8(const Y *pthis,\n                DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6,\n                                                      Param7 p7, Param8 p8)\n                    const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  template <class X, class Y>\n  inline void\n  bind(const Y *pthis,\n       DesiredRetType (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                             Param4 p4, Param5 p5, Param6 p6,\n                                             Param7 p7, Param8 p8) const) {\n    m_Closure.bindconstmemfunc(detail::implicit_cast<const X *>(pthis),\n                               function_to_bind);\n  }\n  // Static functions. We convert them into a member function call.\n  // This constructor also provides implicit conversion\n  FastDelegate8(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                   Param3 p3, Param4 p4,\n                                                   Param5 p5, Param6 p6,\n                                                   Param7 p7, Param8 p8)) {\n    bind(function_to_bind);\n  }\n  // for efficiency, prevent creation of a temporary\n  void operator=(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                    Param3 p3, Param4 p4,\n                                                    Param5 p5, Param6 p6,\n                                                    Param7 p7, Param8 p8)) {\n    bind(function_to_bind);\n  }\n  inline void bind(DesiredRetType (*function_to_bind)(Param1 p1, Param2 p2,\n                                                      Param3 p3, Param4 p4,\n                                                      Param5 p5, Param6 p6,\n                                                      Param7 p7, Param8 p8)) {\n    m_Closure.bindstaticfunc(this, &FastDelegate8::InvokeStaticFunction,\n                             function_to_bind);\n  }\n  // Invoke the delegate\n  RetType operator()(Param1 p1, Param2 p2, Param3 p3, Param4 p4, Param5 p5,\n                     Param6 p6, Param7 p7, Param8 p8) const {\n    return (m_Closure.GetClosureThis()->*(m_Closure.GetClosureMemPtr()))(\n        p1, p2, p3, p4, p5, p6, p7, p8);\n  }\n  // Implicit conversion to \"bool\" using the safe_bool idiom\nprivate:\n  typedef struct SafeBoolStruct {\n    int a_data_pointer_to_this_is_0_on_buggy_compilers;\n    StaticFunctionPtr m_nonzero;\n  } UselessTypedef;\n  typedef StaticFunctionPtr SafeBoolStruct::*unspecified_bool_type;\n\npublic:\n  operator unspecified_bool_type() const {\n    return empty() ? 0 : &SafeBoolStruct::m_nonzero;\n  }\n  // necessary to allow ==0 to work despite the safe_bool idiom\n  inline bool operator==(StaticFunctionPtr funcptr) {\n    return m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!=(StaticFunctionPtr funcptr) {\n    return !m_Closure.IsEqualToStaticFuncPtr(funcptr);\n  }\n  inline bool operator!() const { // Is it bound to anything?\n    return !m_Closure;\n  }\n  inline bool empty() const { return !m_Closure; }\n  void clear() { m_Closure.clear(); }\n  // Conversion to and from the DelegateMemento storage class\n  const DelegateMemento &GetMemento() { return m_Closure; }\n  void SetMemento(const DelegateMemento &any) { m_Closure.CopyFrom(this, any); }\n\nprivate: // Invoker for static functions\n  RetType InvokeStaticFunction(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                               Param5 p5, Param6 p6, Param7 p7,\n                               Param8 p8) const {\n    return (*(m_Closure.GetStaticFunction()))(p1, p2, p3, p4, p5, p6, p7, p8);\n  }\n};\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 4:\n//\n//                FastDelegate<> class (Original author: Jody Hagins)\n//    Allows boost::function style syntax like:\n//            FastDelegate< double (int, long) >\n// instead of:\n//            FastDelegate2< int, long, double >\n//\n////////////////////////////////////////////////////////////////////////////////\n\n#ifdef FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n// Declare FastDelegate as a class template.  It will be specialized\n// later for all number of arguments.\ntemplate <typename Signature> class FastDelegate;\n\n// N=0\n//  Specialization to allow use of\n//  FastDelegate< R (  ) >\n//  instead of\n//  FastDelegate0 < R >\ntemplate <typename R>\nclass FastDelegate<R()>\n    // Inherit from FastDelegate0 so that it can be treated just like a\n    // FastDelegate0\n    : public FastDelegate0<R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate0<R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis, R (X::*function_to_bind)())\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis, R (X::*function_to_bind)() const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)()) : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=1\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1 ) >\n//  instead of\n//  FastDelegate1 < Param1, R >\ntemplate <typename R, class Param1>\nclass FastDelegate<R(Param1)>\n    // Inherit from FastDelegate1 so that it can be treated just like a\n    // FastDelegate1\n    : public FastDelegate1<Param1, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate1<Param1, R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis, R (X::*function_to_bind)(Param1 p1) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1)) : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=2\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2 ) >\n//  instead of\n//  FastDelegate2 < Param1, Param2, R >\ntemplate <typename R, class Param1, class Param2>\nclass FastDelegate<R(Param1, Param2)>\n    // Inherit from FastDelegate2 so that it can be treated just like a\n    // FastDelegate2\n    : public FastDelegate2<Param1, Param2, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate2<Param1, Param2, R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=3\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3 ) >\n//  instead of\n//  FastDelegate3 < Param1, Param2, Param3, R >\ntemplate <typename R, class Param1, class Param2, class Param3>\nclass FastDelegate<R(Param1, Param2, Param3)>\n    // Inherit from FastDelegate3 so that it can be treated just like a\n    // FastDelegate3\n    : public FastDelegate3<Param1, Param2, Param3, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate3<Param1, Param2, Param3, R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=4\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3, Param4 ) >\n//  instead of\n//  FastDelegate4 < Param1, Param2, Param3, Param4, R >\ntemplate <typename R, class Param1, class Param2, class Param3, class Param4>\nclass FastDelegate<R(Param1, Param2, Param3, Param4)>\n    // Inherit from FastDelegate4 so that it can be treated just like a\n    // FastDelegate4\n    : public FastDelegate4<Param1, Param2, Param3, Param4, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate4<Param1, Param2, Param3, Param4, R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis, R (X::*function_to_bind)(Param1 p1, Param2 p2,\n                                                  Param3 p3, Param4 p4))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                     Param4 p4))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=5\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3, Param4, Param5 ) >\n//  instead of\n//  FastDelegate5 < Param1, Param2, Param3, Param4, Param5, R >\ntemplate <typename R, class Param1, class Param2, class Param3, class Param4,\n          class Param5>\nclass FastDelegate<R(Param1, Param2, Param3, Param4, Param5)>\n    // Inherit from FastDelegate5 so that it can be treated just like a\n    // FastDelegate5\n    : public FastDelegate5<Param1, Param2, Param3, Param4, Param5, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate5<Param1, Param2, Param3, Param4, Param5, R> BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                     Param5 p5))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=6\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6 ) >\n//  instead of\n//  FastDelegate6 < Param1, Param2, Param3, Param4, Param5, Param6, R >\ntemplate <typename R, class Param1, class Param2, class Param3, class Param4,\n          class Param5, class Param6>\nclass FastDelegate<R(Param1, Param2, Param3, Param4, Param5, Param6)>\n    // Inherit from FastDelegate6 so that it can be treated just like a\n    // FastDelegate6\n    : public FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, R>\n      BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                     Param5 p5, Param6 p6))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=7\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7 ) >\n//  instead of\n//  FastDelegate7 < Param1, Param2, Param3, Param4, Param5, Param6, Param7, R >\ntemplate <typename R, class Param1, class Param2, class Param3, class Param4,\n          class Param5, class Param6, class Param7>\nclass FastDelegate<R(Param1, Param2, Param3, Param4, Param5, Param6, Param7)>\n    // Inherit from FastDelegate7 so that it can be treated just like a\n    // FastDelegate7\n    : public FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6,\n                           Param7, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                        R>\n      BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6,\n                                        Param7 p7))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6,\n                                        Param7 p7) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                     Param5 p5, Param6 p6, Param7 p7))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n// N=8\n//  Specialization to allow use of\n//  FastDelegate< R ( Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n//  Param8 ) > instead of FastDelegate8 < Param1, Param2, Param3, Param4,\n//  Param5, Param6, Param7, Param8, R >\ntemplate <typename R, class Param1, class Param2, class Param3, class Param4,\n          class Param5, class Param6, class Param7, class Param8>\nclass FastDelegate<R(Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                     Param8)>\n    // Inherit from FastDelegate8 so that it can be treated just like a\n    // FastDelegate8\n    : public FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6,\n                           Param7, Param8, R> {\npublic:\n  // Make using the base type a bit easier via typedef.\n  typedef FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                        Param8, R>\n      BaseType;\n\n  // Allow users access to the specific type of this delegate.\n  typedef FastDelegate SelfType;\n\n  // Mimic the base class constructors.\n  FastDelegate() : BaseType() {}\n\n  template <class X, class Y>\n  FastDelegate(Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6,\n                                        Param7 p7, Param8 p8))\n      : BaseType(pthis, function_to_bind) {}\n\n  template <class X, class Y>\n  FastDelegate(const Y *pthis,\n               R (X::*function_to_bind)(Param1 p1, Param2 p2, Param3 p3,\n                                        Param4 p4, Param5 p5, Param6 p6,\n                                        Param7 p7, Param8 p8) const)\n      : BaseType(pthis, function_to_bind) {}\n\n  FastDelegate(R (*function_to_bind)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                     Param5 p5, Param6 p6, Param7 p7,\n                                     Param8 p8))\n      : BaseType(function_to_bind) {}\n  void operator=(const BaseType &x) { *static_cast<BaseType *>(this) = x; }\n};\n\n#endif // FASTDELEGATE_ALLOW_FUNCTION_TYPE_SYNTAX\n\n////////////////////////////////////////////////////////////////////////////////\n//                        Fast Delegates, part 5:\n//\n//                MakeDelegate() helper function\n//\n//            MakeDelegate(&x, &X::func) returns a fastdelegate of the type\n//            necessary for calling x.func() with the correct number of\n//            arguments. This makes it possible to eliminate many typedefs from\n//            user code.\n//\n////////////////////////////////////////////////////////////////////////////////\n\n// Also declare overloads of a MakeDelegate() global function to\n// reduce the need for typedefs.\n// We need seperate overloads for const and non-const member functions.\n// Also, because of the weird rule about the class of derived member function\n// pointers, implicit downcasts may need to be applied later to the 'this'\n// pointer. That's why two classes (X and Y) appear in the definitions. Y must\n// be implicitly castable to X.\n\n// Workaround for VC6. VC6 needs void return types converted into DefaultVoid.\n// GCC 3.2 and later won't compile this unless it's preceded by 'typename',\n// but VC6 doesn't allow 'typename' in this context.\n// So, I have to use a macro.\n\n#ifdef FASTDLGT_VC6\n#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type\n#else\n#define FASTDLGT_RETTYPE RetType\n#endif\n\n// N=0\ntemplate <class X, class Y, class RetType>\nFastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y *x, RetType (X::*func)()) {\n  return FastDelegate0<FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class RetType>\nFastDelegate0<FASTDLGT_RETTYPE> MakeDelegate(Y *x, RetType (X::*func)() const) {\n  return FastDelegate0<FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=1\ntemplate <class X, class Y, class Param1, class RetType>\nFastDelegate1<Param1, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1)) {\n  return FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class RetType>\nFastDelegate1<Param1, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1) const) {\n  return FastDelegate1<Param1, FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=2\ntemplate <class X, class Y, class Param1, class Param2, class RetType>\nFastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2)) {\n  return FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class RetType>\nFastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2) const) {\n  return FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=3\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class RetType>\nFastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3)) {\n  return FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class RetType>\nFastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3) const) {\n  return FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=4\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class RetType>\nFastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x,\n             RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4)) {\n  return FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x,\n                                                                         func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class RetType>\nFastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4) const) {\n  return FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x,\n                                                                         func);\n}\n\n// N=5\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class RetType>\nFastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4, Param5 p5)) {\n  return FastDelegate5<Param1, Param2, Param3, Param4, Param5,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class RetType>\nFastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4, Param5 p5) const) {\n  return FastDelegate5<Param1, Param2, Param3, Param4, Param5,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=6\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class RetType>\nFastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4, Param5 p5, Param6 p6)) {\n  return FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class RetType>\nFastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6, FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4, Param5 p5, Param6 p6) const) {\n  return FastDelegate6<Param1, Param2, Param3, Param4, Param5, Param6,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=7\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class Param7, class RetType>\nFastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n              FASTDLGT_RETTYPE>\nMakeDelegate(Y *x,\n             RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                Param5 p5, Param6 p6, Param7 p7)) {\n  return FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class Param7, class RetType>\nFastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n              FASTDLGT_RETTYPE>\nMakeDelegate(Y *x,\n             RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                Param5 p5, Param6 p6, Param7 p7) const) {\n  return FastDelegate7<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                       FASTDLGT_RETTYPE>(x, func);\n}\n\n// N=8\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class Param7, class Param8,\n          class RetType>\nFastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8,\n              FASTDLGT_RETTYPE>\nMakeDelegate(Y *x,\n             RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3, Param4 p4,\n                                Param5 p5, Param6 p6, Param7 p7, Param8 p8)) {\n  return FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                       Param8, FASTDLGT_RETTYPE>(x, func);\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class Param6, class Param7, class Param8,\n          class RetType>\nFastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7, Param8,\n              FASTDLGT_RETTYPE>\nMakeDelegate(Y *x, RetType (X::*func)(Param1 p1, Param2 p2, Param3 p3,\n                                      Param4 p4, Param5 p5, Param6 p6,\n                                      Param7 p7, Param8 p8) const) {\n  return FastDelegate8<Param1, Param2, Param3, Param4, Param5, Param6, Param7,\n                       Param8, FASTDLGT_RETTYPE>(x, func);\n}\n\n// clean up after ourselves...\n#undef FASTDLGT_RETTYPE\n\n} // namespace fastdelegate\n\n"
  },
  {
    "path": "src/base/FastDelegateImpl.h",
    "content": "#pragma once\n\n#include <atltrace.h>\n#include \"FastDelegate.h\"\n#include \"WeakPtr.h\"\n\nusing namespace base;\n\nnamespace fastdelegate {\n#ifdef FASTDLGT_VC6\n#define FASTDLGT_RETTYPE detail::VoidToDefaultVoid<RetType>::type\n#else\n#define FASTDLGT_RETTYPE RetType\n#endif\n\nclass __declspec(novtable) CCounter {\npublic:\n  virtual ~CCounter() {};\n  virtual unsigned AddRef() = 0;\n  virtual unsigned ReleaseRef() = 0;\n  static const int IniCounter = 1;\n};\n\ntemplate <typename RetType>\nclass __declspec(novtable) ExecDelegate : public CCounter {\npublic:\n  virtual RetType Run() = 0;\n  virtual ~ExecDelegate() {}\n};\n\ntemplate <class RetType>\nclass FunctionEntity0 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  FunctionEntity0(FASTDLGT_RETTYPE (*func_no_para)())\n      : _Ref(CCounter::IniCounter), m_func_no_para(func_no_para) {}\n  virtual FASTDLGT_RETTYPE Run() {\n    if (m_func_no_para) {\n      return m_func_no_para();\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  FASTDLGT_RETTYPE (*m_func_no_para)();\n  unsigned _Ref;\n};\n\ntemplate <typename Param1, class P1, class RetType>\nclass FunctionEntity1 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  FunctionEntity1(FASTDLGT_RETTYPE (*func_1_para)(Param1), const P1 &p1)\n      : _Ref(CCounter::IniCounter), m_func_1_para(func_1_para), _p1(p1) {}\n  virtual FASTDLGT_RETTYPE Run() {\n    if (m_func_1_para) {\n      return m_func_1_para(_p1);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  FASTDLGT_RETTYPE (*m_func_1_para)(Param1);\n  P1 _p1;\n  unsigned _Ref;\n};\n\ntemplate <typename Param1, class Param2, class P1, class P2, class RetType>\nclass FunctionEntity2 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  FunctionEntity2(FASTDLGT_RETTYPE (*func_2_para)(Param1, Param2), const P1 &p1,\n                  const P2 &p2)\n      : _Ref(CCounter::IniCounter), m_func_2_para(func_2_para), _p1(p1),\n        _p2(p2) {}\n  virtual FASTDLGT_RETTYPE Run() {\n    if (m_func_2_para) {\n      return m_func_2_para(_p1, _p2);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  FASTDLGT_RETTYPE (*m_func_2_para)(Param1, Param2);\n  P1 _p1;\n  P2 _p2;\n  unsigned _Ref;\n};\n\ntemplate <typename Param1, class Param2, class Param3, class P1, class P2,\n          class P3, class RetType>\nclass FunctionEntity3 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  FunctionEntity3(FASTDLGT_RETTYPE (*func_3_para)(Param1, Param2, Param3),\n                  const P1 &p1, const P2 &p2, const P3 &p3)\n      : _Ref(CCounter::IniCounter), m_func_3_para(func_3_para), _p1(p1),\n        _p2(p2), _p3(p3) {}\n  virtual FASTDLGT_RETTYPE Run() {\n    if (m_func_3_para) {\n      return m_func_3_para(_p1, _p2, _p3);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  FASTDLGT_RETTYPE (*m_func_3_para)(Param1, Param2, Param3);\n  P1 _p1;\n  P2 _p2;\n  P3 _p3;\n  unsigned _Ref;\n};\n\ntemplate <typename Param1, class Param2, class Param3, class Param4, class P1,\n          class P2, class P3, class P4, class RetType>\nclass FunctionEntity4 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  FunctionEntity4(FASTDLGT_RETTYPE (*func_4_para)(Param1, Param2, Param3,\n                                                  Param4),\n                  const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)\n      : _Ref(CCounter::IniCounter), m_func_4_para(func_4_para), _p1(p1),\n        _p2(p2), _p3(p3), _p4(p4) {}\n  virtual FASTDLGT_RETTYPE Run() {\n    if (m_func_4_para) {\n      return m_func_4_para(_p1, _p2, _p3, _p4);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  FASTDLGT_RETTYPE (*m_func_4_para)(Param1, Param2, Param3, Param4);\n  P1 _p1;\n  P2 _p2;\n  P3 _p3;\n  P4 _p4;\n  unsigned _Ref;\n};\n\ntemplate <class RetType>\nFunctionEntity0<FASTDLGT_RETTYPE> *\nMakeFunctionEntity(FASTDLGT_RETTYPE (*func)()) {\n  return (new FunctionEntity0<FASTDLGT_RETTYPE>(func));\n}\n\ntemplate <typename Param1, class P1, class RetType>\ninline FunctionEntity1<Param1, P1, FASTDLGT_RETTYPE> *\nMakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1), const P1 &p1) {\n  return (new FunctionEntity1<Param1, P1, FASTDLGT_RETTYPE>(func, p1));\n}\n\ntemplate <class Param1, class Param2, class P1, class P2, class RetType>\ninline FunctionEntity2<Param1, Param2, P1, P2, FASTDLGT_RETTYPE> *\nMakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2), const P1 &p1,\n                   const P2 &p2) {\n  return (new FunctionEntity2<Param1, Param2, P1, P2, FASTDLGT_RETTYPE>(\n      func, p1, p2));\n}\n\ntemplate <typename Param1, class Param2, class Param3, class P1, class P2,\n          class P3, class RetType>\ninline FunctionEntity3<Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE> *\nMakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2, Param3),\n                   const P1 &p1, const P2 &p2, const P3 &p3) {\n  return (\n      new FunctionEntity3<Param1, Param2, Param3, P1, P2, P3, FASTDLGT_RETTYPE>(\n          func, p1, p2, p3));\n}\n\ntemplate <typename Param1, class Param2, class Param3, class Param4, class P1,\n          class P2, class P3, class P4, class RetType>\ninline FunctionEntity4<Param1, Param2, Param3, Param4, P1, P2, P3, P4,\n                       FASTDLGT_RETTYPE> *\nMakeFunctionEntity(FASTDLGT_RETTYPE (*func)(Param1, Param2, Param3, Param4),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {\n  return (FunctionEntity4<Param1, Param2, Param3, Param4, P1, P2, P3, P4,\n                          FASTDLGT_RETTYPE>(func, p1, p2, p3, p4));\n}\n\ntemplate <class X, class Y, class RetType>\nclass DelegateEntity0 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity0(Y *that, const FastDelegate0<FASTDLGT_RETTYPE> &func_no_para)\n      : m_func_no_para(func_no_para), _Ref(CCounter::IniCounter) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_no_para) {\n      return m_func_no_para();\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate0<FASTDLGT_RETTYPE> m_func_no_para;\n  unsigned _Ref;\n};\n\ntemplate <class X, class Y, typename Param1, typename P1, class RetType>\nclass DelegateEntity1 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity1(Y *that,\n                  const FastDelegate1<Param1, FASTDLGT_RETTYPE> &func_1_para,\n                  const P1 &p1)\n      : m_func_1_para(func_1_para), _Ref(CCounter::IniCounter), _p1(p1) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_1_para) {\n      return m_func_1_para(_p1);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate1<Param1, FASTDLGT_RETTYPE> m_func_1_para;\n  unsigned _Ref;\n  P1 _p1;\n};\n\ntemplate <class X, class Y, class Param1, class Param2, typename P1,\n          typename P2, class RetType>\nclass DelegateEntity2 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity2(\n      Y *that,\n      const FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> &func_2_para,\n      const P1 &p1, const P2 &p2)\n      : m_func_2_para(func_2_para), _Ref(CCounter::IniCounter), _p1(p1),\n        _p2(p2) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_2_para) {\n      return m_func_2_para(_p1, _p2);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE> m_func_2_para;\n  unsigned _Ref;\n  P1 _p1;\n  P2 _p2;\n};\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class P1,\n          class P2, typename P3, class RetType>\nclass DelegateEntity3 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity3(Y *that,\n                  const FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>\n                      &func_3_para,\n                  const P1 &p1, const P2 &p2, const P3 &p3)\n      : m_func_3_para(func_3_para), _Ref(CCounter::IniCounter), _p1(p1),\n        _p2(p2), _p3(p3) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_3_para) {\n      return m_func_3_para(_p1, _p2, _p3);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE> m_func_3_para;\n  unsigned _Ref;\n  P1 _p1;\n  P2 _p2;\n  P3 _p3;\n};\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class P1, class P2, class P3, class P4, class RetType>\nclass DelegateEntity4 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity4(Y *that,\n                  const FastDelegate4<Param1, Param2, Param3, Param4,\n                                      FASTDLGT_RETTYPE> &func_4_para,\n                  const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4)\n      : m_func_4_para(func_4_para), _Ref(CCounter::IniCounter), _p1(p1),\n        _p2(p2), _p3(p3), _p4(p4) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_4_para) {\n      return m_func_4_para(_p1, _p2, _p3, _p4);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n  virtual unsigned AddRef() { return ++_Ref; }\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE> m_func_4_para;\n  unsigned _Ref;\n  P1 _p1;\n  P2 _p2;\n  P3 _p3;\n  P4 _p4;\n};\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class P1, class P2, class P3, class P4,\n          class P5, class RetType>\nclass DelegateEntity5 : public ExecDelegate<FASTDLGT_RETTYPE> {\npublic:\n  DelegateEntity5(Y *that,\n                  const FastDelegate5<Param1, Param2, Param3, Param4, Param5,\n                                      FASTDLGT_RETTYPE> &func_5_para,\n                  const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4,\n                  const P5 &p5)\n      : m_func_5_para(func_5_para), _Ref(CCounter::IniCounter), _p1(p1),\n        _p2(p2), _p3(p3), _p4(p4), _p5(p5) {\n    _that.reset(that);\n    if (_that.get()) {\n      _that->AddRef();\n    }\n  }\n\n  virtual FASTDLGT_RETTYPE Run() {\n    if (_that->IsWeakPtr()) {\n      if (NULL == _that->get())\n        return FASTDLGT_RETTYPE();\n    }\n    if (m_func_5_para) {\n      return m_func_5_para(_p1, _p2, _p3, _p4, _p5);\n    }\n    return FASTDLGT_RETTYPE();\n  }\n\n  virtual unsigned AddRef() { return ++_Ref; }\n\n  virtual unsigned ReleaseRef() {\n    --_Ref;\n    assert(_Ref >= 0);\n    if (0 == _Ref) {\n      if (_that.get())\n        _that->Release();\n      delete this;\n      return 0;\n    }\n    return _Ref;\n  }\n\nprotected:\n  std::auto_ptr<Y> _that;\n  FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>\n      m_func_5_para;\n  unsigned _Ref;\n  P1 _p1;\n  P2 _p2;\n  P3 _p3;\n  P4 _p4;\n  P5 _p5;\n};\n\ntemplate <class X, class Y, class RetType>\ninline DelegateEntity0<X, NormalWrapper<Y>, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x, RetType (X::*func)()) {\n  return (new DelegateEntity0<X, NormalWrapper<Y>, FASTDLGT_RETTYPE>(\n      new NormalWrapper<Y>(x), FastDelegate0<FASTDLGT_RETTYPE>((x), func)));\n}\n\ntemplate <class X, class Y, class Param1, typename P1, class RetType>\ninline DelegateEntity1<X, NormalWrapper<Y>, Param1, P1, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x, RetType (X::*func)(Param1), const P1 &p1) {\n  return (\n      new DelegateEntity1<X, NormalWrapper<Y>, Param1, P1, FASTDLGT_RETTYPE>(\n          new NormalWrapper<Y>(x),\n          FastDelegate1<Param1, FASTDLGT_RETTYPE>((x), func), p1));\n}\n\ntemplate <typename X, class Y, class Param1, class Param2, class P1,\n          typename P2, class RetType>\ninline DelegateEntity2<X, NormalWrapper<Y>, Param1, Param2, P1, P2,\n                       FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2), const P1 &p1,\n                   const P2 &p2) {\n  return (new DelegateEntity2<X, NormalWrapper<Y>, Param1, Param2, P1, P2,\n                              FASTDLGT_RETTYPE>(\n      new NormalWrapper<Y>(x),\n      FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>((x), func), p1, p2));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class P1,\n          typename P2, class P3, class RetType>\ninline DelegateEntity3<X, NormalWrapper<Y>, Param1, Param2, Param3, P1, P2, P3,\n                       FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2, Param3),\n                   const P1 &p1, const P2 &p2, const P3 &p3) {\n  return (new DelegateEntity3<X, NormalWrapper<Y>, Param1, Param2, Param3, P1,\n                              P2, P3, FASTDLGT_RETTYPE>(\n      new NormalWrapper<Y>(x),\n      FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>((x), func), p1,\n      p2, p3));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class P1, typename P2, class P3, class P4,\n          class RetType>\ninline DelegateEntity4<X, NormalWrapper<Y>, Param1, Param2, Param3, Param4, P1,\n                       P2, P3, P4, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x, RetType (X::*func)(Param1, Param2, Param3, Param4),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {\n  return (new DelegateEntity4<X, NormalWrapper<Y>, Param1, Param2, Param3,\n                              Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE>(\n      new NormalWrapper<Y>(x),\n      FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>((x),\n                                                                      func),\n      p1, p2, p3, p4));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class P1, typename P2, class P3, class P4,\n          class P5, class RetType>\ninline DelegateEntity5<X, NormalWrapper<Y>, Param1, Param2, Param3, Param4,\n                       Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(Y *x,\n                   RetType (X::*func)(Param1, Param2, Param3, Param4, Param5),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4,\n                   const P5 &p5) {\n  return (\n      new DelegateEntity5<X, NormalWrapper<Y>, Param1, Param2, Param3, Param4,\n                          Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>(\n          new NormalWrapper<Y>(x),\n          FastDelegate5<Param1, Param2, Param3, Param4, Param5,\n                        FASTDLGT_RETTYPE>((x), func),\n          p1, p2, p3, p4, p5));\n}\n\ntemplate <class X, class T, class RetType>\ninline DelegateEntity0<X, UnretainedWrapper<T>, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<T> *x, RetType (X::*func)()) {\n  return (new DelegateEntity0<X, UnretainedWrapper<T>, FASTDLGT_RETTYPE>(\n      x, FastDelegate0<FASTDLGT_RETTYPE>(x->get(), func)));\n}\n\ntemplate <class X, class T, class Param1, class P1, class RetType>\ninline DelegateEntity1<X, UnretainedWrapper<T>, Param1, P1, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<T> *x, RetType (X::*func)(Param1),\n                   const P1 &p1) {\n  return (new DelegateEntity1<X, UnretainedWrapper<T>, Param1, P1,\n                              FASTDLGT_RETTYPE>(\n      x, FastDelegate1<Param1, FASTDLGT_RETTYPE>(x->get(), func), p1));\n}\n\ntemplate <typename X, class Y, class Param1, class Param2, class P1, class P2,\n          class RetType>\ninline DelegateEntity2<X, UnretainedWrapper<Y>, Param1, Param2, P1, P2,\n                       FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<Y> *x, RetType (X::*func)(Param1, Param2),\n                   const P1 &p1, const P2 &p2) {\n  return (new DelegateEntity2<X, UnretainedWrapper<Y>, Param1, Param2, P1, P2,\n                              FASTDLGT_RETTYPE>(\n      x, FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x->get(), func), p1,\n      p2));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class P1,\n          class P2, class P3, class RetType>\ninline DelegateEntity3<X, UnretainedWrapper<Y>, Param1, Param2, Param3, P1, P2,\n                       P3, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<Y> *x,\n                   RetType (X::*func)(Param1, Param2, Param3), const P1 &p1,\n                   const P2 &p2, const P3 &p3) {\n  return (new DelegateEntity3<X, UnretainedWrapper<Y>, Param1, Param2, Param3,\n                              P1, P2, P3, FASTDLGT_RETTYPE>(\n      x,\n      FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x->get(), func),\n      p1, p2, p3));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class P1, class P2, class P3, class P4, class RetType>\ninline DelegateEntity4<X, UnretainedWrapper<Y>, Param1, Param2, Param3, Param4,\n                       P1, P2, P3, P4, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<Y> *x,\n                   RetType (X::*func)(Param1, Param2, Param3, Param4),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {\n  return (new DelegateEntity4<X, UnretainedWrapper<Y>, Param1, Param2, Param3,\n                              Param4, P1, P2, P3, P4, FASTDLGT_RETTYPE>(\n      x,\n      FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x->get(),\n                                                                      func),\n      p1, p2, p3, p4));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class P1, class P2, class P3, class P4,\n          class P5, class RetType>\ninline DelegateEntity5<X, UnretainedWrapper<Y>, Param1, Param2, Param3, Param4,\n                       Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(UnretainedWrapper<Y> *x,\n                   RetType (X::*func)(Param1, Param2, Param3, Param4, Param5),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4,\n                   const P5 &p5) {\n  return (\n      new DelegateEntity5<X, UnretainedWrapper<Y>, Param1, Param2, Param3,\n                          Param4, Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>(\n          x,\n          FastDelegate5<Param1, Param2, Param3, Param4, Param5,\n                        FASTDLGT_RETTYPE>(x->get(), func),\n          p1, p2, p3, p4, p5));\n}\n\ntemplate <class X, class T, class RetType>\ninline DelegateEntity0<X, WeakPtr<T>, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<T> *x, RetType (X::*func)()) {\n  return (new DelegateEntity0<X, WeakPtr<T>, FASTDLGT_RETTYPE>(\n      x, FastDelegate0<FASTDLGT_RETTYPE>(x->ptr_, func)));\n}\n\ntemplate <class X, class T, class Param1, class P1, class RetType>\ninline DelegateEntity1<X, WeakPtr<T>, Param1, P1, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<T> *x, RetType (X::*func)(Param1), const P1 &p1) {\n  return (new DelegateEntity1<X, WeakPtr<T>, Param1, P1, FASTDLGT_RETTYPE>(\n      x, FastDelegate1<Param1, FASTDLGT_RETTYPE>(x->ptr_, func), p1));\n}\n\ntemplate <typename X, class Y, class Param1, class Param2, class P1, class P2,\n          class RetType>\ninline DelegateEntity2<X, WeakPtr<Y>, Param1, Param2, P1, P2,\n                       FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<Y> *x, RetType (X::*func)(Param1, Param2),\n                   const P1 &p1, const P2 &p2) {\n  return (new DelegateEntity2<X, WeakPtr<Y>, Param1, Param2, P1, P2,\n                              FASTDLGT_RETTYPE>(\n      x, FastDelegate2<Param1, Param2, FASTDLGT_RETTYPE>(x->ptr_, func), p1,\n      p2));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class P1,\n          class P2, class P3, class RetType>\ninline DelegateEntity3<X, WeakPtr<Y>, Param1, Param2, Param3, P1, P2, P3,\n                       FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<Y> *x, RetType (X::*func)(Param1, Param2, Param3),\n                   const P1 &p1, const P2 &p2, const P3 &p3) {\n  return (new DelegateEntity3<X, WeakPtr<Y>, Param1, Param2, Param3, P1, P2, P3,\n                              FASTDLGT_RETTYPE>(\n      x, FastDelegate3<Param1, Param2, Param3, FASTDLGT_RETTYPE>(x->ptr_, func),\n      p1, p2, p3));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class P1, class P2, class P3, class P4, class RetType>\ninline DelegateEntity4<X, WeakPtr<Y>, Param1, Param2, Param3, Param4, P1, P2,\n                       P3, P4, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<Y> *x,\n                   RetType (X::*func)(Param1, Param2, Param3, Param4),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4) {\n  return (new DelegateEntity4<X, WeakPtr<Y>, Param1, Param2, Param3, Param4, P1,\n                              P2, P3, P4, FASTDLGT_RETTYPE>(\n      x,\n      FastDelegate4<Param1, Param2, Param3, Param4, FASTDLGT_RETTYPE>(x->ptr_,\n                                                                      func),\n      p1, p2, p3, p4));\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class P1, class P2, class P3, class P4,\n          class P5, class RetType>\ninline DelegateEntity5<X, WeakPtr<Y>, Param1, Param2, Param3, Param4, Param5,\n                       P1, P2, P3, P4, P5, FASTDLGT_RETTYPE> *\nMakeDelegateEntity(WeakPtr<Y> *x,\n                   RetType (X::*func)(Param1, Param2, Param3, Param4, Param5),\n                   const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4,\n                   const P5 &p5) {\n  return (new DelegateEntity5<X, WeakPtr<Y>, Param1, Param2, Param3, Param4,\n                              Param5, P1, P2, P3, P4, P5, FASTDLGT_RETTYPE>(\n      x,\n      FastDelegate5<Param1, Param2, Param3, Param4, Param5, FASTDLGT_RETTYPE>(\n          x->ptr_, func),\n      p1, p2, p3, p4, p5));\n}\n\ntemplate <typename RetType = void>\nclass Task final : public base::RefCountedThreadSafe<Task<RetType>> {\npublic:\n  Task() : m_Func(NULL), m_Class(NULL) { ATLTRACE(\"new TASK\\n\"); }\n  ~Task() {\n    ATLTRACE(\"delete TASK\\n\");\n    if (m_Func) {\n      m_Func->ReleaseRef();\n    }\n    if (m_Class) {\n      m_Class->ReleaseRef();\n    }\n  }\n  void SetFun(ExecDelegate<FASTDLGT_RETTYPE> *p) { m_Func = p; }\n  void SetClass(ExecDelegate<FASTDLGT_RETTYPE> *p) { m_Class = p; }\n  FASTDLGT_RETTYPE Run();\n\nprotected:\n  ExecDelegate<FASTDLGT_RETTYPE> *m_Func;\n  ExecDelegate<FASTDLGT_RETTYPE> *m_Class;\n  friend class RefCountedThreadSafe<Task<RetType>>;\n};\n\ntemplate <class RetType> FASTDLGT_RETTYPE Task<FASTDLGT_RETTYPE>::Run() {\n  if (m_Class) {\n    return m_Class->Run();\n  }\n  if (m_Func) {\n    return m_Func->Run();\n  }\n  return FASTDLGT_RETTYPE();\n}\n\n#undef FASTDLGT_RETTYPE\n} // namespace fastdelegate\n\nnamespace base {\ninline fastdelegate::Task<void> *Bind(void (*func_no_para)()) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetFun(fastdelegate::MakeFunctionEntity(func_no_para));\n  return task;\n}\n\ntemplate <typename Param1, typename P1>\ninline fastdelegate::Task<void> *Bind(void (*func_1para)(Param1),\n                                      const P1 &p1) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetFun(fastdelegate::MakeFunctionEntity(func_1para, p1));\n  return task;\n}\n\ntemplate <class Param1, class Param2, typename P1, typename P2>\ninline fastdelegate::Task<void> *Bind(void (*func_2para)(Param1, Param2),\n                                      const P1 &p1, const P2 &p2) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetFun(fastdelegate::MakeFunctionEntity(func_2para, p1, p2));\n  return task;\n}\n\ntemplate <typename Param1, class Param2, class Param3, class P1, class P2,\n          class P3>\ninline fastdelegate::Task<void> *\nBind(void (*func_3para)(Param1, Param2, Param3), const P1 &p1, const P2 &p2,\n     const P3 &p3) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetFun(fastdelegate::MakeFunctionEntity(func_3para, p1, p2, p3));\n  return task;\n}\n\ntemplate <typename Param1, class Param2, class Param3, class Param4, class P1,\n          class P2, class P3, class P4>\ninline fastdelegate::Task<void> *\nBind(void (*func_4para)(Param1, Param2, Param3, Param4), const P1 &p1,\n     const P2 &p2, const P3 &p3, const P4 &p4) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetFun(fastdelegate::MakeFunctionEntity(func_4para, p1, p2, p3, p4));\n  return task;\n}\n\ntemplate <class X, class Y>\ninline fastdelegate::Task<void> *Bind(Y *obj, void (X::*func)()) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(fastdelegate::MakeDelegateEntity(obj, func));\n  return task;\n}\n\ntemplate <class X, class Y, class Param1, class P1>\ninline fastdelegate::Task<void> *Bind(Y *obj, void (X::*func)(Param1),\n                                      const P1 &p1) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1));\n  return task;\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class P1, class P2>\ninline fastdelegate::Task<void> *Bind(Y *obj, void (X::*func)(Param1, Param2),\n                                      const P1 &p1, const P2 &p2) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2));\n  return task;\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3, class P1,\n          class P2, class P3>\ninline fastdelegate::Task<void> *\nBind(Y *obj, void (X::*func)(Param1, Param2, Param3), const P1 &p1,\n     const P2 &p2, const P3 &p3) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3));\n  return task;\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class P1, class P2, class P3, class P4>\ninline fastdelegate::Task<void> *\nBind(Y *obj, void (X::*func)(Param1, Param2, Param3, Param4), const P1 &p1,\n     const P2 &p2, const P3 &p3, const P4 &p4) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3, p4));\n  return task;\n}\n\ntemplate <class X, class Y, class Param1, class Param2, class Param3,\n          class Param4, class Param5, class P1, class P2, class P3, class P4,\n          class P5>\ninline fastdelegate::Task<void> *\nBind(Y *obj, void (X::*func)(Param1, Param2, Param3, Param4, Param5),\n     const P1 &p1, const P2 &p2, const P3 &p3, const P4 &p4, const P5 &p5) {\n  fastdelegate::Task<void> *task = new fastdelegate::Task<void>;\n  task->SetClass(\n      fastdelegate::MakeDelegateEntity(obj, func, p1, p2, p3, p4, p5));\n  return task;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/MessageLoop.cc",
    "content": "#include \"StdAfx.h\"\n#include \"MessageLoop.h\"\n\nnamespace base {\nstatic base::ThreadLocalPointer<MessageLoop> tls_ptr;\n\nvoid MessageLoop::AddDestructionObserver(\n    DestructionObserver *destruction_observer) {\n  assert(this == current());\n  destruction_observers_.AddObserver(destruction_observer);\n}\n\nvoid MessageLoop::RemoveDestructionObserver(\n    DestructionObserver *destruction_observer) {\n  assert(this == current());\n  destruction_observers_.RemoveObserver(destruction_observer);\n}\n\nMessageLoop::MessageLoop(Type type)\n    : type_(type), running_(false), recent_time_() /*,upLayer_(NULL)*/ {\n  Init();\n  pump_.reset(CreateMessagePumpForType(type));\n}\n\nMessageLoop *MessageLoop::current() { return tls_ptr.Get(); }\n\nvoid MessageLoop::Init() {\n  assert(tls_ptr.Get() == NULL);\n  tls_ptr.Set(this);\n}\n\nvoid MessageLoop::PostTask(fastdelegate::Task<void> *task) {\n  PostDelayedTask(task, TimeDelta());\n}\n\nvoid MessageLoop::PostDelayedTask(fastdelegate::Task<void> *task,\n                                  TimeDelta delay) {\n  assert(delay >= TimeDelta());\n\n  do {\n    if (delay == TimeDelta()) {\n      AppendTask(PendingTask(task));\n      break;\n    }\n    AppendTask(PendingTask(task, CalculateDelayedRuntime(delay)));\n\n  } while (false);\n\n  pump_->ScheduleWork();\n}\n\nvoid MessageLoop::PostQuitTask(fastdelegate::Task<void> *task) {\n  AutoCritSecLock<CriticalSection> lock(m_cs, false);\n  lock.Lock();\n  quitwork_queue_.push_back(PendingTask(task));\n}\n\nvoid MessageLoop::Run() {\n  running_ = true;\n  pump_->Run(this);\n  running_ = false;\n}\n\nvoid MessageLoop::Quit() {\n  PostTask(Bind(Unretained(this), &MessageLoop::QuitInternal));\n}\n\nbool MessageLoop::is_running() const { return running_; }\n\nMessagePump *MessageLoop::CreateMessagePumpForType(Type type) {\n  if (MessageLoop::TYPE_UI == type) {\n    return new MessagePumpForUI();\n  }\n  if (MessageLoop::TYPE_IO == type) {\n    return new MessagePumpForIO();\n  }\n  if (MessageLoop::TYPE_DEFAULT == type) {\n    return new MessagePumpDefault();\n  }\n  return NULL;\n}\n\nvoid MessageLoop::AppendTask(PendingTask &task) {\n  AutoCritSecLock<CriticalSection> lock(m_cs, false);\n  lock.Lock();\n  incoming_queue_.push_back(task);\n}\n\nvoid MessageLoop::AddToDelayedWorkQueue(const PendingTask &pending_task) {\n  delayed_work_queue_.push(pending_task);\n}\n\nvoid MessageLoop::QuitInternal() { pump_->Quit(); }\n\nMessageLoop::~MessageLoop() {\n  assert(this == current());\n  // Clean up any unprocessed tasks\n  DeletePendingTasks();\n  ReloadWorkQueue();\n  DeletePendingTasks();\n  // Let interested parties have one last shot at accessing this.\n  FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,\n                    WillDestroyCurrentMessageLoop());\n  // OK, now make it so that no one can find us.\n  tls_ptr.Set(NULL);\n\n  ExeQuitQueue();\n}\n\nvoid MessageLoop::ExeQuitQueue() {\n  for (; !quitwork_queue_.empty();) {\n    PendingTask pending_task = quitwork_queue_.pick_front();\n    RunPendingTask(pending_task);\n  }\n}\n\nvoid MessageLoop::DeletePendingTasks() {\n  size_t size = working_queue_.size();\n  for (size_t i = 0; i < size; ++i) {\n    PendingTask pending_task = working_queue_.pick_front();\n    pending_task.Reset();\n  }\n  while (!delayed_work_queue_.empty()) {\n    PendingTask pending_task = delayed_work_queue_.top();\n    delayed_work_queue_.pop();\n    pending_task.Reset();\n  }\n}\n\nvoid MessageLoop::ReloadWorkQueue() {\n  if (!working_queue_.empty())\n    return;\n\n  AutoCritSecLock<CriticalSection> lock(m_cs, false);\n  lock.Lock();\n  if (0 == incoming_queue_.size()) {\n  } else {\n    incoming_queue_.swap(working_queue_);\n  }\n}\n\nbool MessageLoop::RunPendingTask(PendingTask &pending_task) {\n  pending_task.Run();\n  return true;\n}\n\nTimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) {\n  TimeTicks delayed_run_time = TimeTicks::Now() + delay;\n  return delayed_run_time;\n}\n\nbool MessageLoop::DoWork() {\n  for (;;) {\n    ReloadWorkQueue();\n    if (working_queue_.empty())\n      break;\n\n    // Execute oldest task.\n    do {\n      PendingTask pending_task = working_queue_.pick_front();\n      if (!pending_task.delayed_run_time_.is_null()) {\n        AddToDelayedWorkQueue(pending_task);\n        // If we changed the topmost task, then it is time to reschedule.\n        if (delayed_work_queue_.top().Equals(pending_task))\n          pump_->ScheduleDelayedWork(pending_task.delayed_run_time_);\n      } else {\n        if (RunPendingTask(pending_task))\n          return true;\n      }\n    } while (!working_queue_.empty());\n  }\n  // Nothing runned.\n  return false;\n}\n\nbool MessageLoop::DoDelayedWork(TimeTicks *next_delayed_work_time) {\n  if (delayed_work_queue_.empty()) {\n    recent_time_ = *next_delayed_work_time = TimeTicks();\n    return false;\n  }\n\n  TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time_;\n  if (next_run_time > recent_time_) {\n    recent_time_ = TimeTicks::Now();\n    if (next_run_time > recent_time_) {\n      *next_delayed_work_time = next_run_time;\n      return false;\n    }\n  }\n\n  PendingTask pending_task = delayed_work_queue_.top();\n  delayed_work_queue_.pop();\n\n  if (!delayed_work_queue_.empty()) {\n    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time_;\n  }\n\n  RunPendingTask(pending_task);\n  return true;\n}\n\nbool MessageLoop::DoIdleWork() { return false; }\n\nMessagePumpWin *MessageLoop::pump_win() {\n  return static_cast<MessagePumpWin *>(pump_.get());\n}\n\n// LayerLoop\nstd::vector<MessageLoop::LayerLoop *> MessageLoop::LayerLoop::layer_;\n\nMessageLoop::LayerLoop::LayerLoop(Type type) {\n  pump_.reset(new MessagePumpForUI(NULL, (MessagePumpForUI *)1));\n}\n\nMessagePumpWin *MessageLoop::LayerLoop::pump_win() {\n  return static_cast<MessagePumpWin *>(pump_.get());\n}\n\nbool MessageLoop::LayerLoop::DoWork() { return false; }\n\nbool MessageLoop::LayerLoop::DoDelayedWork(TimeTicks *next_delayed_work_time) {\n  return false;\n}\n\nbool MessageLoop::LayerLoop::DoIdleWork() { return false; }\n\nvoid MessageLoop::LayerLoop::Run() { pump_->Run(NULL); }\n\nvoid MessageLoop::LayerLoop::PushBackLoop(LayerLoop *loop) {\n  layer_.push_back(loop);\n}\n\nvoid MessageLoop::LayerLoop::PopBackLoop() { layer_.pop_back(); }\n\nMessageLoop::LayerLoop *MessageLoop::LayerLoop::Back() {\n  LayerLoop *back = layer_.back();\n  return back;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/MessageLoop.h",
    "content": "#pragma once\n\n#include <util/util_tools.h>\n#include \"../Event/WaitableEvent.h\"\n#include \"FastDelegateImpl.h\"\n#include \"PendingTask.h\"\n#include \"observer_list.h\"\n#include \"MessagePumpDefault.h\"\n#include \"MessagePumpWin.h\"\n#include \"thread_local.h\"\n\nnamespace base {\nclass MessagePumpWin;\n\nclass MessageLoop : public MessagePump::Delegate {\npublic:\n  enum Type {\n    TYPE_DEFAULT,\n    TYPE_UI,\n    TYPE_IO,\n  };\n\n  template <class T> class DeleteHelper {\n  public:\n    static void DoDelete(const void *object) {\n      delete reinterpret_cast<const T *>(object);\n    }\n    DISALLOW_COPY_AND_ASSIGN(DeleteHelper);\n  };\n\n  class DestructionObserver {\n  public:\n    virtual void WillDestroyCurrentMessageLoop() = 0;\n\n  protected:\n    virtual ~DestructionObserver() {}\n  };\n  void AddDestructionObserver(DestructionObserver *destruction_observer);\n\n  // Remove a DestructionObserver.  It is safe to call this method while a\n  // DestructionObserver is receiving a notification callback.\n  void RemoveDestructionObserver(DestructionObserver *destruction_observer);\n\n  explicit MessageLoop(Type type = TYPE_DEFAULT);\n\n  virtual ~MessageLoop();\n  // static\n  static MessageLoop *current();\n\n  void PostTask(fastdelegate::Task<void> *task);\n  void PostDelayedTask(fastdelegate::Task<void> *task, TimeDelta delay);\n  void PostQuitTask(fastdelegate::Task<void> *task);\n  template <typename T> void DeleteSoon(T *object) {\n    TASK *task = build TASK;\n    PostTask(MAKETASK_FUN1(task, DeleteHelper<T>::DoDelete, object));\n  }\n  void Run();\n  void Quit();\n  Type type() const { return type_; }\n  // Optional call to connect the thread name with this loop.\n  void set_thread_name(const std::string &thread_name) {\n    if (thread_name_.empty())\n      thread_name_ = thread_name;\n  }\n  void reset_thread_name(const std::string &thread_name) {\n    if (!thread_name_.empty())\n      thread_name_ = thread_name;\n  }\n  const std::string &thread_name() const { return thread_name_; }\n\n  // Can only be called from the thread that owns the MessageLoop.\n  bool is_running() const;\n\n  // static\n  static MessagePump *CreateMessagePumpForType(Type type);\n\n  MessagePumpWin *pump_win();\n\nprivate:\n  void ExeQuitQueue();\n  void Init();\n  void AddToDelayedWorkQueue(const PendingTask &pending_task);\n  TimeTicks CalculateDelayedRuntime(TimeDelta delay);\n  void QuitInternal();\n  void DeletePendingTasks();\n  void ReloadWorkQueue();\n  bool RunPendingTask(PendingTask &pending_task);\n  void AppendTask(PendingTask &task);\n  // MessagePump::Delegate methods:\n  virtual bool DoWork() override;\n  virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) override;\n  virtual bool DoIdleWork() override;\n\n  bool running_;\n  std::string thread_name_;\n  Type type_;\n  std::auto_ptr<MessagePump> pump_;\n  ObserverList<DestructionObserver> destruction_observers_;\n\n  TaskQueue incoming_queue_;\n  TaskQueue working_queue_;\n  TaskQueue quitwork_queue_;\n  DelayedTaskQueue delayed_work_queue_;\n  CriticalSection m_cs;\n  TimeTicks recent_time_;\n\npublic:\n  class LayerLoop : public MessagePump::Delegate {\n  public:\n    explicit LayerLoop(Type type = TYPE_DEFAULT);\n    void Run();\n    virtual bool DoWork() override;\n    virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) override;\n    virtual bool DoIdleWork() override;\n    MessagePumpWin *pump_win();\n    std::auto_ptr<MessagePump> pump_;\n    static void PushBackLoop(LayerLoop *loop);\n    static void PopBackLoop();\n    static LayerLoop *Back();\n\n  private:\n    static std::vector<LayerLoop *> layer_;\n  };\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/MessagePump.h",
    "content": "#pragma once\n\n#include \"../time/time.h\"\n\nnamespace base {\nclass __declspec(novtable) MessagePump {\npublic: \n  class __declspec(novtable) Delegate {\n  public:\n    // Called from within Run in response to ScheduleWork or when the message\n    // pump would otherwise call DoDelayedWork.  Returns true to indicate that\n    // work was done.  DoDelayedWork will still be called if DoWork returns\n    // true, but DoIdleWork will not.\n    virtual bool DoWork() = 0;\n\n    // Called from within Run in response to ScheduleDelayedWork or when the\n    // message pump would otherwise sleep waiting for more work.  Returns true\n    // to indicate that delayed work was done.  DoIdleWork will not be called\n    // if DoDelayedWork returns true.  Upon return |next_delayed_work_time|\n    // indicates the time when DoDelayedWork should be called again.  If\n    // |next_delayed_work_time| is null (per Time::is_null), then the queue of\n    // future delayed work (timer events) is currently empty, and no additional\n    // calls to this function need to be scheduled.\n    virtual bool DoDelayedWork(TimeTicks *next_delayed_work_time) = 0;\n\n    // Called from within Run just before the message pump goes to sleep.\n    // Returns true to indicate that idle work was done. Returning false means\n    // the pump will now wait.\n    virtual bool DoIdleWork() = 0;\n  };\n\n  virtual void Run(Delegate* delegate) = 0;\n\n  // Quit immediately from the most recently entered run loop.  This method may\n  // only be used on the thread that called Run.\n  virtual void Quit() = 0;\n\n  // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a\n  // DoWork callback is already scheduled.  This method may be called from any\n  // thread.  Once this call is made, DoWork should not be \"starved\" at least\n  // until it returns a value of false.\n  virtual void ScheduleWork() = 0;\n\n  // Schedule a DoDelayedWork callback to happen at the specified time,\n  // cancelling any pending DoDelayedWork callback.  This method may only be\n  // used on the thread that called Run.\n  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;\n};\n\n}; //base"
  },
  {
    "path": "src/base/MessagePumpDefault.cc",
    "content": "#include \"StdAfx.h\"\n#include \"MessagePumpDefault.h\"\n\nnamespace base {\nMessagePumpDefault::MessagePumpDefault()\n    : keep_running_(true), event_(false, false) {}\n\nMessagePumpDefault::~MessagePumpDefault() {}\n\nvoid MessagePumpDefault::Run(Delegate *delegate) {\n  for (;;) {\n    bool did_work = delegate->DoWork();\n    if (false == keep_running_)\n      break;\n\n    did_work |= delegate->DoDelayedWork(&delayed_work_time_);\n    if (false == keep_running_)\n      break;\n\n    if (did_work)\n      continue;\n\n    did_work = delegate->DoIdleWork();\n    if (false == keep_running_)\n      break;\n\n    if (did_work)\n      continue;\n\n    if (delayed_work_time_.is_null()) {\n      event_.Wait();\n    } else {\n      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();\n      if (delay > TimeDelta()) {\n        event_.TimedWait(delay);\n      } else {\n        // It looks like delayed_work_time_ indicates a time in the past, so we\n        // need to call DoDelayedWork now.\n        delayed_work_time_ = TimeTicks();\n      }\n    }\n  }\n\n  keep_running_ = true;\n}\n\nvoid MessagePumpDefault::Quit() { keep_running_ = false; }\n\nvoid MessagePumpDefault::ScheduleWork() { event_.Signal(); }\n\nvoid MessagePumpDefault::ScheduleDelayedWork(\n    const TimeTicks &delayed_work_time) {\n  // We know that we can't be blocked on Wait right now since this method can\n  // only be called on the same thread as Run, so we only need to update our\n  // record of how long to sleep when we do sleep.\n  delayed_work_time_ = delayed_work_time;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/MessagePumpDefault.h",
    "content": "#pragma once\n\n#include \"../Event/WaitableEvent.h\"\n#include \"MessagePump.h\"\n#include \"macros.h\"\n\nnamespace base {\nclass MessagePumpDefault : public MessagePump {\npublic:\n  MessagePumpDefault();\n  virtual ~MessagePumpDefault();\n\n  // MessagePump methods:\n  virtual void Run(Delegate *delegate) override;\n  virtual void Quit() override;\n  virtual void ScheduleWork() override;\n  virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override;\n\nprivate:\n  // This flag is set to false when Run should return.\n  bool keep_running_;\n\n  // Used to sleep until there is more work to do.\n  WaitableEvent event_;\n\n  // The time at which we should call DoDelayedWork.\n  TimeTicks delayed_work_time_;\n\n  DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);\n};\n} // namespace base\n"
  },
  {
    "path": "src/base/MessagePumpWin.cc",
    "content": "#include \"StdAfx.h\"\n#include \"stringprintf.h\"\n#include \"MessagePumpWin.h\"\n\nnamespace base {\nstatic const wchar_t kWndClassFormat[] = L\"Chrome_MessagePumpWindow_%p\";\nstatic const int kMsgHaveWork = WM_USER + 1;\n\nHMODULE GetModuleFromAddress(void *address) {\n  HMODULE instance = NULL;\n  if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |\n                                GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,\n                            static_cast<char *>(address), &instance)) {\n    assert(0);\n  }\n  return instance;\n}\n// Win\nvoid MessagePumpWin::AddObserver(MessagePumpObserver *observer) {\n  observers_.AddObserver(observer);\n}\n\nvoid MessagePumpWin::RemoveObserver(MessagePumpObserver *observer) {\n  observers_.RemoveObserver(observer);\n}\n\nvoid MessagePumpWin::WillProcessMessage(const MSG &msg) {\n  FOR_EACH_OBSERVER(MessagePumpObserver, observers_, WillProcessEvent(msg));\n}\n\nvoid MessagePumpWin::DidProcessMessage(const MSG &msg) {\n  FOR_EACH_OBSERVER(MessagePumpObserver, observers_, DidProcessEvent(msg));\n}\n\nvoid MessagePumpWin::Quit() { keep_running_ = false; }\n\nint MessagePumpWin::GetCurrentDelay() const {\n  if (delayed_work_time_.is_null())\n    return -1;\n\n  // Be careful here.  TimeDelta has a precision of microseconds, but we want a\n  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or\n  // 6?  It should be 6 to avoid executing delayed work too early.\n  double timeout =\n      ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());\n\n  // If this value is negative, then we need to run delayed work soon.\n  int delay = static_cast<int>(timeout);\n  if (delay < 0)\n    delay = 0;\n\n  return delay;\n}\n\n// UI\nMessagePumpForUI::MessagePumpForUI(Delegate *delegate,\n                                   MessagePumpForUI *upLayer)\n    : atom_(0), message_hwnd_(NULL), delegate_(delegate), upLayer_(upLayer) {\n  if (!upLayer_)\n    InitMessageWnd();\n}\n\nMessagePumpForUI::~MessagePumpForUI() {\n  DestroyWindow(message_hwnd_);\n  UnregisterClass(MAKEINTATOM(atom_), GetModuleFromAddress(&WndProcThunk));\n}\n\nvoid MessagePumpForUI::Run(Delegate *delegate) {\n  assert(delegate_ == NULL || delegate == delegate_);\n  delegate_ = delegate;\n\n  if (!upLayer_) {\n    // for module dialog\n    assert(delegate_);\n    for (;;) {\n      // If we do any work, we may create more messages etc., and more work may\n      // possibly be waiting in another task group.  When we (for example)\n      // ProcessNextWindowsMessage(), there is a good chance there are still\n      // more messages waiting.  On the other hand, when any of these methods\n      // return having done no work, then it is pretty unlikely that calling\n      // them again quickly will find any work to do.  Finally, if they all say\n      // they had no work, then it is a good time to consider sleeping (waiting)\n      // for more work.\n\n      bool more_work_is_plausible = ProcessNextWindowsMessage();\n      if (!keep_running_)\n        break;\n\n      more_work_is_plausible |= delegate->DoWork();\n\n      if (!keep_running_)\n        break;\n\n      more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time_);\n\n      if (!keep_running_)\n        break;\n\n      if (more_work_is_plausible)\n        continue;\n\n      more_work_is_plausible = delegate->DoIdleWork();\n      if (!keep_running_)\n        break;\n\n      if (more_work_is_plausible)\n        continue;\n\n      WaitForWork(); // Wait (sleep) until we have work to do again.\n    }\n  } else {\n    assert(!delegate_);\n    for (;;) {\n      bool more_work_is_plausible = upLayer_->ProcessNextWindowsMessage();\n      if (!keep_running_)\n        break;\n\n      more_work_is_plausible |= upLayer_->PumpDelegate()->DoWork();\n\n      if (!keep_running_)\n        break;\n\n      more_work_is_plausible |=\n          upLayer_->PumpDelegate()->DoDelayedWork(&delayed_work_time_);\n\n      if (!keep_running_)\n        break;\n\n      if (more_work_is_plausible)\n        continue;\n\n      more_work_is_plausible = upLayer_->PumpDelegate()->DoIdleWork();\n      if (!keep_running_)\n        break;\n\n      if (more_work_is_plausible)\n        continue;\n\n      upLayer_->WaitForWork(); // Wait (sleep) until we have work to do again.\n    }\n  }\n  keep_running_ = true;\n}\n\nvoid MessagePumpForUI::ScheduleWork() {\n  if (InterlockedExchange(&have_work_, 1))\n    return;\n\n  BOOL ret = PostMessage(message_hwnd_, kMsgHaveWork, (WPARAM)this, 0);\n\n  if (ret)\n    return; // There was room in the Window Message queue.\n\n  InterlockedExchange(&have_work_, 0);\n}\n\nvoid MessagePumpForUI::ScheduleDelayedWork(const TimeTicks &delayed_work_time) {\n  delayed_work_time_ = delayed_work_time;\n\n  int delay_msec = GetCurrentDelay();\n\n  assert(delay_msec >= 0);\n\n  if (delay_msec < USER_TIMER_MINIMUM)\n    delay_msec = USER_TIMER_MINIMUM;\n\n  KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));\n  BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),\n                      delay_msec, NULL);\n}\n\nvoid MessagePumpForUI::InitMessageWnd() {\n  std::wstring class_name = base::StringPrintf(kWndClassFormat, this);\n  HINSTANCE instance = GetModuleFromAddress(&WndProcThunk);\n  WNDCLASSEX wc = {0};\n  wc.cbSize = sizeof(wc);\n  wc.lpfnWndProc = WndProcThunk;\n  wc.hInstance = instance;\n  wc.lpszClassName = class_name.c_str();\n  atom_ = RegisterClassEx(&wc);\n  assert(atom_);\n  message_hwnd_ = ::CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0,\n                                 HWND_MESSAGE, 0, instance, 0);\n  assert(message_hwnd_);\n}\n\nbool MessagePumpForUI::ProcessMessageHelper(const MSG &msg) {\n  if (WM_QUIT == msg.message) {\n    // Repost the QUIT message so that it will be retrieved by the primary\n    // GetMessage() loop.\n    keep_running_ = false;\n    PostQuitMessage(static_cast<int>(msg.wParam));\n    return false;\n  }\n\n  WillProcessMessage(msg);\n\n  TranslateMessage(&msg);\n  DispatchMessage(&msg);\n\n  DidProcessMessage(msg);\n  return true;\n}\n\nbool MessagePumpForUI::ProcessNextWindowsMessage() {\n  // If there are sent messages in the queue then PeekMessage internally\n  // dispatches the message and returns false. We return true in this\n  // case to ensure that the message loop peeks again instead of calling\n  // MsgWaitForMultipleObjectsEx again.\n  bool sent_messages_in_queue = false;\n  DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);\n  if (HIWORD(queue_status) & QS_SENDMESSAGE)\n    sent_messages_in_queue = true;\n\n  MSG msg;\n  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE)\n    return ProcessMessageHelper(msg);\n\n  return sent_messages_in_queue;\n}\n// static\nLRESULT CALLBACK MessagePumpForUI::WndProcThunk(HWND hwnd, UINT message,\n                                                WPARAM wparam, LPARAM lparam) {\n  switch (message) {\n  case kMsgHaveWork:\n    reinterpret_cast<MessagePumpForUI *>(wparam)->HandleWorkMessage();\n    break;\n  case WM_TIMER:\n    reinterpret_cast<MessagePumpForUI *>(wparam)->HandleTimerMessage();\n    break;\n  }\n  return DefWindowProc(hwnd, message, wparam, lparam);\n}\n\nvoid MessagePumpForUI::WaitForWork() {\n  int delay = GetCurrentDelay();\n  if (delay < 0) // Negative value means no timers waiting.\n    delay = INFINITE;\n\n  DWORD result;\n  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,\n                                       MWMO_INPUTAVAILABLE);\n\n  if (WAIT_OBJECT_0 == result) {\n    // A WM_* message is available.\n    // If a parent child relationship exists between windows across threads\n    // then their thread inputs are implicitly attached.\n    // This causes the MsgWaitForMultipleObjectsEx API to return indicating\n    // that messages are ready for processing (Specifically, mouse messages\n    // intended for the child window may appear if the child window has\n    // capture).\n    // The subsequent PeekMessages call may fail to return any messages thus\n    // causing us to enter a tight loop at times.\n    // The WaitMessage call below is a workaround to give the child window\n    // some time to process its input messages.\n    MSG msg = {0};\n    DWORD queue_status = GetQueueStatus(QS_MOUSE);\n    if (HIWORD(queue_status) & QS_MOUSE &&\n        !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {\n      WaitMessage();\n    }\n    return;\n  }\n}\n\nvoid MessagePumpForUI::HandleWorkMessage() {\n  InterlockedExchange(&have_work_, 0);\n  delegate_->DoWork();\n}\n\nvoid MessagePumpForUI::HandleTimerMessage() {\n  KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));\n\n  delegate_->DoDelayedWork(&delayed_work_time_);\n  if (!delayed_work_time_.is_null()) {\n    ScheduleDelayedWork(delayed_work_time_);\n  }\n}\n\n// IO\nMessagePumpForIO::MessagePumpForIO(Delegate *delegate) : delegate_(delegate) {\n  port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0));\n  assert(port_.IsValid());\n}\n\nMessagePumpForIO::~MessagePumpForIO() {}\n\nvoid MessagePumpForIO::Run(Delegate *delegate) {\n  assert(delegate_ == NULL || delegate == delegate_);\n  delegate_ = delegate;\n\n  for (;;) {\n    bool more_work_is_plausible = delegate->DoWork();\n    if (!keep_running_)\n      break;\n\n    more_work_is_plausible |= WaitForIOCompletion(0, NULL);\n    if (!keep_running_)\n      break;\n\n    more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time_);\n    if (!keep_running_)\n      break;\n\n    if (more_work_is_plausible)\n      continue;\n\n    more_work_is_plausible = delegate->DoIdleWork();\n    if (!keep_running_)\n      break;\n\n    if (more_work_is_plausible)\n      continue;\n\n    WaitForWork();\n  }\n}\n\nvoid MessagePumpForIO::ScheduleWork() {\n  if (InterlockedExchange(&have_work_, 1))\n    return; // Someone else continued the pumping.\n\n  BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0,\n                                        reinterpret_cast<ULONG_PTR>(this),\n                                        reinterpret_cast<OVERLAPPED *>(this));\n\n  if (ret)\n    return;\n\n  InterlockedExchange(&have_work_, 0);\n}\n\nvoid MessagePumpForIO::ScheduleDelayedWork(const TimeTicks &delayed_work_time) {\n  delayed_work_time_ = delayed_work_time;\n}\n\nvoid MessagePumpForIO::Quit() { keep_running_ = false; }\n\nvoid MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,\n                                         IOHandler *handler) {\n  ULONG_PTR key = HandlerToKey(handler, true);\n  HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 0);\n  assert(port_.Get() == port);\n}\n\nbool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler *filter) {\n  IOItem item;\n  if (!GetIOItem(timeout, &item))\n    return false;\n\n  if (ProcessInternalIOItem(item))\n    return true;\n\n  assert(item.context->handler == item.handler);\n  item.handler->OnIOCompleted(item.context, item.bytes_transfered, item.error);\n\n  return true;\n}\n\nvoid MessagePumpForIO::WaitForWork() {\n  int timeout = GetCurrentDelay();\n  if (timeout < 0) {\n    timeout = INFINITE;\n  }\n\n  WaitForIOCompletion(timeout, NULL);\n}\n\nbool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem *item) {\n  memset(item, 0, sizeof(*item));\n  ULONG_PTR key = NULL;\n  OVERLAPPED *overlapped = NULL;\n  if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,\n                                 &overlapped, timeout)) {\n    if (!overlapped)\n      return false; // Nothing in the queue.\n\n    item->error = GetLastError();\n    item->bytes_transfered = 0;\n  }\n\n  item->handler = KeyToHandler(key, &item->has_valid_io_context);\n  item->context = reinterpret_cast<IOContext *>(overlapped);\n  return true;\n}\n\nbool MessagePumpForIO::ProcessInternalIOItem(const IOItem &item) {\n  if (this == reinterpret_cast<MessagePumpForIO *>(item.context) &&\n      this == reinterpret_cast<MessagePumpForIO *>(item.handler)) {\n    // This is our internal completion.\n    assert(!item.bytes_transfered);\n    InterlockedExchange(&have_work_, 0);\n    return true;\n  }\n  return false;\n}\n\n// static\nULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler *handler,\n                                         bool has_valid_io_context) {\n  ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);\n\n  // |IOHandler| is at least pointer-size aligned, so the lowest two bits are\n  // always cleared. We use the lowest bit to distinguish completion keys with\n  // and without the associated |IOContext|.\n  assert((key & 1) == 0);\n\n  // Mark the completion key as context-less.\n  if (!has_valid_io_context)\n    key = key | 1;\n  return key;\n}\n\n// static\nMessagePumpForIO::IOHandler *\nMessagePumpForIO::KeyToHandler(ULONG_PTR key, bool *has_valid_io_context) {\n  *has_valid_io_context = ((key & 1) == 0);\n  return reinterpret_cast<IOHandler *>(key & ~static_cast<ULONG_PTR>(1));\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/MessagePumpWin.h",
    "content": "#pragma once\n\n#include <windows.h>\n#include \"MessagePump.h\"\n#include \"macros.h\"\n#include \"observer_list.h\"\n#include \"scoped_handle.h\"\n\nnamespace base {\n\nclass MessagePumpWin : public MessagePump {\npublic:\n  class __declspec(novtable) MessagePumpObserver {\n  public:\n    // This method is called before processing a NativeEvent. If the\n    // method returns EVENT_HANDLED, it indicates the event has already\n    // been handled, so the event is not processed any farther. If the\n    // method returns EVENT_CONTINUE, the event dispatching proceeds as\n    // normal.\n    virtual void WillProcessEvent(const MSG &event) = 0;\n\n    // This method is called after processing a message. This method\n    // will not be called if WillProcessEvent returns EVENT_HANDLED.\n    virtual void DidProcessEvent(const MSG &event) = 0;\n\n  protected:\n    virtual ~MessagePumpObserver() {}\n  };\n\n  MessagePumpWin() : keep_running_(true), have_work_(0) {}\n  virtual ~MessagePumpWin() {}\n\n  // Add an Observer, which will start receiving notifications immediately.\n  void AddObserver(MessagePumpObserver *observer);\n\n  // Remove an Observer.  It is safe to call this method while an Observer is\n  // receiving a notification callback.\n  void RemoveObserver(MessagePumpObserver *observer);\n\n  // Give a chance to code processing additional messages to notify the\n  // message loop observers that another message has been processed.\n  void WillProcessMessage(const MSG &msg);\n  void DidProcessMessage(const MSG &msg);\n\n  // MessagePump method:\n  virtual void Quit() override;\n\n  virtual HANDLE io_port() { return NULL; }\n\nprotected:\n  int GetCurrentDelay() const;\n\n  ObserverList<MessagePumpObserver> observers_;\n\n  TimeTicks delayed_work_time_;\n\n  bool keep_running_;\n\n  long have_work_;\n};\n\nclass MessagePumpForUI : public MessagePumpWin {\npublic:\n  MessagePumpForUI(Delegate *delegate = NULL, MessagePumpForUI *upLayer = NULL);\n  virtual ~MessagePumpForUI();\n  // MessagePump methods:\n  virtual void Run(Delegate *delegate) override;\n  virtual void ScheduleWork() override;\n  virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override;\n  Delegate *PumpDelegate() { return delegate_; }\n  bool ProcessNextWindowsMessage();\n  void WaitForWork();\n  void upPumpLayer(MessagePumpForUI *upLayer) { upLayer_ = upLayer; }\n\nprivate:\n  static LRESULT CALLBACK WndProcThunk(HWND window_handle, UINT message,\n                                       WPARAM wparam, LPARAM lparam);\n\n  void InitMessageWnd();\n  bool ProcessMessageHelper(const MSG &msg);\n  void HandleWorkMessage();\n  void HandleTimerMessage();\n\n  // Atom representing the registered window class.\n  ATOM atom_;\n\n  // A hidden message-only window.\n  HWND message_hwnd_;\n\n  Delegate *delegate_;\n\n  MessagePumpForUI *upLayer_;\n\n  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);\n};\n\nclass MessagePumpForIO : public MessagePumpWin {\npublic:\n  struct IOContext;\n\n  class IOHandler {\n  public:\n    virtual ~IOHandler() {}\n\n    virtual void OnIOCompleted(IOContext *context, DWORD bytes_transfered,\n                               DWORD error) = 0;\n  };\n\n  struct IOContext {\n    OVERLAPPED overlapped;\n    IOHandler *handler;\n  };\n\n  MessagePumpForIO(Delegate *delegate = NULL);\n  ~MessagePumpForIO();\n  // MessagePump methods:\n  virtual void Run(Delegate *delegate) override;\n  virtual void Quit() override;\n  virtual void ScheduleWork() override;\n  virtual void ScheduleDelayedWork(const TimeTicks &delayed_work_time) override;\n\n  void RegisterIOHandler(HANDLE file_handle, IOHandler *handler);\n\n  virtual HANDLE io_port() override { return port_.Get(); }\n\nprivate:\n  struct IOItem {\n    IOHandler *handler;\n    IOContext *context;\n    DWORD bytes_transfered;\n    DWORD error;\n\n    // In some cases |context| can be a non-pointer value casted to a pointer.\n    // |has_valid_io_context| is true if |context| is a valid IOContext\n    // pointer, and false otherwise.\n    bool has_valid_io_context;\n  };\n\n  bool WaitForIOCompletion(DWORD timeout, IOHandler *filter);\n  void WaitForWork();\n  bool GetIOItem(DWORD timeout, IOItem *item);\n  bool ProcessInternalIOItem(const IOItem &item);\n\n  // static\n  //  Converts an IOHandler pointer to a completion port key.\n  //  |has_valid_io_context| specifies whether completion packets posted to\n  //  |handler| will have valid OVERLAPPED pointers.\n  static ULONG_PTR HandlerToKey(IOHandler *handler, bool has_valid_io_context);\n\n  // Converts a completion port key to an IOHandler pointer.\n  static IOHandler *KeyToHandler(ULONG_PTR key, bool *has_valid_io_context);\n\n  std::list<IOItem> cmpleted_io_;\n\n  ScopedWinHandle<HandleTraits> port_;\n\n  Delegate *delegate_;\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/PendingTask.cpp",
    "content": "#include \"StdAfx.h\"\n#include \"PendingTask.h\"\n\nnamespace base {\nPendingTask::PendingTask() : task_(NULL), sequence_num_(0) {}\n\nPendingTask::PendingTask(fastdelegate::Task<void> *task)\n    : task_(task), sequence_num_(0) {}\n\nPendingTask::PendingTask(fastdelegate::Task<void> *task,\n                         const TimeTicks delayed_run_time)\n    : task_(task), delayed_run_time_(delayed_run_time), sequence_num_(0) {}\n\nPendingTask::~PendingTask() {}\n\nbool PendingTask::is_null() const { return NULL == task_.get(); }\n\nvoid PendingTask::Reset() { task_ = NULL; }\n\nbool PendingTask::Equals(const PendingTask &other) const {\n  return task_.get() == other.task_.get();\n}\n\nvoid PendingTask::Run() {\n  if (task_.get()) {\n    task_->Run();\n  }\n}\n\nbool PendingTask::operator<(const PendingTask &other) const {\n  // Since the top of a priority queue is defined as the \"greatest\" element, we\n  // need to invert the comparison here.  We want the smaller time to be at the\n  // top of the heap.\n\n  if (delayed_run_time_ < other.delayed_run_time_)\n    return false;\n\n  if (delayed_run_time_ > other.delayed_run_time_)\n    return true;\n\n  // If the times happen to match, then we use the sequence number to decide.\n  // Compare the difference to support integer roll-over.\n  return (sequence_num_ > other.sequence_num_);\n}\n\n// task queue\nnamespace taskqueue {\nbool queue::empty() { return _val.empty(); }\n\nint queue::size() { return _val.size(); }\n\nvoid queue::push_back(const PendingTask &val) {\n  val.sequence_num_ = ++sequence_num_;\n  _val.push_back(val);\n}\n\nPendingTask queue::pick_front() {\n  assert(_val.size());\n  PendingTask o = _val.front();\n  _val.pop_front();\n  return o;\n}\n\nPendingTask queue::front() {\n  assert(_val.size());\n  return _val.front();\n}\n\nvoid queue::swap(taskqueue::queue &val) { _val.swap(val._val); }\n\n} // namespace taskqueue\n\n} // namespace base\n"
  },
  {
    "path": "src/base/PendingTask.h",
    "content": "#pragma once\n\n#include <queue>\n#include <list>\n#include \"../time/time.h\"\n#include \"FastDelegateImpl.h\"\n#include \"ref_counted.h\"\n\nnamespace base {\nclass PendingTask {\npublic:\n  explicit PendingTask();\n  explicit PendingTask(fastdelegate::Task<void> *task);\n  explicit PendingTask(fastdelegate::Task<void> *task,\n                       const TimeTicks delayed_run_time);\n  ~PendingTask();\n\n  bool is_null() const;\n\n  void Reset();\n\n  bool Equals(const PendingTask &other) const;\n\n  void Run();\n  // Used to support sorting.\n  bool operator<(const PendingTask &other) const;\n  // The time when the task should be run.\n  base::TimeTicks delayed_run_time_;\n  // Secondary sort key for run time.\n  mutable unsigned int sequence_num_;\n\nprivate:\n  scoped_refptr<fastdelegate::Task<void> > task_;\n};\n\nnamespace taskqueue {\nclass queue {\npublic:\n  queue() : sequence_num_(0) { _val.clear(); }\n  ~queue() { _val.clear(); }\n  bool empty();\n  int size();\n  void push_back(const PendingTask &task);\n  //_val.empty() is false\n  PendingTask pick_front();\n  PendingTask front();\n  void swap(queue &val);\n\nprivate:\n  std::list<PendingTask> _val;\n  unsigned int sequence_num_;\n};\n\n} // end namespace taskqueue\n\ntypedef std::priority_queue<base::PendingTask> DelayedTaskQueue;\ntypedef taskqueue::queue TaskQueue;\n\n} // namespace base\n"
  },
  {
    "path": "src/base/Thread.cc",
    "content": "#include \"StdAfx.h\"\n#include \"Thread.h\"\n\nnamespace base {\nunsigned int __stdcall ThreadFunc(void *params);\n\nThread::Options::Options()\n    : message_loop_type_(MessageLoop::TYPE_DEFAULT), stack_size_(0) {}\nThread::Options::Options(MessageLoop::Type type, size_t size)\n    : message_loop_type_(type), stack_size_(size) {}\n\nThread::Thread()\n    : com_status_(NONE), started_(false), stopping_(false), running_(false),\n      thread_(NULL), message_loop_(NULL), thread_id_(kInvalidThreadId),\n      startup_data_(NULL), thread_context_(NULL) {}\n\nThread::Thread(const char *name)\n    : com_status_(NONE), started_(false), stopping_(false), running_(false),\n      thread_(NULL), message_loop_(NULL), name_(name),\n      thread_id_(kInvalidThreadId), startup_data_(NULL), thread_context_(NULL) {\n\n}\n\nThread::~Thread() { Stop(); }\n\nbool Thread::StartWithOptions(const Options &options) {\n  assert(!message_loop_);\n  StartupData startup_data(options);\n  startup_data_ = &startup_data;\n  if (!CreateThreadInternal(options.stack_size_, this, &thread_)) {\n    startup_data_ = NULL;\n    return false;\n  }\n  startup_data.event_.Wait();\n  startup_data_ = NULL;\n  started_ = true;\n  assert(message_loop_);\n  return true;\n}\n\nbool Thread::CreateThreadInternal(size_t stack_size, Thread *thread,\n                                  HANDLE *out_thread_handle) {\n  unsigned int flags = 0;\n  if (stack_size > 0)\n    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;\n\n  Thread::ThreadParams *params = new Thread::ThreadParams;\n  params->thread_ = thread;\n\n  HANDLE thread_handle =\n      (HANDLE)_beginthreadex(NULL, stack_size, ThreadFunc, params, flags, NULL);\n  if (NULL == thread_handle) {\n    delete params;\n    return false;\n  }\n  if (out_thread_handle) {\n    *out_thread_handle = thread_handle;\n  } else {\n    CloseHandle(thread_handle);\n  }\n  return true;\n}\n\nvoid Thread::ThreadMain() {\n  std::auto_ptr<MessageLoop> message_loop;\n  message_loop.reset(\n      new MessageLoop(startup_data_->options_.message_loop_type_));\n  assert(message_loop.get());\n\n  thread_id_ = GetCurrentThreadId();\n  message_loop->set_thread_name(name_);\n  message_loop_ = message_loop.get();\n\n  std::auto_ptr<ScopedCOMInitializer> com_initializer;\n  if (com_status_ != NONE) {\n    com_initializer.reset((com_status_ == STA) ? new ScopedCOMInitializer()\n                                               : new ScopedCOMInitializer(MTA));\n  }\n  running_ = true;\n  startup_data_->event_.Signal();\n  Run(message_loop_);\n  running_ = false;\n\n  // Let the thread do extra cleanup.\n  CleanUp();\n  com_initializer.reset();\n\n  message_loop_ = NULL;\n}\n\nvoid Thread::Run(MessageLoop *message_loop) { message_loop->Run(); }\n\nbool Thread::IsRunning() const { return running_; }\n\nvoid Thread::SetPriority(ThreadPriority priority) {\n  switch (priority) {\n  case kThreadPriority_Normal:\n    ::SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);\n    break;\n  case kThreadPriority_RealtimeAudio:\n    ::SetThreadPriority(thread_, THREAD_PRIORITY_TIME_CRITICAL);\n    break;\n  default:\n    break;\n  }\n}\n\nvoid Thread::Stop() {\n  if (!started_)\n    return;\n\n  if (stopping_ || !message_loop_)\n    return;\n\n  stopping_ = true;\n\n  message_loop_->Quit();\n\n  HANDLE thread_handle = thread_;\n  DWORD result = WaitForSingleObject(thread_handle, INFINITE);\n  if (result != WAIT_OBJECT_0) {\n    assert(0);\n  }\n  CloseHandle(thread_handle);\n  assert(!message_loop_);\n  started_ = false;\n  stopping_ = false;\n}\n\nbool Thread::set_thread_name(std::string name) {\n  if (name_.empty()) {\n    name_ = name;\n    return true;\n  }\n  return false;\n}\n\n} // namespace base\n\nnamespace base {\n\nunsigned int __stdcall ThreadFunc(void *params) {\n  Thread::ThreadParams *thread_params =\n      static_cast<Thread::ThreadParams *>(params);\n  base::Thread *thread = thread_params->thread_;\n  delete thread_params;\n\n  thread->ThreadMain();\n\n  return NULL;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/Thread.h",
    "content": "#pragma once\n\n#include <string>\n#include \"../Event/WaitableEvent.h\"\n#include \"MessageLoop.h\"\n\nnamespace base {\nclass Thread final {\npublic:\n  typedef bool (*ThreadContextInit)(void *);\n\n  static const DWORD kInvalidThreadId = 0;\n\n  class Options {\n  public:\n    Options();\n    Options(MessageLoop::Type type, size_t size = 0);\n\n    size_t stack_size_;\n    MessageLoop::Type message_loop_type_;\n  };\n  enum ThreadPriority {\n    kThreadPriority_Normal,\n    // Suitable for low-latency, glitch-resistant audio.\n    kThreadPriority_RealtimeAudio,\n    // Suitable for threads which generate data for the display (at ~60Hz).\n    kThreadPriority_Display,\n    // Suitable for threads that shouldn't disrupt high priority work.\n    kThreadPriority_Background\n  };\n\n  enum ComStatus {\n    NONE,\n    STA,\n    MTA,\n  };\n  class ScopedCOMInitializer {\n  public:\n    ScopedCOMInitializer() : thread_id_(Thread::kInvalidThreadId) {\n      Initialize(COINIT_APARTMENTTHREADED);\n    }\n    explicit ScopedCOMInitializer(ComStatus mta)\n        : thread_id_(Thread::kInvalidThreadId) {\n      Initialize(COINIT_MULTITHREADED);\n    }\n    ~ScopedCOMInitializer() {\n      assert(GetCurrentThreadId() == thread_id_);\n      CoUninitialize();\n    }\n\n  private:\n    void Initialize(COINIT init) {\n      thread_id_ = GetCurrentThreadId();\n      CoInitializeEx(NULL, init);\n    }\n    // tid\n    DWORD thread_id_;\n  };\n\n  class StartupData {\n  public:\n    const Options &options_;\n    WaitableEvent event_;\n\n    explicit StartupData(const Options &options)\n        : options_(options), event_(false, false) {}\n  };\n\n  class ThreadParams {\n  public:\n    Thread *thread_;\n  };\n  explicit Thread();\n  explicit Thread(const char *name);\n  virtual ~Thread();\n\n  bool StartWithOptions(const Options &options);\n  void Stop();\n  MessageLoop *message_loop() const { return message_loop_; }\n  const std::string &thread_name() const { return name_; }\n  bool set_thread_name(std::string name);\n  HANDLE thread_handle() { return thread_; }\n  DWORD thread_id() { return thread_id_; }\n  bool IsRunning() const;\n  void SetPriority(ThreadPriority priority);\n\n  void init_com_with_mta(bool use_mta) {\n    assert(!started_);\n    com_status_ = use_mta ? MTA : STA;\n  }\n\n  virtual void ThreadMain();\n\n  // static\n  static bool CreateThreadInternal(size_t stack_size, Thread *thread,\n                                   HANDLE *out_thread_handle);\n\nprotected:\n  virtual void CleanUp() {}\n\nprivate:\n  void Run(MessageLoop *message_loop);\n\n  MessageLoop *message_loop_;\n  HANDLE thread_;\n  std::string name_;\n  DWORD thread_id_;\n  // Whether we successfully started the thread.\n  bool started_;\n\n  // If true, we're in the middle of stopping, and shouldn't access\n  // |message_loop_|. It may non-NULL and invalid.\n  bool stopping_;\n\n  // True while inside of Run().\n  bool running_;\n\n  ComStatus com_status_;\n\n  StartupData *startup_data_;\n\n  ThreadContextInit thread_context_;\n\n  DISALLOW_COPY_AND_ASSIGN(Thread);\n};\n} // namespace base\n"
  },
  {
    "path": "src/base/WeakPtr.cc",
    "content": "#include \"StdAfx.h\"\n#include \"WeakPtr.h\"\n\nnamespace base {\nWeakReference::Flag::~Flag() {}\n\nWeakReference::WeakReference() {}\n\nWeakReference::WeakReference(const Flag *flag) : flag_(flag) {}\n\nWeakReference::~WeakReference() {}\n\nbool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); }\n\nWeakReferenceOwner::WeakReferenceOwner() {}\n\nWeakReferenceOwner::~WeakReferenceOwner() { Invalidate(); }\n\nWeakReference WeakReferenceOwner::GetRef() const {\n  // If we hold the last reference to the Flag then create a new one.\n  if (!HasRefs())\n    flag_ = new WeakReference::Flag();\n\n  return WeakReference(flag_.get());\n}\n\nvoid WeakReferenceOwner::Invalidate() {\n  if (flag_.get()) {\n    flag_->Invalidate();\n    flag_ = NULL;\n  }\n}\n\n} // end namespace base\n"
  },
  {
    "path": "src/base/WeakPtr.h",
    "content": "#pragma once\n\n#include \"macros.h\"\n#include \"WrapperObj.h\"\n#include \"ref_counted.h\"\n\nnamespace base {\nclass WeakReference {\npublic:\n  // Although Flag is bound to a specific thread, it may be deleted from another\n  // via base::WeakPtr::~WeakPtr().\n  class Flag : public RefCountedThreadSafe<Flag> {\n  public:\n    Flag() : is_valid_(true) {}\n\n    void Invalidate() { is_valid_ = false; }\n    bool IsValid() const { return is_valid_; }\n\n  private:\n    friend class base::RefCountedThreadSafe<Flag>;\n\n    ~Flag();\n\n    bool is_valid_;\n  };\n\n  WeakReference();\n  explicit WeakReference(const Flag *flag);\n  ~WeakReference();\n\n  bool is_valid() const;\n\nprivate:\n  scoped_refptr<const Flag> flag_;\n};\n\nclass WeakReferenceOwner {\npublic:\n  WeakReferenceOwner();\n  ~WeakReferenceOwner();\n\n  WeakReference GetRef() const;\n\n  bool HasRefs() const { return flag_.get() && !flag_->HasOneRef(); }\n\n  void Invalidate();\n\nprivate:\n  mutable scoped_refptr<WeakReference::Flag> flag_;\n};\n\ntemplate <typename T> class WeakPtr : public ObjWrapper<T> {\npublic:\n  WeakPtr() : ptr_(NULL) {}\n  explicit WeakPtr(WeakReference &ref, T *o);\n  T *get() const override { return ref_.is_valid() ? ptr_ : NULL; }\n  void AddRef() const override {}\n  void Release() const override {}\n  bool IsWeakPtr() const override;\n\n  T &operator*() const {\n    assert(get() != NULL);\n    return *get();\n  }\n  T *operator->() const {\n    assert(get() != NULL);\n    return get();\n  }\n\n  WeakReference ref_;\n  T *ptr_;\n};\n\ntemplate <typename T>\nWeakPtr<T>::WeakPtr(WeakReference &ref, T *o) : ref_(ref), ptr_(o) {}\n\ntemplate <typename T> bool WeakPtr<T>::IsWeakPtr() const { return true; }\n\n// A class may extend from SupportsWeakPtr to let others take weak pointers to\n// it. This avoids the class itself implementing boilerplate to dispense weak\n// pointers.  However, since SupportsWeakPtr's destructor won't invalidate\n// weak pointers to the class until after the derived class' members have been\n// destroyed, its use can lead to subtle use-after-destroy issues.\ntemplate <class T> class SupportsWeakPtr {\npublic:\n  SupportsWeakPtr() {}\n\n  // for posttask\n  WeakPtr<T> *BldWeakPtr() {\n    return new WeakPtr<T>(weak_reference_owner_.GetRef(),\n                          static_cast<T *>(this));\n  }\n\n  WeakPtr<T> AsWeakPtr() {\n    return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T *>(this));\n  }\n\nprotected:\n  ~SupportsWeakPtr() {}\n\nprivate:\n  WeakReferenceOwner weak_reference_owner_;\n  DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr);\n};\n\n} // end namespace base\n"
  },
  {
    "path": "src/base/WrapperObj.h",
    "content": "#pragma once\n\n// weakprt\n// ref count\n// Unretained\nnamespace base {\n\ntemplate <typename T> class __declspec(novtable) ObjWrapper {\npublic:\n  virtual T *get() const = 0;\n  virtual void AddRef() const = 0;\n  virtual void Release() const = 0;\n  virtual bool IsWeakPtr() const = 0;\n};\n\ntemplate <typename T> class NormalWrapper : public ObjWrapper<T> {\npublic:\n  explicit NormalWrapper(T *o) : ptr_(o) {}\n  virtual T *get() const override { return ptr_; }\n  virtual void AddRef() const override { ptr_->AddRef(); }\n  virtual void Release() const override { ptr_->Release(); }\n  virtual bool IsWeakPtr() const override { return false; }\n\nprivate:\n  T *ptr_;\n};\n\ntemplate <typename T> class UnretainedWrapper : public ObjWrapper<T> {\npublic:\n  explicit UnretainedWrapper(T *o) : ptr_(o) {}\n  T *get() const override { return ptr_; }\n  void AddRef() const override {}\n  void Release() const override {}\n  bool IsWeakPtr() const override { return false; }\n\nprivate:\n  T *ptr_;\n};\n\ntemplate <typename T> static inline UnretainedWrapper<T> *Unretained(T *o) {\n  return new UnretainedWrapper<T>(o);\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/aligned_memory.h",
    "content": "#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_\n#define BASE_MEMORY_ALIGNED_MEMORY_H_\n\n#include <malloc.h>\n\nnamespace base {\n// AlignedMemory is specialized for all supported alignments.\n// Make sure we get a compiler error if someone uses an unsupported alignment.\ntemplate <size_t Size, size_t ByteAlignment> struct AlignedMemory {};\n\n#define BASE_DECL_ALIGNED_MEMORY(byte_alignment)                               \\\n  template <size_t Size> class AlignedMemory<Size, byte_alignment> {           \\\n  public:                                                                      \\\n    __declspec(align(byte_alignment)) unsigned char data_[Size];               \\\n    void *void_data() { return static_cast<void *>(data_); }                   \\\n    const void *void_data() const { return static_cast<const void *>(data_); } \\\n    template <typename Type> Type *data_as() {                                 \\\n      return static_cast<Type *>(void_data());                                 \\\n    }                                                                          \\\n    template <typename Type> const Type *data_as() const {                     \\\n      return static_cast<const Type *>(void_data());                           \\\n    }                                                                          \\\n                                                                               \\\n  private:                                                                     \\\n    void *operator new(size_t);                                                \\\n    void operator delete(void *);                                              \\\n  }\n\n// Specialization for all alignments is required because MSVC (as of VS 2008)\n// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).\n// Greater than 4096 alignment is not supported by some compilers, so 4096 is\n// the maximum specified here.\nBASE_DECL_ALIGNED_MEMORY(1);\nBASE_DECL_ALIGNED_MEMORY(2);\nBASE_DECL_ALIGNED_MEMORY(4);\nBASE_DECL_ALIGNED_MEMORY(8);\nBASE_DECL_ALIGNED_MEMORY(16);\nBASE_DECL_ALIGNED_MEMORY(32);\nBASE_DECL_ALIGNED_MEMORY(64);\nBASE_DECL_ALIGNED_MEMORY(128);\nBASE_DECL_ALIGNED_MEMORY(256);\nBASE_DECL_ALIGNED_MEMORY(512);\nBASE_DECL_ALIGNED_MEMORY(1024);\nBASE_DECL_ALIGNED_MEMORY(2048);\nBASE_DECL_ALIGNED_MEMORY(4096);\n\n} // namespace base\n\n#endif // BASE_MEMORY_ALIGNED_MEMORY_H_\n"
  },
  {
    "path": "src/base/at_exist.cc",
    "content": "#include \"StdAfx.h\"\n#include \"at_exist.h\"\n\nnamespace base {\nstatic AtExitManager *g_top_manager = nullptr;\n\nAtExitManager::AtExitManager() { g_top_manager = this; }\n\nAtExitManager::~AtExitManager() {\n  assert(this == g_top_manager);\n\n  ProcessCallbacksNow();\n\n  g_top_manager = nullptr;\n}\n\n// static\nvoid AtExitManager::RegisterCallback(AtExitCallbackType func, void *param) {\n  assert(func);\n  RegisterTask(base::Bind(func, param));\n}\n\n// static\nvoid AtExitManager::RegisterTask(fastdelegate::Task<void> *task) {\n  if (!g_top_manager) {\n    assert(0);\n    return;\n  }\n\n  AutoCritSecLock<CriticalSection> lock(g_top_manager->m_cs, false);\n  lock.Lock();\n  g_top_manager->stack_.push(task);\n}\n\n// static\nvoid AtExitManager::ProcessCallbacksNow() {\n  if (!g_top_manager) {\n    assert(0);\n    return;\n  }\n\n  AutoCritSecLock<CriticalSection> lock(g_top_manager->m_cs, false);\n  lock.Lock();\n\n  while (!g_top_manager->stack_.empty()) {\n    std::auto_ptr<fastdelegate::Task<void>> task(g_top_manager->stack_.top());\n    task->Run();\n    g_top_manager->stack_.pop();\n  }\n}\n} // namespace base\n"
  },
  {
    "path": "src/base/at_exist.h",
    "content": "#pragma once\n\n#include <stack>\n#include <util/util_tools.h>\n#include \"FastDelegateImpl.h\"\n\nnamespace base {\nclass AtExitManager {\npublic:\n  typedef void (*AtExitCallbackType)(void *);\n  AtExitManager();\n\n  // The dtor calls all the registered callbacks. Do not try to register more\n  // callbacks after this point.\n  ~AtExitManager();\n\n  static void RegisterCallback(AtExitCallbackType func, void *param);\n  // Registers the specified task to be called at exit.\n  static void RegisterTask(fastdelegate::Task<void> *task);\n  // Calls the functions registered with RegisterCallback in LIFO order. It\n  // is possible to register new callbacks after calling this function.\n  static void ProcessCallbacksNow();\n\nprivate:\n  CriticalSection m_cs;\n  std::stack<fastdelegate::Task<void> *> stack_;\n\n  DISALLOW_COPY_AND_ASSIGN(AtExitManager);\n};\n} // namespace base\n"
  },
  {
    "path": "src/base/common_threads.cc",
    "content": "#include \"StdAfx.h\"\n#include \"common_threads.h\"\n\nnamespace base {\nMessageLoop *Threads::threads_[Threads::COUNT] = { 0 };\n\nMessageLoop *Threads::Get(ThreadType type) { return Threads::threads_[type]; }\n\nvoid Threads::Set(ThreadType type, MessageLoop *loop) {\n  assert(type < Threads::COUNT && !Threads::threads_[type]);\n  Threads::threads_[type] = loop;\n}\n} // namespace base\n"
  },
  {
    "path": "src/base/common_threads.h",
    "content": "#pragma once\n\n#include \"MessageLoop.h\"\n\nnamespace base {\nclass MessageLoop;\n\nclass Threads {\npublic:\n  enum ThreadType {\n    UI = 0,\n    IO,\n    FILE,\n    DB,\n    COUNT,\n  };\n\n  static MessageLoop *Get(ThreadType type);\n  static void Set(ThreadType type, MessageLoop *loop);\n\nprivate:\n  static MessageLoop *threads_[COUNT];\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/lazy_instance.cc",
    "content": "#include \"StdAfx.h\"\n#include \"lazy_instance.h\"\n\nnamespace base {\nvoid CompleteLazyInstance(intptr_t *state, intptr_t new_instance,\n                          void *lazy_instance, void (*dtor)(void *)) {\n\n  *state = new_instance;\n\n  // Make sure that the lazily instantiated object will get destroyed at exit.\n  if (dtor)\n    AtExitManager::RegisterCallback(dtor, lazy_instance);\n}\n} // namespace base\n"
  },
  {
    "path": "src/base/lazy_instance.h",
    "content": "#pragma once\n\n#include \"aligned_memory.h\"\n#include \"at_exist.h\"\n\n#define LAZY_INSTANCE_INITIALIZER  { 0 }\n\nnamespace base {\nvoid CompleteLazyInstance(intptr_t *state, intptr_t new_instance,\n                          void *lazy_instance, void (*dtor)(void *));\n\ntemplate <typename Type> struct DefaultLazyInstanceTraits {\n\n  static Type *New(void *instance) { return new (instance) Type(); }\n  static void Delete(Type *instance) {\n    // Explicitly call the destructor.\n    instance->~Type();\n  }\n};\n\ntemplate <typename Type, typename Traits = DefaultLazyInstanceTraits<Type>>\nclass LazyInstance {\npublic:\n  // Do not define a destructor, as doing so makes LazyInstance a\n  // non-POD-struct. We don't want that because then a static initializer will\n  // be created to register the (empty) destructor with atexit() under MSVC, for\n  // example. We handle destruction of the contained Type class explicitly via\n  // the OnExit member function, where needed.\n  // ~LazyInstance() {}\n\n  Type &Get() { return *Pointer(); }\n\n  Type *Pointer() {\n\n    // We will hopefully have fast access when the instance is already created.\n    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating\n    // at most once, the load is taken out of NeedsInstance() as a fast-path.\n    // The load has acquire memory ordering as a thread which sees\n    // private_instance_ > creating needs to acquire visibility over\n    // the associated data (private_buf_). Pairing Release_Store is in\n    // CompleteLazyInstance().\n    intptr_t value = private_instance_;\n    if (!value) {\n      // Create the instance in the space provided by |private_buf_|.\n      value = reinterpret_cast<intptr_t>(Traits::New(private_buf_.void_data()));\n      CompleteLazyInstance(&private_instance_, value, this, OnExit);\n    }\n\n    return instance();\n  }\n\n  bool operator==(Type *p) {\n    switch\n      private_instance_ {\n      case 0:\n        return p == NULL;\n      default:\n        return p == instance();\n      }\n  }\n\n  // Effectively private: member data is only public to allow the linker to\n  // statically initialize it and to maintain a POD class. DO NOT USE FROM\n  // OUTSIDE THIS CLASS.\n\n  intptr_t private_instance_;\n  // Preallocated space for the Type instance.\n  base::AlignedMemory<sizeof(Type), __alignof(Type)> private_buf_;\n\nprivate:\n  Type *instance() { return reinterpret_cast<Type *>(private_instance_); }\n\n  // Adapter function for use with AtExit.  This should be called single\n  // threaded, so don't synchronize across threads.\n  // Calling OnExit while the instance is in use by other threads is a mistake.\n  static void OnExit(void *lazy_instance) {\n    LazyInstance<Type, Traits> *me =\n        reinterpret_cast<LazyInstance<Type, Traits> *>(lazy_instance);\n    Traits::Delete(me->instance());\n    me->private_instance_ = 0;\n  }\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/macros.h",
    "content": "#pragma once\n\n#define DISALLOW_COPY_AND_ASSIGN(TypeName)        \\\n    TypeName(const TypeName &);                   \\\n    TypeName(const TypeName &&);                  \\\n    void operator=(const TypeName&);\n\n#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)  \\\n  TypeName();                                     \\\n  DISALLOW_COPY_AND_ASSIGN(TypeName)\n\ntemplate <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];\n#define arraysize(array) (sizeof(ArraySizeHelper(array)))\n\n#if defined(COMPILER_GCC)\n#define GG_VA_COPY(a, b) (va_copy(a, b))\n#elif defined(COMPILER_MSVC)\n#define GG_VA_COPY(a, b) (a = b)\n#endif\n\n#define DCHECK_GE(a, b) assert((a) >= (b));\n#define DCHECK_LE(a, b) assert((a) <= (b));\n#define DCHECK_NE(a, b) assert((a) != (b));\n#define DCHECK_EQ(a, b) assert((a) == (b));\n#define CHECK(x) assert(x);\n"
  },
  {
    "path": "src/base/notification_details.h",
    "content": "#pragma once\n\nnamespace base {\n\n// Do not declare a NotificationDetails directly--use either\n// \"Details<detailsclassname>(detailsclasspointer)\" or\n// NotificationService::NoDetails().\nclass NotificationDetails {\npublic:\n  NotificationDetails() : ptr_(NULL) {}\n  NotificationDetails(const NotificationDetails &other) : ptr_(other.ptr_) {}\n  ~NotificationDetails() {}\n\n  // NotificationDetails can be used as the index for a map; this method\n  // returns the pointer to the current details as an identifier, for use as a\n  // map index.\n  uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); }\n\n  bool operator!=(const NotificationDetails &other) const {\n    return ptr_ != other.ptr_;\n  }\n\n  bool operator==(const NotificationDetails &other) const {\n    return ptr_ == other.ptr_;\n  }\n\nprotected:\n  explicit NotificationDetails(const void *ptr) : ptr_(ptr) {}\n\n  // Declaring this const allows Details<T> to be used with both T = Foo and\n  // T = const Foo.\n  const void *ptr_;\n};\n\ntemplate <class T> class Details : public NotificationDetails {\npublic:\n  // TODO(erg): Our code hard relies on implicit conversion\n  Details(T *ptr) : NotificationDetails(ptr) {} // NOLINT\n  Details(const NotificationDetails &other)     // NOLINT\n      : NotificationDetails(other) {}\n\n  T *operator->() const { return ptr(); }\n  // The casts here allow this to compile with both T = Foo and T = const Foo.\n  T *ptr() const { return static_cast<T *>(const_cast<void *>(ptr_)); }\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_observer.h",
    "content": "#pragma once\n\nnamespace base {\n\nclass NotificationDetails;\nclass NotificationSource;\n\n// This is the base class for notification observers. When a matching\n// notification is posted to the notification service, Observe is called.\nclass NotificationObserver {\npublic:\n  virtual void Observe(int type, const NotificationSource &source,\n                       const NotificationDetails &details) = 0;\n\nprotected:\n  virtual ~NotificationObserver() {}\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_registrar.cc",
    "content": "#include \"StdAfx.h\"\n#include \"notification_registrar.h\"\n\nnamespace base {\n\nstruct NotificationRegistrar::Record {\n  bool operator==(const Record &other) const;\n\n  NotificationObserver *observer;\n  int type;\n  NotificationSource source;\n};\n\nbool NotificationRegistrar::Record::operator==(const Record &other) const {\n  return observer == other.observer && type == other.type &&\n         source == other.source;\n}\n\nNotificationRegistrar::NotificationRegistrar() {\n  // Force the NotificationService to be constructed (if it isn't already).\n  // This ensures the NotificationService will be registered on the\n  // AtExitManager before any objects which access it via NotificationRegistrar.\n  // This in turn means it will be destroyed after these objects, so they will\n  // never try to access the NotificationService after it's been destroyed.\n  NotificationService::current();\n}\n\nNotificationRegistrar::~NotificationRegistrar() { RemoveAll(); }\n\nvoid NotificationRegistrar::Add(NotificationObserver *observer, int type,\n                                const NotificationSource &source) {\n  Record record = {observer, type, source};\n  registered_.push_back(record);\n\n  NotificationService::current()->AddObserver(observer, type, source);\n}\n\nvoid NotificationRegistrar::Remove(NotificationObserver *observer, int type,\n                                   const NotificationSource &source) {\n\n  Record record = {observer, type, source};\n  RecordVector::iterator found =\n      std::find(registered_.begin(), registered_.end(), record);\n  if (found == registered_.end()) {\n    assert(0);\n    //\"Trying to remove unregistered observer of type \"\n    return;\n  }\n  registered_.erase(found);\n\n  // This can be NULL if our owner outlives the NotificationService, e.g. if our\n  // owner is a Singleton.\n  NotificationService *service = NotificationService::current();\n  if (service)\n    service->RemoveObserver(observer, type, source);\n}\n\nvoid NotificationRegistrar::RemoveAll() {\n  // Early-exit if no registrations, to avoid calling\n  // NotificationService::current.  If we've constructed an object with a\n  // NotificationRegistrar member, but haven't actually used the notification\n  // service, and we reach prgram exit, then calling current() below could try\n  // to initialize the service's lazy TLS pointer during exit, which throws\n  // wrenches at things.\n  if (registered_.empty())\n    return;\n\n  // This can be NULL if our owner outlives the NotificationService, e.g. if our\n  // owner is a Singleton.\n  NotificationService *service = NotificationService::current();\n  if (service) {\n    for (size_t i = 0; i < registered_.size(); i++) {\n      service->RemoveObserver(registered_[i].observer, registered_[i].type,\n                              registered_[i].source);\n    }\n  }\n  registered_.clear();\n}\n\nbool NotificationRegistrar::IsEmpty() const { return registered_.empty(); }\n\nbool NotificationRegistrar::IsRegistered(NotificationObserver *observer,\n                                         int type,\n                                         const NotificationSource &source) {\n  Record record = {observer, type, source};\n  return std::find(registered_.begin(), registered_.end(), record) !=\n         registered_.end();\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_registrar.h",
    "content": "#pragma once\n\n#include <algorithm>\n#include <stdlib.h>\n#include \"macros.h\"\n#include \"notification_observer.h\"\n#include \"notification_service.h\"\n#include \"observer_list.h\"\n\nnamespace base {\n\nclass NotificationObserver;\nclass NotificationSource;\n\n// Aids in registering for notifications and ensures that all registered\n// notifications are unregistered when the class is destroyed.\n//\n// The intended use is that you make a NotificationRegistrar member in your\n// class and use it to register your notifications instead of going through the\n// notification service directly. It will automatically unregister them for\n// you.\nclass NotificationRegistrar {\npublic:\n  // This class must not be derived from (we don't have a virtual destructor so\n  // it won't work). Instead, use it as a member in your class.\n  NotificationRegistrar();\n  ~NotificationRegistrar();\n\n  // Wrappers around NotificationService::[Add|Remove]Observer.\n  void Add(NotificationObserver *observer, int type,\n           const NotificationSource &source);\n  void Remove(NotificationObserver *observer, int type,\n              const NotificationSource &source);\n\n  // Unregisters all notifications.\n  void RemoveAll();\n\n  // Returns true if no notifications are registered.\n  bool IsEmpty() const;\n\n  // Returns true if there is already a registered notification with the\n  // specified details.\n  bool IsRegistered(NotificationObserver *observer, int type,\n                    const NotificationSource &source);\n\nprivate:\n  struct Record;\n\n  // We keep registered notifications in a simple vector. This means we'll do\n  // brute-force searches when removing them individually, but individual\n  // removal is uncommon, and there will typically only be a couple of\n  // notifications anyway.\n  typedef std::vector<Record> RecordVector;\n\n  // Lists all notifications we're currently registered for.\n  RecordVector registered_;\n\n  DISALLOW_COPY_AND_ASSIGN(NotificationRegistrar);\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_service.cc",
    "content": "#include \"StdAfx.h\"\n#include \"lazy_instance.h\"\n#include \"notification_observer.h\"\n#include \"notification_types.h\"\n#include \"notification_service.h\"\n\nnamespace base {\n\nnamespace {\nbase::LazyInstance<NotificationService> lazy_tls_ptr =\n    LAZY_INSTANCE_INITIALIZER;\n} // namespace\n\nNotificationService *NotificationService::current() {\n  return lazy_tls_ptr.Pointer();\n}\n\nNotificationService::~NotificationService() {\n  for (int i = 0; i < static_cast<int>(observer_counts_.size()); i++) {\n    if (observer_counts_[i] > 0) {\n      //\"notification observer(s) leaked \"\n      assert(0);\n    }\n  }\n\n  for (int i = 0; i < static_cast<int>(observers_.size()); i++) {\n    NotificationSourceMap omap = observers_[i];\n    for (NotificationSourceMap::iterator it = omap.begin(); it != omap.end();\n         ++it)\n      delete it->second;\n  }\n}\n\nvoid NotificationService::Notify(int type, const NotificationSource &source,\n                                 const NotificationDetails &details) {\n  // There's no particular reason for the order in which the different\n  // classes of observers get notified here.\n\n  // Notify observers of all types and all sources\n  if (HasKey(observers_[NOTIFICATION_ALL], AllSources()) &&\n      source != AllSources()) {\n    FOR_EACH_OBSERVER(NotificationObserver,\n                      *observers_[NOTIFICATION_ALL][AllSources().map_key()],\n                      Observe(type, source, details));\n  }\n\n  // Notify observers of all types and the given source\n  if (HasKey(observers_[NOTIFICATION_ALL], source)) {\n    FOR_EACH_OBSERVER(NotificationObserver,\n                      *observers_[NOTIFICATION_ALL][source.map_key()],\n                      Observe(type, source, details));\n  }\n\n  // Notify observers of the given type and all sources\n  if (HasKey(observers_[type], AllSources()) && source != AllSources()) {\n    FOR_EACH_OBSERVER(NotificationObserver,\n                      *observers_[type][AllSources().map_key()],\n                      Observe(type, source, details));\n  }\n\n  // Notify observers of the given type and the given source\n  if (HasKey(observers_[type], source)) {\n    FOR_EACH_OBSERVER(NotificationObserver, *observers_[type][source.map_key()],\n                      Observe(type, source, details));\n  }\n}\n\n// static\nbool NotificationService::HasKey(const NotificationSourceMap &map,\n                                 const NotificationSource &source) {\n  return map.find(source.map_key()) != map.end();\n}\n\nvoid NotificationService::AddObserver(NotificationObserver *observer, int type,\n                                      const NotificationSource &source) {\n  // We have gotten some crashes where the observer pointer is NULL. The problem\n  // is that this happens when we actually execute a notification, so have no\n  // way of knowing who the bad observer was. We want to know when this happens\n  // in release mode so we know what code to blame the crash on (since this is\n  // guaranteed to crash later).\n  assert(observer);\n\n  NotificationObserverList *observer_list;\n  if (HasKey(observers_[type], source)) {\n    observer_list = observers_[type][source.map_key()];\n  } else {\n    observer_list = new NotificationObserverList;\n    observers_[type][source.map_key()] = observer_list;\n  }\n\n  observer_list->AddObserver(observer);\n\n  ++observer_counts_[type];\n}\n\nvoid NotificationService::RemoveObserver(NotificationObserver *observer,\n                                         int type,\n                                         const NotificationSource &source) {\n  // This is a very serious bug.  An object is most likely being deleted on\n  // the wrong thread, and as a result another thread's NotificationServiceImpl\n  // has its deleted pointer in its map.  A garbge object will be called in the\n  // future.\n  // NOTE: when this check shows crashes, use BrowserThread::DeleteOnIOThread or\n  // other variants as the trait on the object.\n  assert(HasKey(observers_[type], source));\n\n  NotificationObserverList *observer_list = observers_[type][source.map_key()];\n  if (observer_list) {\n    observer_list->RemoveObserver(observer);\n    if (!observer_list->size()) {\n      observers_[type].erase(source.map_key());\n      delete observer_list;\n    }\n    --observer_counts_[type];\n  }\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_service.h",
    "content": "#pragma once\n\n#include <map>\n#include \"macros.h\"\n#include \"observer_list.h\"\n#include \"notification_details.h\"\n#include \"notification_source.h\"\n\nnamespace base {\n\nclass NotificationObserver;\nclass NotificationRegistrar;\n\nclass NotificationService {\n\npublic:\n  // static\n  static NotificationService *current();\n\n  virtual ~NotificationService();\n\n  NotificationService() {}\n  // Synchronously posts a notification to all interested observers.\n  // Source is a reference to a NotificationSource object representing\n  // the object originating the notification (can be\n  // NotificationService::AllSources(), in which case\n  // only observers interested in all sources will be notified).\n  // Details is a reference to an object containing additional data about\n  // the notification.  If no additional data is needed, NoDetails() is used.\n  // There is no particular order in which the observers will be notified.\n  void Notify(int type, const NotificationSource &source,\n              const NotificationDetails &details);\n\n  // Returns a NotificationSource that represents all notification sources\n  // (for the purpose of registering an observer for events from all sources).\n  static Source<void> AllSources() { return Source<void>(NULL); }\n\n  // Returns a NotificationDetails object that represents a lack of details\n  // associated with a notification.  (This is effectively a null pointer.)\n  static Details<void> NoDetails() { return Details<void>(NULL); }\n\nprivate:\n  friend class NotificationRegistrar;\n\n  typedef ObserverList<NotificationObserver> NotificationObserverList;\n  typedef std::map<uintptr_t, NotificationObserverList *> NotificationSourceMap;\n  typedef std::map<int, NotificationSourceMap> NotificationObserverMap;\n  typedef std::map<int, int> NotificationObserverCount;\n\n  // Convenience function to determine whether a source has a\n  // NotificationObserverList in the given map;\n  static bool HasKey(const NotificationSourceMap &map,\n                     const NotificationSource &source);\n\n  // NOTE: Rather than using this directly, you should use a\n  // NotificationRegistrar.\n  //\n  // Registers a NotificationObserver to be called whenever a matching\n  // notification is posted.  Observer is a pointer to an object subclassing\n  // NotificationObserver to be notified when an event matching the other two\n  // parameters is posted to this service.  Type is the type of events to be\n  // notified about (or NOTIFICATION_ALL to receive events of all\n  // types).\n  // Source is a NotificationSource object (created using\n  // \"Source<classname>(pointer)\"), if this observer only wants to\n  // receive events from that object, or NotificationService::AllSources()\n  // to receive events from all sources.\n  //\n  // A given observer can be registered only once for each combination of\n  // type and source.  If the same object is registered more than once,\n  // it must be removed for each of those combinations of type and source later.\n  //\n  // The caller retains ownership of the object pointed to by observer.\n  void AddObserver(NotificationObserver *observer, int type,\n                   const NotificationSource &source);\n\n  // NOTE: Rather than using this directly, you should use a\n  // NotificationRegistrar.\n  //\n  // Removes the object pointed to by observer from receiving notifications\n  // that match type and source.  If no object matching the parameters is\n  // currently registered, this method is a no-op.\n  void RemoveObserver(NotificationObserver *observer, int type,\n                      const NotificationSource &source);\n\n  // Keeps track of the observers for each type of notification.\n  // Until we get a prohibitively large number of notification types,\n  // a simple array is probably the fastest way to dispatch.\n  NotificationObserverMap observers_;\n\n  // Used to check to see that AddObserver and RemoveObserver calls are\n  // balanced.\n  NotificationObserverCount observer_counts_;\n\n  static NotificationService *server_;\n\n  DISALLOW_COPY_AND_ASSIGN(NotificationService);\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_source.h",
    "content": "#pragma once\n\nnamespace base {\n// Do not declare a NotificationSource directly--use either\n// \"Source<sourceclassname>(sourceclasspointer)\" or\n// NotificationService::AllSources().\nclass NotificationSource {\npublic:\n  NotificationSource(const NotificationSource &other) : ptr_(other.ptr_) {}\n  ~NotificationSource() {}\n\n  // NotificationSource can be used as the index for a map; this method\n  // returns the pointer to the current source as an identifier, for use as a\n  // map index.\n  uintptr_t map_key() const { return reinterpret_cast<uintptr_t>(ptr_); }\n\n  bool operator!=(const NotificationSource &other) const {\n    return ptr_ != other.ptr_;\n  }\n  bool operator==(const NotificationSource &other) const {\n    return ptr_ == other.ptr_;\n  }\n\nprotected:\n  explicit NotificationSource(const void *ptr) : ptr_(ptr) {}\n\n  // Declaring this const allows Source<T> to be used with both T = Foo and\n  // T = const Foo.\n  const void *ptr_;\n};\n\ntemplate <class T> class Source : public NotificationSource {\npublic:\n  // TODO(erg): Our code hard relies on implicit conversion\n  Source(const T *ptr) : NotificationSource(ptr) {} // NOLINT\n  Source(const NotificationSource &other)           // NOLINT\n      : NotificationSource(other) {}\n\n  T *operator->() const { return ptr(); }\n  // The casts here allow this to compile with both T = Foo and T = const Foo.\n  T *ptr() const { return static_cast<T *>(const_cast<void *>(ptr_)); }\n};\n} // namespace base\n"
  },
  {
    "path": "src/base/notification_types.h",
    "content": "#pragma once\n\nnamespace base {\n\nenum NotificationType {\n\n  NOTIFICATION_START = 0,\n\n  // Special signal value to represent an interest in all notifications.\n  // Not valid when posting a notification.\n  NOTIFICATION_ALL = NOTIFICATION_START,\n\n  // Add your code here\n\n  // Custom notifications used by the embedder should start from here.\n  NOTIFICATION_END,\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/observer_list.h",
    "content": "#pragma once\n\n#include \"WeakPtr.h\"\n#include <algorithm>\n#include <limits>\n#include <vector>\n\nnamespace base {\ntemplate <class ObserverType>\nclass ObserverListBase\n    : public base::SupportsWeakPtr<ObserverListBase<ObserverType>> {\npublic:\n  ObserverListBase() : remov_count_(0) {}\n\n  // An iterator class that can be used to access the list of observers.  See\n  // also the FOR_EACH_OBSERVER macro defined below.\n  class Iterator {\n  public:\n    Iterator(ObserverListBase<ObserverType> &list) : index_(0) {\n      list_ = list.AsWeakPtr();\n    }\n\n    ~Iterator() {\n      if (list_.get())\n        list_->Compact();\n    }\n\n    ObserverType *GetNext() {\n      if (!list_.get())\n        return NULL;\n      ListType &observers = list_->observers_;\n      // Advance if the current element is null\n      size_t max_index = observers.size();\n      while (index_ < max_index && !observers[index_])\n        ++index_;\n      return index_ < max_index ? observers[index_++] : NULL;\n    }\n\n  private:\n    base::WeakPtr<ObserverListBase<ObserverType>> list_;\n    size_t index_;\n  };\n  // Add an observer to the list.  An observer should not be added to\n  // the same list more than once.\n  void AddObserver(ObserverType *obs) {\n    if (std::find(observers_.begin(), observers_.end(), obs) !=\n        observers_.end()) {\n      assert(0);\n      return;\n    }\n    observers_.push_back(obs);\n  }\n\n  // Remove an observer from the list if it is in the list.\n  void RemoveObserver(ObserverType *obs) {\n    typename ListType::iterator it =\n        std::find(observers_.begin(), observers_.end(), obs);\n    if (it != observers_.end()) {\n      *it = NULL;\n    }\n    ++remov_count_;\n    if (remov_count_ > 128) {\n      remov_count_ = 0;\n      Compact();\n    }\n  }\n\n  bool HasObserver(ObserverType *observer) const {\n    for (size_t i = 0; i < observers_.size(); ++i) {\n      if (observers_[i] == observer)\n        return true;\n    }\n    return false;\n  }\n\n  void Clear() { observers_.clear(); }\n\n  size_t size() const { return observers_.size(); }\n\nprotected:\n  void Compact() {\n    observers_.erase(std::remove(observers_.begin(), observers_.end(),\n                                 static_cast<ObserverType *>(NULL)),\n                     observers_.end());\n  }\n\nprivate:\n  typedef std::vector<ObserverType *> ListType;\n\n  ListType observers_;\n\n  int remov_count_;\n\n  friend class ObserverListBase::Iterator;\n  DISALLOW_COPY_AND_ASSIGN(ObserverListBase);\n};\n\ntemplate <class ObserverType, bool check_empty = false>\nclass ObserverList : public ObserverListBase<ObserverType> {\npublic:\n  ObserverList() {}\n\n  ~ObserverList() {\n    // When check_empty is true, assert that the list is empty on destruction.\n    if (check_empty) {\n      ObserverListBase<ObserverType>::Compact();\n    }\n  }\n\n  bool might_have_observers() const {\n    return ObserverListBase<ObserverType>::size() != 0;\n  }\n};\n\n#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)                   \\\n  do {                                                                         \\\n    if ((observer_list).might_have_observers()) {                              \\\n      ObserverListBase<ObserverType>::Iterator it_inside_observer_macro(       \\\n          observer_list);                                                      \\\n      ObserverType *obs;                                                       \\\n      while ((obs = it_inside_observer_macro.GetNext()) != NULL)               \\\n        obs->func;                                                             \\\n    }                                                                          \\\n  } while (0)\n\n} // namespace base\n"
  },
  {
    "path": "src/base/ref_counted.cc",
    "content": "// Copyright (c) 2011 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n#include \"StdAfx.h\"\n#include \"ref_counted.h\"\n\nnamespace base {\n\nnamespace subtle {\n\nRefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {}\n\nRefCountedThreadSafeBase::~RefCountedThreadSafeBase() {}\n\nvoid RefCountedThreadSafeBase::AddRef() const {\n  InterlockedExchangeAdd(reinterpret_cast<volatile LONG *>(&ref_count_),\n                         static_cast<LONG>(1));\n}\n\nbool RefCountedThreadSafeBase::Release() const {\n\n  if (0 ==\n      (InterlockedExchangeAdd(reinterpret_cast<volatile LONG *>(&ref_count_),\n                              static_cast<LONG>(-1)) - 1)) {\n    return true;\n  }\n  return false;\n}\n\nbool RefCountedThreadSafeBase::HasOneRef() const { return (ref_count_ == 1); }\n\n} // namespace subtle\n\n} // namespace base\n"
  },
  {
    "path": "src/base/ref_counted.h",
    "content": "#pragma once\n\n#include <cassert>\n#include \"macros.h\"\n\nnamespace base {\n\nnamespace subtle {\n\nclass RefCountedBase {\npublic:\n  bool HasOneRef() const { return ref_count_ == 1; }\n\nprotected:\n  RefCountedBase() : ref_count_(0) {}\n  ~RefCountedBase() {}\n\n  void AddRef() const { ++ref_count_; }\n\n  // Returns true if the object should self-delete.\n  bool Release() const {\n\n    if (--ref_count_ == 0) {\n      return true;\n    }\n    return false;\n  }\n\nprivate:\n  mutable int ref_count_;\n  DISALLOW_COPY_AND_ASSIGN(RefCountedBase);\n};\n\nclass RefCountedThreadSafeBase {\n\npublic:\n  bool HasOneRef() const;\n\nprotected:\n  RefCountedThreadSafeBase();\n  ~RefCountedThreadSafeBase();\n\n  void AddRef() const;\n\n  // Returns true if the object should self-delete.\n  bool Release() const;\n\nprivate:\n  mutable int ref_count_;\n  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);\n};\n\n} // namespace subtle\n\ntemplate <class T> class RefCounted : public subtle::RefCountedBase {\npublic:\n  RefCounted() {}\n\n  void AddRef() const { subtle::RefCountedBase::AddRef(); }\n\n  void Release() const {\n    if (subtle::RefCountedBase::Release()) {\n      delete static_cast<const T *>(this);\n    }\n  }\n\nprotected:\n  ~RefCounted() {}\n\nprivate:\n  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);\n};\n\n// Forward declaration.\ntemplate <class T, typename Traits> class RefCountedThreadSafe;\n\n// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref\n// count reaches 0.  Overload to delete it on a different thread etc.\ntemplate <typename T> struct DefaultRefCountedThreadSafeTraits {\n  static void Destruct(const T *x) {\n    // Delete through RefCountedThreadSafe to make child classes only need to be\n    // friend with RefCountedThreadSafe instead of this struct, which is an\n    // implementation detail.\n    RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(\n        x);\n  }\n};\n\n//\n// A thread-safe variant of RefCounted<T>\n//\n//   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {\n//    ...\n//   };\n//\n// If you're using the default trait, then you should add compile time\n// asserts that no one else is deleting your object.  i.e.\n//    private:\n//     friend class base::RefCountedThreadSafe<MyFoo>;\n//     ~MyFoo();\ntemplate <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>\nclass RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {\npublic:\n  RefCountedThreadSafe() {}\n\n  void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); }\n\n  void Release() const {\n    if (subtle::RefCountedThreadSafeBase::Release()) {\n      Traits::Destruct(static_cast<const T *>(this));\n    }\n  }\n\nprotected:\n  ~RefCountedThreadSafe() {}\n\nprivate:\n  friend struct DefaultRefCountedThreadSafeTraits<T>;\n  static void DeleteInternal(const T *x) { delete x; }\n\n  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);\n};\n\n//\n// A thread-safe wrapper for some piece of data so we can place other\n// things in scoped_refptrs<>.\n//\ntemplate <typename T>\nclass RefCountedData\n    : public base::RefCountedThreadSafe<base::RefCountedData<T>> {\npublic:\n  RefCountedData() : data() {}\n  RefCountedData(const T &in_value) : data(in_value) {}\n\n  T data;\n\nprivate:\n  friend class base::RefCountedThreadSafe<base::RefCountedData<T>>;\n  ~RefCountedData() {}\n};\n\n} // namespace base\n\n//\n// A smart pointer class for reference counted objects.  Use this class instead\n// of calling AddRef and Release manually on a reference counted object to\n// avoid common memory leaks caused by forgetting to Release an object\n// reference.  Sample usage:\n//\n//   class MyFoo : public RefCounted<MyFoo> {\n//    ...\n//   };\n//\n//   void some_function() {\n//     scoped_refptr<MyFoo> foo = new MyFoo();\n//     foo->Method(param);\n//     // |foo| is released when this function returns\n//   }\n//\n//   void some_other_function() {\n//     scoped_refptr<MyFoo> foo = new MyFoo();\n//     ...\n//     foo = NULL;  // explicitly releases |foo|\n//     ...\n//     if (foo)\n//       foo->Method(param);\n//   }\n//\n// The above examples show how scoped_refptr<T> acts like a pointer to T.\n// Given two scoped_refptr<T> classes, it is also possible to exchange\n// references between the two objects, like so:\n//\n//   {\n//     scoped_refptr<MyFoo> a = new MyFoo();\n//     scoped_refptr<MyFoo> b;\n//\n//     b.swap(a);\n//     // now, |b| references the MyFoo object, and |a| references NULL.\n//   }\n//\n// To make both |a| and |b| in the above example reference the same MyFoo\n// object, simply use the assignment operator:\n//\n//   {\n//     scoped_refptr<MyFoo> a = new MyFoo();\n//     scoped_refptr<MyFoo> b;\n//\n//     b = a;\n//     // now, |a| and |b| each own a reference to the same MyFoo object.\n//   }\n//\ntemplate <class T> class scoped_refptr {\npublic:\n  typedef T element_type;\n\n  scoped_refptr() : ptr_(NULL) {}\n\n  scoped_refptr(T *p) : ptr_(p) {\n    if (ptr_)\n      ptr_->AddRef();\n  }\n\n  scoped_refptr(const scoped_refptr<T> &r) : ptr_(r.ptr_) {\n    if (ptr_)\n      ptr_->AddRef();\n  }\n\n  template <typename U>\n  scoped_refptr(const scoped_refptr<U> &r) : ptr_(r.get()) {\n    if (ptr_)\n      ptr_->AddRef();\n  }\n\n  ~scoped_refptr() {\n    if (ptr_)\n      ptr_->Release();\n  }\n\n  T *get() const { return ptr_; }\n\n  // Allow scoped_refptr<C> to be used in boolean expression\n  // and comparison operations.\n  operator T *() const { return ptr_; }\n\n  T *operator->() const {\n    assert(ptr_ != NULL);\n    return ptr_;\n  }\n\n  scoped_refptr<T> &operator=(T *p) {\n    // AddRef first so that self assignment should work\n    if (p)\n      p->AddRef();\n    T *old_ptr = ptr_;\n    ptr_ = p;\n    if (old_ptr)\n      old_ptr->Release();\n    return *this;\n  }\n\n  scoped_refptr<T> &operator=(const scoped_refptr<T> &r) {\n    return *this = r.ptr_;\n  }\n\n  template <typename U> scoped_refptr<T> &operator=(const scoped_refptr<U> &r) {\n    return *this = r.get();\n  }\n\n  void swap(T **pp) {\n    T *p = ptr_;\n    ptr_ = *pp;\n    *pp = p;\n  }\n\n  void swap(scoped_refptr<T> &r) { swap(&r.ptr_); }\n\nprotected:\n  T *ptr_;\n};\n\n// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without\n// having to retype all the template arguments\ntemplate <typename T> scoped_refptr<T> make_scoped_refptr(T *t) {\n  return scoped_refptr<T>(t);\n}\n"
  },
  {
    "path": "src/base/scoped_handle.h",
    "content": "#pragma once\n\n#include <windows.h>\n#include \"macros.h\"\n\nnamespace base {\nclass HandleTraits {\npublic:\n  typedef HANDLE Handle;\n\n  // Closes the handle.\n  static bool CloseHandle(HANDLE handle) {\n    return ::CloseHandle(handle) != FALSE;\n  }\n\n  // Returns true if the handle value is valid.\n  static bool IsHandleValid(HANDLE handle) {\n    return handle != NULL && handle != INVALID_HANDLE_VALUE;\n  }\n\n  // Returns NULL handle value.\n  static HANDLE NullHandle() { return NULL; }\n\nprivate:\n  DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);\n};\n\ntemplate <typename Traits = HandleTraits> class ScopedWinHandle {\npublic:\n  typedef typename Traits::Handle Handle;\n\n  ScopedWinHandle() : handle_(Traits::NullHandle()) {}\n\n  explicit ScopedWinHandle(Handle handle) : handle_(Traits::NullHandle()) {\n    Set(handle);\n  }\n\n  ScopedWinHandle &operator=(ScopedWinHandle &other) {\n    if (handle_ != other.handle_ && IsValid()) {\n      Close();\n    }\n    handle_ = other.Release();\n    return *this;\n  }\n\n  ScopedWinHandle(ScopedWinHandle &other) { handle_ = other.Release(); }\n\n  ~ScopedWinHandle() { Close(); }\n\n  bool IsValid() const { return Traits::IsHandleValid(handle_); }\n\n  void Set(Handle handle) {\n    if (handle_ != handle) {\n      Close();\n    }\n    handle_ = handle;\n  }\n\n  Handle Get() const { return handle_; }\n\n  operator Handle() { return handle_; }\n\n  void Close() {\n    if (Traits::IsHandleValid(handle_)) {\n      if (!Traits::CloseHandle(handle_)) {\n        assert(0);\n      }\n      handle_ = Traits::NullHandle();\n    }\n  }\n\n  Handle Release() {\n    Handle tmp = handle_;\n    handle_ = Traits::NullHandle();\n    return tmp;\n  }\n\nprivate:\n  Handle handle_;\n};\n\n} // namespace base\n"
  },
  {
    "path": "src/base/string_util_win.h",
    "content": "#pragma once\n\n#include <stdio.h>\n#include <string.h>\n#include <wchar.h>\n\nnamespace base {\n\ninline int vsnprintf(char *buffer, size_t size, const char *format,\n                     ::va_list arguments) {\n  int length = _vsprintf_p(buffer, size, format, arguments);\n  if (length < 0) {\n    if (size > 0)\n      buffer[0] = 0;\n    return _vscprintf_p(format, arguments);\n  }\n  return length;\n}\n\ninline int vswprintf(wchar_t *buffer, size_t size, const wchar_t *format,\n                     ::va_list arguments) {\n  int length = _vswprintf_p(buffer, size, format, arguments);\n  if (length < 0) {\n    if (size > 0)\n      buffer[0] = 0;\n    return _vscwprintf_p(format, arguments);\n  }\n  return length;\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/stringprintf.cc",
    "content": "#include \"StdAfx.h\"\n#include \"stringprintf.h\"\n#include \"macros.h\"\n\nnamespace base {\n\ninline int vsnprintfT(char *buffer, size_t buf_size, const char *format,\n                      ::va_list argptr) {\n  return base::vsnprintf(buffer, buf_size, format, argptr);\n}\n\ninline int vsnprintfT(wchar_t *buffer, size_t buf_size, const wchar_t *format,\n                      ::va_list argptr) {\n  return base::vswprintf(buffer, buf_size, format, argptr);\n}\n\ntemplate <class StringType>\nstatic void StringAppendVT(StringType *dst,\n                           const typename StringType::value_type *format,\n                           ::va_list ap) {\n  // First try with a small fixed size buffer.\n  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary\n  // and StringUtilTest.StringPrintfBounds.\n  typename StringType::value_type stack_buf[1024];\n\n  va_list ap_copy;\n  GG_VA_COPY(ap_copy, ap);\n\n  int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);\n  va_end(ap_copy);\n\n  if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {\n    // It fit.\n    dst->append(stack_buf, result);\n    return;\n  }\n\n  // Repeatedly increase buffer size until it fits.\n  int mem_length = arraysize(stack_buf);\n  while (true) {\n    if (result < 0) {\n      {\n        return;\n      }\n      // Try doubling the buffer size.\n      mem_length *= 2;\n    } else {\n      // We need exactly \"result + 1\" characters.\n      mem_length = result + 1;\n    }\n\n    if (mem_length > 32 * 1024 * 1024) {\n      // That should be plenty, don't try anything larger.  This protects\n      // against huge allocations when using vsnprintfT implementations that\n      // return -1 for reasons other than overflow without setting errno.\n      return;\n    }\n\n    std::vector<typename StringType::value_type> mem_buf(mem_length);\n\n    // NOTE: You can only use a va_list once.  Since we're in a while loop, we\n    // need to make a new copy each time so we don't use up the original.\n    GG_VA_COPY(ap_copy, ap);\n    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);\n    va_end(ap_copy);\n\n    if ((result >= 0) && (result < mem_length)) {\n      // It fit.\n      dst->append(&mem_buf[0], result);\n      return;\n    }\n  }\n}\n\nstd::string StringPrintf(const char *format, ...) {\n  ::va_list ap;\n  va_start(ap, format);\n  std::string result;\n  StringAppendV(&result, format, ap);\n  va_end(ap);\n  return result;\n}\n\nstd::wstring StringPrintf(const wchar_t *format, ...) {\n  ::va_list ap;\n  va_start(ap, format);\n  std::wstring result;\n  StringAppendV(&result, format, ap);\n  va_end(ap);\n  return result;\n}\n\nvoid StringAppendV(std::string *dst, const char *format, ::va_list ap) {\n  StringAppendVT(dst, format, ap);\n}\n\nvoid StringAppendV(std::wstring *dst, const wchar_t *format, ::va_list ap) {\n  StringAppendVT(dst, format, ap);\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/base/stringprintf.h",
    "content": "#pragma once\n\n#include \"string_util_win.h\"\n\nnamespace base {\nstd::string  StringPrintf(const char *format, ...);\nstd::wstring StringPrintf(const wchar_t *format, ...);\nvoid StringAppendV(std::string *dst, const char *format, ::va_list ap);\nvoid StringAppendV(std::wstring *dst, const wchar_t *format, ::va_list ap);\n} // namespace base\n"
  },
  {
    "path": "src/base/thread_local.cc",
    "content": "#include \"StdAfx.h\"\n"
  },
  {
    "path": "src/base/thread_local.h",
    "content": "#pragma once\n\n#include \"macros.h\"\n\nnamespace base {\ntemplate <typename Type> class ThreadLocalPointer {\npublic:\n  ThreadLocalPointer() {\n    slot_ = TlsAlloc();\n    assert(slot_ != TLS_OUT_OF_INDEXES);\n  }\n\n  ~ThreadLocalPointer() {\n    if (!TlsFree(slot_)) {\n      assert(0);\n    }\n  }\n\n  Type *Get() { return static_cast<Type *>(TlsGetValue(slot_)); }\n\n  void Set(Type *ptr) {\n    if (!TlsSetValue(slot_,\n                     const_cast<void *>(static_cast<const void *>(ptr)))) {\n      assert(0);\n    }\n  }\n\nprivate:\n  DWORD slot_;\n\n  DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);\n};\n} // namespace base\n"
  },
  {
    "path": "src/base.h",
    "content": "#pragma once\n\n#include \"util/util_tools.h\"\n#include \"Event/WaitableEvent.h\"\n#include \"base/Thread.h\"\n#include \"base/WeakPtr.h\"\n#include \"base/aligned_memory.h\"\n#include \"base/at_exist.h\"\n#include \"base/common_threads.h\"\n#include \"base/lazy_instance.h\"\n#include \"base/notification_registrar.h\"\n"
  },
  {
    "path": "src/net/url_fetcher.cc",
    "content": "#include \"StdAfx.h\"\n#include \"../base.h\"\n#include \"../LogAssist/LogAssist.h\"\n#include \"util/system.h\"\n#include \"url_fetcher.h\"\n\nnamespace net {\n#define DEFAULT_WININET_TIMEOUT (20 * 1000)\n\n#define USER_AGENT                                                \\\n  \"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0;)\"\n\n#define DEFAULT_CONNECT_RETRYS 2\n\nstatic DWORD WINAPI ThreadProc(LPVOID lpParameter);\n\nbool SetTimeout(HINTERNET &hConnect,\n                ULONG uTimeoutSec = DEFAULT_WININET_TIMEOUT) {\n  uTimeoutSec *= 2;\n  bool bret = false;\n  do {\n    if (!::InternetSetOption(hConnect, INTERNET_OPTION_SEND_TIMEOUT,\n                             &uTimeoutSec, sizeof(uTimeoutSec)))\n      break;\n\n    if (!::InternetSetOption(hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT,\n                             &uTimeoutSec, sizeof(uTimeoutSec)))\n      break;\n\n    uTimeoutSec /= 2;\n    if (!::InternetSetOption(hConnect, INTERNET_OPTION_CONNECT_TIMEOUT,\n                             &uTimeoutSec, sizeof(uTimeoutSec)))\n      break;\n\n    ULONG uRetrys = DEFAULT_CONNECT_RETRYS;\n    if (!::InternetSetOption(hConnect, INTERNET_OPTION_CONNECT_RETRIES,\n                             &uRetrys, sizeof(uRetrys)))\n      break;\n\n    bret = true;\n  } while (false);\n  if (!bret) {\n    PRT_LOG3(DebugSet, (\"***failed***\"))\n  }\n  return bret;\n}\n\nURLFetcher *URLFetcher::Create(const Params &params,\n                               URLFetcherDelegate *delegate) {\n  return (new URLFetcher(params, delegate));\n}\n\nURLFetcher::Params::Params(const std::string& url)\n  : url_(url), type_(STRING), beginwoffset_(0), endoffset_(0) {}\n\nURLFetcher::Params::Params(const std::string &url, std::wstring file_name)\n    : url_(url), name_(file_name), type_(FILE), beginwoffset_(0), endoffset_(0) {}\n\nURLFetcher::Params::Params(const std::string &url, DownType type)\n    : url_(url), type_(type), beginwoffset_(0), endoffset_(0) {}\n\nvoid URLFetcher::URLFetcherDelegate::OnURLFetchDownloadProgress(\n    const URLFetcher *source, double cur) {}\n\nURLFetcher::URLFetcherDelegate::~URLFetcherDelegate() {}\n\nURLFetcher::URLFetcher(const Params &params, URLFetcherDelegate *delegate)\n    : download_url_(params.url_), type_(params.type_),\n      download_file_name_(params.name_), delegate_(delegate),\n      input_state_(this), fdownloadprogress_(0.0), status_(false),\n      event_(true, false), quit_status_(false),\n      beginwoffset_(params.beginwoffset_), endoffset_(params.endoffset_),\n      file_totle_len_(0), support_breakpoint_(true), error_type_(ERROR_NO),\n      already_byteinfile_(0), orginal_begin_offset_(0) {\n  assert(download_url_.length());\n  io_port_ = base::Threads::Get(Threads::IO)->pump_win()->io_port();\n  assert(io_port_);\n}\n\nURLFetcher::~URLFetcher() {\n  if (type_ == DownType::FILE && download_file_name_.length()) {\n    SystemCommon::FilePathHelper::DeepDeleteFile(download_file_name_);\n  }\n}\n\nvoid URLFetcher::Start() {\n  assert(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  base::Threads::Get(Threads::IO)\n      ->PostTask(Bind(this, &URLFetcher::StartInternal));\n}\n\nvoid URLFetcher::Stop() {\n  assert(base::MessageLoop::current() == base::Threads::Get(Threads::UI));\n  delegate_ = nullptr;\n  quit_status_ = true;\n}\n\nvoid URLFetcher::WillDestroyCurrentMessageLoop() {\n  quit_status_ = true;\n  event_.Wait();\n  Release();\n}\n\nvoid URLFetcher::OnIOCompleted(base::MessagePumpForIO::IOContext* context,\n  DWORD bytes_transfered, DWORD error) {\n  base::Threads::Get(Threads::IO)->RemoveDestructionObserver(this);\n\n  if (delegate_) {\n    base::Threads::Get(Threads::UI)\n      ->PostTask(Bind(this, &URLFetcher::FetchComplete));\n  }\n\n  Release();\n}\n\nvoid URLFetcher::FetchComplete() {\n  if (delegate_) {\n    delegate_->OnURLFetchComplete(this);\n  }\n}\n\nvoid URLFetcher::FetchDownloadProgress(double cur) {\n  fdownloadprogress_ = cur;\n  if (delegate_) {\n    delegate_->OnURLFetchDownloadProgress(this, fdownloadprogress_);\n  }\n}\n\nvoid URLFetcher::StartInternal() {\n  AddRef();\n  AddRef();\n  base::Threads::Get(Threads::IO)->AddDestructionObserver(this);\n  if (!QueueUserWorkItem(ThreadProc, this, WT_EXECUTEDEFAULT)) {\n    Release();\n    base::Threads::Get(Threads::IO)->RemoveDestructionObserver(this);\n    status_ = false;\n    base::Threads::Get(Threads::UI)\n        ->PostTask(Bind(this, &URLFetcher::FetchComplete));\n    Release();\n    return;\n  }\n}\n\nvoid  URLFetcher::StopInternal() {\n\n}\n\nDWORD WINAPI ThreadProc(LPVOID lpParameter) {\n  URLFetcher *const url_fetcher = reinterpret_cast<URLFetcher *>(lpParameter);\n\n  bool bResult = false;\n  const std::string &url = url_fetcher->durl();\n\n  switch (url_fetcher->type()) {\n  case URLFetcher::STRING: {\n    std::string &contents = url_fetcher->data();\n    HINTERNET hSession = ::InternetOpenA(\n        USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);\n    if (hSession) {\n      SetTimeout(hSession);\n      HINTERNET hRequest = ::InternetOpenUrlA(hSession, url.c_str(), NULL, 0,\n                                              INTERNET_FLAG_RELOAD, NULL);\n      if (hRequest) {\n        TCHAR szBuffer[256] = {0};\n        DWORD dwSize = _countof(szBuffer);\n        if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize,\n                          NULL) &&\n            _tcscmp(szBuffer, _T(\"200\")) == 0) {\n\n          for (;;) {\n            if (url_fetcher->quit_status()) {\n              break;\n            }\n            char btBuffer[1024 + 1] = {0};\n            DWORD dwFileLength = 0;\n            if (!::InternetReadFile(hRequest, btBuffer, 1024, &dwFileLength)) {\n              break;\n            }\n\n            if (dwFileLength == 0) {\n              bResult = true;\n              break;\n            }\n            btBuffer[dwFileLength] = NULL;\n            contents += btBuffer;\n          }\n        }\n\n        ::InternetCloseHandle(hRequest);\n      }\n\n      ::InternetCloseHandle(hSession);\n    }\n  } break;\n  case URLFetcher::FILE: {\n    HINTERNET hSession = ::InternetOpenA(\n        USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);\n    if (hSession) {\n      SetTimeout(hSession);\n      HINTERNET hRequest =\n          ::InternetOpenUrlA(hSession, url.c_str(), NULL, 0, 0, NULL);\n      if (hRequest) {\n        TCHAR szBuffer[256] = {0};\n        DWORD dwSize = _countof(szBuffer);\n        DWORD dwContentLength = -1;\n        DWORD dwAlreadyReadLen = 0;\n        if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize,\n                          NULL) &&\n            _tcscmp(szBuffer, _T(\"200\")) == 0) {\n          dwSize = sizeof(dwContentLength);\n\n          BOOL issucc = HttpQueryInfo(\n              hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,\n              &dwContentLength, &dwSize, NULL);\n          if (!issucc || -1 == dwContentLength) {\n            url_fetcher->error_type_ = URLFetcher::ERROR_SERV;\n            ::InternetCloseHandle(hRequest);\n            ::InternetCloseHandle(hSession);\n            break;\n          }\n          std::wstring filepath = url_fetcher->download_file_name();\n          HANDLE hFile =\n              ::CreateFileW(filepath.c_str(), GENERIC_WRITE, NULL, NULL,\n                            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n          if (INVALID_HANDLE_VALUE != hFile) {\n            do {\n              SetFilePointer(hFile, dwContentLength, NULL, FILE_BEGIN);\n              if (SetEndOfFile(hFile) == FALSE) {\n                url_fetcher->error_type_ = URLFetcher::DISK_NO_SPACE;\n                break;\n              }\n              SetFilePointer(hFile, 0, NULL, FILE_BEGIN);\n              DWORD dwSizePost = 0;\n              for (;;) {\n                if (url_fetcher->quit_status()) {\n                  break;\n                }\n                char btBuffer[1024 * 8 + 1] = {0};\n                DWORD dwFileLength = 0;\n                if (!::InternetReadFile(hRequest, btBuffer, 1024 * 8,\n                                        &dwFileLength)) {\n                  break;\n                }\n                dwAlreadyReadLen += dwFileLength;\n                dwSizePost += dwFileLength;\n                if (dwFileLength == 0) {\n                  base::Threads::Get(Threads::UI)\n                      ->PostTask(Bind(url_fetcher,\n                                      &URLFetcher::FetchDownloadProgress, 1.0));\n                  bResult = true;\n                  break;\n                }\n\n                DWORD dwWriteLength = 0;\n                ::WriteFile(hFile, btBuffer, dwFileLength, &dwWriteLength,\n                            NULL);\n                url_fetcher->already_byteinfile_ += dwFileLength;\n                if (dwSizePost > 1024 * 8) {\n                  dwSizePost = 0;\n                  double cur =\n                      static_cast<double>(dwAlreadyReadLen) / dwContentLength;\n                  base::Threads::Get(Threads::UI)\n                      ->PostTask(Bind(url_fetcher,\n                                      &URLFetcher::FetchDownloadProgress, cur));\n                }\n              }\n            } while (false);\n            ::CloseHandle(hFile);\n          }\n        }\n        ::InternetCloseHandle(hRequest);\n      }\n      ::InternetCloseHandle(hSession);\n    }\n  } break;\n  case URLFetcher::TEST_BREAKPOINT_SUPPORT: {\n    if (!url_fetcher->support_breakpoint_) {\n      url_fetcher->error_type_ = URLFetcher::NOT_SUPPORT_BREAKPOINT;\n      break;\n    }\n    HINTERNET hSession = NULL;\n    hSession = ::InternetOpenA(USER_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL,\n                               NULL, 0);\n    if (hSession) {\n      SetTimeout(hSession);\n      char vheaders[200] = {0};\n      DWORD dwZero = 0;\n      _snprintf_s(vheaders, 200, _TRUNCATE, \"Range:bytes=%u-\\r\\n\", dwZero);\n      HINTERNET hRequest =\n          ::InternetOpenUrlA(hSession, url.c_str(), vheaders, -1L, 0, NULL);\n      if (hRequest) {\n        TCHAR szBuffer[256] = {0};\n        DWORD dwSize = _countof(szBuffer);\n        if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, szBuffer, &dwSize,\n                          NULL) &&\n            _tcscmp(szBuffer, _T(\"206\")) == 0) {\n          DWORD dwContentLength = -1;\n          DWORD dwSize = sizeof(dwContentLength);\n          BOOL issucc = HttpQueryInfo(\n              hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,\n              &dwContentLength, &dwSize, NULL);\n          if (FALSE == issucc || -1 == dwContentLength) {\n            url_fetcher->error_type_ = URLFetcher::ERROR_SERV;\n            ::InternetCloseHandle(hRequest);\n            ::InternetCloseHandle(hSession);\n            break;\n          }\n          url_fetcher->file_totle_len_ = dwContentLength;\n          bResult = true;\n        } else {\n          url_fetcher->support_breakpoint_ = false;\n        }\n        ::InternetCloseHandle(hRequest);\n      }\n      ::InternetCloseHandle(hSession);\n    }\n  } break;\n\n  default:\n    assert(0);\n    break;\n  }\n\n  url_fetcher->set_status(bResult);\n\n  PostQueuedCompletionStatus(\n      url_fetcher->io_port(),\n      (url_fetcher->type() == URLFetcher::STRING) ? url_fetcher->data().length()\n                                                  : 0,\n      reinterpret_cast<ULONG_PTR>(\n          static_cast<base::MessagePumpForIO::IOHandler *>(url_fetcher)),\n      &url_fetcher->state().context.overlapped);\n\n  url_fetcher->event().Signal();\n\n  url_fetcher->Release();\n\n  return 0;\n}\n\n} // namespace net\n"
  },
  {
    "path": "src/net/url_fetcher.h",
    "content": "#pragma once\n\n#include \"../Event/WaitableEvent.h\"\n#include \"../base/MessageLoop.h\"\n#include \"../base/MessagePumpWin.h\"\n#include \"../base/macros.h\"\n#include \"../base/notification_observer.h\"\n#include \"../base/notification_registrar.h\"\n\nnamespace net {\nclass URLFetcher : public base::MessagePumpForIO::IOHandler,\n                   public base::MessageLoop::DestructionObserver,\n                   public base::RefCountedThreadSafe<URLFetcher> {\npublic:\n  class URLFetcherDelegate {\n  public:\n    virtual void OnURLFetchComplete(const URLFetcher *source) = 0;\n    virtual void OnURLFetchDownloadProgress(const URLFetcher *source,\n                                            double cur);\n    virtual ~URLFetcherDelegate();\n  };\n  enum ErrorType {\n    ERROR_NO,\n    DISK_NO_SPACE,\n    FILE_NO_EXIST,\n    NOT_SUPPORT_BREAKPOINT,\n    ERROR_SERV,\n  };\n\n  enum DownType {\n    STRING,\n    FILE,\n    TEST_BREAKPOINT_SUPPORT,\n  };\n\n  struct Params {\n    explicit Params(const std::string& url);\n    explicit Params(const std::string &url, std::wstring file_name);\n    explicit Params(const std::string &url, DownType type);\n\n    std::string url_;\n    std::wstring name_;\n    DownType type_;\n    DWORD beginwoffset_;\n    DWORD endoffset_;\n  };\n\n  struct State {\n    explicit State(URLFetcher *fetcher) { context.handler = fetcher; }\n    ~State() {}\n    base::MessagePumpForIO::IOContext context;\n  };\n\n  static URLFetcher *Create(const Params &params, URLFetcherDelegate *delegate);\n\n  ~URLFetcher();\n\n  void Start();\n\n  void Stop();\n\n  virtual void WillDestroyCurrentMessageLoop() override;\n\n  virtual void OnIOCompleted(base::MessagePumpForIO::IOContext *context,\n                             DWORD bytes_transfered, DWORD error) override;\n\n  void FetchComplete();\n  void FetchDownloadProgress(double cur);\n\n  void set_download_url(const std::string &url) { download_url_ = url; }\n  void set_file_loadpath(const std::wstring &path) { download_file_name_ = path; }\n  void set_status(const bool status) { status_ = status; }\n\n  bool status() const { return status_; }\n  bool quit_status() { return quit_status_; }\n  std::string& data() { return data_; }\n  const std::string& durl() { return download_url_; }\n  const std::wstring& download_file_name() { return download_file_name_; }\n\n  HANDLE io_port() { return io_port_; }\n  base::WaitableEvent& event() { return event_; }\n  State &state() { return input_state_; }\n  DownType type() { return type_; }\n\nprivate:\n  explicit URLFetcher(const Params &params, URLFetcherDelegate *delegate);\n\n  void StartInternal();\n  void StopInternal();\n\n  bool status_;\n  bool quit_status_;\n\n  std::string data_;\n  std::string download_url_;\n  std::wstring download_file_name_;\n\n  HANDLE io_port_;\n  State input_state_;\n  DownType type_;\n  URLFetcherDelegate *delegate_;\n  base::WaitableEvent event_;\n\npublic:\n  ErrorType error_type_;\n  double fdownloadprogress_;\n  bool support_breakpoint_;\n  DWORD already_byteinfile_;\n  DWORD file_totle_len_;\n\n  DWORD beginwoffset_;\n  DWORD endoffset_;\n  DWORD orginal_begin_offset_;\n};\n\n} // namespace net\n"
  },
  {
    "path": "src/res/xml/EngUIAgreement.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"2\" title=\"\" left=\"0\" top=\"0\" width=\"644\" height=\"360\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"0\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\" c_left=\"20\" c_top=\"45\">\n  <static id=\"id_static_tip1\" title=\"License\" left=\"253\"  top=\"16\" width=\"150\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"255,132,0\" bigfont=\"1\"/>\n</window>\n"
  },
  {
    "path": "src/res/xml/EngUICannotDown.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"2\" title=\"\" left=\"0\" top=\"0\" width=\"382\" height=\"232\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"41\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\">\n  <button id=\"id_btn_close\" title=\"\" left=\"33\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_CLOSE\" />\n  <static id=\"id_static_tip1\" title=\"Are you sure to cancel?\" left=\"120\"  top=\"96\" width=\"200\" height=\"30\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\"/>\n  <button id=\"id_btn_ok\" title=\"Yes\" left=\"98\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"250,250,250\"/>\n  <button id=\"id_btn_cancal\" title=\"No\" left=\"201\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\"/>\n  <static id=\"id_static_tip2\" title=\"Your computer does not have enough disk space or memory to use this program, and the installation will be terminated.\" left=\"41\"  top=\"80\" width=\"300\" height=\"60\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\"/>\n  <button id=\"id_btn_quit\" title=\"Yes\" left=\"151\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\"/>  \n</window>\n"
  },
  {
    "path": "src/res/xml/EngUIContent.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"\" title=\"\" left=\"0\" top=\"0\" width=\"600\" height=\"288\" center=\"\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"0\" icon=\"\" logo=\"\" frame=\"\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\">\n <static id=\"id_static_tip2\" title=\"Users of this software, if you do not accept these terms, please do not use the services provided by the platform; once you use them, it indicates that you have agreed to the following terms. If you violate the following terms, this software has the right to ban you from entering this software without your knowledge, or take legal measures.\n1. The information content and data published or generated by the user on this software are jointly owned by the user and this software. No other organization or individual may copy, reproduce or modify the content without the authorization and consent of the user and this software. If reproduced Please indicate the source. Users are not allowed to publish information containing the following content on this software:\n1) Violates the basic principles stipulated in the national constitution;\n2) Endangering national security, leaking state secrets, subverting state power, and undermining national unity;\n3) Damaging national honor and interests;\n4) Inciting ethnic hatred, ethnic discrimination, and undermining ethnic unity;\n5) Undermining national religious policies and promoting cults and feudal superstitions;\n6) Spread rumors, disrupt social order, and undermine social stability;\n7) Spread obscenity, pornography, gambling, violence, murder, terror or instigate crime;\n8) Insulting or defaming others and infringing upon others' legitimate rights and interests;\n9) Contains other content prohibited by laws and administrative regulations;\n10) For other content that this software deems inappropriate to publish here, this software reserves the right to delete and change the above-mentioned relevant information. Any losses caused to users shall be borne by the users themselves.\n2. Users should ensure that they provide true registration information, ensure that the information is correct and complete, and update relevant content in a timely manner when user-related information changes. This software does not assume any liability for losses when any losses are caused due to untrue information.\n3. Users are advised to keep their account information safe. Once the account information is lost or leaked, this software will not bear any liability for losses.\n4. This software cannot guarantee that the services provided can meet all user requirements, nor can it guarantee whether existing services will be interrupted during use, nor can it guarantee the timeliness, security, and accuracy of the services.\n5. If the user causes losses to the software or any third party due to violation of relevant laws, regulations or any terms of the agreement, the user agrees to bear all liability for damages caused thereby.\n6. Within the scope permitted by law, this software reserves the right to interpret any terms of this agreement and the right to change it at any time.\" left=\"35\"  top=\"0\" width=\"545\" height=\"288\" xAlignment=\"left\" yAlignment=\"top\" color=\"255,255,255\" bigfont=\"0\" viewport=\"1\"/>\n</window>\n"
  },
  {
    "path": "src/res/xml/EngUIMainWindow.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"1\" title=\"\" left=\"0\" top=\"0\" width=\"492\" height=\"402\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"246\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" topmost=\"1\">\n  <button id=\"id_close\" title=\"\" left=\"33\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_CLOSE\" />\n  <button id=\"id_btn_min\" title=\"\" left=\"76\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_MIN\"/>\n  <panel id=\"id_panel_main\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <button id=\"id_install\" title=\"Install now\" left=\"180\"  top=\"28\" width=\"120\" height=\"42\" xAlignment=\"left\" yAlignment=\"top\" image=\"DLG_BTN_INSTALL\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"-5\" bigfont=\"1\" discolor=\"153,153,153\"/>\n    <checkbox id=\"id_checkbox\" title=\"Accept\" tip=\"\" left=\"20\" top=\"89\" width=\"50\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <link id=\"id_openurl\" title=\"Agreement\" tip=\"\" left=\"70\" top=\"94\" width=\"120\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" linkcolor=\"250,250,250\" hovercolor=\"250,250,250\" visitedcolor=\"250,250,250\"/>\n    <link id=\"id_userinstall\" title=\"Custom >\" tip=\"\" left=\"385\" top=\"94\" width=\"120\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" linkcolor=\"0,213,254\" hovercolor=\"0,213,254\" visitedcolor=\"0,213,254\"/>\n  </panel>\n  <panel id=\"id_panel_userdef\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"220\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <button id=\"id_btn_installdir\" title=\"Path\" left=\"102\"  top=\"28\" width=\"82\" height=\"29\" xAlignment=\"right\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"0\"/>\n    <button id=\"id_btn_backmain\" title=\"Back\" left=\"264\"  top=\"145\" width=\"93\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"-5\" bigfont=\"1\"/>\n    <button id=\"id_btn_installnow\" title=\"Install\" left=\"124\"  top=\"145\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"DLG_BTN_INSTALL\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\" hdelta=\"-5\" bigfont=\"1\" discolor=\"153,153,153\"/>\n    <checkbox id=\"id_checkbox_shortcut\" title=\"Desk shortcut\" tip=\"\" left=\"20\" top=\"87\" width=\"125\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_easymenu\" title=\"TaskBar shortcut\" tip=\"\" left=\"198\" top=\"87\" width=\"102\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_autorun\"  title=\"Autorun\" tip=\"\" left=\"358\" top=\"87\" width=\"102\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <static id=\"\" title=\"Location：\" tip=\"\" left=\"20\" top=\"33\" width=\"230\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\" bigfont=\"0\"/>\n    <layedit id=\"id_edit_installpath\" title=\"\" tip=\"\" left=\"91\" top=\"27\" width=\"268\" height=\"30\" style=\"0\" xAlignment=\"left\" yAlignment=\"top\" bordercolor=\"69,68,73\" backcolor=\"69,68,73\" image=\"EDIT_INSTALL_BACK\" textcolor=\"255,255,255\" checkpath=\"1\"/>\n    <static id=\"id_static_patherror\" title=\"Choose other location!\" left=\"91\" top=\"62\" width=\"230\" heigth=\"29\"  xAlignment=\"left\" yAlignment=\"top\" color=\"255,0,0\"/>\n  </panel>\n  <panel id=\"id_panel_download\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <static id=\"id_static_downing\" title=\"Downloading...Please wait!~\" tip=\"\" left=\"150\" top=\"28\" width=\"280\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\" bigfont=\"0\"/>\n    <progress id=\"id_progress_download\" title=\"\" left=\"20\" top=\"84\" width=\"442\" height=\"2\"  xAlignment=\"left\" yAlignment=\"top\" image=\"LIGHTPOINT\" progress_width=\"405\" lightpointdela=\"-6\"/>\n  </panel>\n  <panel id=\"id_panel_complete\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <checkbox id=\"id_checkbox_present\" title=\"Win gift!\" tip=\"\" left=\"20\" top=\"28\" width=\"200\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_favirate\" title=\"Add to favorites\" tip=\"\" left=\"329\" top=\"28\" width=\"150\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <button id=\"id_btn_usenow\" title=\"Use now\" left=\"112\"  top=\"92\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\" hdelta=\"-4\" bigfont=\"1\"/>\n    <button id=\"id_btn_complete\" title=\"Complete\" left=\"253\"  top=\"92\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"250,250,250\" hovercolor=\"250,250,250\" downcolor=\"250,250,250\" hdelta=\"-4\" bigfont=\"1\"/>\n  </panel>\n  <static id=\"id_static_tryshutdown\" title=\"Installing... Please wait!~\" left=\"156\" top=\"274\" width=\"230\" heigth=\"29\"  xAlignment=\"left\" yAlignment=\"top\" color=\"255,0,0\"/>\n</window>\n"
  },
  {
    "path": "src/res/xml/UIAgreement.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"2\" title=\"\" left=\"0\" top=\"0\" width=\"644\" height=\"360\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"0\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\" c_left=\"20\" c_top=\"45\">\n  <static id=\"id_static_tip1\" title=\"用户服务协议\" left=\"253\"  top=\"16\" width=\"150\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"255,132,0\" bigfont=\"1\"/>\n</window>\n"
  },
  {
    "path": "src/res/xml/UICannotDown.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"2\" title=\"\" left=\"0\" top=\"0\" width=\"382\" height=\"232\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"41\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\">\n  <button id=\"id_btn_close\" title=\"\" left=\"33\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_CLOSE\" />\n  <static id=\"id_static_tip1\" title=\"您确定要退出安装吗？\" left=\"120\"  top=\"96\" width=\"200\" height=\"30\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\"/>\n  <button id=\"id_btn_ok\" title=\"确定\" left=\"98\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"250,250,250\"/>\n  <button id=\"id_btn_cancal\" title=\"取消\" left=\"201\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\"/>\n  <static id=\"id_static_tip2\" title=\"您的电脑磁盘空间或者内存不足，无法使用本程序，安装将终止。\" left=\"56\"  top=\"96\" width=\"270\" height=\"40\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\"/>\n  <button id=\"id_btn_quit\" title=\"知道了\" left=\"151\"  top=\"162\" width=\"84\" height=\"28\" xAlignment=\"left\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\"/>  \n</window>\n"
  },
  {
    "path": "src/res/xml/UIContent.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"\" title=\"\" left=\"0\" top=\"0\" width=\"600\" height=\"288\" center=\"\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"0\" icon=\"\" logo=\"\" frame=\"\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" roundcorner=\"0\">\n <static id=\"id_static_tip2\" title=\"本软件的使用者，若您不接受此条款，请勿使用平台提供的服务；一旦使用，表明您已同意以下条款。若您违背以下条款，本软件有权在您不知情的情况下，禁止您进入本软件，或采取法律措施。\n一、用户在本软件上发布或产生的信息内容、数据由用户及本软件共同所有，任何其他组织或个人未经用户本人及本软件授权同意，不得复制、转载、擅改其内容，如若转载请注明出处。用户不得在本软件发布含有下列内容的信息：\n1）违反国家宪法所规定的基本原则的；\n2）危害国家安全，泄露国家秘密，颠覆国家政权，破坏国家统一的；\n3）损害国家荣誉和利益的；\n4）煽动民族仇恨、民族歧视，破坏民族团结的；\n5）破坏国家宗教政策，宣扬邪教和封建迷信的；\n6）散布谣言，扰乱社会秩序，破坏社会稳定的；\n7）散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的；\n8）侮辱或者诽谤他人，侵害他人合法权益的；\n9）含有法律、行政法规禁止的其他内容的；\n10）其他本软件认为不适当在此发布的内容，本软件保留删除和变更上述相关信息的权利。造成用户损失的，用户自行承担。\n二、用户应保证提供真实的注册信息，确保信息是正确且完整的，用户相关信息变更时需及时更新相关内容。当由于信息不真实而造成任何损失时，本软件不承担任何损失责任。\n三、请用户保管好自己的账户信息，一旦账号信息丢失或泄露，本软件不承担任何损失责任。\n四、本软件不能保证提供的服务能够满足用户的所有要求，也不能保证已存在的服务是否会在使用时中断，以及服务的及时性、安全性、准确性也不能保证。\n五、用户因违反有关法律、法规或协议规定中的任何条款而给本软件或任何第三方造成的损失，用户同意承担由此造成的一切损害赔偿责任。\n六、在法律允许的范围内，本软件保留对本协议任何条款的解释权和随时变更的权利。\" left=\"35\"  top=\"0\" width=\"545\" height=\"288\" xAlignment=\"left\" yAlignment=\"top\" color=\"255,255,255\" bigfont=\"0\" viewport=\"1\"/>\n</window>\n"
  },
  {
    "path": "src/res/xml/UIMainWindow.xml",
    "content": "﻿<?xml version=\"1.0\"  encoding=\"utf-8\"?>\n<window id=\"1\" title=\"\" left=\"0\" top=\"0\" width=\"492\" height=\"402\" center=\"1\" style=\"2248146944\" style_ex=\"0\" titleHeight=\"246\" icon=\"\" logo=\"\" frame=\"ABOUTDIALOG\"  frameCorner=\"10,10,10,10\" drawSimple = \"1\" topmost=\"1\">\n  <button id=\"id_close\" title=\"\" left=\"33\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_CLOSE\" />\n  <button id=\"id_btn_min\" title=\"\" left=\"76\"  top=\"21\" width=\"11\" height=\"12\" xAlignment=\"right\" yAlignment=\"top\" image=\"DLG_BTN_MIN\"/>\n  <panel id=\"id_panel_main\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <button id=\"id_install\" title=\"快速安装\" left=\"180\"  top=\"28\" width=\"120\" height=\"42\" xAlignment=\"left\" yAlignment=\"top\" image=\"DLG_BTN_INSTALL\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"-5\" bigfont=\"1\" discolor=\"153,153,153\"/>\n    <checkbox id=\"id_checkbox\" title=\"接受\" tip=\"\" left=\"20\" top=\"89\" width=\"50\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <link id=\"id_openurl\" title=\"《用户服务协议》\" tip=\"\" left=\"70\" top=\"94\" width=\"120\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" linkcolor=\"250,250,250\" hovercolor=\"250,250,250\" visitedcolor=\"250,250,250\"/>\n    <link id=\"id_userinstall\" title=\"自定义安装 >\" tip=\"\" left=\"385\" top=\"94\" width=\"120\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" linkcolor=\"0,213,254\" hovercolor=\"0,213,254\" visitedcolor=\"0,213,254\"/>\n  </panel>\n  <panel id=\"id_panel_userdef\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"220\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <button id=\"id_btn_installdir\" title=\"选择路径\" left=\"102\"  top=\"28\" width=\"82\" height=\"29\" xAlignment=\"right\" yAlignment=\"top\" image=\"SELECTPATH\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"0\"/>\n    <button id=\"id_btn_backmain\" title=\"返回\" left=\"264\"  top=\"145\" width=\"93\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"250,250,250\" hovercolor=\"255,255,255\" downcolor=\"255,255,255\" hdelta=\"-5\" bigfont=\"1\"/>\n    <button id=\"id_btn_installnow\" title=\"立即安装\" left=\"124\"  top=\"145\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"DLG_BTN_INSTALL\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\" hdelta=\"-5\" bigfont=\"1\" discolor=\"153,153,153\"/>\n    <checkbox id=\"id_checkbox_shortcut\" title=\"创建桌面快捷方式\" tip=\"\" left=\"20\" top=\"87\" width=\"125\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_easymenu\" title=\"添加到快捷栏\" tip=\"\" left=\"198\" top=\"87\" width=\"102\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_autorun\"  title=\"开机自动启动\" tip=\"\" left=\"358\" top=\"87\" width=\"102\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <static id=\"\" title=\"安装位置：\" tip=\"\" left=\"20\" top=\"33\" width=\"230\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\" bigfont=\"0\"/>\n    <layedit id=\"id_edit_installpath\" title=\"\" tip=\"\" left=\"91\" top=\"27\" width=\"268\" height=\"30\" style=\"0\" xAlignment=\"left\" yAlignment=\"top\" bordercolor=\"69,68,73\" backcolor=\"69,68,73\" image=\"EDIT_INSTALL_BACK\" textcolor=\"255,255,255\" checkpath=\"1\"/>\n    <static id=\"id_static_patherror\" title=\"所选目录无法安装，请选择其他目录\" left=\"91\" top=\"62\" width=\"230\" heigth=\"29\"  xAlignment=\"left\" yAlignment=\"top\" color=\"255,0,0\"/>\n  </panel>\n  <panel id=\"id_panel_download\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <static id=\"id_static_downing\" title=\"正在全力下载安装包，请稍等！~\" tip=\"\" left=\"150\" top=\"28\" width=\"280\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"250,250,250\" bigfont=\"0\"/>\n    <static id=\"id_static_downing_size\" title=\"\" tip=\"\" left=\"200\" top=\"60\" width=\"280\" height=\"29\" xAlignment=\"left\" yAlignment=\"top\" color=\"6,161,193\" samllfont=\"1\"/>    \n    <progress id=\"id_progress_download\" title=\"\" left=\"20\" top=\"84\" width=\"442\" height=\"2\"  xAlignment=\"left\" yAlignment=\"top\" image=\"LIGHTPOINT\" progress_width=\"405\" lightpointdela=\"-6\"/>\n  </panel>\n  <panel id=\"id_panel_complete\" title=\"\" left=\"6\"  top=\"246\" width=\"480\" height=\"150\" xAlignment=\"left\" yAlignment=\"top\" xStretch=\"fill\" yStretch=\"none\">\n    <checkbox id=\"id_checkbox_present\" title=\"参与体验优化计划赢取奖品\" tip=\"\" left=\"20\" top=\"28\" width=\"200\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <checkbox id=\"id_checkbox_favirate\" title=\"将官网加入收藏夹\" tip=\"\" left=\"329\" top=\"28\" width=\"150\" height=\"27\" xAlignment=\"left\" yAlignment=\"top\" image=\"CHECK_BOX\" textcolor=\"250,250,250\"/>\n    <button id=\"id_btn_usenow\" title=\"立即使用\" left=\"112\"  top=\"92\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"0,213,254\" hovercolor=\"0,213,254\" downcolor=\"0,213,254\" hdelta=\"-4\" bigfont=\"1\"/>\n    <button id=\"id_btn_complete\" title=\"安装完成\" left=\"253\"  top=\"92\" width=\"120\" height=\"37\" xAlignment=\"left\" yAlignment=\"top\" image=\"BACKMAIN\" textcolor=\"250,250,250\" hovercolor=\"250,250,250\" downcolor=\"250,250,250\" hdelta=\"-4\" bigfont=\"1\"/>\n  </panel>\n  <static id=\"id_static_tryshutdown\" title=\"正在安装，请稍作等待！~\" left=\"156\" top=\"274\" width=\"230\" heigth=\"29\"  xAlignment=\"left\" yAlignment=\"top\" color=\"255,0,0\"/>\n</window>\n"
  },
  {
    "path": "src/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ ɵİļ\n//  downloader.rc ʹ\n//\n#define IDR_MAINFRAME                   0x80\n#define PNG                             0x1770\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        101\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1000\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "src/time/time.cc",
    "content": "// Copyright (c) 2011 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n#include \"stdafx.h\"\n#include \"util/util_tools.h\"\n#include \"time.h\"\n\n#pragma comment(lib, \"winmm.lib\")\n\nnamespace base {\n// Accumulation of time lost due to rollover (in milliseconds).\nINT64 rollover_ms = 0;\n\n// The last timeGetTime value we saw, to detect rollover.\nDWORD last_seen_now = 0;\n\nCriticalSection m_cs;\n\nTimeDelta RolloverProtectedNow() {\n  AutoCritSecLock<CriticalSection> lock(m_cs, false);\n  lock.Lock();\n  // We should hold the lock while calling tick_function to make sure that\n  // we keep last_seen_now stay correctly in sync.\n  DWORD now = ::timeGetTime();\n  if (now < last_seen_now)\n    rollover_ms += 0x100000000I64; // ~49.7 days.\n  last_seen_now = now;\n  lock.Unlock();\n  return TimeDelta::FromMilliseconds(now + rollover_ms);\n}\n\nint TimeDelta::InDays() const {\n  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);\n}\n\nint TimeDelta::InHours() const {\n  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);\n}\n\nint TimeDelta::InMinutes() const {\n  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);\n}\n\ndouble TimeDelta::InSecondsF() const {\n  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;\n}\n\nINT64 TimeDelta::InSeconds() const {\n  return delta_ / Time::kMicrosecondsPerSecond;\n}\n\ndouble TimeDelta::InMillisecondsF() const {\n  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;\n}\n\nINT64 TimeDelta::InMilliseconds() const {\n  return delta_ / Time::kMicrosecondsPerMillisecond;\n}\n\nINT64 TimeDelta::InMillisecondsRoundedUp() const {\n  return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /\n         Time::kMicrosecondsPerMillisecond;\n}\n\nINT64 TimeDelta::InMicroseconds() const { return delta_; }\n\nbool TimeTicks::is_null() const { return 0 == ticks_; }\n\n// static\nTimeTicks TimeTicks::Now() {\n  return TimeTicks() + RolloverProtectedNow();\n}\n\n} // namespace base\n"
  },
  {
    "path": "src/time/time.h",
    "content": "#pragma once\n\n#include <string>\n#include <assert.h>\n#include <mmsystem.h>\n#include <windows.h>\n#include \"../base/macros.h\"\n\nnamespace base {\nclass TimeTicks;\n\nclass Time {\npublic:\n  static const INT64 kMillisecondsPerSecond = 1000;\n  static const INT64 kMicrosecondsPerMillisecond = 1000;\n  static const INT64 kMicrosecondsPerSecond =\n      kMicrosecondsPerMillisecond * kMillisecondsPerSecond;\n  static const INT64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;\n  static const INT64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;\n  static const INT64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24;\n  static const INT64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;\n  static const INT64 kNanosecondsPerMicrosecond = 1000;\n  static const INT64 kNanosecondsPerSecond =\n      kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;\n};\n\nclass TimeDelta {\npublic:\n  TimeDelta() : delta_(0) {}\n  explicit TimeDelta(const INT64 &delta) : delta_(delta) {}\n\n  TimeDelta &operator=(TimeDelta other) {\n    delta_ = other.delta_;\n    return *this;\n  }\n\n  INT64 ToInternalValue() const { return delta_; }\n\n  // Returns the time delta in some unit. The F versions return a floating\n  // point value, the \"regular\" versions return a rounded-down value.\n  //\n  // InMillisecondsRoundedUp() instead returns an integer that is rounded up\n  // to the next full millisecond.\n  int InDays() const;\n  int InHours() const;\n  int InMinutes() const;\n  double InSecondsF() const;\n  INT64 InSeconds() const;\n  double InMillisecondsF() const;\n  INT64 InMilliseconds() const;\n  INT64 InMillisecondsRoundedUp() const;\n  INT64 InMicroseconds() const;\n\n  // Converts units of time to TimeDeltas.\n  static TimeDelta FromDays(INT64 days);\n  static TimeDelta FromHours(INT64 hours);\n  static TimeDelta FromMinutes(INT64 minutes);\n  static TimeDelta FromSeconds(INT64 secs);\n  static TimeDelta FromMilliseconds(INT64 ms);\n  static TimeDelta FromMicroseconds(INT64 us);\n\n  // Comparison operators.\n  bool operator==(const TimeDelta &other) const {\n    return delta_ == other.delta_;\n  }\n  bool operator!=(const TimeDelta &other) const {\n    return delta_ != other.delta_;\n  }\n  bool operator<(const TimeDelta &other) const { return delta_ < other.delta_; }\n  bool operator<=(const TimeDelta &other) const {\n    return delta_ <= other.delta_;\n  }\n  bool operator>(const TimeDelta &other) const { return delta_ > other.delta_; }\n  bool operator>=(const TimeDelta &other) const {\n    return delta_ >= other.delta_;\n  }\n\n  // Computations with other deltas.\n  TimeDelta operator+(TimeDelta other) const {\n    return TimeDelta(delta_ + other.delta_);\n  }\n  TimeDelta operator-(TimeDelta other) const {\n    return TimeDelta(delta_ - other.delta_);\n  }\n\n  TimeDelta &operator+=(TimeDelta other) {\n    delta_ += other.delta_;\n    return *this;\n  }\n  TimeDelta &operator-=(TimeDelta other) {\n    delta_ -= other.delta_;\n    return *this;\n  }\n  TimeDelta operator-() const { return TimeDelta(-delta_); }\n\n  TimeTicks operator+(TimeTicks t) const;\n  // Computations with ints, note that we only allow multiplicative operations\n  // with ints, and additive operations with other deltas.\n  TimeDelta operator*(INT64 a) const { return TimeDelta(delta_ * a); }\n  TimeDelta operator/(INT64 a) const { return TimeDelta(delta_ / a); }\n  TimeDelta &operator*=(INT64 a) {\n    delta_ *= a;\n    return *this;\n  }\n  TimeDelta &operator/=(INT64 a) {\n    delta_ /= a;\n    return *this;\n  }\n  INT64 operator/(TimeDelta a) const { return delta_ / a.delta_; }\n  friend class TimeTicks;\n\nprivate:\n  INT64 delta_;\n};\n\n// static\ninline TimeDelta TimeDelta::FromDays(INT64 days) {\n  return TimeDelta(days * Time::kMicrosecondsPerDay);\n}\n\n// static\ninline TimeDelta TimeDelta::FromHours(INT64 hours) {\n  return TimeDelta(hours * Time::kMicrosecondsPerHour);\n}\n\n// static\ninline TimeDelta TimeDelta::FromMinutes(INT64 minutes) {\n  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);\n}\n\n// static\ninline TimeDelta TimeDelta::FromSeconds(INT64 secs) {\n  return TimeDelta(secs * Time::kMicrosecondsPerSecond);\n}\n\n// static\ninline TimeDelta TimeDelta::FromMilliseconds(INT64 ms) {\n  return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);\n}\n\n// static\ninline TimeDelta TimeDelta::FromMicroseconds(INT64 us) { return TimeDelta(us); }\n\nclass TimeTicks {\npublic:\n  TimeTicks() : ticks_(0) {}\n  explicit TimeTicks(INT64 ticks) : ticks_(ticks) {}\n  bool is_null() const;\n  // Returns the internal numeric value of the TimeTicks object.\n  // For serializing, use FromInternalValue to reconstitute.\n  INT64 ToInternalValue() const { return ticks_; }\n  // Now\n  static TimeTicks Now();\n\n  TimeTicks &operator=(const TimeTicks &other) {\n    ticks_ = other.ticks_;\n    return *this;\n  }\n\n  // Compute the difference between two times.\n  TimeDelta operator-(TimeTicks other) const {\n    return TimeDelta(ticks_ - other.ticks_);\n  }\n\n  // Modify by some time delta.\n  TimeTicks &operator+=(TimeDelta delta) {\n    ticks_ += delta.delta_;\n    return *this;\n  }\n  TimeTicks &operator-=(TimeDelta delta) {\n    ticks_ -= delta.delta_;\n    return *this;\n  }\n\n  // Return a new TimeTicks modified by some delta.\n  TimeTicks operator+(TimeDelta delta) const {\n    return TimeTicks(ticks_ + delta.delta_);\n  }\n  TimeTicks operator-(TimeDelta delta) const {\n    return TimeTicks(ticks_ - delta.delta_);\n  }\n\n  // Return a new TimeTicks modified by some delta.\n  TimeTicks operator+(INT64 delta) const { return TimeTicks(ticks_ + delta); }\n  TimeTicks operator-(INT64 delta) const { return TimeTicks(ticks_ - delta); }\n\n  // Comparison operators\n  bool operator==(const TimeTicks &other) const {\n    return ticks_ == other.ticks_;\n  }\n  bool operator!=(const TimeTicks &other) const {\n    return ticks_ != other.ticks_;\n  }\n  bool operator<(const TimeTicks &other) const { return ticks_ < other.ticks_; }\n  bool operator<=(const TimeTicks &other) const {\n    return ticks_ <= other.ticks_;\n  }\n  bool operator>(const TimeTicks &other) const { return ticks_ > other.ticks_; }\n  bool operator>=(const TimeTicks &other) const {\n    return ticks_ >= other.ticks_;\n  }\n  friend class TimeDelta;\n\n  // Tick count in microseconds.\nprivate:\n  INT64 ticks_;\n};\n\ninline TimeTicks TimeDelta::operator+(TimeTicks t) const {\n  return TimeTicks(t.ticks_ + delta_);\n}\n\n} // namespace base\n"
  }
]