[
  {
    "path": ".gitattributes",
    "content": "*.doc  diff=astextplain\n*.DOC\tdiff=astextplain\n*.docx\tdiff=astextplain\n*.DOCX\tdiff=astextplain\n*.dot\tdiff=astextplain\n*.DOT\tdiff=astextplain\n*.pdf\tdiff=astextplain\n*.PDF\tdiff=astextplain\n*.rtf\tdiff=astextplain\n*.RTF\tdiff=astextplain\n\n*.jpg  \tbinary\n*.png \tbinary\n*.gif \tbinary\n\n*.cs text diff=csharp\n*.vb text\n*.c text\n*.cpp text\n*.cxx text\n*.h text\n*.hxx text\n*.py text\n*.rb text\n*.java text\n*.html text\n*.htm text\n*.css text\n*.scss text\n*.sass text\n*.less text\n*.js text\n*.lisp text\n*.clj text\n*.sql text\n*.php text\n*.lua text\n*.m text\n*.asm text\n*.erl text\n*.fs text\n*.fsx text\n*.hs text\n\n*.csproj text merge=union \n*.vbproj text merge=union \n*.fsproj text merge=union \n*.dbproj text merge=union \n*.sln text eol=crlf merge=union \n\nsrc/Setup/resource.h binary\nsrc/Setup/Setup.rc binary\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Feedback to help us improve the project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Squirrel version(s)**\n_Which version(s) of the project are you using?_\n\n**Description**\n_Replace this text with a short description of the problem_\n\n**Steps to recreate**\n1. Replace this\n2. text with \n3. the steps\n4. to recreate\n\n**Expected behavior**\n_Explain what it's doing and why it's wrong_\n\n**Actual behavior**\n_Explain what it should be doing after it's fixed_\n\n**Additional information**\n_Add any other context about the problem here_\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build Squirrel\n\non:\n  push:\n    branches:\n      - master\n      - develop\n  pull_request:\n    branches:\n      - master\n      - develop\n\nenv:\n  DOTNET_NOLOGO: true\n  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n  DOTNET_CLI_TELEMETRY_OPTOUT: true\n  NUGET_XMLDOC_MODE: skip\n\njobs:\n  build:\n    name: Build\n    runs-on: windows-2019\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n          submodules: recursive\n\n      - name: Build Squirrel\n        shell: cmd\n        run: ./src/build_official.cmd\n\n      - name: Test Squirrel\n        shell: cmd\n        run: ./test/test_official.cmd\n\n      - name: Save build\n        uses: actions/upload-artifact@v2\n        with:\n          name: artifacts\n          path: build/artifacts/\n"
  },
  {
    "path": ".gitignore",
    "content": "\n#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/**\ntmp/**\ntmp/**/*\n*.tmp\n*.bak\n*.swp\n*~.nib\nlocal.properties\n.classpath\n.settings/\n.loadpath\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n\n#################\n## Visual Studio\n#################\n\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n*.sln.ide\n\n# Build results\n**/[Dd]ebug/\n**/[Rr]elease/\n*_i.c\n*_p.c\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.vspscc\n.builds\n**/*.dotCover\n**/packages/\n\npackages\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n\n# Visual Studio profiler\n*.psess\n*.vsp\n\n# ReSharper is a .NET coding add-in\n_ReSharper*\n\n# Installshield output folder \n[Ee]xpress\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish\n\n# Others\n[Bb]in\n[Oo]bj\nsql\nTestResults\n*.Cache\nClientBin\nstylecop.*\n~$*\n*.dbmdl\nGenerated_Code #added for RIA/Silverlight projects\n\n# Backup & report files from converting an old project file to a newer\n# Visual Studio version. Backup files are not needed, because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\n\n\n\n############\n## Windows\n############\n\n# Windows image file caches\nThumbs.db \n\n# Folder config file\nDesktop.ini\n\n\n#############\n## Python\n#############\n\n*.py[co]\n\n# Packages\n*.egg\n*.egg-info\ndist\nbuild\neggs\nparts\nbin\nvar\nsdist\ndevelop-eggs\n.installed.cfg\n\n# Installer logs\npip-log.txt\n\n# Unit test / coverage reports\n.coverage\n.tox\n\n#Translations\n*.mo\n\n#Mr Developer\n.mr.developer.cfg\n\n# Mac crap\n.DS_Store\n\n# NCrunch crap\n*ncrunch*\n\n## WiX PDBs\n*.wixpdb\n*.wixobj\n\n## NUnit Test Output\nnunit-Squirrel.Tests.xml\n\n## Pester Test Output\ntests/Test.xml\n\n## CPP db crap\n*.db\n*.opendb\n.vs/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"vendor/nuget\"]\n\tpath = vendor/nuget\n\turl = https://github.com/Squirrel/NuGet\n\tbranch = fix-prerelease-comparison\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, sex characteristics, gender identity and expression,\nlevel of experience, education, socio-economic status, nationality, personal\nappearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\n advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at github@brendanforster.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see\nhttps://www.contributor-covenant.org/faq\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright (c) 2012 GitHub, Inc.\n\nPermission is hereby granted,  free of charge,  to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to  use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "| README.md |\n|:---|\n\n# Contributors Needed\n\nWe are looking for help with maintaining this important project - please read the discussion in [#1470](https://github.com/Squirrel/Squirrel.Windows/issues/1470) for more information.\n\n---\n\n# Squirrel: It's like ClickOnce but Works™\n\n![](docs/artwork/Squirrel-Logo.png)\n\n[![Build Status](https://dev.azure.com/squirrel-installers/Squirrel.Windows/_apis/build/status/Squirrel.Squirrel.Windows?branchName=master)](https://dev.azure.com/squirrel-installers/Squirrel.Windows/_build/latest?definitionId=1&branchName=master)\n\nSquirrel is both a set of tools and a library, to completely manage both installation and updating your Desktop Windows application, written in either C# or any other language (i.e., Squirrel can manage native C++ applications).\n\nSquirrel uses NuGet packages to create installation and update packages, which means that you probably already know most of what you need to create an installer.\n\n## What Do We Want?\n\nWindows apps should be as fast and as easy to install and update as apps like Google Chrome. From an app developer's side, it should be really straightforward to create an installer for my app, and publish updates to it, without having to jump through insane hoops. \n\n* **Integrating** an app to use Squirrel should be extremely easy, provide a client API, and be developer friendly.\n* **Packaging** is really easy, can be automated, and supports delta update packages.\n* **Distributing** should be straightforward, use simple HTTP updates, and provide multiple \"channels\" (a-la Chrome Dev/Beta/Release).\n* **Installing** is Wizard-Free™, with no UAC dialogs, does not require reboot, and is .NET Framework friendly.\n* **Updating** is in the background, doesn't interrupt the user, and does not require a reboot.\n\nRefer to our full list of goals for [integrating, packaging, distributing, installing, and updating](docs/goals.md).\n\n## Documentation\n\nSee the documentation [Table of Contents](docs/readme.md) for an overview of the available documentation for Squirrel.Windows. It includes a [Getting Started Guide](docs/getting-started/0-overview.md) as well as additional topics related to using Squirrel in your applications. \n\n## Building Squirrel\nFor the impatient:\n\n```sh\ngit clone --recursive https://github.com/squirrel/squirrel.windows\ncd squirrel.windows\ndevbuild.cmd\n```\nSee [Contributing](docs/contributing/contributing.md) for additional information on building and contributing to Squirrel.\n\n\n## License and Usage\n\nSee [COPYING](COPYING) for details on copyright and usage of the Squirrel.Windows software.\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Squirrel.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.28803.352\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Squirrel\", \"src\\Squirrel\\Squirrel.csproj\", \"{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Squirrel.Tests\", \"test\\Squirrel.Tests\\Squirrel.Tests.csproj\", \"{98AEB048-E27D-42F4-9440-505B7F78BAFD}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Setup\", \"src\\Setup\\Setup.vcxproj\", \"{C1D40624-A484-438A-B846-052F321C89D1}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Update\", \"src\\Update\\Update.csproj\", \"{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"SyncReleases\", \"src\\SyncReleases\\SyncReleases.csproj\", \"{EB521191-1EBF-4D06-8541-ED192E2EE378}\"\r\nEndProject\r\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"SolutionLevel\", \"SolutionLevel\", \"{ED657D2C-F8A0-4012-A64F-7367D41BE4D2}\"\r\n\tProjectSection(SolutionItems) = preProject\r\n\t\tsrc\\Squirrel.nuspec = src\\Squirrel.nuspec\r\n\t\tvendor\\wix\\template.wxs = vendor\\wix\\template.wxs\r\n\tEndProjectSection\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Core\", \"vendor\\nuget\\src\\Core\\Core.csproj\", \"{F879F274-EFA0-4157-8404-33A19B4E6AEC}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"WriteZipToSetup\", \"src\\WriteZipToSetup\\WriteZipToSetup.vcxproj\", \"{4D3C8B70-075D-48A5-9FF3-EDB87347B136}\"\r\nEndProject\r\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Update-Mono\", \"src\\Update\\Update-Mono.csproj\", \"{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}\"\r\nEndProject\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"StubExecutable\", \"src\\StubExecutable\\StubExecutable.vcxproj\", \"{C028DB2A-E7C5-4232-8C22-D5FBA2176136}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tCIBuild|Any CPU = CIBuild|Any CPU\r\n\t\tCIBuild|Mixed Platforms = CIBuild|Mixed Platforms\r\n\t\tCIBuild|x64 = CIBuild|x64\r\n\t\tCIBuild|x86 = CIBuild|x86\r\n\t\tCoverage|Any CPU = Coverage|Any CPU\r\n\t\tCoverage|Mixed Platforms = Coverage|Mixed Platforms\r\n\t\tCoverage|x64 = Coverage|x64\r\n\t\tCoverage|x86 = Coverage|x86\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tDebug|Mixed Platforms = Debug|Mixed Platforms\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tMono Debug|Any CPU = Mono Debug|Any CPU\r\n\t\tMono Debug|Mixed Platforms = Mono Debug|Mixed Platforms\r\n\t\tMono Debug|x64 = Mono Debug|x64\r\n\t\tMono Debug|x86 = Mono Debug|x86\r\n\t\tMono Release|Any CPU = Mono Release|Any CPU\r\n\t\tMono Release|Mixed Platforms = Mono Release|Mixed Platforms\r\n\t\tMono Release|x64 = Mono Release|x64\r\n\t\tMono Release|x86 = Mono Release|x86\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\t\tRelease|Mixed Platforms = Release|Mixed Platforms\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|x64.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.CIBuild|x86.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|x64.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Coverage|x86.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|x64.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Mono Release|x86.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1436E22A-FE3C-4D68-9A85-9E74DF2E6A92}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|x64.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|x64.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|x86.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.CIBuild|x86.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|x64.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|x64.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|x86.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Coverage|x86.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|x64.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Mono Release|x86.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{98AEB048-E27D-42F4-9440-505B7F78BAFD}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|Any CPU.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|x64.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|x64.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|x86.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.CIBuild|x86.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|Any CPU.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|x64.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|x64.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|x86.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Coverage|x86.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|Any CPU.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|x64.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Debug|x86.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|x64.ActiveCfg = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|x64.Build.0 = Debug|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|x86.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Mono Release|x86.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|x64.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{C1D40624-A484-438A-B846-052F321C89D1}.Release|x86.Build.0 = Release|Win32\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|x64.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.CIBuild|x86.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|x64.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Coverage|x86.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|x64.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Mono Release|x86.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{1EEBACBC-6982-4696-BD4E-899ED0AC6CD2}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x64.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.CIBuild|x86.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x64.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Coverage|x86.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x64.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Mono Release|x86.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{EB521191-1EBF-4D06-8541-ED192E2EE378}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|Any CPU.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|Any CPU.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|Mixed Platforms.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|Mixed Platforms.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|x64.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|x64.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|x86.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.CIBuild|x86.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|Any CPU.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|Any CPU.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|Mixed Platforms.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|Mixed Platforms.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|x64.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|x64.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|x86.ActiveCfg = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Coverage|x86.Build.0 = Coverage|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|Any CPU.ActiveCfg = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|Any CPU.Build.0 = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|Mixed Platforms.ActiveCfg = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|Mixed Platforms.Build.0 = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|x64.ActiveCfg = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|x64.Build.0 = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|x86.ActiveCfg = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Debug|x86.Build.0 = Mono Debug|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|Any CPU.ActiveCfg = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|Any CPU.Build.0 = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|Mixed Platforms.ActiveCfg = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|Mixed Platforms.Build.0 = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|x64.ActiveCfg = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|x64.Build.0 = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|x86.ActiveCfg = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Mono Release|x86.Build.0 = Mono Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{F879F274-EFA0-4157-8404-33A19B4E6AEC}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Any CPU.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|x64.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|x64.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|x86.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.CIBuild|x86.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|Any CPU.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|x64.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|x64.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|x86.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Coverage|x86.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|x64.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|x64.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Debug|x86.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|Any CPU.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|x64.ActiveCfg = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|x64.Build.0 = Debug|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|x86.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Mono Release|x86.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|x64.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{4D3C8B70-075D-48A5-9FF3-EDB87347B136}.Release|x86.Build.0 = Release|Win32\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|x64.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|x64.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|x86.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.CIBuild|x86.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|x64.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|x64.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|x86.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Coverage|x86.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|x64.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Mono Release|x86.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{5B4BC824-73FC-49D7-BD9D-CE53AA1AA86E}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|Any CPU.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|Any CPU.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|x64.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|x64.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|x86.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.CIBuild|x86.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|Any CPU.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|Any CPU.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|x64.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|x64.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|x86.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Coverage|x86.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|Any CPU.ActiveCfg = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|Any CPU.Build.0 = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Debug|x86.Build.0 = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|Any CPU.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|Any CPU.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|Mixed Platforms.Build.0 = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|x64.Build.0 = Debug|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|x86.ActiveCfg = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Debug|x86.Build.0 = Debug|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|Any CPU.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|Any CPU.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|x64.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|x64.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|x86.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Mono Release|x86.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|Any CPU.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|Any CPU.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|Mixed Platforms.Build.0 = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x64.Build.0 = Release|x64\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x86.ActiveCfg = Release|Win32\r\n\t\t{C028DB2A-E7C5-4232-8C22-D5FBA2176136}.Release|x86.Build.0 = Release|Win32\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {68CA987A-9BAB-4C75-8EEB-4596BA6BBD07}\r\n\tEndGlobalSection\r\n\tGlobalSection(MonoDevelopProperties) = preSolution\r\n\t\tPolicies = $0\r\n\t\t$0.TextStylePolicy = $1\r\n\t\t$1.inheritsSet = VisualStudio\r\n\t\t$1.inheritsScope = text/plain\r\n\t\t$1.scope = text/plain\r\n\t\t$0.CSharpFormattingPolicy = $2\r\n\t\t$2.IndentSwitchBody = True\r\n\t\t$2.IndentBlocksInsideExpressions = True\r\n\t\t$2.AnonymousMethodBraceStyle = NextLine\r\n\t\t$2.PropertyBraceStyle = NextLine\r\n\t\t$2.PropertyGetBraceStyle = NextLine\r\n\t\t$2.PropertySetBraceStyle = NextLine\r\n\t\t$2.EventBraceStyle = NextLine\r\n\t\t$2.EventAddBraceStyle = NextLine\r\n\t\t$2.EventRemoveBraceStyle = NextLine\r\n\t\t$2.StatementBraceStyle = NextLine\r\n\t\t$2.ElseNewLinePlacement = NewLine\r\n\t\t$2.CatchNewLinePlacement = NewLine\r\n\t\t$2.FinallyNewLinePlacement = NewLine\r\n\t\t$2.WhileNewLinePlacement = DoNotCare\r\n\t\t$2.ArrayInitializerWrapping = DoNotChange\r\n\t\t$2.ArrayInitializerBraceStyle = NextLine\r\n\t\t$2.BeforeMethodDeclarationParentheses = False\r\n\t\t$2.BeforeMethodCallParentheses = False\r\n\t\t$2.BeforeConstructorDeclarationParentheses = False\r\n\t\t$2.NewLineBeforeConstructorInitializerColon = NewLine\r\n\t\t$2.NewLineAfterConstructorInitializerColon = SameLine\r\n\t\t$2.BeforeDelegateDeclarationParentheses = False\r\n\t\t$2.NewParentheses = False\r\n\t\t$2.SpacesBeforeBrackets = False\r\n\t\t$2.inheritsSet = Mono\r\n\t\t$2.inheritsScope = text/x-csharp\r\n\t\t$2.scope = text/x-csharp\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "devbuild.cmd",
    "content": "@echo off\n\nsetlocal\npushd %~dp0\n\n:parse_args\nif /i \"%1\"==\"release\" set _C=/p:Configuration=Release\nif /i \"%1\"==\"init\" set _INIT=1\nif /i \"%1\"==\"initialize\" set _INIT=1\nif /i \"%1\"==\"inc\" set _INCREMENTAL=1\nif /i \"%1\"==\"incremental\" set _INCREMENTAL=1\nif /i \"%1\"==\"clean\" set _INCREMENTAL= & set _CLEAN=1\nif not \"%1\"==\"\" shift & goto parse_args\n\nif not \"%_INCREMENTAL\"==\"1\" rd /s /q build packages 2> nul\nif not \"%_CLEAN%\"==\"\" goto end\n\nif \"%_INIT%\"==\"1\" git submodule update --init --recursive\n\nnuget restore\n\nmsbuild -Restore %_C% -m -nr:false -v:m\n\n:end\npopd\nendlocal\n"
  },
  {
    "path": "docs/contributing/branching-strategy.md",
    "content": "| [docs](..)  / [contributing](.) / branching-strategy.md\n|:---|\n\n# tl;dr\n\n1. Fork Squirrel.Windows on GitHub\n2. Send features/fixes via pull request targeting the default branch: `develop`\n\n\n# Branching Strategy\n\nSquirrel.Windows uses a very lightweight rendition of [gitflow](https://nvie.com/posts/a-successful-git-branching-model/).\n\n* `master` branch - the `master` branch is where official releases of squirrel are built. Changes to `master` are made only via merge commits from the `develop` branch. Tags are made for each each release.\n* `develop` branch - the `develop` branch is where the next version of squirrel is under development. Changes to `develop` are made via pull request from forks and feature branches. So `develop` is the default branch on GitHub.\n* fork - your development takes place in fork. When a feature/fix is ready, a pull request is sent to Squirrel.Windows targeting  the `develop` branch.\n\n**Why gitflow?** This lightweight rendition of giflow adds minimal \"overhead\" in the `develop` branch. The `develop` branch allows us to experiment with new ideas and iterate on features. When \"enough\" work is completed for a release, complete integration testing--including multi-version upgrades--is done on the `develop` branch. When the testing is completed successfully, the `develop` branch is integrated into `master` and a release is automatically built and released.\n\n\n## See Also\n\n* [Building Squirrel](building-squirrel.md) - steps to build squirrel for the impatient.\n* [VS Solution Overview](vs-solution-overview.md) - overview of the various projects in the Squirrel.Windows Visual Studio solution.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/contributing/building-squirrel.md",
    "content": "| [docs](..)  / [contributing](.) / building-squirrel.md\n|:---|\n\n# Building Squirrel\n\nSquirrel.Windows is a fairly typical C# / C++ project, the only special part is making sure to clone submodules via the command shown below.\n\nFor the Impatient:\n\n```sh\ngit clone https://github.com/squirrel/squirrel.windows\ncd squirrel.windows\ngit submodule update --init --recursive       ## THIS IS THE PART YOU PROBABLY FORGOT\ndevbuild.cmd\n```\n\n**Tip:** You can compile the Squirrel.Windows solution with Visual Studio version 2019 and above (including community edition).\n\n**Tip:** For Visual Studio versions that use the Visual Studio Installer (2017/2019 and above), you will need to have at least both Desktop .NET development and Desktop C++ development workloads checked in the Visual Studio Installer. You will also need to make sure that the individual package for the VC++ version used by Squirrel is checked.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/contributing/contributing.md",
    "content": "| [docs](..)  / [contributing](.) / contributing.md\n|:---|\n\n# Contributing\n\nWhy not give back and help make Squirrel even better? Here is an overview of ways you can become more involved.\n\n* **Contribute Documentation** - improve the documentation or provide additional code examples to benefit others.\n* **Subscribe to Issues on GitHub** - have some experience using Squirrel? Help answer questions under issues or post a Pull Request fixing a bug.\n* **Contribute Code** -  have a great feature that you feel is a good fit for Squirrel? Send a Pull Request.\n\n\n## See Also\n\n* [Building Squirrel](building-squirrel.md) - steps to build squirrel for the impatient.\n* [VS Solution Overview](vs-solution-overview.md) - overview of the various projects in the Squirrel.Windows Visual Studio solution.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/contributing/vs-solution-overview.md",
    "content": "| [docs](..)  / [contributing](.) / vs-solution-overview.md\r\n|:---|\r\n\r\n# Visual Studio Solution Overview\r\n\r\nAn overview of the various projects in the Squirrel.Windows Visual Studio solution and how they relate to different aspects of the update process.\r\n\r\n\r\n| Project / Assembly Name | Libraries (NuGet) | Libraries (NuGet) | Releases Directory (releasify output) | MyApp (install location) |\r\n|--------------------------------|---------|-----|------------------|-------------| \r\n| **Core** NuGet.Squirrel.dll | NuGet.Squirrel.dll | | | |\r\n| **Squirrel** Squirrel.dll | Squirrel.dll | | | |\r\n| **SyncRelease** SyncRelease.exe |           | SyncRelease.exe | | |\r\n| **Update** Update.exe          |           | Squirrel.exe |             | Update.exe    |\r\n| **Setup**  Setup.exe |           | Setup.exe | Setup.exe (+MyApp.Latest.nupkg) | |\r\n| **WriteZipToSetup** WriteZipToSetup.exe  |           | WriteZipToSetup.exe | | |\r\n\r\n* **Project / Assembly Name**: Solution project name (from Squirrel.sln) and output assembly name.\r\n* **Libraries (NuGet)**: Program libraries installed added as references in your MyApp solution when adding the Squirrel.Windows NuGet package to your project.\r\n* **Libraries (NuGet)**: Executable tools included in the Squirrel.Windows NuGet package used to prepare deployments via the Package Manager Console (e.g., Squirrel.exe).\r\n* **Releases Directory (releasify output)**: Directory where the Squirrel --releasify process outputs the packages and Setup application for your project (e.g., MyAppSourceCode/Releases).\r\n* **MyApp (install location)**: MyApp install directory (e.g., %LOCALAPPDATA%\\MyApp) where the application is actually installed and updated via Squirrel.Windows.\r\n\r\n**Note**: Note that the Squirrel.exe application found in the tools directory of the Squirrel.Windows NuGet package is actually a renamed version of the Update.exe application (see Squirrel.Windows\\src\\Squirrel.nuspec) \r\n\r\n---\r\n| Return: [Table of Contents](../readme.md) |\r\n|----|\r\n\r\n"
  },
  {
    "path": "docs/faq.md",
    "content": "| [docs](.) / faq.md |\n|:---|\n\n# Frequently Asked Questions (FAQ)\n\nFrequently Asked Questions for Squirrel.Windows, organized by area below.\n\n## Integrating\n\n1. **Can Squirrel.Windows be used on applications that aren't made with .Net?**  \n   Yes, you can package a non-c# application in the same manner as described in the Getting Started guide. For additional customization, see [custom squirrel events for non-c# apps](using/custom-squirrel-events-non-cs.md).  \n1. **How do I migrate a ClickOnce app to Squirrel?**  \n   You may want to look into the [ClickOnceToSquirrelMigrator](https://github.com/flagbug/ClickOnceToSquirrelMigrator) migration helper.\n1. **How can I determine if my app is a Squirrel app? I provide a squirrel and non-squirrel install version and want to know which is running.**  \n   You can check for the `Update.exe` in the parent directory to determine if the app is using Squirrel ([see #574](https://github.com/Squirrel/Squirrel.Windows/issues/574#issuecomment-176043311)).\n   \n```\nvar assembly = Assembly.GetEntryAssembly();   \nvar updateDotExe = Path.Combine(Path.GetDirectoryName(assembly.Location), \"..\", \"Update.exe\");\nvar isSquirrelInstall = File.Exists(updateDotExe);\n```\n\n## Packaging\n\n1. **How can I tell what is going wrong with the releasify?**  \n   Check `packages\\Squirrel.Windows.VERSION\\tools\\SquirrelSetup.log` for logging information when creating packages.\n2. **Do I really have to add all the Squirrel DLLs to my app ?**\n   Yes, you have to add them all to the NuGet package, however, [others](https://github.com/Squirrel/Squirrel.Windows/issues/531) have used [ILMerge](https://www.microsoft.com/en-us/research/people/mbarnett/#ilmerge) to generate a single assembly.\n\n## Distributing\n\n1. **Can I distribute update files on IIS?**  \n   Yes you can, see [Microsoft IIS](using/microsoft-iis.md) for details.\n\n## Installing   \n\n1. **The Initial Install via `Setup.exe` is failing. How do I learn what is going wrong?**  \n   Check `%LocalAppData%\\SquirrelTemp\\SquirrelSetup.log` for logs related to the initial install.\n1. **Installer application doesn't do anything. The animation flashes but the application never starts.**  \n   The app is likely crashing on the first run (see [Debugging Installs](using/debugging-installs.md) for details).\n1. **The Installer seems to be blocked in Enterprise environments. How can I confirm this?**  \n   Squirrel may be prevented from installing if Group Policy disallows the running of executables from `%LocalAppData%`. In this case, the \"show log\" button on the \"installation failed\" dialog will fail because `Update.exe` can not run to create a log file.  \n   The `Setup.exe` for your application should still copy files to `%LocalAppData%\\SquirrelTemp` as a pre-installation step. To verify that Group Policy is restricting you, execute `Update.exe` from the command line as follows:  \n   ```\n   C:\\>%LocalAppData\\MyApp\\Update.exe\n   This program is blocked by group policy. For more information, contact your system administrator.    \n   ```\n   The best course of action is to request that executables for Squirrel and your application be whitelisted by your corporate overlords. \n1. **No Shortcuts are Created for my Application**   \n   Verify that the NuGet Package Metadata `id` property doesn't have a [space or \\[dot\\]](https://github.com/Squirrel/Squirrel.Windows/issues/530) in it.\n1. **Can I use a different name for the `Setup.exe` install application?**  \n   Yes, you can rename the `Setup.exe` to what ever you wish (e.g., `MyAppSetup.exe`) ([see #611](https://github.com/Squirrel/Squirrel.Windows/issues/611))\n1. **Virus scanner is returning false positives on `MyApp.exe` or `Update.exe`. What can I do?**   \n   [Application Signing](using/application-signing.md) will help. In addition, you can submit false positives to the various antivirus authors (e.g., [Symantec](https://submit.symantec.com/false_positive/), [Microsoft](https://www.microsoft.com/security/portal/Submission/Submit.aspx), [AVG](http://www.avg.com/submit-sample), [Comodo](https://www.comodo.com/home/internet-security/submit.php), [McAfee](https://support.mcafeesaas.com/MCAFEE/_cs/AnswerDetail.aspx?aid=65), [List of Submission Locations](http://www.techsupportalert.com/content/how-report-malware-or-false-positives-multiple-antivirus-vendors.htm), [see #218](https://github.com/Squirrel/Squirrel.Windows/issues/218#issuecomment-166406180)).\n1. **Why is my application icon mangled after installation?**  \n   Application icons specified in the [NuGet Package Metadata](using/nuget-package-metadata.md) must be of type icon (.ICO) rather than an image file (source: [issue #745](https://github.com/Squirrel/Squirrel.Windows/issues/745))\n\n## Updating\n\n1. **How do I determine what is going wrong with the UpdateManager in MyApp?**  \n   You can setup your `\\bin` directory so you can execute MyApp in the Visual Studio debugger and simply step through the update process as well as catch exceptions and log the results (see [Debugging Updates](using/debugging-updates.md) for details)\n2. **I've Distributed a Broken Copy of Update.exe. How can I fix this?**  \n   Sometimes, you might ship a broken copy of `Update.exe` that succeeds the initial install, but doesn't do what you want for some reason. To fix this, you can force an update of the `Update.exe` by including a copy of `Squirrel.exe` in your app update package. If Squirrel sees this, it will copy in this latest version to the local app installation.\n3. **How can you replace DLLs while they're loaded? Impossible!**  \n   You can't. So, how can you do it? The basic trick that ClickOnce uses is, you have a folder of EXEs and DLLs, and an Application Shortcut. When ClickOnce goes to update its stuff, it builds a completely *new* folder of binaries, then the last thing it does is rewrite the app shortcut to point to the new folder.\n4. **My previous application version is still around after the update. Doesn't Squirrel clean up old versions?**  \n   The current and immediately previous version of your application are not deleted on clean up (see [issue #589](https://github.com/Squirrel/Squirrel.Windows/issues/589)). \n5. **How can I persist the [.NET Application Settings](https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/application-settings-overview) after an update?**\n   See (https://github.com/Squirrel/Squirrel.Windows/issues/198#issuecomment-299262613) for a simple workaround if you want to keep using .NET Application Settings. Alternatively, consider using a solution that lets you control where the settings are persisted, and store settings in an app-specific location under `%LOCALAPPDATA%`.\n\n---\n| Return: [Table of Contents](readme.md) |\n|:---|\n"
  },
  {
    "path": "docs/getting-started/0-overview.md",
    "content": "| [docs](..) / [getting-started](.) / 0-overview.md|\n|:---|\n\n# Getting Started Guide\n\nGetting Started will walk you through the integration of Squirrel.Windows for a basic c# Windows Forms application named MyApp.\n\n## MyApp\n\nMyApp simply displays the assembly location and application version on a simple form.\n\n![](images/1-MyApp.png)\n\nFor simplicity, any unneeded references and files have been removed from the solution.\n\n![](images/1-MyApp-Solution.png)\n\nIf you wish to follow along, you can [download](example/MyApp.zip) a zip file of the MyApp solution.\n\n## Overview\nThis guide will go over the following steps to demonstrate using Squirrel.Windows to distribute and update MyApp.\n\n1. [Integrating](1-integrating.md) - integrating Squirrel `UpdateManager` into your application.\n1. [Packaging](2-packaging.md) - packaging application files and preparing them for release.\n1. [Distributing](3-distributing.md) - providing install and update files for users.\n1. [Installing](4-installing.md) - process of initial installation of your application.\n1. [Updating](5-updating.md) - process of updating an existing install.\n\n---\n| Next: [1. Integrating](1-integrating.md)|\n|:---|\n\n\n\n"
  },
  {
    "path": "docs/getting-started/1-integrating.md",
    "content": "| [docs](..) / [getting-started](.) / 1-integrating.md |\n|:---|\n\n\n\n# Step 1. Integrating\n\nThe first step is to configure MyApp to work with Squirrel.Windows. This requires you to install the Squirrel.Windows NuGet Package into the `MyApp.sln`.\n\n## Installing Squirrel.Windows\n\nThe easiest way to install the Squirrel.Windows is using the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) in Visual Studio after loading the MyApp solution.\n\n~~~powershell\nPM> Install-Package Squirrel.Windows\n~~~\n\n### Squirrel.Windows References\n\nThe package will install a number of dependent packages as well as tools that will be used to prepare MyApp to be released. The References in the Solution Explorer of the MyApp project now looks like the following (as of Squirrel.Windows version 1.2.2):\n\n![](images/1.1-post-package-install.png)\n\n**Tip:** Alternatively, you can use the \"Manage NuGet Packages\" GUI to install Squirrel.Windows (right clicking on your project in the Solution Explorer of Visual Studio and select \"Manage NuGet Packages...\"). \n\n## Basic Updating\n\nFor the basic example we are going to have MyApp update from your local file system rather than distributing the files via the web.  See section [Packaging](2-packaging.md) for additional options related to the distributing the update files.\n\n### Basic Squirrel.Windows Update Code\nThe following code is added to MyApp `Program.cs` to cause the application to check for, download, and install any new releases of MyApp in the background while you use the application. \n\n**`Program.cs`**\n\n~~~cs\nusing Squirrel;\nusing System.Threading.Tasks;\n~~~\n\n**`static async Task Main()`**\n\n~~~cs\nusing (var mgr = new UpdateManager(\"C:\\\\Projects\\\\MyApp\\\\Releases\"))\n{\n    await mgr.UpdateApp();\n}\n~~~\n\nThe code above demonstrates the most basic update mechanism using the `UpdateApp()` method in an asynchronous task. The actions it takes will be discussed further in section [Updating](5-updating.md).\n\n**Caution:** The path you provide the `UpdateManager` is the path to the directory where the `RELEASES` file is located (which is also named `Releases` by default), and not the actual `RELEASES` file.\n\n**Tip:** By default, the files for updating MyApp will be placed in the same directory as your `MyApp.sln` file under a `Releases` directory (e.g., `C:\\Projects\\MyApp\\Releases`).\n\n\n**Tip:** In this example we simply put the code in the `Program.cs` file. For a production application, place the update code later in start-up process so as to avoid slowing down your program start. \n\n**Tip:** If you attempt to debug the application via Visual Studio, you will get an exception of `Update.exe not found, not a Squirrel-installed app?`. You can resolve this by placing a copy of the Update.exe in your bin directory (see [Debugging Updates: Update.exe not found?](../using/debugging-updates.md) section for details).\n\n---\n| Previous: [Getting Started Guide](0-overview.md) | Next: [2. Packaging](2-packaging.md)|\n|:---|:---|\n"
  },
  {
    "path": "docs/getting-started/2-packaging.md",
    "content": "| [docs](..) / [getting-started](.) / 2-packaging.md |\n|:---|\n\n# Step 2. Packaging\n\nPackaging is the process of building, packing, and preparing MyApp release packages for distribution.\n\n## Building\n\nThe first step in preparing the application for distribution is to build the application. \n\n1. **Set MyApp Version** - set the initial application version.\n \n   \t**`Properties\\AssemblyInfo.cs`**\n   \n   \t~~~cs\n  \t[assembly: AssemblyVersion(\"1.0.0\")]\n\t[assembly: AssemblyFileVersion(\"1.0.0\")]\n   \t~~~\n2. **Switch to Release** - switch your build configuration to `Release`.\n3. **Build MyApp** - build your application to ensure the latest changes are included in the package we will be creating.\n\n## Packing\n\nSquirrel uses [NuGet](https://www.NuGet.org/) for bundling application files and various application properties (e.g., application name, version, description) in a single release package.\n\nSection [NuGet Package Metadata](../using/nuget-package-metadata.md) provides additional details on using NuGet and `.nuspec` files to automate the packing of your application. We will be going through the process using the [NuGet Package Explorer](https://github.com/NuGetPackageExplorer/NuGetPackageExplorer) to manually create a NuGet package.\n\n1. **Creating a New NuGet Package** - the first step is to create a new NuGet package.\n2. **Edit Metadata** - update package metadata for MyApp.\n   * **Id** - name of the application (no spaces)\n   * **Version** - version specified in `Properties\\Assembly.cs`\n   * **Dependencies** - Squirrel expects no dependencies in the package (all files should be explicitly added to the package)\n3. **Add lib & net45** - add the `lib` folder and the `net45` folder to the project. Squirrel is expecting a single `lib / net45` directory provided regardless of whether your app is a `net45` application.\n4. **Add Release Files** - add all the files from `bin\\Release` needed by MyApp to execute (including the various files required by Squirrel).\n   * **Include MyApp Files:** MyApp.exe, MyApp.exe.config, any non-standard .NET dll's needed by MyApp.exe.\n   * **Include Squirrel Files:** Squirrel.dll, Splat.dll, NuGet.Squirrel.dll, Mono.Cecil.\\*, DeltaCompressionDotNet.\\*,\n   * **Exclude:** *.vshost.\\*, *.pdb files \n5. **Save the NuGet Package File** - save the NuGet package file to where you can easily access later (e.g., `MyApp.sln` directory). Follow the given naming format (e.g., `MyApp.1.0.0.nupkg`).\n \n![](images/1.2-nuget-package-explorer.png)\n\n## Releasifying\n\nReleasifying is the process of preparing the `MyApp.1.0.0.nupkg` for distribution. \n\n### Using Releasify\n\nYou use the `Squirrel.exe` tool that was included in the Squirrel.Windows package you installed in the `MyApp.sln` previously. \n\nUse the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) to execute `Squirrel.exe --releasify` command.\n\n~~~powershell\nPM> Squirrel --releasify MyApp.1.0.0.nupkg\n~~~ \n\n**Tip:** If you get an error stating that `...'Squirrel' is not recognized...` then you may simply need to restart Visual Studio so the `Package Manager Console` will have loaded all the package tools.\n\n### Releasify Output\n\nThe `Squirrel --releasify` command completes the following:\n\n* **Create `Releases` Directory** - creates a Releases directory (in the `MyApp.sln` directory by default). \n* **Create `Setup.exe`** - creates a `Setup.exe` file which includes the latest version of the application to be installed.\n* **Create `RELEASES` File** - creates a file that provides a list of all release files for MyApp to be used during the update process\n* **Create `MyApp.1.0.0-full.nupkg`** - copies the package you created to the `Releases` directory.\n* **Create `MyApp.*.*.*-delta.nupkg`** - if you are releasing an update, releasify creates a delta file package to reduce the update package size (see [Updating](5-updating.md) for details).\n\n**`C:\\Projects\\MyApp\\Releases`**\n\n![](images/1.2-releases-directory.png)\n\n## See Also\n\n* [Visual Studio Build Packaging](../using/visual-studio-packaging.md) - integrating NuGet packaging into your visual studio build process to include packing and releasifying.\n\n\n---\n| Previous: [1. Integrating](1-integrating.md) | Next: [3. Distributing](3-distributing.md)|\n|:---|:---|\n"
  },
  {
    "path": "docs/getting-started/3-distributing.md",
    "content": "| [docs](..) / [getting-started](.) / 3-distributing.md |\n|:---|\n\n# Step 3. Distributing\r\n\nAfter packaging MyApp for distribution, the various files in the `Releases` directory are used to distribute MyApp to users. \n \n* **Setup Application** - the `Setup.exe` application is provided to new users to install the current version of MyApp (see [Installing](4-installing.md) for details). \n* **Update Files** - the `RELEASES` file, along with versioned full and delta packages, are used by the update process (see [Updating](5-updating.md) for details).  \n\n## Local File Distribution\n\nFor simplicity, this Getting Started guide uses a local file system location for updates. The location is defined in the update location provided to the `UpdateManager` (see code in [Integrating: Basic Updating](1-integrating.md)).\n\nThis generally is not practical for updates, unless all your users have access to similar network path where the files could be easily placed.  \n\n\n\n---\n| Previous: [2. Packaging](2-packaging.md) | Next: [4. Installing](4-installing.md)|\n|:---|:---|\n\n"
  },
  {
    "path": "docs/getting-started/4-installing.md",
    "content": "| [docs](..) / [getting-started](.) / 4-installing.md |\n|:---|\n# Step 4. Installing\r\n\r\nThe process to install MyApp is as simple as executing the `Setup.exe` application. `Setup.exe` is generated by the `Squirrel --releasify` process and is located in the `Releases` directory. \r\n\n## Setup.exe\n\n`Setup.exe` is a C++ bootstrapper application used to install MyApp on the user's local system. It includes the latest full version of the MyApp package files embedded in the exe file (see [Install Process](../using/install-process.md) for details).\n\n## Install Process Overview\n\nThe `Setup.exe` application does the following (see [Install Process](../using/install-process.md) for details):\n\n* Creates a `%LocalAppData%\\MyApp` directory for the MyApp to be installed.\n* Extracts and prepares the MyApp files under an `app-1.0.0` directory.\n* Launches `app-1.0.0\\MyApp.exe` at the end of the setup process.\n\n### Installed File Structure\n\nAn installation for MyApp will look like the following after the initial installation. \n\n#### `%LocalAppData%\\MyApp` Directory\n\n![](images/1.3-local-app-data-dir.png)\r\n\n\n---\n| Previous: [3. Distributing](3-distributing.md) | Next: [5. Updating](5-updating.md)|\n|:---|:---|\n\n"
  },
  {
    "path": "docs/getting-started/5-updating.md",
    "content": "| [docs](..) / [getting-started](.) / 5-updating.md |\n|:---|\n\n# Step 5. Updating\r\n\r\nThe update process uses the update files generated by the `Squirrel --releasify` process. This includes the `RELEASES` file as well as versioned full and delta packages as required. The location of where to look for the distributed update files is provided to the `UpdateManager` in the MyApp code (see code in [Integrating: Basic Updating](1-integrating.md)). \n\nUpdating MyApp to a new version is the culmination of integrating, packaging, and distributing after installing MyApp. The process will cause you to revisit the packaging and distributing steps.\nHH\n\nTo release a new update, you must first build, pack, and releasify your updated application.\n\n### Building\n\n1. **Update MyApp Version** - update the application version.\n \n   \t**`Properties\\AssemblyInfo.cs`**\n   \n   \t~~~cs\n  \t[assembly: AssemblyVersion(\"1.0.1\")]\r\t[assembly: AssemblyFileVersion(\"1.0.1\")]\n   \t~~~\n2. **Switch to Release** - switch your build configuration to `Release`.\n3. **Build MyApp** - build your application to ensure the latest changes are included in the package we will be creating.\n\n### Packing\n\nUsing [NuGet Package Explorer](https://npe.codeplex.com/) complete the following:\n\n1. **Open Previous NuGet Package** - open the previous NuGet package you created for MyApp version 1.0.0.\n2. **Update Version** - update the version in the metadata.\n4. **Replace Release Files** - replace the changed files under `lib\\net45`. You can simply drag and drop any program specific files that have changed (i.e., the `MyApp.exe` file is the only one that has updated in the example). \n5. **Save the NuGet Package File as New Version** - use the \"Save As...\" feature to save the new version of the package `MyApp.1.0.1.nupkg`.\n\n### Releasifying\n\nUse the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) to execute `Squirrel.exe --releasify` command using the new  `MyApp.1.0.1.nupkg` package.\n\n~~~powershell\nPM> Squirrel --releasify MyApp.1.0.1.nupkg\n~~~ \n\n**Tip:** If you get an error stating that `...'Squirrel' is not recognized...` then you may simply need to restart Visual Studio so the `Package Manager Console` will have loaded all the package tools. This behavior has been seen on the Community Edition of VS 2013 and 2015.\n\n#### Releasify Output\n\nAfter packaging the new MyApp version 1.0.1, the `Releases` directory has been updated as follows: \n \n* **Updated Setup Application** - the `Setup.exe` application has been updated to include the latest MyApp version 1.0.1 package.\n* **Updated Files** - the `RELEASES` file has been appended to include the newly created full and delta packages.\n\n## Distributing the New Release\n\nThe `Releases` directory now includes the updated files to distribute to your users. \n\n**`Releases` Directory**\n\n![](images/1.5-releases-directory.png)\n\nThe `RELEASES` file contains SHA1 hash, filename, and file size for each package. This information is utilized by the application update process. \n\n**`RELEASES` File**\n\n~~~\nE3F67244E4166A65310C816221A12685C83F8E6F MyApp-1.0.0-full.nupkg 600725\n0D777EA94C612E8BF1EA7379164CAEFBA6E24463 MyApp-1.0.1-delta.nupkg 6030\n85F4D657F8424DD437D1B33CC4511EA7AD86B1A7 MyApp-1.0.1-full.nupkg 600752\n~~~\n\n\n## Application Updating\n\nIn [Step 1. Integrating](1-integrating.md), we configured MyApp to look for and install any updates in the background each time MyApp is executed. In the MyApp example, a path to the `Releases` directory on the file system was specified. \n\n### Updating Process Overview\n\nThe following steps are performed by the `UpdateManager` each time MyApp is executed (see [Update Process](../using/update-process.md) for details):\n\n* The `UpdateManager` checks the `RELEASES` file at the distribution location for any updates.\n* Any update packages are downloaded and the new MyApp is prepared for execution. \n* App shortcuts are updated and old versions of MyApp are cleaned up.\n\n### MyApp Example\n\nThe first time I run MyApp after providing the update the application is executed like normal.\n\n![](images/1-MyApp.png)\n\nIn the background, MyApp has obtained and applied the updates in the installation directory.\n\n![](images/1.5-local-app-data-dir.png)\n\nThe next time MyApp is executed, it will be the newly installed version.\n\n![](images/1.5-MyApp.png)\n\n---\n| Previous: [4. Installing](4-installing.md) | Return: [Table of Contents](../readme.md)|\n|:---|:---|\n\n"
  },
  {
    "path": "docs/goals.md",
    "content": "| [docs](.) / goals.md |\n|:---|\n\n# What Do We Want?\r\n\r\nDeployment and Updates for Desktop applications are a real drag. ClickOnce almost works, but has some glaring bugs that don't seem like they'll ever be fixed. So let's own our own future and build a new one.\n\nWindows apps should be as fast and as easy to install and update as apps like Google Chrome. From an app developer's side, it should be really straightforward to create an installer for my app, and publish updates to it, without having to jump through insane hoops\n\n## Configuring\n\n* Integrating the installer for an existing .NET application should be really easy.\n* The client API should be able to check for updates and receive a (preferably in HTML) ChangeLog.\n* Developer should have control over custom actions and events during installing and updating.\n* Uninstall gives a chance for the application to clean up (i.e. I get to run a chunk of code on uninstall)\n\n## Packaging\n\n* Generating an installer given an existing .NET application should be really easy, like it is for ClickOnce.\n* Creating an update for my app should be a very simple process that is easily automated.\n* Packaging will support delta files to reduce the size of update packages.\n\n## Distributing\n\n* Hosting an update server should be really straightforward, and should be able to be done using simple HTTP (i.e. I should be able to host my installer and update feed via S3).\n* Support for multiple \"channels\" (a-la Chrome Dev/Beta/Release).\n\n## Installing \n\n* Install is Wizard-Free™ and doesn't look awful (or at least, it should have the *possibility* to not look awful).\n* No UAC dialogs, which means....\n* ...installs to the local user account (i.e. under `%LocalAppData%`).\n* No Reboots. None!\n* Can pull down the .NET Framework if need be.\n\n## Updating\n\n* Updates should be able to be applied while the application is running.\n* At no time should the user ever be forced to stop what he or she is doing.\n* No Reboots. None!\n\n\n\n---\n| Return: [Table of Contents](readme.md) |\n|:---|\n"
  },
  {
    "path": "docs/readme.md",
    "content": "| [docs](.) / readme.md |\n|:---|\n\n![](artwork/Squirrel-Logo.png)\n\n# Table of Contents\n\nThis document provides a table of contents for all the Squirrel documentation.\n\n## General Documentation\n\n* **[Squirrel Goals](goals.md)** - overview of the goals of the Squirrel.Windows project.\n* **[Frequently Asked Questions (FAQ)](faq.md)** - list of frequently asked questions.\n* **[Squirrel.Windows License](../COPYING)** - copyright and license for using Squirrel.Windows\n\n## Getting Started Guide\n\nThe **[Getting Started Guide](getting-started/0-overview.md)** provides a step-by-step guide for integrating Squirrel into a simple Windows Forms application named MyApp.\n\n1. **[Integrating](getting-started/1-integrating.md)** - integrating Squirrel `UpdateManager` into MyApp.\n1. **[Packaging](getting-started/2-packaging.md)** - packaging MyApp files and preparing them for release.\n1. **[Distributing](getting-started/3-distributing.md)** - providing install and update files for MyApp.\n1. **[Installing](getting-started/4-installing.md)** - process of initial installation of MyApp.\n1. **[Updating](getting-started/5-updating.md)** - process of updating an existing install of MyApp.\n\n## Using Squirrel\n\n\n* **Installing** - documentation related to the initial installation of your application via Setup.exe (and Setup.msi).\n  * [Install Process](using/install-process.md) - overview of the steps in the install process.\n  * [Custom Squirrel Events](using/custom-squirrel-events.md) - preforming custom actions for Squirrel events.\n  * [Custom Squirrel Events (non-c# apps)](using/custom-squirrel-events-non-cs.md) - steps on making a non-c# application Squirrel Aware and handling custom events.\n  * [Loading GIF](using/loading-gif.md) - specify a \"loading\" image during initial install of large applications.\n  * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating.\n  * [Machine-wide Installs](using/machine-wide-installs.md) - generating an MSI file suitable for installation via Group Policy.\n  * [Debugging Installs](using/debugging-installs.md) - tips for debugging Squirrel.Windows initial installs.\n* **Packaging** - documentation related to packaging app files and preparing them for release.\n  * [Naming Conventions](using/naming.md) - overview of sources used in naming (e.g., shortcut name).\n  * [NuGet Package Metadata](using/nuget-package-metadata.md) - overview of the NuGet metadata and its uses by Squirrel.\n  * [Packaging Tools](using/packaging-tools.md) - tools available to assist in the process of packaging your application (e.g., NuGet, OctoPack, Auto.Squirrel)\n  * [Squirrel Command Line](using/squirrel-command-line.md) - command line options for `Squirrel --releasify`\n  * [Delta Packages](using/delta-packages.md) - an overview of how `Squirrel.exe` creates delta packages.\n  * [Application Signing](using/application-signing.md) - adding code signing to `Setup.exe` and your application.\n* **Distributing** - documentation related to distributing the Setup.exe and update package files.\n  * [Microsoft IIS](using/microsoft-iis.md) - overview of using Microsoft IIS for distributing your application.\n  * [Amazon S3](using/amazon-s3.md) - overview of using Amazon S3 for distributing your application.\n  * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating.\n* **Updating** - documentation related to updating an existing install via the `UpdateManager`.\n  * [Update Process](using/update-process.md) - overview of the steps in the update process.\n  * [Update Manager](using/update-manager.md) - reference guide for the `UpdateManager`.\n  * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating.\n  * [Debugging Updates](using/debugging-updates.md) - tips for debugging Squirrel.Windows updates.\n  * [Staged Rollouts](using/staged-rollouts.md) - how to use staged rollouts to ramp up install distribution over time\n\n\n## Contributing\n\nWhy not give back and help make Squirrel even better by contributing to the project.\n\n* [Contributing](contributing/contributing.md) - overview of ways you can become more involved with Squirrel.Windows.\n* [Building Squirrel](contributing/building-squirrel.md) - steps to build squirrel for the impatient.\n* [VS Solution Overview](contributing/vs-solution-overview.md) - overview of the various projects in the Squirrel.Windows Visual Studio solution.\n* [Branching Strategy](contributing/branching-strategy.md) - overview of the different branches used in squirrel development.\n"
  },
  {
    "path": "docs/using/amazon-s3.md",
    "content": "| [docs](..)  / [using](.) / amazon-s3.md\n|:---|\n\n# Amazon S3\n\nAmazon S3 can be used as an easy mechanism to host your releases\n\n## Amazon S3 Setup\n\nThe following steps setup an S3 account and prepares MyApp for distribution.\n\n1. **Register for Amazon AWS** - if you haven't already, register for an Amazon AWS account and go to the AWS Console.\n2. **Create Bucket** - create a new bucket to hold your application updates\n3. **Update the Package Location** - update the package location on the `UpdateManager` in MyApp to use the S3 `Link` address for the files minus the actual file name. This is the address for downloading the file and is similar to the following address:  \n    `https://s3-us-west-2.amazonaws.com/myapp.bucket`\n4. **Build, Pack, Releasify** - perform the necessary steps to build, package, and releasify MyApp for distribution.\n3. **Upload Files** - upload the files from the Squirrel `Releases` directory into the S3 bucket.\n4. **Make Public** - make the files public by selecting the files and performing the \"Make Public\" action.\n\n## Amazon S3 Updates\n\nAfter you have setup your S3 account, the following steps will distribute a new package for release.\n\n4. **Build, Pack, Releasify** - perform the necessary steps to build, package, and releasify MyApp for distribution.\n3. **Upload Files** - upload the new files from the Squirrel `Releases` directory. Make sure to include the new `Setup.exe` and `RELEASES` file along with any full and delta files for the new version.\n4. **Make Public** - make the new files public by selecting the files and performing the \"Make Public\" action.\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/application-signing.md",
    "content": "| [docs](..)  / [using](.) / application-signing.md\r\n|:---|\r\n\r\n\r\n# Application Signing\r\n\r\nSigning your installer with a valid code signing certificate is one of the most important things that you need to do for production apps. Both IE SmartScreen as well as virus scanning software will give a significant amount of \"points\" to apps that are signed correctly, preventing your users from getting scary dialogs.\r\n\r\nAcquire a code-signing certificate - it's recommended to get a Windows Error Reporting-compatible certificate, see this [MSDN article](https://msdn.microsoft.com/library/windows/hardware/hh801887.aspx) for more information, then pass the -n parameter, which are the parameters you would pass to `signtool.exe sign` to sign the app.\r\n\r\nSquirrel makes signing easy, as it signs all of your application's executables *as well* as the final generated Setup.exe.\r\n\r\nAn example invocation including both of these features would be something like:\r\n\r\n~~~powershell\r\nPM> Squirrel --releasify MyApp.1.0.0.nupkg -n \"/a /f CodeCert.pfx /p MySecretCertPassword /fd sha256 /tr http://timestamp.digicert.com /td sha256\"\r\n~~~\r\n\r\nIf you are using the [Visual Studio Build Packaging](visual-studio-packaging.md) process be careful how you escape your quotation marks in the `XML` of your `.csproj` file for the -n, --signWithParams argument. The wrapping quotation marks must be defined in `XML` safe ampersand escape strings or `&quot;`. Within this command you will likely need quotation marks around your certificate password. Since this is already within a quoted string you will need to double quote the password: `/p &quot;&quot;PASSWORD&quot;&quot;`.\r\n\r\n~~~xml\r\n  <Target Name=\"AfterBuild\" Condition=\" '$(Configuration)' == 'Release'\">\r\n    <GetAssemblyIdentity AssemblyFiles=\"$(TargetPath)\">\r\n      <Output TaskParameter=\"Assemblies\" ItemName=\"myAssemblyInfo\" />\r\n    </GetAssemblyIdentity>\r\n    <Exec Command=\"nuget pack MyApp.nuspec -Version %(myAssemblyInfo.Version) -Properties Configuration=Release -OutputDirectory $(OutDir) -BasePath $(OutDir)\" />\r\n    <!-- Notice the use of &quot; rather than \" after the \\n flag. For the password to contain spaces we need to double-&quot; the string.  -->\r\n    <Exec Command=\"squirrel --releasify $(OutDir)MyApp.$([System.Version]::Parse(%(myAssemblyInfo.Version)).ToString(3)).nupkg -n &quot;/a /f .\\CertificateInProjectFolder.pfx /p &quot;&quot;CERTIFICATE PASSWORD&quot;&quot; /fd sha256 /tr http://timestamp.digicert.com /td sha256&quot;\" />\r\n  </Target>\r\n~~~\r\n\r\n\r\n\r\n## See Also\r\n* [Squirrel Command Line](squirrel-command-line.md) - command line options for `Squirrel --releasify`\r\n* [Visual Studio Build Packaging](visual-studio-packaging.md) - integrating Squirrel packaging into your build process\r\n\r\n\r\n---\r\n| Return: [Table of Contents](../readme.md) |\r\n|----|\r\n"
  },
  {
    "path": "docs/using/custom-squirrel-events-non-cs.md",
    "content": "| [docs](..)  / [using](.) / custom-squirrel-events-non-cs.md\n|:---|\n\n# Custom Squirrel Events (Non-C# Apps)\n\nSquirrel events allow you to handle custom events around the installation and updating process.\n\n### Making Your App Squirrel Aware \n\nAdd an entry to the *English* Version Block info called \"SquirrelAwareVersion\" with a value of \"1\". Typically this is done via the \"App.rc\" resource file. Here's a typical entry:\n\n```\nBLOCK \"StringFileInfo\"\nBEGIN\n    BLOCK \"040904b0\"\n    BEGIN\n        VALUE \"FileDescription\", \"Installer for Squirrel-based applications\"\n        VALUE \"FileVersion\", \"0.5.0.0\"\n        VALUE \"InternalName\", \"Setup.exe\"\n        VALUE \"LegalCopyright\", \"Copyright (C) 2014\"\n        VALUE \"OriginalFilename\", \"Setup.exe\"\n        VALUE \"ProductName\", \"Squirrel-based application\"\n        VALUE \"ProductVersion\", \"0.5.0.0\"\n        VALUE \"SquirrelAwareVersion\", \"1\"\n    END\nEND\n```\n\n### Application Startup Commands\n\nThis means that this EXE will be executed by the installer in a number of different scenarios, with special flags - you should handle them correctly:\n\n* `--squirrel-install x.y.z.m` - called when your app is installed. Exit as soon as you're finished setting up the app\n* `--squirrel-firstrun` - called after everything is set up. You should treat this like a normal app run (maybe show the \"Welcome\" screen)\n* `--squirrel-updated x.y.z.m` - called when your app is updated to the given version. Exit as soon as you're finished.\n* `--squirrel-obsolete x.y.z.m` - called when your out-of-date app is no longer the newest version. Exit as soon as you're finished.\n* `--squirrel-uninstall x.y.z.m` - called when your app is uninstalled. Exit as soon as you're finished.\n\n## See Also\n\n* [Custom Squirrel Events for c# Apps](custom-squirrel-events.md) - steps on making a c# application Squirrel Aware and handling custom events.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|"
  },
  {
    "path": "docs/using/custom-squirrel-events.md",
    "content": "| [docs](..)  / [using](.) / custom-squirrel-events.md\n|:---|\n\n# Custom Squirrel Events\n\n## Handling Squirrel Events\n\nSquirrel events allow you to handle custom events around the installation and updating process, which is important because Squirrel doesn't do much of anything at installation time automatically. However, since the code is executing inside your application, it's way easier to do stuff than other systems where you're writing custom \"installer DLLs\".\n\n### Overriding Default Behaviors\n\nWhen none of the apps in your package are \"Squirrel-Aware\", Squirrel does some things on your behalf to make your life easier, the primary one being that every EXE in your app package automatically gets a shortcut on both the Desktop and the Start Menu. Once you enable Squirrel events *for even a single EXE file*, you must do this yourself.\n\n### Making Your App Squirrel Aware \n\nIn your app's `AssemblyInfo.cs`, add the following line:\n\n```\n[assembly: AssemblyMetadata(\"SquirrelAwareVersion\", \"1\")]\n```\n\n### Using the `SquirrelAwareApp` Helper\n\nIf you are writing a C# app, it is **highly encouraged** to use the `SquirrelAwareApp` helper class to implement this. Here's an implementation that is similar to the default (i.e. non-squirrel-aware) behavior:\n\n```cs\nstatic bool ShowTheWelcomeWizard;\n...\nstatic int Main(string[] args) \n{\n    // NB: Note here that HandleEvents is being called as early in startup\n    // as possible in the app. This is very important! Do _not_ call this\n    // method as part of your app's \"check for updates\" code.\n\n    using (var mgr = new UpdateManager(updateUrl))\n    {\n        // Note, in most of these scenarios, the app exits after this method\n        // completes!\n        SquirrelAwareApp.HandleEvents(\n          onInitialInstall: v => mgr.CreateShortcutForThisExe(),\n          onAppUpdate: v => mgr.CreateShortcutForThisExe(),\n          onAppUninstall: v => mgr.RemoveShortcutForThisExe(),\n          onFirstRun: () => ShowTheWelcomeWizard = true);\n    }\n}\n```\n\n## App Setup Helper Methods\n\nThese methods help you to set up your application in Squirrel events - if you're not using custom Squirrel events, you probably don't need to call these methods.\n\n* `[Create/Remove]ShortcutsForExecutable` - creates and removes shortcuts on the desktop or in the Start Menu.\n\n* `[Create/Remove]UninstallerRegistryEntry` - creates and removes the uninstaller entry. Normally called by `Update.exe`.\n\n## See Also\n\n* [Custom Squirrel Events for non-c# Apps](custom-squirrel-events-non-cs.md) - steps on making a non-c# application Squirrel Aware and handling custom events.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/using/debugging-installs.md",
    "content": "| [docs](..)  / [using](.) / debugging-installs.md\n|:---|\n\n# Debugging Installs\n\nThe following tips will help you to debug the installation of an Squirrel app.\n\n## Simulating an Install and First Run\n\nIf the install of your application doesn't seem to be working, you can explore the behavior by executing the install steps from the command line:\n\n~~~ps\nC:\\user\\AppData\\Local\\MyApp> Update.exe --squirrel-install 1.0.0\nC:\\user\\AppData\\Local\\MyApp> Update.exe --squirrel-firstrun\n~~~\n\nThe first cmd should create some shortcuts then immediately exit, then the 2nd one should start your app ([source](https://github.com/Squirrel/Squirrel.Windows/issues/525))\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|"
  },
  {
    "path": "docs/using/debugging-updates.md",
    "content": "| [docs](..)  / [using](.) / debugging-updates.md\n|:---|\n\n# Debugging Updates\n\nThe following tips will help you to debug the update process in your application.\n\n## Update.exe not found?\n\nExecuting MyApp from Visual Studio will execute the update process and you will get the following exception from the `UpdateManager`:\n\n~~~\nUpdate.exe not found, not a Squirrel-installed app?\n~~~\n\nThe `UpdateManager` is expecting to find the `Update.exe` application installed one directory up from the EXE (e.g., the `\\bin` directory for default Visual Studio projects). \n\nTo resolve this, you can simply place a file named `Update.exe` or you can copy the `Squirrel.exe` from the `MyApp\\packages\\squirrel.windows.1.2.2.tools` directory and rename it Update.exe (this is the actual Update.exe packaged inside `Setup.exe`). \n\nExecuting MyApp from Visual Studio will now cause it to complete the update process and your `\\bin` directory will resemble the `%LocalAppData\\MyApp%` install directory:\n\n![](images/debugging-update-dir.png)\n\n**Tip:** If you want to ensure that the Update.exe is always available in your output directory, you can add the Update.exe file to the Visual Studio project and set its Properties > Copy To Output Directory to 'Copy if newer'. \n\n## Catching Update Exceptions\n\nYou can catch thrown exceptions and log the results. \n\n~~~cs\nusing (var mgr = new UpdateManager(\"C:\\\\Projects\\\\MyApp\\\\Releases\"))\n{\n    await mgr.UpdateApp();\n}\n~~~\n\nAlternatively, set up Splat Logging, see [here](https://github.com/Squirrel/Squirrel.Windows.Next/blob/6d7ae23602a3d9a7636265403d42c1090260e6dc/src/Update/Program.cs#L53) for an example.\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/using/delta-packages.md",
    "content": "| [docs](..)  / [using](.) / delta-packages.md\n|:---|\n\n\n# Delta Packages\r\n\nNow, once we've got a full package, we need to generate a Delta package. To do this, we'll replace all the DLL/EXEs in the NuGet packages with bsdiff files. [bspatch/bsdiff](http://code.logos.com/blog/2010/12/binary_patching_with_bsdiff.html) is a  mostly efficient algorithm for calculating diffs between binary files (especially Native binaries, but it works well for .NET ones too), and a way to apply them.\n\nSo, this is pretty easy:\n\n1. Extract the previous NuGet package\n1. Extract the current NuGet package\n1. Replace every EXE/DLL with the bsdiff. So, `lib\\net40\\MyCoolApp.exe` becomes `lib\\net40\\MyCoolApp.exe.diff`. Create a file that contains a SHA1 of the expected resulting file and its filesize called `lib\\net40\\MyCoolApp.exe.shasum`\n1. New DLLs in current get put in verbatim\n1. Zip it back up\n\nThe .shasum file has the same format as the Releases file described in the \"'Latest' Pointer\" section, except that it will only have one entry.\n\nSo now we've got all of the *metadata* of the original package, just none of its *contents*. To get the final package, we do the following:\n\n1. Take the previous version, expand it out\n1. Take the delta version, do the same\n1. For each DLL in the previous package, we bspatch it, then check the shasum file to ensure we created the correct resulting file\n1. If we find a DLL in the new package, just copy it over\n1. If we can't find a bspatch for a file, nuke it (it doesn't exist in the new rev)\n1. Zip it back up\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/github.md",
    "content": "| [docs](..)  / [using](.) / github.md\n|:---|\n\n# Using GitHub\n\nGitHub release assets can be used to distribute the necessary Squirrel files for the Squirrel install and update process. It still requires you to upload all the release files as assets for each release, but provides you a means of hosting your update files via your GitHub repository.\n\n**Important:** GitHub since February 22, 2018 [only support TLS 1.2 connections](https://githubengineering.com/crypto-removal-notice/). The host application is therefore required to use .NET framework 4.6.1, otherwise TLS 1.1 is the default protocol and check for update won't work. \n\n## Installing from GitHub\n\nGitHub allows you to provide a [static link](https://help.github.com/articles/linking-to-releases/) to a repositories latest release page. You can direct your users to download the `Setup.exe` from the list of assets you uploaded for the release.\n\n~~~\nhttps://github.com/myuser/MyApp/releases/latest\n~~~\n\n**Tip:** This link simply redirects to the repositories latest release page, and cannot be used to download an asset directly (i.e., you can't simply make a static link to \".../releases/latest/Setup.exe\"). However, you can use the [GitHub API with ajax](http://stackoverflow.com/a/26454035) to provide a direct link on your website and avoid the user having to select the correct file or navigate to the GitHub website.\n\n## Distributing from GitHub\n\nThe following steps are required to distribute your RELEASES and update NuGet packages with GitHub:\n\n1. **Commit Latest Code** - In order for GitHub to mark a new release as the `Latest`, you have at least one additional commit since the last release tag was added (i.e., releases tags must not share the same commit).\n1. **Create a New Release** - [Create a new GitHub release](https://help.github.com/articles/creating-releases/) in your MyApp repository matching your current release version (e.g., 1.0.0).\n2. **Upload Release Files** - upload all of the files from `Releases` as assets of the GitHub release (e.g., RELEASES, MyApp.1.0.0-full.nupkg, MyApp.1.0.1-delta.nupkg, MyApp.1.0.1-full.nupkg). \n3. **Set Pre-release (optional)** - if desired, set the release as a pre-release. \n4. **Publish the Release** - click the \"Publish Release\" to make the release available to the general public and your users.\n\n**Important:** You must upload all packages as assets you wish to be available for update (i.e., the GitHubUpdateManager doesn't look back to previous GitHub releases for previous version packages). If you only include the latest packages, Squirrel will be forced to download the latest full package for each update.\n\n\n## Updating with GitHub\n\nThe Updating process requires you to build, package, releasify, and distribute the update files. \n\n**Important:** You must ensure there is at least one additional commit since the last version release before adding a new release. GitHub will not update the latest release if the new release tag is tied to the same last commit as a previous release tag.\n\n### GitHub Update Manager\n\nTo use GitHub release assets as your distribution mechanism you need to replace `UpdateManager` with `GitHubUpdateManager` when integrating Squirrel in your app:  \n\n**`Program.cs`**\n\n~~~cs\nusing Squirrel;\nusing System.Threading.Tasks;\n~~~\n\n**`static async Task Main()`**\n\n~~~cs\nusing (var mgr = UpdateManager.GitHubUpdateManager(\"https://github.com/myuser/myapp\"))\n{\n  await mgr.Result.UpdateApp();\n}\n~~~\n\n**Important:** Make sure your url doesn't end in a forward slash (\"/\"). Adding the trailing forward slash will cause it to fail with a 404 error ([see #641](https://github.com/Squirrel/Squirrel.Windows/issues/641#issuecomment-201478324)).\n\n**Tip:** You can also specify that the update manager should use `prerelease` for updating (see method signature for details).\n\n**Source:** See [Issue #442](https://github.com/Squirrel/Squirrel.Windows/issues/442) for more information.\n\n### How it Works\n\nThe GitHub API is used by the `GitHubUpdateManager` to obtain the correct release and asset files for downloading. The following actions are performed:\n\n1. Extracts the username and repository from the url (e.g., \"myuser\" and \"myapp\").\n2. Uses the GitHub API to get the latest release information. For example, the following url obtains a json list of all release information for the Squirrel.Windows repository: [https://api.github.com/repos/Squirrel/Squirrel.Windows/releases](https://api.github.com/repos/Squirrel/Squirrel.Windows/releases)\n3. Obtains the correct download path from the `html_url` attribute of the latest release (or pre-release if specified) to be used as the path for downloading assets. \n4. Follows the normal Squirrel update process by looking for a `RELEASES` file and downloading the necessary delta or full application packages.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/install-process.md",
    "content": "| [docs](..)  / [using](.) / install-process.md\n|:---|\n\n# Install Process\n\nThis section goes into detail about the install process.\n\n## Setup.exe \n\n`Setup.exe` is a C++ bootstrapper application used to install your app on the user's local system. It is generated as part of the `Squirrel --releasify` process.\n\nThe `Setup.exe` file includes the `Update.exe` application and the latest version of the MyApp package to be installed. A single executable file can be provided due to the `WriteZipToSetup.exe` tool injecting the appropriate files into the exe. \n\nIn addition, the `Setup.exe` will also ensure that .NET 4.5 is installed on the user's computer.\n\n## Install Location\n\nThe `Setup.exe`, and later the `UpdateManager` in MyApp must have the ability to write files to and execute files from the application install location. To ensure permission for all types of users, the user's application data directory is selected as the install location (i.e., `%LocalAppData%\\MyApp`).\n\nThe installation root really only needs to consist of two types of folders:\n\n* **Packages** - folder used to download and assemble the update package files.\n* **App Folders** - the \"installed\" application files for a given version of MyApp.\n\n```\n\\%LocalAppData%\\MyApp\n   \\packages\n      MyApp-1.0.0.nupkg\n      MyApp-1.0.1-delta.nupkg\n      MyApp-1.0.1.nupkg   \n   \\app-1.0.0\n      MyApp.exe\n   \\app-1.0.1\n      MyApp.exe\n```\n\nThe packages directory is effectively immutable, it simply consists of the packages we've downloaded. Using the user's local application data directory means that we the needed write-access to the install directory on a per-user basis. \n\n**Tip:** See [Machine-wide Installs](machine-wide-installs.md) for more information on ensuring your application pushed to all users in an enterprise environment. \n\n## Install Process Overview\n\nThe `Setup.exe` application preforms the following:\n\n1. **Ensures .NET Framework Installed** - determines if .NET Framework is available, and if not relaunches itself with `/installfx45` to download and launch the .NET Framework installer.\n1. **Create `%LocalAppData%\\MyApp` Directory** - creates a directory for the MyApp to be installed.\n2. **Extracts `Update.exe`** - extracts the `Update.exe` application to the application directory (`%LocalAppData%\\MyApp`).\n3. **Extracts `MyApp.1.0.0-full.nupkg`** - extracts the MyApp full application package to the  `%LocalAppData%\\MyApp\\packages\\temp` directory.\n4. **Executes `Update.exe` to Finish Install** - executes the `Update.exe` application with the `/install` switch to finish the application installation and then launch the application.\n    1. **Copy MyApp to `app-1.0.0` Directory** - copy the full version of MyApp files to a application sub-directory (e.g., `MyApp\\app-1.0.0`). \n    2. **Launch MyApp** - at the end of the setup process, the Updater launches the  newly installed version of MyApp.\n6. **MyApp Creates Shortcuts** - the first execution of the application will cause shortcuts to be created on the desktop and Windows start menu for MyApp. \n\n## Desktop & Windows Start Shortcuts\n\nBy default, application shortcuts are created on the desktop and the Windows Start menu that point to the `Update.exe` application with additional arguments pointing to the correct application to execute.\n\n**`MyApp.lnk` (Application Shortcut)**\n\n* **Target:** `C:\\Users\\kbailey\\AppData\\Local\\MyApp\\Update.exe --processStart MyApp.exe`\n* **Start in:** `C:\\Users\\kbailey\\AppData\\Local\\MyApp\\app-1.0.0`\n\n\n## See Also\n\n* [Loading GIF](loading-gif.md) - specify a \"loading\" image during initial install of large applications.\n* [Machine-wide Installs](machine-wide-installs.md) - generating an MSI file suitable for installation via Group Policy.\n* [NuGet Package Metadata](nuget-package-metadata.md) - overview of the NuGet metadata and its uses by Squirrel.\n* [Naming Conventions](naming.md) - A more complete view of how Squirrel names everything.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n"
  },
  {
    "path": "docs/using/loading-gif.md",
    "content": "| [docs](..)  / [using](.) / loading-gif.md\n|:---|\n\n# Loading GIF\r\n\nSquirrel installers don't have any UI - the goal of a Squirrel installer is to install so blindingly fast that double-clicking on Setup.exe *feels* like double-clicking on an app shortcut. Make your installer **fast**.\n\nHowever, for large applications, this isn't possible. For these apps, Squirrel will optionally display a graphic as a \"splash screen\" while installation is processing, but only if installation takes more than a pre-set amount of time. This will be centered, backed by a transparent window, and can optionally be an animated GIF. Specify this via the `-g` parameter.\n\n~~~powershell\nPM> Squirrel --releasify MyApp.1.0.0.nupkg -g .\\loading.gif\n~~~ \n\n## See Also\n* [Squirrel Command Line](squirrel-command-line.md) - command line options for `Squirrel --releasify`\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/using/machine-wide-installs.md",
    "content": "| [docs](..)  / [using](.) / machine-wide-installs.md\r\n|:---|\r\n\r\n\r\n# Machine-wide Installs\r\n\r\nSquirrel's Releasify command generates an MSI file suitable for installation via Group Policy. This MSI isn't a general-purpose installer, this means that once you run the MSI, users from now on will get the app installed, on next Login.\r\n\r\nSo, most normal users should continue to run the Setup.exe's generated by Releasify, but if you want to have an IT Admin Friendly version, you can hand off the MSI\r\n\r\n## Common pitfalls\r\n\r\n### Missing data in `.nuspec`\r\n\r\nMost users of Squirrel won't have to do anything new to enable this behavior, though certain NuGet package IDs / names might cause problems with MSI. \r\n\r\n**Source:** See [issue #466](https://github.com/Squirrel/Squirrel.Windows/issues/466) for more details.\r\n\r\n### Nothing happens on login\r\n\r\nIn cases where the end user has previously installed your application, the installer that runs on login will not re-install your application on every login. This can easily be the case if you as a developer is testing out both the EXE and the MSI.\r\n\r\nSquirrel leaves behind an almost-empty `%LocalAppData%\\MyApp` folder after an uninstall. Deleting this folder (the entire folder, not just the contents) will allow the installer that runs on login to install successfully.\r\n\r\n**Source:**: See [issue #555](https://github.com/Squirrel/Squirrel.Windows/issues/555#issuecomment-253265130) for details.\r\n\r\n## Disabling MSI Generation\r\nGenerating MSIs can be disabled via the --no-msi flag as shown below:\r\n\r\n~~~powershell\r\nPM> Squirrel --releasify MyApp.1.0.0.nupkg --no-msi\r\n~~~ \r\n\r\n---\r\n| Return: [Table of Contents](../readme.md) |\r\n|----|\r\n"
  },
  {
    "path": "docs/using/microsoft-iis.md",
    "content": "| [docs](..)  / [using](.) / microsoft-iis.md\n|:---|\n\n# Microsoft IIS\n\nIf you use Microsoft IIS to distribute the necessary Squirrel files, you must provide a custom `Web.config` file as described below.\n\n## Hosting on IIS\n\nAll versions of IIS (including Microsoft Azure PaaS) deny serving files when\nthe extension MIME type is unknown. If you are hosting your updates in this\nmanner then you will need to add a `Web.config` to your downloads repository as\nfollows:\n\n**`~/downloads/Web.config` File**\n\n~~~xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <staticContent>\n      <mimeMap fileExtension=\".nupkg\" mimeType=\"application/zip\" />\n      <mimeMap fileExtension=\".\" mimeType=\"text/plain\" />\n    </staticContent>\n  </system.webServer>\n</configuration>\n~~~\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n\n"
  },
  {
    "path": "docs/using/naming.md",
    "content": "| [docs](..)  / [using](.) / naming.md\n|:---|\n\n# Naming Conventions\n\nIn addition to the [NuGet Package Metadata](nuget-package-metadata.md), there are other places that squirrel pulls naming information from. Here is the logic:\n\n## Shortcut name\n\nThe shortcut name is selected from the first non-null item below:\n\n1. `[assembly: AssemblyProduct(\"MyApp\")` (from `AssemblyInfo.cs`)\n2. Squirrel NuGet Package Metadata `title` property.\n3. `[assembly: AssemblyDescription(\"MyApp\")` (from `AssemblyInfo.cs`)\n4. Filename of the Exe (e.g., MyApp)\n\n## Local Install location\n\nThe local install location is determined by the `id` in the NuGet package metadata.\n\n* `%LocalAppData%\\<NuGet Package ID>`\n\n**Warning:** Using \\[dots\\] (i.e., \".\"'s) in your package id will cause issues ([see issue #523](https://github.com/Squirrel/Squirrel.Windows/issues/523)).\n\n## Program and Features Entry\nThe entry in the Windows Uninstall is determined as follows: \n\n* Squirrel NuGet Package Metadata `title` property\n\n## Releases Folder\n\nThe `Squirrel --releasify` command will create update packages based on the following:\n\n* `<NuGet Package ID>-<NuGet Package Version>-delta.nupkg`\n* `<NuGet Package ID>-<NuGet Package Version>-full.nupkg`\n\n![](images/naming-releases.png)\n\n## See Also\n\n* [NuGet Package Metadata](nuget-package-metadata.md) - naming from the NuGet Package Metadata perspective.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/using/nuget-package-metadata.md",
    "content": "| [docs](..)  / [using](.) / nuget-package-metadata.md\n|:---|\n\n# NuGet Package Metadata\n\nSquirrel uses information from your app's EXE as well as the NuGet package Metadata for the setup and uninstall UI.\n\n* **Id** - name of the application (**warning:** you must **[avoid using spaces and dots](https://github.com/Squirrel/Squirrel.Windows/issues/523)** in the Id).\n  * Name of the release packages (e.g., **MyApp**-1.0.0-full.nupkg). \n  * Local installation directory (e.g., `%LocalAppData%\\MyApp`).\n* **Title** - used for the name of the application in the Windows Application Uninstaller.\n* **Version** - version specified in `Properties\\Assembly.cs`. \n  * Name of the release package (e.g., MyApp-**1.0.0**-full.nupkg).\n  * Version number in the Windows Uninstaller (see screenshot below).\n* **Icon Url** - url to an icon to be used for the application. Used for the shortcuts and Windows Uninstaller icons. This must be an icon file (*.ICO) to work correctly. Note that the icon is fetched at installation time rather than\n packaging (source: [issue #745](https://github.com/Squirrel/Squirrel.Windows/issues/745))\n* **Language** Changes the codepage in to support non english characters. Defaults to 1252 if not present.\n\n![](images/uninstall-app.png)\n\n## See Also\n\n* [Naming Conventions](naming.md) - overview of sources used naming (including those outside of the NuGet Package Metadata).\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n"
  },
  {
    "path": "docs/using/octopack.md",
    "content": "| [docs](..)  / [using](.) / octopack.md\n|:---|\n\n# Using OctoPack\n\nIn order to automatically construct your nuget packages you can use [OctoPack](https://github.com/OctopusDeploy/OctoPack).  Octopack allows you to specify a .nuspec file which will be used to specify how your .nupkg should be created.\n\nFollow the core instructions for creating your .nuspec file on the  [OctoPack](https://github.com/OctopusDeploy/OctoPack) page.\n\nYou'll then need to add a files specification to match Squirrel's expected .nupkg structure:\n\n~~~\n  <files>\n    <file src=\"bin\\Release\\*.*\" target=\"lib\\net45\\\" exclude=\"bin\\release\\*.pdb;bin\\release\\*.nupkg;bin\\release\\*.vshost.*\"/>\n  </files>\n~~~\n\nIf you're building using Visual Studio, you will also need to edit your .csproj file to include a property group.\n\n~~~\n  <PropertyGroup>\n    <RunOctoPack>true</RunOctoPack>\n  </PropertyGroup>\n~~~\n\nIf you're using a build server, see OctoPack's guides on how to trigger it to be run.\n\n---\n| Return: [Packaging Tools](packaging-tools.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/packaging-tools.md",
    "content": "| [docs](..)  / [using](.) / packaging-tools.md\n|:---|\n\n\n# Packaging Tools\n\nThe following tools can simplify and/or automate the packaging process.\n\n* [NuGet Docs](http://docs.nuget.org/) - documentation for NuGet packaging manager.\n* [NuGet Package Explorer](https://npe.codeplex.com/) - GUI tool for building NuGet packages.\n* [Visual Studio Build Packaging](visual-studio-packaging.md) - integrating NuGet packaging into your visual studio build process.\n* [OctoPack](octopack.md) - steps to use OctoPack to build the source NuGet package to provide to `squirrel --releasify`.\n* [Auto.Squirrel Package Manager](https://github.com/tenacious/Auto.Squirrel) - tool to fully automatize the application deploy, from build to upload the updated files.\n* [Paket](http://fsprojects.github.io/Paket/template-files.html) -  dependency manager for .NET and mono projects, which is designed to work well with NuGet packages and also enables referencing files directly from Git repositories or any HTTP resource.\n* [TeamCity](teamcity.md) - tips on using the TeamCity build server to package your app.  \n \n\n## See Also\n\n* [Step 2. Packaging](../getting-started/2-packaging.md) - step from getting started guide on using NuGet Package Explorer. \n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n"
  },
  {
    "path": "docs/using/squirrel-command-line.md",
    "content": "| [docs](..)  / [using](.) / squirrel-command-line.md\n|:---|\n\n# Squirrel Command Line\r\n\nHere is a simplified help output specifically around creating releases:\n\n```\nUsage: Squirrel.exe command [OPTS]\nCreates Squirrel packages\n\nCommands\n      --releasify=VALUE      Update or generate a releases directory with a\n                               given NuGet package\n\nOptions:\n  -h, -?, --help             Display Help and exit\n  -r, --releaseDir=VALUE     Path to a release directory to use with Releasify\n  -p, --packagesDir=VALUE    Path to the NuGet Packages directory for C# apps\n      --bootstrapperExe=VALUE\n                             Path to the Setup.exe to use as a template\n  -g, --loadingGif=VALUE     Path to an animated GIF to be displayed during\n                               installation\n  -n, --signWithParams=VALUE Sign the installer via SignTool.exe with the\n                               parameters given\n      --setupIcon=VALUE       Path to an ICO file that will be used for the \n                               Setup executable's icon\n  -b  --baseUrl=VALUE         Provides a base URL to prefix the RELEASES file \n                               packages with\n      --no-msi                Don't generate an MSI package\n      --msi-win64             Mark the MSI as 64-bit, which is useful in\n                               Enterprise deployment scenarios\n      --no-delta              Don't generate delta packages to save time\n      --framework-version=VALUE \n                              Set the required .NET framework version, e.g. net461\n```\n\n## See Also\n* [Loading GIF](loading-gif.md) - specify a \"loading\" image during initial install of large applications.\n* [Application Signing](application-signing.md) - adding code signing to `Setup.exe` and your application.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/staged-rollouts.md",
    "content": "| [docs](..)  / [using](.) / staged-rollouts.md\n|:---|\n\n# Staged Rollouts\n\nStaged rollouts allow you to distribute the latest version of your app to a subset of users that you can increase over time, similar to rollouts on platforms like Google Play. This feature requires Squirrel.Windows 1.4.0 or above.\n\n### How to use\n\nStaged rollouts are controlled by manually editing your `RELEASES` file. Here's an example:\n\n~~~\ne3f67244e4166a65310c816221a12685c83f8e6f myapp-1.0.0-full.nupkg 600725\n~~~\n\nNow let's ship a new version to 10% of our userbase.\n\n```\ne3f67244e4166a65310c816221a12685c83f8e6f myapp-1.0.0-full.nupkg 600725\n0d777ea94c612e8bf1ea7379164caefba6e24463 myapp-1.0.1-delta.nupkg 6030# 10%\n85f4d657f8424dd437d1b33cc4511ea7ad86b1a7 myapp-1.0.1-full.nupkg 600752# 10%\n```\n\nNote that the syntax is `# nn%` - due to a bug in earlier versions of Squirrel.Windows, for now, you *must* put the `#` immediately following the file size, no spaces. Once all of your users have Squirrel 1.4.0 or higher, you can add a space after the `#` (similar to a comment).\n\nAssuming that this rollout is going well, at some point you can upload a new version of the `RELEASES` file:\n\n```\ne3f67244e4166a65310c816221a12685c83f8e6f myapp-1.0.0-full.nupkg 600725\n0d777ea94c612e8bf1ea7379164caefba6e24463 myapp-1.0.1-delta.nupkg 6030# 50%\n85f4d657f8424dd437d1b33cc4511ea7ad86b1a7 myapp-1.0.1-full.nupkg 600752# 50%\n```\n\nWhen you're confident that this release has gone successfully, you can remove the comment so that 100% of users get the file:\n\n```\ne3f67244e4166a65310c816221a12685c83f8e6f myapp-1.0.0-full.nupkg 600725\n0d777ea94c612e8bf1ea7379164caefba6e24463 myapp-1.0.1-delta.nupkg 6030\n85f4d657f8424dd437d1b33cc4511ea7ad86b1a7 myapp-1.0.1-full.nupkg 600752\n```\n\n### Handling failed rollouts\n\nIf you want to pull a staged release because it hasn't gone well, you should hand-edit the RELEASES file to completely remove the bad version:\n\n~~~\ne3f67244e4166a65310c816221a12685c83f8e6f myapp-1.0.0-full.nupkg 600725\n~~~\n\nOnce you do this, you **must** increment the version number higher than your broken release (in this example, we would need to release MyApp 1.0.2). Because some of your users will be on the broken 1.0.1, releasing a _new_ 1.0.1 would result in them staying on a broken version.\n"
  },
  {
    "path": "docs/using/teamcity.md",
    "content": "| [docs](..)  / [using](.) / teamcity.md\n|:---|\n\n\n# Team City Packaging\n\n\n## Adding the Packaging Step\n\rWhen TeamCity pulls down your code, the squirrel.exe will sit under packages if it was added to your solution using NuGet.\r\r1. Add a NuGet Pack process which will create the .nupkg based on a .nuspec file to ensure the package is correct.\r2. Create a command line build process and add the following:\r\r~~~\r%system.teamcity.build.workingDir%\\packages\\squirrel.windows.1.4.0\\tools\\squirrel --releasify [BUILD_SERVER_NUPKG_PATH]\\%system.build.number%.nupkg -r [OUTPUT_PATH]\r~~~\r\r**Note:** Paths may vary depending on your structure so make sure to update the path information above correctly.\n\nThis will cause the appropriate files to be created just as if you had run it from the Package Manager Console.\r\n\n**Source:** [Issue #737](https://github.com/Squirrel/Squirrel.Windows/issues/737)\n\n## See Also\n\n* [Packaging Tools](packaging-tools.md) - list of packaging tools to simplify and/or automate the packaging process.\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n"
  },
  {
    "path": "docs/using/update-manager.md",
    "content": "| [docs](..)  / [using](.) / update-manager.md\r\n|:---|\r\n\r\n# Update Manager Reference\r\n\r\n## Basic Updating\r\n\r\nThe \"Easy Mode\" method that does everything all in one go.\r\n\r\n* `UpdateApp` - downloads and updates the app to the latest version. \r\n\r\n## Advanced Updating\r\n\r\nThe following methods are provided to allow you to have more control of the update process (i.e., to interact with app updates and apply them if desired).\r\n\r\n* `CheckForUpdate` - checks on the server if there are updates available. Returns an `UpdateInfo` object that contains information about any pending updates.\r\n\r\n* `DownloadReleases` - downloads release files (the `nupkg` file deltas) from the server to the local machine\r\n\r\n* `ApplyReleases` - installs the downloaded packages, and returns the new `app-[version]` directory path.\r\n\r\n### UpdateInfo\r\n\r\nThe `UpdateInfo` class contains information about available and installed releases.\r\n\r\n~~~cs\r\npublic class UpdateInfo\r\n{\r\n\tpublic ReleaseEntry CurrentlyInstalledVersion;\r\n\tpublic ReleaseEntry FutureReleaseEntry;\r\n\tpublic List<ReleaseEntry> ReleasesToApply;\r\n}\r\n~~~\r\n\r\n### ReleaseEntry\r\n\r\nThe `ReleaseEntry` class contains the specifics of each release.\r\n\r\n~~~cs\r\npublic interface ReleaseEntry\r\n{\r\n    public string SHA1;\r\n    public string Filename;\r\n    public long Filesize;\r\n    public bool IsDelta;\r\n}\r\n~~~\r\n\r\n\r\n## See Also\r\n* [Update Process](update-process.md) - overview of the steps in the update process.\r\n* [GitHub Update Manager](github.md) - process of using `GitHubUpdateManager`.\r\n\r\n---\r\n| Return: [Table of Contents](../readme.md) |\r\n|----|\r\n\r\n"
  },
  {
    "path": "docs/using/update-process.md",
    "content": "| [docs](..)  / [using](.) / update-process.md\n|:---|\n\n\n# Update Process\n\nThe following steps are performed by the `UpdateManager` each time your app is executed:\n\n1. **Check for Updates** - the `RELEASES` file at the distribution location is downloaded and compared to local `RELEASES` file to check for any updates.\n2. **Download & Verify Update Packages** - if there is a new release, the `UpdateManager` determines whether to download the deltas or the latest full package (by calculating which one requires less total downloading) to update to the current version. The packages are compared against their SHA1 in the `RELEASES` file for verification.\n3. **Build Full Package from Deltas** - if delta packages were downloaded, a new full package is created from the previous full package and the downloaded delta file.\n3. **Install New Version** - the current version of MyApp is extracted from the full package and placed in a new `%LocalAppData%\\MyApp` install directory based on the version number (e.g., `app-1.0.1`).\n4. **Update Shortcuts** - desktop and Windows Start Menu shortcuts are updated to point to the new MyApp version (via the `--processStart` command line parameter passed to `Update.exe`)\u0010.\n5. **Previous Version Clean-up** - on the next startup of MyApp, all but current and immediately previous version of your app are deleted as part of clean up (e.g., after updating to app-1.0.5, app-1.0.4 will remain, but app-1.0.3 and before will be deleted - see [issue #589](https://github.com/Squirrel/Squirrel.Windows/issues/589)). \n\n## Rollback\n\nCurrently, there is no built-in support for rolling back to a previous version.\n\n## See Also\n\n* [Update Manager](update-manager.md) - reference guide for the `UpdateManager`. \n* [Debugging Updates](debugging-updates.md) - tips on debugging your Squirrel application.\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|\n\n"
  },
  {
    "path": "docs/using/visual-studio-packaging.md",
    "content": "| [docs](..)  / [using](.) / visual-studio-packaging.md\n|:---|\n\n# Visual Studio Build Packaging\n\nSquirrel packaging can be easily integrated directly into your build process using only NuGet and Squirrel. \n\n## Define Build Target\n\nThe first step is to define a build target in your `.csproj` file.\n\n```xml\n<Target Name=\"AfterBuild\" Condition=\" '$(Configuration)' == 'Release'\">\n  <GetAssemblyIdentity AssemblyFiles=\"$(TargetPath)\">\n    <Output TaskParameter=\"Assemblies\" ItemName=\"myAssemblyInfo\"/>\n  </GetAssemblyIdentity>\n  <Exec Command=\"nuget pack MyApp.nuspec -Version %(myAssemblyInfo.Version) -Properties Configuration=Release -OutputDirectory $(OutDir) -BasePath $(OutDir)\" />\n  <Exec Command=\"squirrel --releasify $(OutDir)MyApp.$([System.Version]::Parse(%(myAssemblyInfo.Version)).ToString(3)).nupkg\" />\n</Target>\n```\n\nThis will generate a NuGet package from .nuspec file setting version from AssemblyInfo.cs and place it in OutDir (by default bin\\Release). Then it will generate release files from it.\n\n## Example .nuspec file for MyApp\n\nHere is an example `MyApp.nuspec` file for the above build target example.\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n  <metadata>\n    <id>MyApp</id>\n    <!-- version will be replaced by MSBuild -->\n    <version>0.0.0.0</version>\n    <title>title</title>\n    <authors>authors</authors>\n    <description>description</description>\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <copyright>Copyright 2016</copyright>\n    <dependencies />\n  </metadata>\n  <files>\n    <file src=\"*.*\" target=\"lib\\net45\\\" exclude=\"*.pdb;*.nupkg;*.vshost.*\"/>\n  </files>\n</package>\n```\n\n## Additional Notes\n\nPlease be aware of the following when using this solution:\n\n* Solution needs to have nuget.exe available which can be accomplished by installing `NuGet.CommandLine` package in your solution.  \n\n```pm\nPM>  Install-Package NuGet.CommandLine\n```\n\n* It suffers from a bug when sometimes NuGet packages are not loaded properly and throws nuget/squirrel is not recogized (9009) errors.  \n **Tip:** In this case you may simply need to restart Visual Studio so the Package Manager Console will have loaded all the package tools\n* If you get the following error you may need add the full path to squirrel.exe in the build target `Exec Command` call. `'squirrel' is not recognized as an internal or external command`\n\n**Source:** [Issue #630](https://github.com/Squirrel/Squirrel.Windows/issues/630)\n\n---\n| Return: [Packaging Tools](packaging-tools.md) |\n|----|\n\n\n\n"
  },
  {
    "path": "docs/using/x-doc-template.md",
    "content": "| [docs](..)  / [using](.) / filename.md\n|:---|\n\n# Title\n\ntext\n\n## Sub-title\n\ntext\n\n~~~cs\ncode\n~~~\n\n**Tip:** text\n\n\n## See Also\n\n* [seealso]() - text\n\n\n---\n| Return: [Table of Contents](../readme.md) |\n|----|"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <EnableSourceLink Condition=\" '$(NCrunch)' == '1' \">false</EnableSourceLink>\n\n    <ProjectName Condition=\" '$(ProjectName)' == '' \">$(MSBuildProjectName)</ProjectName>\n    <BaseOutputPath>$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\\build\\))</BaseOutputPath>\n    <BaseIntermediateOutputPath>$(BaseOutputPath)obj\\$(Configuration)\\$(ProjectName)\\</BaseIntermediateOutputPath>\n    <OutputPath>$(BaseOutputPath)$(Configuration)\\</OutputPath>\n\n    <Company>GitHub</Company>\n    <Copyright>Copyright © GitHub 2013-2015</Copyright>\n    <PackageLicenseExpression>MS-RL</PackageLicenseExpression>\n    <Product>Squirrel</Product>\n  </PropertyGroup>\n\n  <ItemGroup Condition=\" '$(MSBuildProjectExtension)'=='.csproj' \">\n    <PackageReference Include=\"Microsoft.SourceLink.GitHub\" Version=\"1.0.0-beta2-18618-05\" PrivateAssets=\"All\" />\n    <PackageReference Include=\"Nerdbank.GitVersioning\" Version=\"3.4.240\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n  <PropertyGroup Condition=\" '$(MSBuildProjectExtension)'=='.vcxproj' \">\n    <Platform Condition=\" '$(Platform)' == '' OR '$(Platform)' == 'AnyCPU' \">Win32</Platform>\n    <IntDir>$(BaseIntermediateOutputPath)$(Configuration)\\$(Platform)\\</IntDir>\n    <OutDir>$(OutputPath)$(Platform)\\</OutDir>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "src/Setup/FxHelper.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FxHelper.h\"\n#include \"resource.h\"\n\n// http://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx#net_b\nstatic const wchar_t* ndpPath = L\"SOFTWARE\\\\Microsoft\\\\NET Framework Setup\\\\NDP\\\\v4\\\\Full\";\nstatic const int fx45ReleaseVersion = 378389;\nstatic const int fx451ReleaseVersion = 378675; //Minimum version for .NET 4.5.1\nstatic const int fx452ReleaseVersion = 379893;\nstatic const int fx46ReleaseVersion = 393295; //Windows 10 version, other systems are higher\nstatic const int fx461ReleaseVersion = 394254; // Minimum version for .NET 4.6.1\nstatic const int fx462ReleaseVersion = 394802; // Minimum version for .NET 4.6.2\nstatic const int fx47ReleaseVersion = 460798; // Minimum version for .NET 4.7\nstatic const int fx471ReleaseVersion = 461308; // Minimum version for .NET 4.7.1\nstatic const int fx472ReleaseVersion = 461808; // Minimum version for .NET 4.7.2\nstatic const int fx48ReleaseVersion = 528040; // Minimum version for .NET 4.8\n\n// According to https://msdn.microsoft.com/en-us/library/8z6watww%28v=vs.110%29.aspx,\n// to install .NET 4.5 we must be Vista SP2+, Windows 7 SP1+, or later.\n// However Anas thinks this is just for customer support, anything >= Vista will generally work.\nbool CFxHelper::CanInstallDotNet4_5()\n{\n\treturn IsWindowsVistaOrGreater();\n}\n\nNetVersion CFxHelper::GetRequiredDotNetVersion()\n{\n\twchar_t* versionFlag = (wchar_t*)LoadResource(NULL, FindResource(NULL, (LPCWSTR)IDR_FX_VERSION_FLAG, L\"FLAGS\"));\n\tCString resourceFlag(versionFlag);\n\tif (resourceFlag.Compare(L\"net451\") == 0) return NetVersion::net451;\n\tif (resourceFlag.Compare(L\"net452\") == 0) return NetVersion::net452;\n\tif (resourceFlag.Compare(L\"net46\") == 0) return NetVersion::net46;\n\tif (resourceFlag.Compare(L\"net461\") == 0) return NetVersion::net461;\n\tif (resourceFlag.Compare(L\"net462\") == 0) return NetVersion::net462;\n\tif (resourceFlag.Compare(L\"net47\") == 0) return NetVersion::net47;\n\tif (resourceFlag.Compare(L\"net471\") == 0) return NetVersion::net471;\n\tif (resourceFlag.Compare(L\"net472\") == 0) return NetVersion::net472;\n\tif (resourceFlag.Compare(L\"net48\") == 0) return NetVersion::net48;\n\n\t//Default to standard net45\n\treturn NetVersion::net45;\n}\n\nbool CFxHelper::IsDotNetInstalled(NetVersion required)\n{\n\tATL::CRegKey key;\n\n\tif (key.Open(HKEY_LOCAL_MACHINE, ndpPath, KEY_READ) != ERROR_SUCCESS) {\n\t\treturn false;\n\t}\n\n\tDWORD dwReleaseInfo = 0;\n\tif (key.QueryDWORDValue(L\"Release\", dwReleaseInfo) != ERROR_SUCCESS ||\n\t\tdwReleaseInfo < GetDotNetVersionReleaseNumber(required)) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nUINT CFxHelper::GetDotNetVersionReleaseNumber(NetVersion version)\n{\n\tswitch (version) {\n\tcase NetVersion::net451:\n\t\treturn fx451ReleaseVersion;\n\tcase NetVersion::net452:\n\t\treturn fx452ReleaseVersion;\n\tcase NetVersion::net46:\n\t\treturn fx46ReleaseVersion;\n\tcase NetVersion::net461:\n\t\treturn fx461ReleaseVersion;\n\tcase NetVersion::net462:\n\t\treturn fx462ReleaseVersion;\n\tcase NetVersion::net47:\n\t\treturn fx47ReleaseVersion;\n\tcase NetVersion::net471:\n\t\treturn fx471ReleaseVersion;\n\tcase NetVersion::net472:\n\t\treturn fx472ReleaseVersion;\n\tcase NetVersion::net48:\n\t\treturn fx48ReleaseVersion;\n\tcase NetVersion::net45:\n\tdefault:\n\t\treturn fx45ReleaseVersion;\n\t}\n}\n\nclass ATL_NO_VTABLE CDownloadProgressCallback :\n\tpublic CComObjectRoot,\n\tpublic IBindStatusCallback\n{\npublic:\n\tCDownloadProgressCallback()\n\t{\n\t}\n\n\tDECLARE_NOT_AGGREGATABLE(CDownloadProgressCallback)\n\n\tBEGIN_COM_MAP(CDownloadProgressCallback)\n\t\tCOM_INTERFACE_ENTRY(IBindStatusCallback)\n\tEND_COM_MAP()\n\n\tDECLARE_PROTECT_FINAL_CONSTRUCT()\n\n\tHRESULT FinalConstruct() { return S_OK; }\n\n\tvoid FinalRelease()\n\t{\n\t}\n\n\tvoid SetProgressDialog(IProgressDialog* pd)\n\t{\n\t\tm_spProgressDialog = pd;\n\t}\n\n\tSTDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax, ULONG /*ulStatusCode*/, LPCWSTR /*szStatusText*/)\n\t{\n\t\tif (m_spProgressDialog != nullptr) {\n\t\t\tif (m_spProgressDialog->HasUserCancelled()) {\n\t\t\t\treturn E_ABORT;\n\t\t\t}\n\n\t\t\tm_spProgressDialog->SetProgress(ulProgress, ulProgressMax);\n\t\t}\n\n\t\treturn S_OK;\n\t}\n\n\tSTDMETHOD(OnStartBinding)(DWORD /*dwReserved*/, IBinding *pBinding) { return E_NOTIMPL; }\n\tSTDMETHOD(GetPriority)(LONG *pnPriority) { return E_NOTIMPL; }\n\tSTDMETHOD(OnLowResource)(DWORD /*reserved*/) { return E_NOTIMPL; }\n\tSTDMETHOD(OnStopBinding)(HRESULT /*hresult*/, LPCWSTR /*szError*/) { return E_NOTIMPL; }\n\tSTDMETHOD(GetBindInfo)(DWORD *pgrfBINDF, BINDINFO *pbindInfo) { return E_NOTIMPL; }\n\tSTDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC * /*pformatetc*/, STGMEDIUM *pstgmed) { return E_NOTIMPL; }\n\tSTDMETHOD(OnObjectAvailable)(REFIID /*riid*/, IUnknown * /*punk*/) { return E_NOTIMPL; }\n\nprivate:\n\tCComPtr<IProgressDialog> m_spProgressDialog;\n};\n\nHRESULT CFxHelper::InstallDotNetFramework(NetVersion version, bool isQuiet)\n{\n\tif (!isQuiet) {\n\t\tCTaskDialog dlg;\n\t\tTASKDIALOG_BUTTON buttons[] = {\n\t\t\t{ 1, L\"Install\", },\n\t\t\t{ 2, L\"Cancel\", },\n\t\t};\n\n\n\t\tdlg.SetButtons(buttons, 2);\n\t\tdlg.SetMainInstructionText(GetInstallerMainInstructionForVersion(version));\n\t\tdlg.SetContentText(GetInstallerContentForVersion(version));\n\t\tdlg.SetMainIcon(TD_INFORMATION_ICON);\n\n\t\tdlg.SetExpandedInformationText(GetInstallerExpandedInfoForVersion(version));\n\n\t\tint nButton;\n\t\tif (FAILED(dlg.DoModal(::GetActiveWindow(), &nButton)) || nButton != 1) {\n\t\t\treturn S_FALSE;\n\t\t}\n\t}\n\n\tHRESULT hr = E_FAIL;\n\tWCHAR szFinalTempFileName[_MAX_PATH] = L\"\";\n\tCComPtr<IBindStatusCallback> bscb;\n\tCComPtr<IProgressDialog> pd;\n\tSHELLEXECUTEINFO execInfo = { sizeof(execInfo), };\n\n\tCString url;\n\turl.LoadString(GetInstallerUrlForVersion(version));\n\n\tWCHAR szTempPath[_MAX_PATH];\n\tDWORD dwTempPathResult = GetTempPath(_MAX_PATH, szTempPath);\n\n\tif (dwTempPathResult == 0) {\n\t\thr = AtlHresultFromLastError();\n\t\tgoto out;\n\t} else if (dwTempPathResult > _MAX_PATH) {\n\t\thr = DISP_E_BUFFERTOOSMALL;\n\t\tgoto out;\n\t}\n\n\tWCHAR szTempFileName[_MAX_PATH];\n\tif (!GetTempFileName(szTempPath, L\"NDP\", 0, szTempFileName)) {\n\t\thr = AtlHresultFromLastError();\n\t\tgoto out;\n\t}\n\n\tszTempFileName[_countof(szTempFileName) - 1] = L'\\0';\n\tif (wcscpy_s(szFinalTempFileName, _countof(szFinalTempFileName), szTempFileName) != 0) {\n\t\thr = E_FAIL;\n\t\tgoto out;\n\t}\n\n\tWCHAR* pLastDot = wcsrchr(szFinalTempFileName, L'.');\n\tif (pLastDot == nullptr) {\n\t\tif (wcscat_s(szFinalTempFileName, _countof(szFinalTempFileName), L\".exe\") != 0) {\n\t\t\thr = E_FAIL;\n\t\t\tgoto out;\n\t\t}\n\t} else {\n\t\tif (wcscpy_s(pLastDot, _countof(szFinalTempFileName) - (pLastDot - szFinalTempFileName), L\".exe\") != 0) {\n\t\t\thr = E_FAIL;\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\tif (!MoveFile(szTempFileName, szFinalTempFileName)) {\n\t\thr = AtlHresultFromLastError();\n\t\tgoto out;\n\t}\n\n\tif (!isQuiet) {\n\t\tpd.CoCreateInstance(CLSID_ProgressDialog);\n\n\t\tif (pd != nullptr) {\n\t\t\tpd->SetTitle(L\"Downloading\");\n\t\t\tpd->SetLine(1, L\"Downloading the .NET Framework installer\", FALSE, nullptr);\n\t\t\tpd->StartProgressDialog(nullptr, nullptr, 0, nullptr);\n\n\t\t\tCComObject<CDownloadProgressCallback>* bscbObj = nullptr;\n\t\t\tif (SUCCEEDED(CComObject<CDownloadProgressCallback>::CreateInstance(&bscbObj))) {\n\t\t\t\tbscbObj->SetProgressDialog(pd);\n\t\t\t\tbscb = bscbObj;\n\t\t\t}\n\t\t}\n\t}\n\n\thr = URLDownloadToFile(nullptr, url, szFinalTempFileName, 0, bscb);\n\tif (pd != nullptr) {\n\t\tpd->StopProgressDialog();\n\t}\n\tif (hr != S_OK) {\n\t\tgoto out;\n\t}\n\n\texecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;\n\texecInfo.lpVerb = L\"open\";\n\texecInfo.lpFile = szFinalTempFileName;\n\n\tif (isQuiet) {\n\t\texecInfo.lpParameters = L\"/q /norestart\";\n\t}\n\telse {\n\t\texecInfo.lpParameters = L\"/passive /norestart /showrmui\";\n\t}\n\n\texecInfo.nShow = SW_SHOW;\n\tif (!ShellExecuteEx(&execInfo)) {\n\t\thr = AtlHresultFromLastError();\n\t\tgoto out;\n\t}\n\n\tWaitForSingleObject(execInfo.hProcess, INFINITE);\n\n\tDWORD exitCode;\n\tif (!GetExitCodeProcess(execInfo.hProcess, &exitCode)) {\n\t\thr = AtlHresultFromLastError();\n\t\tgoto out;\n\t}\n\n\tif (exitCode == 1641 || exitCode == 3010) {\n\t\t// The framework installer wants a reboot before we can continue\n\t\t// See https://msdn.microsoft.com/en-us/library/ee942965%28v=vs.110%29.aspx\n\t\thr = HandleRebootRequirement(isQuiet);\n\t\t// Exit as a failure, so that setup doesn't carry on now\n\t}\n\telse {\n\t\thr = exitCode != 0 ? E_FAIL : S_OK;\n\t}\n\n\nout:\n\tif (execInfo.hProcess != NULL && execInfo.hProcess != INVALID_HANDLE_VALUE) {\n\t\tCloseHandle(execInfo.hProcess);\n\t}\n\n\tif (*szFinalTempFileName != L'\\0') {\n\t\tDeleteFile(szFinalTempFileName);\n\t}\n\n\treturn hr;\n}\n\nUINT CFxHelper::GetInstallerMainInstructionForVersion(NetVersion version)\n{\n\tif (version >= NetVersion::net48) {\n\t\treturn IDS_FXINSTRUCTION48;\n\t}\n\n\tif (version >= NetVersion::net47) {\n\t\treturn IDS_FXINSTRUCTION47;\n\t}\n\n\tif (version >= NetVersion::net46) {\n\t\treturn IDS_FXINSTRUCTION46;\n\t}\n\treturn IDS_FXINSTRUCTION;\n}\n\nUINT CFxHelper::GetInstallerContentForVersion(NetVersion version)\n{\n\tif (version >= NetVersion::net48) {\n\t\treturn IDS_FXCONTENT48;\n\t}\n\n\tif (version >= NetVersion::net47) {\n\t\treturn IDS_FXCONTENT47;\n\t}\n\n\tif (version >= NetVersion::net46) {\n\t\treturn IDS_FXCONTENT46;\n\t}\n\treturn IDS_FXCONTENT;\n}\n\nUINT CFxHelper::GetInstallerExpandedInfoForVersion(NetVersion version)\n{\n\tif (version >= NetVersion::net48) {\n\t\treturn IDS_FXEXPANDEDINFO48;\n\t}\n\n\tif (version >= NetVersion::net47) {\n\t\treturn IDS_FXEXPANDEDINFO47;\n\t}\n\n\tif (version >= NetVersion::net46) {\n\t\treturn IDS_FXEXPANDEDINFO46;\n\t}\n\treturn IDS_FXEXPANDEDINFO;\n}\n\nUINT CFxHelper::GetInstallerUrlForVersion(NetVersion version)\n{\n\tif (version >= NetVersion::net48) {\n\t\treturn IDS_FXDOWNLOADURL48;\n\t}\n\n\tif (version >= NetVersion::net47) {\n\t\treturn IDS_FXDOWNLOADURL47;\n\t}\n\n\tif (version >= NetVersion::net46) {\n\t\treturn IDS_FXDOWNLOADURL46;\n\t}\n\treturn IDS_FXDOWNLOADURL;\n}\n\n// Deal with the aftermath of the framework installer telling us that we need to reboot\nHRESULT CFxHelper::HandleRebootRequirement(bool isQuiet)\n{\n\tif (isQuiet) {\n\t\t// Don't silently reboot - just error-out\n\t\tfprintf_s(stderr, \"A reboot is required following .NET installation - reboot then run installer again.\\n\");\n\t\treturn E_FAIL;\n\t}\n\n\tCTaskDialog dlg;\n\tTASKDIALOG_BUTTON buttons[] = {\n\t\t{ 1, L\"Restart Now\", },\n\t\t{ 2, L\"Cancel\", },\n\t};\n\n\tdlg.SetButtons(buttons, 2);\n\tdlg.SetMainInstructionText(L\"Restart System\");\n\tdlg.SetContentText(L\"To finish installing the .NET Framework, the system now needs to restart.  The installation will finish after you restart and log-in again.\");\n\tdlg.SetMainIcon(TD_INFORMATION_ICON);\n\n\tdlg.SetExpandedInformationText(L\"If you click 'Cancel', you'll need to re-run this setup program yourself, after restarting your system.\");\n\n\tint nButton;\n\tif (FAILED(dlg.DoModal(::GetActiveWindow(), &nButton)) || nButton != 1) {\n\t\treturn S_FALSE;\n\t}\n\n\t// We need to set up a runonce entry to restart this installer once the reboot has happened\n\tif (!WriteRunOnceEntry()) {\n\t\treturn E_FAIL;\n\t}\n\n\t// And now, reboot\n\tif (!RebootSystem()) {\n\t\treturn E_FAIL;\n\t}\n\n\t// About to reboot, but just in case...\n\treturn S_FALSE;\n}\n\n//\n// Write a runonce entry to the registry to tell it to continue with\n// setup after a reboot\n//\nbool CFxHelper::WriteRunOnceEntry()\n{\n\tATL::CRegKey key;\n\n\tif (key.Open(HKEY_CURRENT_USER, L\"SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\RunOnce\", KEY_WRITE) != ERROR_SUCCESS) {\n\t\treturn false;\n\t}\n\n\tTCHAR exePath[MAX_PATH];\n\tGetModuleFileName(NULL, exePath, MAX_PATH);\n\n\tif (key.SetStringValue(L\"SquirrelInstall\", exePath) != ERROR_SUCCESS) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool CFxHelper::RebootSystem()\n{\n\t// First we need to enable the SE_SHUTDOWN_NAME privilege\n\tLUID luid;\n\tif (!LookupPrivilegeValue(L\"\", SE_SHUTDOWN_NAME, &luid)) {\n\t\treturn false;\n\t}\n\n\tHANDLE hToken = NULL;\n\tif (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {\n\t\treturn false;\n\t}\n\n\tTOKEN_PRIVILEGES tp;\n\ttp.PrivilegeCount = 1;\n\ttp.Privileges[0].Luid = luid;\n\ttp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n\tif (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, 0)) {\n\t\tCloseHandle(hToken);\n\t\treturn false;\n\t}\n\n\t// Now we have that privilege, we can ask Windows to restart\n\treturn ExitWindowsEx(EWX_REBOOT, 0) != 0;\n}\n"
  },
  {
    "path": "src/Setup/FxHelper.h",
    "content": "#pragma once\n\nenum class NetVersion {net45=0, net451=1, net452=2, net46=3, net461=4, net462=5, net47=6, net471=7, net472=8, net48=9};\n\nclass CFxHelper\n{\npublic:\n\tstatic NetVersion GetRequiredDotNetVersion();\n\tstatic bool CanInstallDotNet4_5();\n\tstatic bool IsDotNetInstalled(NetVersion requiredVersion);\n\tstatic HRESULT InstallDotNetFramework(NetVersion version, bool isQuiet);\nprivate:\n\tstatic HRESULT HandleRebootRequirement(bool isQuiet);\n\tstatic bool WriteRunOnceEntry();\n\tstatic bool RebootSystem();\n\tstatic UINT GetDotNetVersionReleaseNumber(NetVersion version);\n\tstatic UINT GetInstallerUrlForVersion(NetVersion version);\n\tstatic UINT GetInstallerMainInstructionForVersion(NetVersion version);\n\tstatic UINT GetInstallerContentForVersion(NetVersion version);\n\tstatic UINT GetInstallerExpandedInfoForVersion(NetVersion version);\n};\n"
  },
  {
    "path": "src/Setup/MachineInstaller.cpp",
    "content": "#include \"stdafx.h\"\n#include \"unzip.h\"\n#include \"MachineInstaller.h\"\n#include \"resource.h\"\n#include <sddl.h>\n\nbool directoryExists(wchar_t* path) {\n\tDWORD dwResult = GetFileAttributes(path);\n\n\tif (dwResult != INVALID_FILE_ATTRIBUTES) {\n\t\treturn true;\n\t}\n\n\t// NB: The directory could exist but we can't access it, let's check\n\tDWORD dwLastError = GetLastError();\n\tif (dwLastError == ERROR_FILE_NOT_FOUND) return false;\n\tif (dwLastError == ERROR_PATH_NOT_FOUND) return false;\n\n\treturn true;\n}\n\nbool MachineInstaller::ShouldSilentInstall()\n{\n\t// Figure out the package name from our own EXE name \n\t// The name consist of [$pkgName]DeploymentTool.exe\n\twchar_t ourFile[MAX_PATH];\n\tHMODULE hMod = GetModuleHandle(NULL);\n\tGetModuleFileName(hMod, ourFile, _countof(ourFile));\n\n\tCString fullPath = CString(ourFile);\n\tCString pkgName = CString(ourFile + fullPath.ReverseFind(L'\\\\'));\n\tpkgName.Replace(L\"DeploymentTool.exe\", L\"\");\n\t\n\twchar_t installFolder[MAX_PATH];\n\n\t// NB: Users often get into the sitch where they install the MSI, then try to\n\t// install the standalone package on top of that. In previous versions we tried\n\t// to detect if the app was properly installed, but now we're taking the much \n\t// more conservative approach, that if the package dir exists in any way, we're\n\t// bailing out\n\n\t// C:\\Users\\Username\\AppData\\Local\\$pkgName\n\tSHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, installFolder);\n\twcscat(installFolder, L\"\\\\\");\n\twcscat(installFolder, pkgName);\n\n\tif (directoryExists(installFolder)) {\n\t\treturn false;\n\t}\n\n\t// C:\\ProgramData\\$pkgName\\$username\n\twchar_t username[512];\n\tDWORD unamesize = _countof(username);\n\tSHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, installFolder);\n\tGetUserName(username, &unamesize);\n\twcscat(installFolder, L\"\\\\\");\n\twcscat(installFolder, pkgName);\n\twcscat(installFolder, L\"\\\\\");\n\twcscat(installFolder, username);\n\n\tif (directoryExists(installFolder)) {\n\t\treturn false;\n\t}\n\n\t// None of these exist, we should install\n\treturn true;\n}\n"
  },
  {
    "path": "src/Setup/MachineInstaller.h",
    "content": "#pragma once\nclass MachineInstaller\n{\npublic:\n\tstatic bool ShouldSilentInstall();\n};\n"
  },
  {
    "path": "src/Setup/Setup.h",
    "content": "#pragma once\n\n#include \"resource.h\"\n"
  },
  {
    "path": "src/Setup/Setup.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C1D40624-A484-438A-B846-052F321C89D1}</ProjectGuid>\n    <ConfigurationType>Application</ConfigurationType>\n    <Keyword>Win32Proj</Keyword>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <RootNamespace>Setup</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <UseOfMfc>false</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)/wtl90</IncludePath>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)/wtl90</IncludePath>\n  </PropertyGroup>\n  <!-- <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='CIBuild|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <IncludePath>C:\\WinDDK\\7600.16385.1\\inc\\atl71;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)/wtl90</IncludePath>\n    <OutDir>$(ProjectDir)bin\\$(Configuration)\\</OutDir>\n    <IntDir>$(ProjectDir)obj\\$(Configuration)\\</IntDir>\n    <LibraryPath>C:\\WinDDK\\7600.16385.1\\lib\\ATL\\i386;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86)</LibraryPath>\n  </PropertyGroup> -->\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>urlmon.lib</AdditionalDependencies>\n      <DelayLoadDLLs>comctl32.dll;shell32.dll;shlwapi.dll;urlmon.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <Manifest>\n      <AdditionalManifestFiles>compat.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MinSpace</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\n      <StringPooling>true</StringPooling>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <BrowseInformation>true</BrowseInformation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\n      <AdditionalDependencies>urlmon.lib</AdditionalDependencies>\n      <DelayLoadDLLs>comctl32.dll;shell32.dll;shlwapi.dll;urlmon.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\n    </Link>\n    <Manifest>\n      <AdditionalManifestFiles>compat.manifest</AdditionalManifestFiles>\n    </Manifest>\n    <Bscmake>\n      <PreserveSbr>true</PreserveSbr>\n    </Bscmake>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"FxHelper.h\" />\n    <ClInclude Include=\"MachineInstaller.h\" />\n    <ClInclude Include=\"Resource.h\" />\n    <ClInclude Include=\"Setup.h\" />\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"targetver.h\" />\n    <ClInclude Include=\"unzip.h\" />\n    <ClInclude Include=\"UpdateRunner.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"FxHelper.cpp\" />\n    <ClCompile Include=\"MachineInstaller.cpp\" />\n    <ClCompile Include=\"unzip.cpp\" />\n    <ClCompile Include=\"UpdateRunner.cpp\" />\n    <ClCompile Include=\"winmain.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Setup.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"Setup.ico\" />\n    <Image Include=\"small.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"flags1.bin\" />\n    <None Include=\"update.zip\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "src/Setup/Setup.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"targetver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Setup.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FxHelper.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"unzip.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"UpdateRunner.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MachineInstaller.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"winmain.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FxHelper.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"unzip.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"UpdateRunner.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MachineInstaller.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Setup.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"small.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"Setup.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"update.zip\">\n      <Filter>Resource Files</Filter>\n    </None>\n    <None Include=\"flags1.bin\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/Setup/UpdateRunner.cpp",
    "content": "#include \"stdafx.h\"\n#include \"unzip.h\"\n#include \"Resource.h\"\n#include \"UpdateRunner.h\"\n#include <vector>\n\nvoid CUpdateRunner::DisplayErrorMessage(CString& errorMessage, wchar_t* logFile)\n{\n\tCTaskDialog dlg;\n\tTASKDIALOG_BUTTON buttons[] = {\n\t\t{ 1, L\"Open Setup Log\", },\n\t\t{ 2, L\"Close\", },\n\t};\n\n\t// TODO: Something about contacting support?\n\tif (logFile == NULL) {\n\t\tdlg.SetButtons(&buttons[1], 1, 1);\n\t} else {\n\t\tdlg.SetButtons(buttons, 2, 1);\n\t}\n\n\tdlg.SetMainInstructionText(L\"Installation has failed\");\n\tdlg.SetContentText(errorMessage);\n\tdlg.SetMainIcon(TD_ERROR_ICON);\n\n\tint nButton;\n\n\tif (FAILED(dlg.DoModal(::GetActiveWindow(), &nButton))) {\n\t\treturn;\n\t}\n\n\tif (nButton == 1 && logFile != NULL) {\n\t\tShellExecute(NULL, NULL, logFile, NULL, NULL, SW_SHOW);\n\t}\n}\n\nHRESULT CUpdateRunner::AreWeInWine()\n{\n\t// NB: Behaving differently in Wine is *usually* discouraged\n\t// https://wiki.winehq.org/Developer_FAQ#How_can_I_detect_Wine.3F\n\tHMODULE hntdll = GetModuleHandle(L\"ntdll.dll\");\n\tif (!hntdll) {\n\t\t// NB: This can never fail but we'll be pedantic\n\t\treturn E_FAIL;\n\t}\n\n\treturn GetProcAddress(hntdll, \"wine_get_version\") != NULL ? S_OK : S_FALSE;\n}\n\nHRESULT CUpdateRunner::AreWeUACElevated()\n{\n\tHANDLE hProcess = GetCurrentProcess();\n\tHANDLE hToken = 0;\n\tHRESULT hr;\n\n\tif (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {\n\t\thr = HRESULT_FROM_WIN32(GetLastError());\n\t\tgoto out;\n\t}\n\n\tTOKEN_ELEVATION_TYPE elevType;\n\tDWORD dontcare;\n\tif (!GetTokenInformation(hToken, TokenElevationType, &elevType, sizeof(TOKEN_ELEVATION_TYPE), &dontcare)) {\n\t\thr = HRESULT_FROM_WIN32(GetLastError());\n\t\tgoto out;\n\t}\n\n\thr = (elevType == TokenElevationTypeFull ? S_OK : S_FALSE);\n\nout:\n\tif (hToken) {\n\t\tCloseHandle(hToken);\n\t}\n\n\treturn hr;\n}\n\nHRESULT FindDesktopFolderView(REFIID riid, void **ppv)\n{\n\tHRESULT hr;\n\n\tCComPtr<IShellWindows> spShellWindows;\n\tspShellWindows.CoCreateInstance(CLSID_ShellWindows);\n\n\tCComVariant vtLoc(CSIDL_DESKTOP);\n\tCComVariant vtEmpty;\n\tlong lhwnd;\n\tCComPtr<IDispatch> spdisp;\n\n\thr = spShellWindows->FindWindowSW(\n\t\t&vtLoc, &vtEmpty,\n\t\tSWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp);\n\tif (FAILED(hr)) return hr;\n\n\tCComPtr<IShellBrowser> spBrowser;\n\thr = CComQIPtr<IServiceProvider>(spdisp)->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&spBrowser));\n\tif (FAILED(hr)) return hr;\n\n\tCComPtr<IShellView> spView;\n\thr = spBrowser->QueryActiveShellView(&spView);\n\tif (FAILED(hr)) return hr;\n\n\thr = spView->QueryInterface(riid, ppv);\n\tif (FAILED(hr)) return hr;\n\n\treturn S_OK;\n}\n\nHRESULT GetDesktopAutomationObject(REFIID riid, void **ppv)\n{\n\tHRESULT hr;\n\n\tCComPtr<IShellView> spsv;\n\thr = FindDesktopFolderView(IID_PPV_ARGS(&spsv));\n\tif (FAILED(hr)) return hr;\n\n\tCComPtr<IDispatch> spdispView;\n\thr = spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView));\n\tif (FAILED(hr)) return hr;\n\n\treturn spdispView->QueryInterface(riid, ppv);\n}\n\nHRESULT CUpdateRunner::ShellExecuteFromExplorer(LPWSTR pszFile, LPWSTR pszParameters)\n{\n\tHRESULT hr;\n\n\tCComPtr<IShellFolderViewDual> spFolderView;\n\thr = GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));\n\tif (FAILED(hr)) return hr;\n\n\tCComPtr<IDispatch> spdispShell;\n\thr = spFolderView->get_Application(&spdispShell);\n\tif (FAILED(hr)) return hr;\n\n\treturn CComQIPtr<IShellDispatch2>(spdispShell)->ShellExecute(\n\t\tCComBSTR(pszFile),\n\t\tCComVariant(pszParameters ? pszParameters : L\"\"),\n\t\tCComVariant(L\"\"),\n\t\tCComVariant(L\"\"),\n\t\tCComVariant(SW_SHOWDEFAULT));\n}\n\nbool CUpdateRunner::DirectoryExists(wchar_t* szPath)\n{\n\tDWORD dwAttrib = GetFileAttributes(szPath);\n\n\treturn (dwAttrib != INVALID_FILE_ATTRIBUTES &&\n\t\t(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));\n}\n\nbool CUpdateRunner::DirectoryIsWritable(wchar_t * szPath)\n{\n\t\twchar_t szTempFileName[MAX_PATH];\n\t\tUINT uRetVal = GetTempFileNameW(szPath, L\"Squirrel\", 0, szTempFileName);\n\t\tif (uRetVal == 0) {\n\t\t\treturn false;\n\t\t}\n\t\tDeleteFile(szTempFileName);\n\t\treturn true;\n}\n\nint CUpdateRunner::ExtractUpdaterAndRun(wchar_t* lpCommandLine, bool useFallbackDir)\n{\n\tPROCESS_INFORMATION pi = { 0 };\n\tSTARTUPINFO si = { 0 };\n\tCResource zipResource;\n\twchar_t targetDir[MAX_PATH] = { 0 };\n\twchar_t logFile[MAX_PATH];\n\n\tstd::vector<CString> to_delete;\n\n\twchar_t* envSquirrelTemp = _wgetenv(L\"SQUIRREL_TEMP\");\n\tif (envSquirrelTemp &&\n\t\tDirectoryExists(envSquirrelTemp) &&\n\t\tDirectoryIsWritable(envSquirrelTemp) &&\n\t\t!PathIsUNCW(envSquirrelTemp)) {\n\t\t_swprintf_c(targetDir, _countof(targetDir), L\"%s\", envSquirrelTemp);\n\t\tgoto gotADir;\n\t}\n\n\tif (!useFallbackDir) {\n\t\tSHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, targetDir);\n\t\tgoto gotADir;\n\t}\n\n\twchar_t username[512];\n\twchar_t appDataDir[MAX_PATH];\n\tULONG unameSize = _countof(username);\n\n\tSHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_CURRENT, appDataDir);\n\tGetUserName(username, &unameSize);\n\n\t_swprintf_c(targetDir, _countof(targetDir), L\"%s\\\\%s\", appDataDir, username);\n\n\tif (!CreateDirectory(targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {\n\t\twchar_t err[4096];\n\t\t_swprintf_c(err, _countof(err), L\"Unable to write to %s - IT policies may be restricting access to this folder\", targetDir);\n\t\tDisplayErrorMessage(CString(err), NULL);\n\n\t\treturn -1;\n\t}\n\ngotADir:\n\n\twcscat_s(targetDir, _countof(targetDir), L\"\\\\SquirrelTemp\");\n\n\tif (!CreateDirectory(targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {\n\t\twchar_t err[4096];\n\t\t_swprintf_c(err, _countof(err), L\"Unable to write to %s - IT policies may be restricting access to this folder\", targetDir);\n\n\t\tif (useFallbackDir) {\n\t\t\tDisplayErrorMessage(CString(err), NULL);\n\t\t}\n\n\t\tgoto failedExtract;\n\t}\n\n\tswprintf_s(logFile, L\"%s\\\\SquirrelSetup.log\", targetDir);\n\n\tif (!zipResource.Load(L\"DATA\", IDR_UPDATE_ZIP)) {\n\t\tgoto failedExtract;\n\t}\n\n\tDWORD dwSize = zipResource.GetSize();\n\tif (dwSize < 0x100) {\n\t\tgoto failedExtract;\n\t}\n\n\tBYTE* pData = (BYTE*)zipResource.Lock();\n\tHZIP zipFile = OpenZip(pData, dwSize, NULL);\n\tSetUnzipBaseDir(zipFile, targetDir);\n\n\t// NB: This library is kind of a disaster\n\tZRESULT zr;\n\tint index = 0;\n\tdo {\n\t\tZIPENTRY zentry;\n\t\twchar_t targetFile[MAX_PATH];\n\n\t\tzr = GetZipItem(zipFile, index, &zentry);\n\t\tif (zr != ZR_OK && zr != ZR_MORE) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// NB: UnzipItem won't overwrite data, we need to do it ourselves\n\t\tswprintf_s(targetFile, L\"%s\\\\%s\", targetDir, zentry.name);\n\t\tDeleteFile(targetFile);\n\n\t\tif (UnzipItem(zipFile, index, zentry.name) != ZR_OK) break;\n\t\tto_delete.push_back(CString(targetFile));\n\t\tindex++;\n\t} while (zr == ZR_MORE || zr == ZR_OK);\n\n\tCloseZip(zipFile);\n\tzipResource.Release();\n\n\t// nfi if the zip extract actually worked, check for Update.exe\n\twchar_t updateExePath[MAX_PATH];\n\tswprintf_s(updateExePath, L\"%s\\\\%s\", targetDir, L\"Update.exe\");\n\n\tif (GetFileAttributes(updateExePath) == INVALID_FILE_ATTRIBUTES) {\n\t\tgoto failedExtract;\n\t}\n\n\t// Run Update.exe\n\tsi.cb = sizeof(STARTUPINFO);\n\tsi.wShowWindow = SW_SHOW;\n\tsi.dwFlags = STARTF_USESHOWWINDOW;\n\n\tif (!lpCommandLine || wcsnlen_s(lpCommandLine, MAX_PATH) < 1) {\n\t\tlpCommandLine = L\"\";\n\t}\n\n\twchar_t cmd[MAX_PATH];\n\tswprintf_s(cmd, L\"\\\"%s\\\" --install . %s\", updateExePath, lpCommandLine);\n\n\tif (!CreateProcess(NULL, cmd, NULL, NULL, false, 0, NULL, targetDir, &si, &pi)) {\n\t\tgoto failedExtract;\n\t}\n\n\tWaitForSingleObject(pi.hProcess, INFINITE);\n\n\tDWORD dwExitCode;\n\tif (!GetExitCodeProcess(pi.hProcess, &dwExitCode)) {\n\t\tdwExitCode = (DWORD)-1;\n\t}\n\n\tif (dwExitCode != 0) {\n\t\tDisplayErrorMessage(CString(\n\t\t\tL\"There was an error while installing the application. \"\n\t\t\tL\"Check the setup log for more information and contact the author.\"), logFile);\n\t}\n\n\tfor (unsigned int i = 0; i < to_delete.size(); i++) {\n\t\tDeleteFile(to_delete[i]);\n\t}\n\n\tCloseHandle(pi.hProcess);\n\tCloseHandle(pi.hThread);\n\treturn (int) dwExitCode;\n\nfailedExtract:\n\tif (!useFallbackDir) {\n\t\t// Take another pass at it, using C:\\ProgramData instead\n\t\treturn ExtractUpdaterAndRun(lpCommandLine, true);\n\t}\n\n\tDisplayErrorMessage(CString(L\"Failed to extract installer\"), NULL);\n\treturn (int) dwExitCode;\n}\n"
  },
  {
    "path": "src/Setup/UpdateRunner.h",
    "content": "#pragma once\nclass CUpdateRunner\n{\n\npublic:\n\tstatic void DisplayErrorMessage(CString& errorMessage, wchar_t* logFile);\n\tstatic HRESULT AreWeInWine();\n\tstatic HRESULT AreWeUACElevated();\n\tstatic HRESULT ShellExecuteFromExplorer(LPWSTR pszFile, LPWSTR pszParameters);\n\tstatic bool DirectoryExists(wchar_t* szPath);\n\tstatic bool DirectoryIsWritable(wchar_t* szPath);\n\tstatic int ExtractUpdaterAndRun(wchar_t* lpCommandLine, bool useFallbackDir);\n};\n"
  },
  {
    "path": "src/Setup/compat.manifest",
    "content": "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n    <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"> \n        <application> \n            <!-- Windows Vista -->\n            <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/> \n            <!-- Windows 7 -->\n            <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n            <!-- Windows 8 -->\n            <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n            <!-- Windows 8.1 -->\n            <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n        </application> \n    </compatibility>\n</assembly>\n"
  },
  {
    "path": "src/Setup/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\n// Setup.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n// TODO: reference any additional headers you need in STDAFX.H\n// and not in this file\n"
  },
  {
    "path": "src/Setup/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently, but\n// are changed infrequently\n//\n\n#define _CRT_SECURE_NO_WARNINGS 1\n\n#pragma once\n\n#include \"targetver.h\"\n\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\n#define SECURITY_WIN32\n\n// Windows Header Files:\n#include <windows.h>\n#include <shellapi.h>\n#include <shlobj.h>\n#include <urlmon.h>\n\n// C RunTime Header Files\n#include <stdlib.h>\n#include <malloc.h>\n#include <memory.h>\n#include <tchar.h>\n\n#include <atlbase.h>\n#include <atlapp.h>\n#include <atlmisc.h>\n#include <atldlgs.h>\n#include <atlwin.h>\n\n#include <windows.h>\n#include <security.h>\n#include <shlobj.h>\n#include <exdisp.h>\n#include <shlwapi.h>\n\n#if defined _M_IX86\n#pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_IA64\n#pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_X64\n#pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#else\n#pragma comment(linker, \"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#endif\n"
  },
  {
    "path": "src/Setup/targetver.h",
    "content": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n\n#include <WinSDKVer.h>\n\n#define _WIN32_WINNT 0x0600\n#include <SDKDDKVer.h>\n"
  },
  {
    "path": "src/Setup/unzip.cpp",
    "content": "#include \"stdafx.h\"\n#include \"unzip.h\"\n\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 modifications were: incorporate the bugfixes of 1.1.4, allow\n// unzipping to/from handles/pipes/files/memory, encryption, unicode,\n// a windowsish api, and putting everything into a single .cpp file.\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 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 ZIP_HANDLE   1\n#define ZIP_FILENAME 2\n#define ZIP_MEMORY   3\n\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\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\n// unz_global_info structure contain global data about the ZIPfile\ntypedef struct unz_global_info_s\n{ unsigned long 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\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#define UNZ_PASSWORD            (-106)\n\n\n\n\n\n\n\n#define ZLIB_VERSION \"1.1.3\"\n\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\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\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\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\n\n\n\n\n\n\n\n\n\n\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\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\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\n\n\n\n\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 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 was\n//  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\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\n\n\n\n\nint inflateSetDictionary (z_streamp strm,\n                                             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\n\nint inflateSync (z_streamp strm);\n//\n//    Skips invalid compressed data until a full flush point can be found, or 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 found,\n//  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success\n//  case, the application may save the current current value of total_in which\n//  indicates where valid compressed data was found. In the error case, the\n//  application may repeatedly call inflateSync, providing more input each time,\n//  until success or end of the input data.\n\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\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\n\n\n\nconst char   *zError           (int err);\nint           inflateSyncPoint (z_streamp z);\nconst uLong *get_crc_table    (void);\n\n\n\ntypedef unsigned char  uch;\ntypedef uch uchf;\ntypedef unsigned short ush;\ntypedef ush ushf;\ntypedef unsigned long  ulg;\n\n\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\n#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]\n\n#define ERR_RETURN(strm,err) \\\n  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\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\n\n         // functions\n\n#define zmemzero(dest, len) memset(dest, 0, len)\n\n// Diagnostic functions\n#define LuAssert(cond,msg)\n#define LuTrace(x)\n#define LuTracev(x)\n#define LuTracevv(x)\n#define LuTracec(c,x)\n#define LuTracecv(c,x)\n\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) {if (p) ZFREE(s, p);}\n\n\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\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 (\n    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 (\n    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 (\n    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\n\n\n\n\nstruct inflate_blocks_state;\ntypedef struct inflate_blocks_state inflate_blocks_statef;\n\ninflate_blocks_statef * inflate_blocks_new (\n    z_streamp z,\n    check_func c,               // check function\n    uInt w);                   // window size\n\nint inflate_blocks (\n    inflate_blocks_statef *,\n    z_streamp ,\n    int);                      // initial return code\n\nvoid inflate_blocks_reset (\n    inflate_blocks_statef *,\n    z_streamp ,\n    uLong *);                  // check value on output\n\nint inflate_blocks_free (\n    inflate_blocks_statef *,\n    z_streamp);\n\nvoid inflate_set_dictionary (\n    inflate_blocks_statef *s,\n    const Byte *d,  // dictionary\n    uInt  n);       // dictionary length\n\nint inflate_blocks_sync_point (\n    inflate_blocks_statef *s);\n\n\n\n\nstruct inflate_codes_state;\ntypedef struct inflate_codes_state inflate_codes_statef;\n\ninflate_codes_statef *inflate_codes_new (\n    uInt, uInt,\n    const inflate_huft *, const inflate_huft *,\n    z_streamp );\n\nint inflate_codes (\n    inflate_blocks_statef *,\n    z_streamp ,\n    int);\n\nvoid inflate_codes_free (\n    inflate_codes_statef *,\n    z_streamp );\n\n\n\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}      // 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\n         *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\n\n// defines for inflate input/output\n//   update pointers and return\n#define UPDBITS {s->bitb=b;s->bitk=k;}\n#define UPDIN {z->avail_in=n;z->total_in+=(uLong)(p-z->next_in);z->next_in=p;}\n#define UPDOUT {s->write=q;}\n#define UPDATE {UPDBITS UPDIN UPDOUT}\n#define LEAVE {UPDATE return inflate_flush(s,z,r);}\n//   get bytes and bits\n#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}\n#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}\n#define NEXTBYTE (n--,*p++)\n#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}\n#define DUMPBITS(j) {b>>=(j);k-=(j);}\n//   output bytes\n#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)\n#define LOADOUT {q=s->write;m=(uInt)WAVAIL;m;}\n#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}\n#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}\n#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}\n#define OUTBYTE(a) {*q++=(Byte)(a);m--;}\n//   load local pointers\n#define LOAD {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] = {\n    0x0000,\n    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,\n    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff\n};\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 *, inflate_blocks_statef *, z_streamp );\n\n\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}\n  };\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\n\n\n\n\n\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{\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 = z->avail_out;\n  if (n && r == Z_BUF_ERROR) 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  { 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  {\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 = z->avail_out;\n    if (n && r == Z_BUF_ERROR) 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    if (n!=0) {memcpy(p,q,n); p+=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\n\n\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}  // 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};\n\n\ninflate_codes_statef *inflate_codes_new(\nuInt bl, uInt bd,\nconst inflate_huft *tl,\nconst inflate_huft *td, // need separate declaration for Borland C++\nz_streamp z)\n{\n  inflate_codes_statef *c;\n\n  if ((c = (inflate_codes_statef *)\n       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)\n  {\n    c->mode = START;\n    c->lbits = (Byte)bl;\n    c->dbits = (Byte)bd;\n    c->ltree = tl;\n    c->dtree = td;\n    LuTracev((stderr, \"inflate:       codes new\\n\"));\n  }\n  return c;\n}\n\n\nint inflate_codes(inflate_blocks_statef *s, z_streamp z, int r)\n{\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 (c->mode)\n  {             // 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      {\n        UPDATE\n        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);\n        LOAD\n        if (r != Z_OK)\n        {\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        LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?\n                 \"inflate:         literal '%c'\\n\" :\n                 \"inflate:         literal 0x%02x\\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        LuTracevv((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      LuTracevv((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      LuTracevv((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 = q - c->sub.copy.dist;\n      while (f < s->window)             // modulo window size-\"while\" instead\n        f += s->end - s->window;        // of \"if\" handles invalid distances\n      while (c->len)\n      {\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\n\nvoid inflate_codes_free(inflate_codes_statef *c,z_streamp z)\n{ ZFREE(z, c);\n  LuTracev((stderr, \"inflate:       codes free\\n\"));\n}\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\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\n\nvoid inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c)\n{\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  LuTracev((stderr, \"inflate:   blocks reset\\n\"));\n}\n\n\ninflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w)\n{\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 =\n       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)\n  {\n    ZFREE(z, s);\n    return Z_NULL;\n  }\n  if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL)\n  {\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  LuTracev((stderr, \"inflate:   blocks allocated\\n\"));\n  inflate_blocks_reset(s, z, Z_NULL);\n  return s;\n}\n\n\nint inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r)\n{\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  {\n    case IBM_TYPE:\n      NEEDBITS(3)\n      t = (uInt)b & 7;\n      s->last = t & 1;\n      switch (t >> 1)\n      {\n        case 0:                         // stored\n          LuTracev((stderr, \"inflate:     stored block%s\\n\",\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          LuTracev((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            {\n              r = Z_MEM_ERROR;\n              LEAVE\n            }\n          }\n          DUMPBITS(3)\n          s->mode = IBM_CODES;\n          break;\n        case 2:                         // dynamic\n          LuTracev((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      {\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      LuTracev((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) t = n;\n      if (t > m) t = m;\n      memcpy(q, p, t);\n      p += t;  n -= t;\n      q += t;  m -= t;\n      if ((s->sub.left -= t) != 0)\n        break;\n      LuTracev((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      {\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      {\n        r = Z_MEM_ERROR;\n        LEAVE\n      }\n      DUMPBITS(14)\n      s->sub.trees.index = 0;\n      LuTracev((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      {\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      {\n        r = t;\n        if (r == Z_DATA_ERROR)\n        {\n          ZFREE(z, s->sub.trees.blens);\n          s->mode = IBM_BAD;\n        }\n        LEAVE\n      }\n      s->sub.trees.index = 0;\n      LuTracev((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      {\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        {\n          DUMPBITS(t)\n          s->sub.trees.blens[s->sub.trees.index++] = c;\n        }\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          {\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        if (t != Z_OK)\n        {\n          if (t == (uInt)Z_DATA_ERROR)\n          {\n            ZFREE(z, s->sub.trees.blens);\n            s->mode = IBM_BAD;\n          }\n          r = t;\n          LEAVE\n        }\n        LuTracev((stderr, \"inflate:       trees ok\\n\"));\n        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)\n        {\n          r = Z_MEM_ERROR;\n          LEAVE\n        }\n        s->sub.decode.codes = c;\n      }\n      ZFREE(z, s->sub.trees.blens);\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\n      LuTracev((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      {\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\n\nint inflate_blocks_free(inflate_blocks_statef *s, z_streamp z)\n{\n  inflate_blocks_reset(s, z, Z_NULL);\n  ZFREE(z, s->window);\n  ZFREE(z, s->hufts);\n  ZFREE(z, s);\n  LuTracev((stderr, \"inflate:   blocks freed\\n\"));\n  return Z_OK;\n}\n\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\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\n\n\nint huft_build (\n    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, 33, 49, 65, 97, 129, 193,\n        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n        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, 6,\n        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,\n        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\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(\nuInt *b,               // code lengths in bits (all assumed <= BMAX)\nuInt n,                 // number of codes (assumed <= 288)\nuInt s,                 // number of simple-valued codes (0..s-1)\nconst uInt *d,         // list of base values for non-simple codes\nconst uInt *e,         // list of extra bits for non-simple codes\ninflate_huft * *t,  // result: starting table\nuInt *m,               // maximum lookup bits, returns actual\ninflate_huft *hp,       // space for trees\nuInt *hn,               // hufts used in space\nuInt *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), or Z_DATA_ERROR if the input is invalid.\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\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; p;                          // clear c[]--assume BMAX+1 is 16\n  p = b;  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\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\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\n  // Generate starting offsets into the value table for each length\n  x[1] = j = 0;\n  p = c + 1;  xp = x + 2;\n  while (--i) {                 // note that i == g from above\n    *xp++ = (j += *p++);\n  }\n\n\n  // Make a table of values in order of bit lengths\n  p = b;  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\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  {\n    a = c[k];\n    while (a--)\n    {\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      {\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_DATA_ERROR;  // overflow of MANY\n        u[h] = q = hp + *hn;\n        *hn += z;\n\n        // connect to last table, if there is one\n        if (h)\n        {\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        }\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      {\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      }\n      else\n      {\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      {\n        h--;                    // don't need to update q\n        w -= l;\n        mask = (1 << w) - 1;\n      }\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\n\nint inflate_trees_bits(\nuInt *c,               // 19 code lengths\nuInt *bb,              // bits tree desired/actual depth\ninflate_huft * *tb, // bits tree result\ninflate_huft *hp,       // space for trees\nz_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,\n                 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  {\n    z->msg = (char*)\"incomplete dynamic bit lengths tree\";\n    r = Z_DATA_ERROR;\n  }\n  ZFREE(z, v);\n  return r;\n}\n\n\nint inflate_trees_dynamic(\nuInt nl,                // number of literal/length codes\nuInt nd,                // number of distance codes\nuInt *c,               // that many (total) code lengths\nuInt *bl,              // literal desired/actual bit depth\nuInt *bd,              // distance desired/actual bit depth\ninflate_huft * *tl, // literal/length tree result\ninflate_huft * *td, // distance tree result\ninflate_huft *hp,       // space for trees\nz_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  {\n    if (r == Z_DATA_ERROR)\n      z->msg = (char*)\"oversubscribed literal/length tree\";\n    else if (r != Z_MEM_ERROR)\n    {\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  {\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    }\n    else if (r != Z_MEM_ERROR)\n    {\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\n\n\n\n\nint inflate_trees_fixed(\nuInt *bl,               // literal desired/actual bit depth\nuInt *bd,               // distance desired/actual bit depth\nconst inflate_huft * * tl,     // literal/length tree result\nconst inflate_huft * *td,     // distance tree result\nz_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\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\n//struct inflate_codes_state {int dummy;}; // for buggy compilers\n\n\n// macros for bit input with no checking and for returning unused bytes\n#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}\n#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;}\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(\nuInt bl, uInt bd,\nconst inflate_huft *tl,\nconst inflate_huft *td, // need separate declaration for Borland C++\ninflate_blocks_statef *s,\nz_streamp z)\n{\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    {\n      DUMPBITS(t->bits)\n      LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?\n                \"inflate:         * literal '%c'\\n\" :\n                \"inflate:         * literal 0x%02x\\n\", t->base));\n      *q++ = (Byte)t->base;\n      m--;\n      continue;\n    }\n    for (;;) {\n      DUMPBITS(t->bits)\n      if (e & 16)\n      {\n        // get extra bits for length\n        e &= 15;\n        c = t->base + ((uInt)b & inflate_mask[e]);\n        DUMPBITS(e)\n        LuTracevv((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          {\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            LuTracevv((stderr, \"inflate:         * distance %u\\n\", d));\n\n            // do the copy\n            m -= c;\n            r = q - d;\n            if (r < s->window)                  // wrap if needed\n            {\n              do {\n                r += s->end - s->window;        // force pointer in window\n              } while (r < s->window);          // covers invalid distances\n              e = (uInt) (s->end - r);\n              if (c > e)\n              {\n                c -= e;                         // wrapped copy\n                do {\n                    *q++ = *r++;\n                } while (--e);\n                r = s->window;\n                do {\n                    *q++ = *r++;\n                } while (--c);\n              }\n              else                              // normal copy\n              {\n                *q++ = *r++;  c--;\n                *q++ = *r++;  c--;\n                do {\n                    *q++ = *r++;\n                } while (--c);\n              }\n            }\n            else                                /* normal copy */\n            {\n              *q++ = *r++;  c--;\n              *q++ = *r++;  c--;\n              do {\n                *q++ = *r++;\n              } while (--c);\n            }\n            break;\n          }\n          else if ((e & 64) == 0)\n          {\n            t += t->base;\n            e = (t += ((uInt)b & inflate_mask[e]))->exop;\n          }\n          else\n          {\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      {\n        t += t->base;\n        if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0)\n        {\n          DUMPBITS(t->bits)\n          LuTracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?\n                    \"inflate:         * literal '%c'\\n\" :\n                    \"inflate:         * literal 0x%02x\\n\", t->base));\n          *q++ = (Byte)t->base;\n          m--;\n          break;\n        }\n      }\n      else if (e & 32)\n      {\n        LuTracevv((stderr, \"inflate:         * end of block\\n\"));\n        UNGRAB\n        UPDATE\n        return Z_STREAM_END;\n      }\n      else\n      {\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\n\n\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\n\n\n\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};\n\nconst uLong * get_crc_table()\n{ return (const uLong *)crc_table;\n}\n\n#define CRC_DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);\n#define CRC_DO2(buf)  CRC_DO1(buf); CRC_DO1(buf);\n#define CRC_DO4(buf)  CRC_DO2(buf); CRC_DO2(buf);\n#define CRC_DO8(buf)  CRC_DO4(buf); CRC_DO4(buf);\n\nuLong ucrc32(uLong crc, const Byte *buf, uInt len)\n{ if (buf == Z_NULL) return 0L;\n  crc = crc ^ 0xffffffffL;\n  while (len >= 8)  {CRC_DO8(buf); len -= 8;}\n  if (len) do {CRC_DO1(buf);} while (--len);\n  return crc ^ 0xffffffffL;\n}\n\n\n\n// =============================================================\n// some decryption routines\n#define CRC32(c, b) (crc_table[((int)(c)^(b))&0xff]^((c)>>8))\nvoid Uupdate_keys(unsigned long *keys, char c)\n{ keys[0] = CRC32(keys[0],c);\n  keys[1] += keys[0] & 0xFF;\n  keys[1] = keys[1]*134775813L +1;\n  keys[2] = CRC32(keys[2], keys[1] >> 24);\n}\nchar Udecrypt_byte(unsigned long *keys)\n{ unsigned temp = ((unsigned)keys[2] & 0xffff) | 2;\n  return (char)(((temp * (temp ^ 1)) >> 8) & 0xff);\n}\nchar zdecode(unsigned long *keys, char c)\n{ c^=Udecrypt_byte(keys);\n  Uupdate_keys(keys,c);\n  return c;\n}\n\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\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)  {s1 += buf[i]; s2 += s1;}\n#define AD_DO2(buf,i)  AD_DO1(buf,i); AD_DO1(buf,i+1);\n#define AD_DO4(buf,i)  AD_DO2(buf,i); AD_DO2(buf,i+2);\n#define AD_DO8(buf,i)  AD_DO4(buf,i); AD_DO4(buf,i+4);\n#define AD_DO16(buf)   AD_DO8(buf,0); AD_DO8(buf,8);\n\n// =========================================================================\nuLong adler32(uLong adler, const Byte *buf, uInt len)\n{\n    unsigned long s1 = adler & 0xffff;\n    unsigned long s2 = (adler >> 16) & 0xffff;\n    int k;\n\n    if (buf == Z_NULL) 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\t    buf += 16;\n            k -= 16;\n        }\n        if (k != 0) do {\n            s1 += *buf++;\n\t    s2 += s1;\n        } while (--k);\n        s1 %= BASE;\n        s2 %= BASE;\n    }\n    return (s2 << 16) | s1;\n}\n\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\n\n\n\n\n\nconst char * zlibVersion()\n{\n    return ZLIB_VERSION;\n}\n\n// exported to allow conversion of error code to string for compress() and\n// uncompress()\nconst char * zError(int err)\n{ return ERR_MSG(err);\n}\n\n\n\n\nvoidpf zcalloc (voidpf opaque, unsigned items, unsigned size)\n{\n    if (opaque) items += size - size; // make compiler happy\n    return (voidpf)calloc(items, size);\n}\n\nvoid  zcfree (voidpf opaque, voidpf ptr)\n{\n    zfree(ptr);\n    if (opaque) return; // make compiler happy\n}\n\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}      // 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\n    *blocks;            // current inflate_blocks state\n\n};\n\nint inflateReset(z_streamp z)\n{\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  LuTracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nint inflateEnd(z_streamp z)\n{\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  LuTracev((stderr, \"inflate: end\\n\"));\n  return Z_OK;\n}\n\n\nint inflateInit2(z_streamp z)\n{ const char *version = ZLIB_VERSION; int stream_size = sizeof(z_stream);\n  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != sizeof(z_stream)) 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 created by gzip.\n  // 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) return Z_STREAM_ERROR;\n  z->msg = Z_NULL;\n  if (z->zalloc == Z_NULL)\n  {\n    z->zalloc = zcalloc;\n    z->opaque = (voidpf)0;\n  }\n  if (z->zfree == Z_NULL) z->zfree = zcfree;\n  if ((z->state = (struct internal_state *)\n       ZALLOC(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  {\n    w = - w;\n    z->state->nowrap = 1;\n  }\n\n  // set window size\n  if (w < 8 || w > 15)\n  {\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 =\n      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))\n      == Z_NULL)\n  {\n    inflateEnd(z);\n    return Z_MEM_ERROR;\n  }\n  LuTracev((stderr, \"inflate: allocated\\n\"));\n\n  // reset state\n  inflateReset(z);\n  return Z_OK;\n}\n\n\n\n#define IM_NEEDBYTE {if(z->avail_in==0)return r;r=f;}\n#define IM_NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)\n\nint inflate(z_streamp z, int f)\n{\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 (;;) switch (z->state->mode)\n  {\n    case IM_METHOD:\n      IM_NEEDBYTE\n      if (((z->state->sub.method = IM_NEXTBYTE) & 0xf) != Z_DEFLATED)\n      {\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      {\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      {\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      LuTracev((stderr, \"inflate: zlib header ok\\n\"));\n      if (!(b & PRESET_DICT))\n      {\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; 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      {\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      {\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      {\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      LuTracev((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\n\n\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\n\n\n#define UNZ_BUFSIZE (16384)\n#define UNZ_MAXFILENAMEINZIP (256)\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n\n\n\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{\n    uLong offset_curfile;// relative offset of local header 4 bytes\n} unz_file_info_internal;\n\n\ntypedef struct\n{ bool is_handle; // either a handle or memory\n  bool canseek;\n  // for handles:\n  HANDLE h; bool herr; unsigned long initial_offset; bool mustclosehandle;\n  // for memory:\n  void *buf; unsigned int len,pos; // if it's a memory block\n} LUFILE;\n\n\nLUFILE *lufopen(void *z,unsigned int len,DWORD flags,ZRESULT *err)\n{ if (flags!=ZIP_HANDLE && flags!=ZIP_FILENAME && flags!=ZIP_MEMORY) {*err=ZR_ARGS; return NULL;}\n  //\n  HANDLE h=0; bool canseek=false; *err=ZR_OK;\n  bool mustclosehandle=false;\n  if (flags==ZIP_HANDLE||flags==ZIP_FILENAME)\n  { if (flags==ZIP_HANDLE)\n    { HANDLE hf = z;\n      h=hf; mustclosehandle=false;\n#ifdef DuplicateHandle\n      BOOL res = DuplicateHandle(GetCurrentProcess(),hf,GetCurrentProcess(),&h,0,FALSE,DUPLICATE_SAME_ACCESS);\n      if (!res) mustclosehandle=true;\n#endif\n    }\n    else\n    { h=CreateFile((const TCHAR*)z,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);\n      if (h==INVALID_HANDLE_VALUE) {*err=ZR_NOFILE; return NULL;}\n      mustclosehandle=true;\n    }\n    // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE.\n    DWORD res = SetFilePointer(h,0,0,FILE_CURRENT);\n    canseek = (res!=0xFFFFFFFF);\n  }\n  LUFILE *lf = new LUFILE;\n  if (flags==ZIP_HANDLE||flags==ZIP_FILENAME)\n  { lf->is_handle=true; lf->mustclosehandle=mustclosehandle;\n    lf->canseek=canseek;\n    lf->h=h; lf->herr=false;\n    lf->initial_offset=0;\n    if (canseek) lf->initial_offset = SetFilePointer(h,0,NULL,FILE_CURRENT);\n  }\n  else\n  { lf->is_handle=false;\n    lf->canseek=true;\n    lf->mustclosehandle=false;\n    lf->buf=z; lf->len=len; lf->pos=0; lf->initial_offset=0;\n  }\n  *err=ZR_OK;\n  return lf;\n}\n\n\nint lufclose(LUFILE *stream)\n{ if (stream==NULL) return EOF;\n  if (stream->mustclosehandle) CloseHandle(stream->h);\n  delete stream;\n  return 0;\n}\n\nint luferror(LUFILE *stream)\n{ if (stream->is_handle && stream->herr) return 1;\n  else return 0;\n}\n\nlong int luftell(LUFILE *stream)\n{ if (stream->is_handle && stream->canseek) return SetFilePointer(stream->h,0,NULL,FILE_CURRENT)-stream->initial_offset;\n  else if (stream->is_handle) return 0;\n  else 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) SetFilePointer(stream->h,stream->initial_offset+offset,0,FILE_BEGIN);\n    else if (whence==SEEK_CUR) SetFilePointer(stream->h,offset,NULL,FILE_CURRENT);\n    else if (whence==SEEK_END) SetFilePointer(stream->h,offset,NULL,FILE_END);\n    else return 19; // EINVAL\n    return 0;\n  }\n  else if (stream->is_handle) return 29; // ESPIPE\n  else\n  { if (whence==SEEK_SET) stream->pos=offset;\n    else if (whence==SEEK_CUR) stream->pos+=offset;\n    else if (whence==SEEK_END) stream->pos=stream->len+offset;\n    return 0;\n  }\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; BOOL res = ReadFile(stream->h,ptr,toread,&red,NULL);\n    if (!res) stream->herr=true;\n    return red/size;\n  }\n  if (stream->pos+toread > stream->len) toread = stream->len-stream->pos;\n  memcpy(ptr, (char*)stream->buf + stream->pos, toread); DWORD red = toread;\n  stream->pos += red;\n  return red/size;\n}\n\n\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{\n\tchar  *read_buffer;         // internal buffer for compressed data\n\tz_stream stream;            // zLib stream structure for inflate\n\n\tuLong pos_in_zipfile;       // position in byte on the zipfile, for fseek\n\tuLong stream_initialised;   // flag set if stream structure is initialised\n\n\tuLong offset_local_extrafield;// offset of the local extra field\n\tuInt  size_local_extrafield;// size of the local extra field\n\tuLong pos_local_extrafield;   // position in the local extra field in read\n\n\tuLong crc32;                // crc32 of all data uncompressed\n\tuLong crc32_wait;           // crc32 we must obtain after decompress all\n\tuLong rest_read_compressed; // number of byte to be decompressed\n\tuLong rest_read_uncompressed;//number of byte to be obtained after decomp\n\tLUFILE* file;                 // io structore of the zipfile\n\tuLong compression_method;   // compression method (0==store)\n\tuLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx)\n  bool encrypted;               // is it encrypted?\n  unsigned long keys[3];        // decryption keys, initialized by unzOpenCurrentFile\n  int encheadleft;              // the first call(s) to unzReadCurrentFile will read this many encryption-header bytes first\n  char crcenctest;              // if encrypted, we'll check the encryption buffer against this\n} file_in_zip_read_info_s;\n\n\n// unz_s contain internal information about the zipfile\ntypedef struct\n{\n\tLUFILE* file;               // io structore of the zipfile\n\tunz_global_info gi;         // public global information\n\tuLong byte_before_the_zipfile;// byte before the zipfile, (>0 for sfx)\n\tuLong num_file;             // number of the current file in the zipfile\n\tuLong pos_in_central_dir;   // pos of the current file in the central dir\n\tuLong current_file_ok;      // flag about the usability of the current file\n\tuLong central_pos;          // position of the beginning of the central dir\n\n\tuLong size_central_dir;     // size of the central directory\n\tuLong offset_central_dir;   // offset of start of central directory with respect to the starting disk number\n\n\tunz_file_info cur_file_info; // public info about the current file in zip\n\tunz_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 file if we are decompressing it\n} unz_s, *unzFile;\n\n\nint unzStringFileNameCompare (const char* fileName1,const char* fileName2,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\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  }\n  else\n  { if (luferror(fin)) return UNZ_ERRNO;\n    else return UNZ_EOF;\n  }\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{\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{\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\n// My own strcmpi / strcasecmp\nint strcmpcasenosensitive_internal (const char* fileName1,const char *fileName2)\n{\n\tfor (;;)\n\t{\n\t\tchar c1=*(fileName1++);\n\t\tchar c2=*(fileName2++);\n\t\tif ((c1>='a') && (c1<='z'))\n\t\t\tc1 -= (char)0x20;\n\t\tif ((c2>='a') && (c2<='z'))\n\t\t\tc2 -= (char)0x20;\n\t\tif (c1=='\\0')\n\t\t\treturn ((c2=='\\0') ? 0 : -1);\n\t\tif (c2=='\\0')\n\t\t\treturn 1;\n\t\tif (c1<c2)\n\t\t\treturn -1;\n\t\tif (c1>c2)\n\t\t\treturn 1;\n\t}\n}\n\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 strcasecmp)\n//\nint unzStringFileNameCompare (const char*fileName1,const char*fileName2,int iCaseSensitivity)\n{ if (iCaseSensitivity==1) return strcmp(fileName1,fileName2);\n  else return strcmpcasenosensitive_internal(fileName1,fileName2);\n}\n\n#define BUFREADCOMMENT (0x400)\n\n\n//  Locate the Central directory of a zipfile (at the end, just before\n// the global comment). Lu bugfix 2005.07.26 - returns 0xFFFFFFFF if not found,\n// rather than 0, since 0 is a valid central-dir-location for an empty zipfile.\nuLong unzlocal_SearchCentralDir(LUFILE *fin)\n{ if (lufseek(fin,0,SEEK_END) != 0) return 0xFFFFFFFF;\n  uLong uSizeFile = luftell(fin);\n\n  uLong uMaxBack=0xffff; // maximum size of global comment\n  if (uMaxBack>uSizeFile) uMaxBack = uSizeFile;\n\n  unsigned char *buf = (unsigned char*)zmalloc(BUFREADCOMMENT+4);\n  if (buf==NULL) return 0xFFFFFFFF;\n  uLong uPosFound=0xFFFFFFFF;\n\n  uLong uBackRead = 4;\n  while (uBackRead<uMaxBack)\n  { uLong uReadSize,uReadPos ;\n    int i;\n    if (uBackRead+BUFREADCOMMENT>uMaxBack) uBackRead = uMaxBack;\n    else uBackRead+=BUFREADCOMMENT;\n    uReadPos = uSizeFile-uBackRead ;\n    uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);\n    if (lufseek(fin,uReadPos,SEEK_SET)!=0) break;\n    if (lufread(buf,(uInt)uReadSize,1,fin)!=1) break;\n    for (i=(int)uReadSize-3; (i--)>=0;)\n    { if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&\t((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))\n      { uPosFound = uReadPos+i;\tbreak;\n      }\n    }\n    if (uPosFound!=0) break;\n  }\n  if (buf) zfree(buf);\n  return uPosFound;\n}\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 NULL.\n// Otherwise, the return value is a unzFile Handle, usable with other unzip functions\nunzFile unzOpenInternal(LUFILE *fin)\n{ if (fin==NULL) return NULL;\n  if (unz_copyright[0]!=' ') {lufclose(fin); return NULL;}\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==0xFFFFFFFF) err=UNZ_ERRNO;\n  if (lufseek(fin,central_pos,SEEK_SET)!=0) err=UNZ_ERRNO;\n  // the signature, already checked\n  if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO;\n  // number of this disk\n  uLong number_disk;          // number of the current dist, used for spanning ZIP, unsupported, always 0\n  if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) 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 spaning ZIP, unsupported, always 0\n  if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) 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) 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 than number_entry on nospan)\n  if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO;\n  if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE;\n  // size of the central directory\n  if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO;\n  // offset of start of central directory with respect to the starting disk number\n  if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO;\n  // zipfile comment length\n  if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO;\n  if ((central_pos+fin->initial_offset<us.offset_central_dir+us.size_central_dir) && (err==UNZ_OK)) err=UNZ_BADZIPFILE;\n  if (err!=UNZ_OK) {lufclose(fin);return NULL;}\n\n  us.file=fin;\n  us.byte_before_the_zipfile = central_pos+fin->initial_offset - (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 = 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\n\n//  Close a ZipFile opened with unzipOpen.\n//  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),\n//    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n//  return UNZ_OK if there is no problem.\nint unzClose (unzFile file)\n{\n\tunz_s* s;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\n    if (s->pfile_in_zip_read!=NULL)\n        unzCloseCurrentFile(file);\n\n\tlufclose(s->file);\n\tif (s) zfree(s); // unused s=0;\n\treturn UNZ_OK;\n}\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{\n\tunz_s* s;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\t*pglobal_info=s->gi;\n\treturn UNZ_OK;\n}\n\n\n//   Translate date/time from Dos format to tm_unz (readable more easilty)\nvoid unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm)\n{\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 (unzFile file,\n                                                  unz_file_info *pfile_info,\n                                                  unz_file_info_internal\n                                                  *pfile_info_internal,\n                                                  char *szFileName,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong fileNameBufferSize,\n                                                  void *extraField,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong extraFieldBufferSize,\n                                                  char *szComment,\n\t\t\t\t\t\t\t\t\t\t\t\t  uLong commentBufferSize);\n\nint unzlocal_GetCurrentFileInfoInternal (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{\n\tunz_s* s;\n\tunz_file_info file_info;\n\tunz_file_info_internal file_info_internal;\n\tint err=UNZ_OK;\n\tuLong uMagic;\n\tlong lSeek=0;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (lufseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)\n\t\terr=UNZ_ERRNO;\n\n\n\t// we check the magic\n\tif (err==UNZ_OK)\n\t\tif (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)\n\t\t\terr=UNZ_ERRNO;\n\t\telse if (uMagic!=0x02014b50)\n\t\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);\n\n\tif (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tlSeek+=file_info.size_filename;\n\tif ((err==UNZ_OK) && (szFileName!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_filename<fileNameBufferSize)\n\t\t{\n\t\t\t*(szFileName+file_info.size_filename)='\\0';\n\t\t\tuSizeRead = file_info.size_filename;\n\t\t}\n\t\telse\n\t\t\tuSizeRead = fileNameBufferSize;\n\n\t\tif ((file_info.size_filename>0) && (fileNameBufferSize>0))\n\t\t\tif (lufread(szFileName,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\tlSeek -= uSizeRead;\n\t}\n\n\n\tif ((err==UNZ_OK) && (extraField!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_file_extra<extraFieldBufferSize)\n\t\t\tuSizeRead = file_info.size_file_extra;\n\t\telse\n\t\t\tuSizeRead = extraFieldBufferSize;\n\n\t\tif (lSeek!=0)\n\t\t\tif (lufseek(s->file,lSeek,SEEK_CUR)==0)\n\t\t\t\tlSeek=0;\n\t\t\telse\n\t\t\t\terr=UNZ_ERRNO;\n\t\tif ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))\n\t\t\tif (lufread(extraField,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\tlSeek += file_info.size_file_extra - uSizeRead;\n\t}\n\telse\n\t\tlSeek+=file_info.size_file_extra;\n\n\n\tif ((err==UNZ_OK) && (szComment!=NULL))\n\t{\n\t\tuLong uSizeRead ;\n\t\tif (file_info.size_file_comment<commentBufferSize)\n\t\t{\n\t\t\t*(szComment+file_info.size_file_comment)='\\0';\n\t\t\tuSizeRead = file_info.size_file_comment;\n\t\t}\n\t\telse\n\t\t\tuSizeRead = commentBufferSize;\n\n\t\tif (lSeek!=0)\n\t\t\tif (lufseek(s->file,lSeek,SEEK_CUR)==0)\n\t\t\t\t{} // unused lSeek=0;\n\t\t\telse\n\t\t\t\terr=UNZ_ERRNO;\n\t\tif ((file_info.size_file_comment>0) && (commentBufferSize>0))\n\t\t\tif (lufread(szComment,(uInt)uSizeRead,1,s->file)!=1)\n\t\t\t\terr=UNZ_ERRNO;\n\t\t//unused lSeek+=file_info.size_file_comment - uSizeRead;\n\t}\n\telse {} //unused lSeek+=file_info.size_file_comment;\n\n\tif ((err==UNZ_OK) && (pfile_info!=NULL))\n\t\t*pfile_info=file_info;\n\n\tif ((err==UNZ_OK) && (pfile_info_internal!=NULL))\n\t\t*pfile_info_internal=file_info_internal;\n\n\treturn err;\n}\n\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, void *extraField, uLong extraFieldBufferSize,\n  char *szComment, uLong commentBufferSize)\n{ return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,szFileName,fileNameBufferSize,\n      extraField,extraFieldBufferSize, szComment,commentBufferSize);\n}\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{\n\tint err;\n\tunz_s* s;\n\tif (file==NULL) return UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\ts->pos_in_central_dir=s->offset_central_dir;\n\ts->num_file=0;\n\terr=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n\t\t\t\t\t\t\t\t\t\t\t &s->cur_file_info_internal,\n\t\t\t\t\t\t\t\t\t\t\t NULL,0,NULL,0,NULL,0);\n\ts->current_file_ok = (err == UNZ_OK);\n\treturn err;\n}\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{\n\tunz_s* s;\n\tint err;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\tif (s->num_file+1==s->gi.number_entry)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\n\ts->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +\n\t\t\ts->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;\n\ts->num_file++;\n\terr = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n\t\t\t\t\t\t\t\t\t\t\t   &s->cur_file_info_internal,\n\t\t\t\t\t\t\t\t\t\t\t   NULL,0,NULL,0,NULL,0);\n\ts->current_file_ok = (err == UNZ_OK);\n\treturn err;\n}\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 char *szFileName, int iCaseSensitivity)\n{\n\tunz_s* s;\n\tint err;\n\n\n\tuLong num_fileSaved;\n\tuLong pos_in_central_dirSaved;\n\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)\n        return UNZ_PARAMERROR;\n\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_END_OF_LIST_OF_FILE;\n\n\tnum_fileSaved = s->num_file;\n\tpos_in_central_dirSaved = s->pos_in_central_dir;\n\n\terr = unzGoToFirstFile(file);\n\n\twhile (err == UNZ_OK)\n\t{\n\t\tchar szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];\n\t\tunzGetCurrentFileInfo(file,NULL,\n\t\t\t\t\t\t\t\tszCurrentFileName,sizeof(szCurrentFileName)-1,\n\t\t\t\t\t\t\t\tNULL,0,NULL,0);\n\t\tif (unzStringFileNameCompare(szCurrentFileName,szFileName,iCaseSensitivity)==0)\n\t\t\treturn UNZ_OK;\n\t\terr = unzGoToNextFile(file);\n\t}\n\n\ts->num_file = num_fileSaved ;\n\ts->pos_in_central_dir = pos_in_central_dirSaved ;\n\treturn err;\n}\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, uInt  *psize_local_extrafield)\n{\n\tuLong uMagic,uData,uFlags;\n\tuLong size_filename;\n\tuLong size_extra_field;\n\tint err=UNZ_OK;\n\n\t*piSizeVar = 0;\n\t*poffset_local_extrafield = 0;\n\t*psize_local_extrafield = 0;\n\n\tif (lufseek(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,SEEK_SET)!=0)\n\t\treturn UNZ_ERRNO;\n\n\n\tif (err==UNZ_OK)\n\t\tif (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)\n\t\t\terr=UNZ_ERRNO;\n\t\telse if (uMagic!=0x04034b50)\n\t\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getShort(s->file,&uData) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n//\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))\n//\t\terr=UNZ_BADZIPFILE;\n\tif (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getShort(s->file,&uData) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))\n\t\terr=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\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) // date/time\n\t\terr=UNZ_ERRNO;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) // crc\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&\n\t\t                      ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size compr\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&\n\t\t\t\t\t\t\t  ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\tif (unzlocal_getLong(s->file,&uData) != UNZ_OK) // size uncompr\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&\n\t\t\t\t\t\t\t  ((uFlags & 8)==0))\n\t\terr=UNZ_BADZIPFILE;\n\n\n\tif (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\telse if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))\n\t\terr=UNZ_BADZIPFILE;\n\n\t*piSizeVar += (uInt)size_filename;\n\n\tif (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)\n\t\terr=UNZ_ERRNO;\n\t*poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +\n\t\t\t\t\t\t\t\t\tSIZEZIPLOCALHEADER + size_filename;\n\t*psize_local_extrafield = (uInt)size_extra_field;\n\n\t*piSizeVar += (uInt)size_extra_field;\n\n\treturn err;\n}\n\n\n\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, const char *password)\n{\n\tint err;\n\tint Store;\n\tuInt iSizeVar;\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tuLong offset_local_extrafield;  // offset of the local extra field\n\tuInt  size_local_extrafield;    // size of the local extra field\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n\tif (!s->current_file_ok)\n\t\treturn UNZ_PARAMERROR;\n\n    if (s->pfile_in_zip_read != NULL)\n        unzCloseCurrentFile(file);\n\n\tif (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,\n\t\t\t\t&offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)\n\t\treturn UNZ_BADZIPFILE;\n\n\tpfile_in_zip_read_info = (file_in_zip_read_info_s*)zmalloc(sizeof(file_in_zip_read_info_s));\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_INTERNALERROR;\n\n\tpfile_in_zip_read_info->read_buffer=(char*)zmalloc(UNZ_BUFSIZE);\n\tpfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;\n\tpfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;\n\tpfile_in_zip_read_info->pos_local_extrafield=0;\n\n\tif (pfile_in_zip_read_info->read_buffer==NULL)\n\t{\n\t\tif (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); //unused pfile_in_zip_read_info=0;\n\t\treturn UNZ_INTERNALERROR;\n\t}\n\n\tpfile_in_zip_read_info->stream_initialised=0;\n\n\tif ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED))\n        { // unused err=UNZ_BADZIPFILE;\n        }\n\tStore = s->cur_file_info.compression_method==0;\n\n\tpfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;\n\tpfile_in_zip_read_info->crc32=0;\n\tpfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;\n\tpfile_in_zip_read_info->file=s->file;\n\tpfile_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\tif (!Store)\n\t{\n\t  pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n\t  pfile_in_zip_read_info->stream.zfree = (free_func)0;\n\t  pfile_in_zip_read_info->stream.opaque = (voidpf)0;\n\n          err=inflateInit2(&pfile_in_zip_read_info->stream);\n\t  if (err == Z_OK)\n\t    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\t}\n\tpfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ;\n\tpfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ;\n  pfile_in_zip_read_info->encrypted = (s->cur_file_info.flag&1)!=0;\n  bool extlochead = (s->cur_file_info.flag&8)!=0;\n  if (extlochead) pfile_in_zip_read_info->crcenctest = (char)((s->cur_file_info.dosDate>>8)&0xff);\n  else pfile_in_zip_read_info->crcenctest = (char)(s->cur_file_info.crc >> 24);\n  pfile_in_zip_read_info->encheadleft = (pfile_in_zip_read_info->encrypted?12:0);\n  pfile_in_zip_read_info->keys[0] = 305419896L;\n  pfile_in_zip_read_info->keys[1] = 591751049L;\n  pfile_in_zip_read_info->keys[2] = 878082192L;\n  for (const char *cp=password; cp!=0 && *cp!=0; cp++) Uupdate_keys(pfile_in_zip_read_info->keys,*cp);\n\n\tpfile_in_zip_read_info->pos_in_zipfile =\n            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +\n\t\t\t  iSizeVar;\n\n\tpfile_in_zip_read_info->stream.avail_in = (uInt)0;\n\n\ts->pfile_in_zip_read = pfile_in_zip_read_info;\n\n  return UNZ_OK;\n}\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 (and also sets *reached_eof)\n//  return 0 if the end of file was reached. (and also sets *reached_eof).\n//  return <0 with error code if there is an error. (in which case *reached_eof is meaningless)\n//    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\nint unzReadCurrentFile  (unzFile file, voidp buf, unsigned len, bool *reached_eof)\n{ int err=UNZ_OK;\n  uInt iRead = 0;\n  if (reached_eof!=0) *reached_eof=false;\n\n  unz_s *s = (unz_s*)file;\n  if (s==NULL) 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) return UNZ_PARAMERROR;\n  if ((pfile_in_zip_read_info->read_buffer == NULL)) return UNZ_END_OF_LIST_OF_FILE;\n  if (len==0) 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 = (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) && (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) uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;\n      if (uReadThis == 0) {if (reached_eof!=0) *reached_eof=true; return UNZ_EOF;}\n      if (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) return UNZ_ERRNO;\n      if (lufread(pfile_in_zip_read_info->read_buffer,uReadThis,1,pfile_in_zip_read_info->file)!=1) 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 = (Byte*)pfile_in_zip_read_info->read_buffer;\n      pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;\n      //\n      if (pfile_in_zip_read_info->encrypted)\n      { char *buf = (char*)pfile_in_zip_read_info->stream.next_in;\n        for (unsigned int i=0; i<uReadThis; i++) buf[i]=zdecode(pfile_in_zip_read_info->keys,buf[i]);\n      }\n    }\n\n    unsigned int uDoEncHead = pfile_in_zip_read_info->encheadleft;\n    if (uDoEncHead>pfile_in_zip_read_info->stream.avail_in) uDoEncHead=pfile_in_zip_read_info->stream.avail_in;\n    if (uDoEncHead>0)\n    { char bufcrc=pfile_in_zip_read_info->stream.next_in[uDoEncHead-1];\n      pfile_in_zip_read_info->rest_read_uncompressed-=uDoEncHead;\n      pfile_in_zip_read_info->stream.avail_in -= uDoEncHead;\n      pfile_in_zip_read_info->stream.next_in += uDoEncHead;\n      pfile_in_zip_read_info->encheadleft -= uDoEncHead;\n      if (pfile_in_zip_read_info->encheadleft==0)\n      { if (bufcrc!=pfile_in_zip_read_info->crcenctest) return UNZ_PASSWORD;\n      }\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 < pfile_in_zip_read_info->stream.avail_in)\n      { uDoCopy = pfile_in_zip_read_info->stream.avail_out ;\n      }\n      else\n      { uDoCopy = pfile_in_zip_read_info->stream.avail_in ;\n      }\n      for (i=0;i<uDoCopy;i++) *(pfile_in_zip_read_info->stream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i);\n      pfile_in_zip_read_info->crc32 = ucrc32(pfile_in_zip_read_info->crc32,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      if (pfile_in_zip_read_info->rest_read_uncompressed==0) {if (reached_eof!=0) *reached_eof=true;}\n    }\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      //\n      err=inflate(&pfile_in_zip_read_info->stream,flush);\n      //\n      uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;\n      uOutThis = uTotalOutAfter-uTotalOutBefore;\n      pfile_in_zip_read_info->crc32 = 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 || pfile_in_zip_read_info->rest_read_uncompressed==0)\n      { if (reached_eof!=0) *reached_eof=true;\n        return iRead;\n      }\n      if (err!=Z_OK) break;\n    }\n  }\n\n  if (err==Z_OK) return iRead;\n  return err;\n}\n\n\n//  Give the current position in uncompressed data\nz_off_t unztell (unzFile file)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\treturn (z_off_t)pfile_in_zip_read_info->stream.total_out;\n}\n\n\n//  return 1 if the end of file was reached, 0 elsewhere\nint unzeof (unzFile file)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\tif (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\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 buf.\n//  the return value is the number of bytes copied in buf, or (if <0) the error code\nint unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len)\n{\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tuInt read_now;\n\tuLong size_to_read;\n\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\tsize_to_read = (pfile_in_zip_read_info->size_local_extrafield -\n\t\t\t\tpfile_in_zip_read_info->pos_local_extrafield);\n\n\tif (buf==NULL)\n\t\treturn (int)size_to_read;\n\n\tif (len>size_to_read)\n\t\tread_now = (uInt)size_to_read;\n\telse\n\t\tread_now = (uInt)len ;\n\n\tif (read_now==0)\n\t\treturn 0;\n\n\tif (lufseek(pfile_in_zip_read_info->file, pfile_in_zip_read_info->offset_local_extrafield +  pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)\n\t\treturn UNZ_ERRNO;\n\n\tif (lufread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)\n\t\treturn UNZ_ERRNO;\n\n\treturn (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{\n\tint err=UNZ_OK;\n\n\tunz_s* s;\n\tfile_in_zip_read_info_s* pfile_in_zip_read_info;\n\tif (file==NULL)\n\t\treturn UNZ_PARAMERROR;\n\ts=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n\tif (pfile_in_zip_read_info==NULL)\n\t\treturn UNZ_PARAMERROR;\n\n\n\tif (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n\t{\n\t\tif (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)\n\t\t\terr=UNZ_CRCERROR;\n\t}\n\n\n\tif (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\tpfile_in_zip_read_info->read_buffer = NULL;\n\tif (pfile_in_zip_read_info->stream_initialised)\n\t\tinflateEnd(&pfile_in_zip_read_info->stream);\n\n\tpfile_in_zip_read_info->stream_initialised = 0;\n        if (pfile_in_zip_read_info!=0) zfree(pfile_in_zip_read_info); // unused pfile_in_zip_read_info=0;\n\n    s->pfile_in_zip_read=NULL;\n\n\treturn err;\n}\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, uLong uSizeBuf)\n{ //int err=UNZ_OK;\n  unz_s* s;\n  uLong uReadThis ;\n  if (file==NULL) return UNZ_PARAMERROR;\n  s=(unz_s*)file;\n  uReadThis = uSizeBuf;\n  if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment;\n  if (lufseek(s->file,s->central_pos+22,SEEK_SET)!=0) return UNZ_ERRNO;\n  if (uReadThis>0)\n  { *szComment='\\0';\n    if (lufread(szComment,(uInt)uReadThis,1,s->file)!=1) return UNZ_ERRNO;\n  }\n  if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\\0';\n  return (int)uReadThis;\n}\n\n\n\n\n\nint unzOpenCurrentFile (unzFile file, const char *password);\nint unzReadCurrentFile (unzFile file, void *buf, unsigned len);\nint unzCloseCurrentFile (unzFile file);\n\n\ntypedef unsigned __int32 lutime_t;       // define it ourselves since we don't include time.h\n\nFILETIME timet2filetime(const lutime_t t)\n{ LONGLONG i = Int32x32To64(t,10000000) + 116444736000000000;\n  FILETIME ft;\n  ft.dwLowDateTime = (DWORD) i;\n  ft.dwHighDateTime = (DWORD)(i >>32);\n  return ft;\n}\n\nFILETIME dosdatetime2filetime(WORD dosdate,WORD dostime)\n{ // date: bits 0-4 are day of month 1-31. Bits 5-8 are month 1..12. Bits 9-15 are year-1980\n  // time: bits 0-4 are seconds/2, bits 5-10 are minute 0..59. Bits 11-15 are hour 0..23\n  SYSTEMTIME st;\n  st.wYear = (WORD)(((dosdate>>9)&0x7f) + 1980);\n  st.wMonth = (WORD)((dosdate>>5)&0xf);\n  st.wDay = (WORD)(dosdate&0x1f);\n  st.wHour = (WORD)((dostime>>11)&0x1f);\n  st.wMinute = (WORD)((dostime>>5)&0x3f);\n  st.wSecond = (WORD)((dostime&0x1f)*2);\n  st.wMilliseconds = 0;\n  FILETIME ft; SystemTimeToFileTime(&st,&ft);\n  return ft;\n}\n\n\n\nclass TUnzip\n{ public:\n  TUnzip(const char *pwd) : uf(0), unzbuf(0), currentfile(-1), czei(-1), password(0) {if (pwd!=0) {password=new char[strlen(pwd)+1]; strcpy_s(password,MAX_PATH,pwd);}}\n  ~TUnzip() {if (password!=0) delete[] password; password=0; if (unzbuf!=0) delete[] unzbuf; unzbuf=0;}\n\n  unzFile uf; int currentfile; ZIPENTRY cze; int czei;\n  char *password;\n  char *unzbuf;            // lazily created and destroyed, used by Unzip\n  TCHAR rootdir[MAX_PATH]; // includes a trailing slash\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 SetUnzipBaseDir(const TCHAR *dir);\n  ZRESULT Close();\n};\n\n\nZRESULT TUnzip::Open(void *z,unsigned int len,DWORD flags)\n{ if (uf!=0 || currentfile!=-1) return ZR_NOTINITED;\n  //\n#ifdef GetCurrentDirectory\n  GetCurrentDirectory(MAX_PATH,rootdir);\n#else\n  _tcscpy(rootdir,_T(\"\\\\\"));\n#endif\n  TCHAR lastchar = rootdir[_tcslen(rootdir)-1];\n  if (lastchar!='\\\\' && lastchar!='/') _tcscat_s(rootdir,_T(\"\\\\\"));\n  //\n  if (flags==ZIP_HANDLE)\n  { // test if we can seek on it. We can't use GetFileType(h)==FILE_TYPE_DISK since it's not on CE.\n    DWORD res = SetFilePointer(z,0,0,FILE_CURRENT);\n    bool canseek = (res!=0xFFFFFFFF);\n    if (!canseek) return ZR_SEEK;\n  }\n  ZRESULT e; LUFILE *f = lufopen(z,len,flags,&e);\n  if (f==NULL) return e;\n  uf = unzOpenInternal(f);\n  if (uf==0) return ZR_NOFILE;\n  return ZR_OK;\n}\n\nZRESULT TUnzip::SetUnzipBaseDir(const TCHAR *dir)\n{\n  _tcscpy_s(rootdir, MAX_PATH, dir);\n  TCHAR lastchar = rootdir[_tcslen(rootdir)-1];\n  if (lastchar!='\\\\' && lastchar!='/') _tcscat_s(rootdir,_T(\"\\\\\"));\n  return ZR_OK;\n}\n\nZRESULT TUnzip::Get(int index,ZIPENTRY *ze)\n{ if (index<-1 || index>=(int)uf->gi.number_entry) return ZR_ARGS;\n  if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1;\n  if (index==czei && index!=-1) {memcpy(ze,&cze,sizeof(ZIPENTRY)); return ZR_OK;}\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; ze->atime.dwHighDateTime=0;\n    ze->ctime.dwLowDateTime=0; ze->ctime.dwHighDateTime=0;\n    ze->mtime.dwLowDateTime=0; 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) unzGoToFirstFile(uf);\n  while ((int)uf->num_file<index) unzGoToNextFile(uf);\n  unz_file_info ufi; char fn[MAX_PATH];\n  unzGetCurrentFileInfo(uf,&ufi,fn,MAX_PATH,NULL,0,NULL,0);\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; unsigned long offset;\n  int res = unzlocal_CheckCurrentFileCoherencyHeader(uf,&iSizeVar,&offset,&extralen);\n  if (res!=UNZ_OK) return ZR_CORRUPT;\n  if (lufseek(uf->file,offset,SEEK_SET)!=0) return ZR_READ;\n  unsigned char *extra = new unsigned char[extralen];\n  if (lufread(extra,1,(uInt)extralen,uf->file)!=extralen) {delete[] extra; return ZR_READ;}\n  //\n  ze->index=uf->num_file;\n  TCHAR tfn[MAX_PATH];\n#ifdef UNICODE\n  MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH);\n#else\n  strcpy(tfn,fn);\n#endif\n  // As a safety feature: if the zip filename had sneaky stuff\n  // like \"c:\\windows\\file.txt\" or \"\\windows\\file.txt\" or \"fred\\..\\..\\..\\windows\\file.txt\"\n  // then we get rid of them all. That way, when the programmer does UnzipItem(hz,i,ze.name),\n  // it won't be a problem. (If the programmer really did want to get the full evil information,\n  // then they can edit out this security feature from here).\n  // In particular, we chop off any prefixes that are \"c:\\\" or \"\\\" or \"/\" or \"[stuff]\\..\" or \"[stuff]/..\"\n  const TCHAR *sfn=tfn;\n  for (;;)\n  { if (sfn[0]!=0 && sfn[1]==':') {sfn+=2; continue;}\n    if (sfn[0]=='\\\\') {sfn++; continue;}\n    if (sfn[0]=='/') {sfn++; continue;}\n    const TCHAR *c;\n    c=_tcsstr(sfn,_T(\"\\\\..\\\\\")); if (c!=0) {sfn=c+4; continue;}\n    c=_tcsstr(sfn,_T(\"\\\\../\")); if (c!=0) {sfn=c+4; continue;}\n    c=_tcsstr(sfn,_T(\"/../\")); if (c!=0) {sfn=c+4; continue;}\n    c=_tcsstr(sfn,_T(\"/..\\\\\")); if (c!=0) {sfn=c+4; continue;}\n    break;\n  }\n  _tcscpy_s(ze->name, MAX_PATH, sfn);\n\n\n  // zip has an 'attribute' 32bit value. Its lower half is windows stuff\n  // its upper half is standard unix stat.st_mode. We'll start trying\n  // to read it in unix mode\n  unsigned long a = ufi.external_fa;\n  bool isdir  =   (a&0x40000000)!=0;\n  bool readonly=  (a&0x00800000)==0;\n  //bool readable=  (a&0x01000000)!=0; // unused\n  //bool executable=(a&0x00400000)!=0; // unused\n  bool hidden=false, system=false, archive=true;\n  // but in normal hostmodes these are overridden by the lower half...\n  int host = ufi.version>>8;\n  if (host==0 || host==7 || host==11 || host==14)\n  { readonly=  (a&0x00000001)!=0;\n    hidden=    (a&0x00000002)!=0;\n    system=    (a&0x00000004)!=0;\n    isdir=     (a&0x00000010)!=0;\n    archive=   (a&0x00000020)!=0;\n  }\n  ze->attr=0;\n  if (isdir) ze->attr |= FILE_ATTRIBUTE_DIRECTORY;\n  if (archive) ze->attr|=FILE_ATTRIBUTE_ARCHIVE;\n  if (hidden) ze->attr|=FILE_ATTRIBUTE_HIDDEN;\n  if (readonly) ze->attr|=FILE_ATTRIBUTE_READONLY;\n  if (system) 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 ftd = dosdatetime2filetime(dosdate,dostime);\n  FILETIME ft; LocalFileTimeToFileTime(&ftd,&ft);\n  ze->atime=ft; ze->ctime=ft; 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]; etype[0]=extra[epos+0]; etype[1]=extra[epos+1]; etype[2]=0;\n    int size = extra[epos+2];\n    if (strcmp(etype,\"UT\")!=0) {epos += 4+size; continue;}\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    { lutime_t mtime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);\n\t  epos+=4;\n      ze->mtime = timet2filetime(mtime);\n    }\n    if (hasatime)\n    { lutime_t atime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);\n      epos+=4;\n      ze->atime = timet2filetime(atime);\n    }\n    if (hasctime)\n    { lutime_t ctime = ((extra[epos+0])<<0) | ((extra[epos+1])<<8) |((extra[epos+2])<<16) | ((extra[epos+3])<<24);\n      epos+=4;\n      ze->ctime = timet2filetime(ctime);\n    }\n    break;\n  }\n  //\n  if (extra!=0) delete[] extra;\n  memcpy(&cze,ze,sizeof(ZIPENTRY)); czei=index;\n  return ZR_OK;\n}\n\nZRESULT TUnzip::Find(const TCHAR *tname,bool ic,int *index,ZIPENTRY *ze)\n{ char name[MAX_PATH];\n#ifdef UNICODE\n  WideCharToMultiByte(CP_UTF8,0,tname,-1,name,MAX_PATH,0,0);\n#else\n  strcpy(name,tname);\n#endif\n  int res = unzLocateFile(uf,name,ic?CASE_INSENSITIVE:CASE_SENSITIVE);\n  if (res!=UNZ_OK)\n  { if (index!=0) *index=-1;\n    if (ze!=NULL) {ZeroMemory(ze,sizeof(ZIPENTRY)); ze->index=-1;}\n    return ZR_NOTFOUND;\n  }\n  if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1;\n  int i = (int)uf->num_file;\n  if (index!=NULL) *index=i;\n  if (ze!=NULL)\n  { ZRESULT zres = Get(i,ze);\n    if (zres!=ZR_OK) return zres;\n  }\n  return ZR_OK;\n}\n\nvoid EnsureDirectory(const TCHAR *rootdir, const TCHAR *dir)\n{ if (rootdir!=0 && GetFileAttributes(rootdir)==0xFFFFFFFF) CreateDirectory(rootdir,0);\n  if (*dir==0) return;\n  const TCHAR *lastslash=dir, *c=lastslash;\n  while (*c!=0) {if (*c=='/' || *c=='\\\\') lastslash=c; c++;}\n  const TCHAR *name=lastslash;\n  if (lastslash!=dir)\n  { TCHAR tmp[MAX_PATH]; memcpy(tmp,dir,sizeof(TCHAR)*(lastslash-dir));\n    tmp[lastslash-dir]=0;\n    EnsureDirectory(rootdir,tmp);\n    name++;\n  }\n  TCHAR cd[MAX_PATH]; *cd=0; if (rootdir!=0) _tcscpy_s(cd, MAX_PATH, rootdir); _tcscat_s(cd,dir);\n  if (GetFileAttributes(cd)==0xFFFFFFFF) CreateDirectory(cd,NULL);\n}\n\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) return ZR_ARGS;\n  if (flags==ZIP_MEMORY)\n  { if (index!=currentfile)\n    { if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1;\n      if (index>=(int)uf->gi.number_entry) return ZR_ARGS;\n      if (index<(int)uf->num_file) unzGoToFirstFile(uf);\n      while ((int)uf->num_file<index) unzGoToNextFile(uf);\n      unzOpenCurrentFile(uf,password); currentfile=index;\n    }\n    bool reached_eof;\n    int res = unzReadCurrentFile(uf,dst,len,&reached_eof);\n    if (res<=0) {unzCloseCurrentFile(uf); currentfile=-1;}\n    if (reached_eof) return ZR_OK;\n    if (res>0) return ZR_MORE;\n    if (res==UNZ_PASSWORD) return ZR_PASSWORD;\n    return ZR_FLATE;\n  }\n  // otherwise we're writing to a handle or a file\n  if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1;\n  if (index>=(int)uf->gi.number_entry) return ZR_ARGS;\n  if (index<(int)uf->num_file) unzGoToFirstFile(uf);\n  while ((int)uf->num_file<index) unzGoToNextFile(uf);\n  ZIPENTRY ze; Get(index,&ze);\n  // zipentry=directory is handled specially\n  if ((ze.attr&FILE_ATTRIBUTE_DIRECTORY)!=0)\n  { if (flags==ZIP_HANDLE) return ZR_OK; // don't do anything\n    const TCHAR *dir = (const TCHAR*)dst;\n    bool isabsolute = (dir[0]=='/' || dir[0]=='\\\\' || (dir[0]!=0 && dir[1]==':'));\n    if (isabsolute) EnsureDirectory(0,dir); else EnsureDirectory(rootdir,dir);\n    return ZR_OK;\n  }\n  // otherwise, we write the zipentry to a file/handle\n  HANDLE h;\n  if (flags==ZIP_HANDLE) h=dst;\n  else\n  { const TCHAR *ufn = (const TCHAR*)dst;\n    // We'll qualify all relative names to our root dir, and leave absolute names as they are\n    // ufn=\"zipfile.txt\"  dir=\"\"  name=\"zipfile.txt\"  fn=\"c:\\\\currentdir\\\\zipfile.txt\"\n    // ufn=\"dir1/dir2/subfile.txt\"  dir=\"dir1/dir2/\"  name=\"subfile.txt\"  fn=\"c:\\\\currentdir\\\\dir1/dir2/subfiles.txt\"\n    // ufn=\"\\z\\file.txt\"  dir=\"\\z\\\"  name=\"file.txt\"  fn=\"\\z\\file.txt\"\n    // This might be a security risk, in the case where we just use the zipentry's name as \"ufn\", where\n    // a malicious zip could unzip itself into c:\\windows. Our solution is that GetZipItem (which\n    // is how the user retrieve's the file's name within the zip) never returns absolute paths.\n    const TCHAR *name=ufn; const TCHAR *c=name; while (*c!=0) {if (*c=='/' || *c=='\\\\') name=c+1; c++;}\n    TCHAR dir[MAX_PATH]; _tcscpy_s(dir, MAX_PATH, ufn); if (name==ufn) *dir=0; else dir[name-ufn]=0;\n    TCHAR fn[MAX_PATH];\n    bool isabsolute = (dir[0]=='/' || dir[0]=='\\\\' || (dir[0]!=0 && dir[1]==':'));\n    if (isabsolute) {wsprintf(fn,_T(\"%s%s\"),dir,name); EnsureDirectory(0,dir);}\n    else {wsprintf(fn,_T(\"%s%s%s\"),rootdir,dir,name); EnsureDirectory(rootdir,dir);}\n    //\n    h = CreateFile(fn,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,ze.attr,NULL);\n  }\n  if (h==INVALID_HANDLE_VALUE) return ZR_NOFILE;\n  unzOpenCurrentFile(uf,password);\n  if (unzbuf==0) unzbuf=new char[16384]; DWORD haderr=0;\n  //\n\n  for (; haderr==0;)\n  { bool reached_eof;\n    int res = unzReadCurrentFile(uf,unzbuf,16384,&reached_eof);\n    if (res==UNZ_PASSWORD) {haderr=ZR_PASSWORD; break;}\n    if (res<0) {haderr=ZR_FLATE; break;}\n    if (res>0) {DWORD writ; BOOL bres=WriteFile(h,unzbuf,res,&writ,NULL); if (!bres) {haderr=ZR_WRITE; break;}}\n    if (reached_eof) break;\n    if (res==0) {haderr=ZR_FLATE; break;}\n  }\n  if (!haderr) SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); // may fail if it was a pipe\n  if (flags!=ZIP_HANDLE) CloseHandle(h);\n  unzCloseCurrentFile(uf);\n  if (haderr!=0) return haderr;\n  return ZR_OK;\n}\n\nZRESULT TUnzip::Close()\n{ if (currentfile!=-1) unzCloseCurrentFile(uf); currentfile=-1;\n  if (uf!=0) unzClose(uf); uf=0;\n  return ZR_OK;\n}\n\n\n\n\n\nZRESULT lasterrorU=ZR_OK;\n\nunsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len)\n{ if (code==ZR_RECENT) code=lasterrorU;\n  const TCHAR *msg=_T(\"unknown zip result code\");\n  switch (code)\n  { case ZR_OK: msg=_T(\"Success\"); break;\n    case ZR_NODUPH: msg=_T(\"Culdn't duplicate handle\"); break;\n    case ZR_NOFILE: msg=_T(\"Couldn't create/open file\"); break;\n    case ZR_NOALLOC: msg=_T(\"Failed to allocate memory\"); break;\n    case ZR_WRITE: msg=_T(\"Error writing to file\"); break;\n    case ZR_NOTFOUND: msg=_T(\"File not found in the zipfile\"); break;\n    case ZR_MORE: msg=_T(\"Still more data to unzip\"); break;\n    case ZR_CORRUPT: msg=_T(\"Zipfile is corrupt or not a zipfile\"); break;\n    case ZR_READ: msg=_T(\"Error reading file\"); break;\n    case ZR_PASSWORD: msg=_T(\"Correct password required\"); break;\n    case ZR_ARGS: msg=_T(\"Caller: faulty arguments\"); break;\n    case ZR_PARTIALUNZ: msg=_T(\"Caller: the file had already been partially unzipped\"); break;\n    case ZR_NOTMMAP: msg=_T(\"Caller: can only get memory of a memory zipfile\"); break;\n    case ZR_MEMSIZE: msg=_T(\"Caller: not enough space allocated for memory zipfile\"); break;\n    case ZR_FAILED: msg=_T(\"Caller: there was a previous error\"); break;\n    case ZR_ENDED: msg=_T(\"Caller: additions to the zip have already been ended\"); break;\n    case ZR_ZMODE: msg=_T(\"Caller: mixing creation and opening of zip\"); break;\n    case ZR_NOTINITED: msg=_T(\"Zip-bug: internal initialisation not completed\"); break;\n    case ZR_SEEK: msg=_T(\"Zip-bug: trying to seek the unseekable\"); break;\n    case ZR_MISSIZE: msg=_T(\"Zip-bug: the anticipated size turned out wrong\"); break;\n    case ZR_NOCHANGE: msg=_T(\"Zip-bug: tried to change mind, but not allowed\"); break;\n    case ZR_FLATE: msg=_T(\"Zip-bug: an internal error during flation\"); break;\n  }\n  unsigned int mlen=(unsigned int)_tcslen(msg);\n  if (buf==0 || len==0) return mlen;\n  unsigned int n=mlen; if (n+1>len) n=len-1;\n  _tcsncpy_s(buf,MAX_PATH,msg,n); buf[n]=0;\n  return mlen;\n}\n\n\ntypedef struct\n{ DWORD flag;\n  TUnzip *unz;\n} TUnzipHandleData;\n\nHZIP OpenZipInternal(void *z,unsigned int len,DWORD flags, const char *password)\n{ TUnzip *unz = new TUnzip(password);\n  lasterrorU = unz->Open(z,len,flags);\n  if (lasterrorU!=ZR_OK) {delete unz; return 0;}\n  TUnzipHandleData *han = new TUnzipHandleData;\n  han->flag=1; han->unz=unz; return (HZIP)han;\n}\nHZIP OpenZipHandle(HANDLE h, const char *password) {return OpenZipInternal((void*)h,0,ZIP_HANDLE,password);}\nHZIP OpenZip(const TCHAR *fn, const char *password) {return OpenZipInternal((void*)fn,0,ZIP_FILENAME,password);}\nHZIP OpenZip(void *z,unsigned int len, const char *password) {return OpenZipInternal(z,len,ZIP_MEMORY,password);}\n\n\nZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *ze)\n{ ze->index=0; *ze->name=0; ze->unc_size=0;\n  if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;}\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;}\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Get(index,ze);\n  return lasterrorU;\n}\n\nZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze)\n{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;}\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;}\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Find(name,ic,index,ze);\n  return lasterrorU;\n}\n\nZRESULT UnzipItemInternal(HZIP hz, int index, void *dst, unsigned int len, DWORD flags)\n{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;}\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;}\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->Unzip(index,dst,len,flags);\n  return lasterrorU;\n}\nZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h) {return UnzipItemInternal(hz,index,(void*)h,0,ZIP_HANDLE);}\nZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn) {return UnzipItemInternal(hz,index,(void*)fn,0,ZIP_FILENAME);}\nZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len) {return UnzipItemInternal(hz,index,z,len,ZIP_MEMORY);}\n\nZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir)\n{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;}\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;}\n  TUnzip *unz = han->unz;\n  lasterrorU = unz->SetUnzipBaseDir(dir);\n  return lasterrorU;\n}\n\n\nZRESULT CloseZipU(HZIP hz)\n{ if (hz==0) {lasterrorU=ZR_ARGS;return ZR_ARGS;}\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  if (han->flag!=1) {lasterrorU=ZR_ZMODE;return ZR_ZMODE;}\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) return false;\n  TUnzipHandleData *han = (TUnzipHandleData*)hz;\n  return (han->flag==1);\n}"
  },
  {
    "path": "src/Setup/unzip.h",
    "content": "#ifndef _unzip_H\n#define _unzip_H\n\n// UNZIPPING functions -- for unzipping.\n// This file is a repackaged form of extracts from the zlib code available\n// at www.gzip.org/zlib, by Jean-Loup Gailly and Mark Adler. The original\n// copyright notice may be found in unzip.cpp. The repackaging was done\n// by Lucian Wischik to simplify and extend its use in Windows/C++. Also\n// encryption and unicode filenames have been added.\n\n\n#ifndef _zip_H\nDECLARE_HANDLE(HZIP);\n#endif\n// An HZIP identifies a zip file that has been opened\n\ntypedef DWORD ZRESULT;\n// return codes from any of the zip functions. Listed later.\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} ZIPENTRY;\n\n\nHZIP OpenZip(const TCHAR *fn, const char *password);\nHZIP OpenZip(void *z,unsigned int len, const char *password);\nHZIP OpenZipHandle(HANDLE h, const char *password);\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:             OpenZipHandle(hpipe_read,0);\n// from a file (by handle): OpenZipHandle(hfile,0);\n// from a file (by name):   OpenZip(\"c:\\\\test.zip\",\"password\");\n// from a memory block:     OpenZip(bufstart, buflen,0);\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 in any other way, then full random access is possible.\n// Note: pipe input is not yet implemented.\n// Note: zip passwords are ascii, not unicode.\n// Note: for windows-ce, you cannot close the handle until after CloseZip.\n// but for real windows, the zip makes its own copy of your handle, so you\n// can close yours anytime.\n\nZRESULT GetZipItem(HZIP hz, int index, ZIPENTRY *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\nZRESULT FindZipItem(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *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\nZRESULT UnzipItem(HZIP hz, int index, const TCHAR *fn);\nZRESULT UnzipItem(HZIP hz, int index, void *z,unsigned int len);\nZRESULT UnzipItemHandle(HZIP hz, int index, HANDLE h);\n// UnzipItem - given an index to an item, unzips it. You can unzip to:\n// to a pipe:             UnzipItemHandle(hz,i, hpipe_write);\n// to a file (by handle): UnzipItemHandle(hz,i, hfile);\n// to a file (by name):   UnzipItem(hz,i, ze.name);\n// to a memory block:     UnzipItem(hz,i, buf,buflen);\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.\nZRESULT SetUnzipBaseDir(HZIP hz, const TCHAR *dir);\n// if unzipping to a filename, and it's a relative filename, then it will be relative to here.\n// (defaults to current-directory).\n\n\nZRESULT CloseZip(HZIP hz);\n// CloseZip - the zip handle must be closed with this function.\n\nunsigned int FormatZipMessage(ZRESULT code, TCHAR *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#define ZR_PASSWORD   0x00001000     // we didn't get the right password to unzip 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);\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);\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, 0);\n//   - unzip to a membuffer -\n// ZIPENTRY ze; int i; FindZipItem(hz,\"file.dat\",true,&i,&ze);\n// char *ibuf = new char[ze.unc_size];\n// UnzipItem(hz,i, ibuf, ze.unc_size);\n// delete[] ibuf;\n//   - unzip to a fixed membuff -\n// ZIPENTRY ze; int i; FindZipItem(hz,\"file.dat\",true,&i,&ze);\n// char ibuf[1024]; ZRESULT zr=ZR_MORE; unsigned long totsize=0;\n// while (zr==ZR_MORE)\n// { zr = UnzipItem(hz,i, ibuf,1024);\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 hwrite; HANDLE hthread=CreateWavReaderThread(&hwrite);\n// int i; ZIPENTRY ze; FindZipItem(hz,\"sound.wav\",true,&i,&ze);\n// UnzipItemHandle(hz,i, hwrite);\n// CloseHandle(hwrite);\n// WaitForSingleObject(hthread,INFINITE);\n// CloseHandle(hwrite); 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,0,0);\n// CreateZipWriterThread(hwrite);\n// HZIP hz = OpenZipHandle(hread,0);\n// for (int i=0; ; i++)\n// { ZIPENTRY ze;\n//   ZRESULT zr=GetZipItem(hz,i,&ze); if (zr!=ZR_OK) break; // no more\n//   UnzipItem(hz,i, ze.name);\n// }\n// CloseZip(hz);\n//\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.\nZRESULT CloseZipU(HZIP hz);\nunsigned int FormatZipMessageU(ZRESULT code, TCHAR *buf,unsigned int len);\nbool IsZipHandleU(HZIP hz);\n#ifdef _zip_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\n#endif // _unzip_H\n"
  },
  {
    "path": "src/Setup/winmain.cpp",
    "content": "// Setup.cpp : Defines the entry point for the application.\n//\n\n#include \"stdafx.h\"\n#include \"Setup.h\"\n#include \"FxHelper.h\"\n#include \"UpdateRunner.h\"\n#include \"MachineInstaller.h\"\n#include <cstdio>\n#include <string>\n\nCAppModule* _Module;\n\ntypedef BOOL(WINAPI *SetDefaultDllDirectoriesFunction)(DWORD DirectoryFlags);\n\n// Some libraries are still loaded from the current directories.\n// If we pre-load them with an absolute path then we are good.\nstatic void PreloadLibs()\n{\n\twchar_t sys32Folder[MAX_PATH];\n\tGetSystemDirectory(sys32Folder, MAX_PATH);\n\n\tstd::wstring version = (std::wstring(sys32Folder) + L\"\\\\version.dll\");\n\tstd::wstring logoncli = (std::wstring(sys32Folder) + L\"\\\\logoncli.dll\");\n\tstd::wstring sspicli = (std::wstring(sys32Folder) + L\"\\\\sspicli.dll\");\n\tstd::wstring urlmon = (std::wstring(sys32Folder) + L\"\\\\urlmon.dll\");\n\n\tLoadLibrary(version.c_str());\n\tLoadLibrary(logoncli.c_str());\n\tLoadLibrary(sspicli.c_str());\n\tLoadLibrary(urlmon.c_str());\n}\n\nstatic void MitigateDllHijacking()\n{\n\t// Set the default DLL lookup directory to System32 for ourselves and kernel32.dll\n\tHMODULE hKernel32 = LoadLibrary(L\"kernel32.dll\");\n\tif (hKernel32)\n\t{\n\t\tSetDefaultDllDirectoriesFunction pfn = (SetDefaultDllDirectoriesFunction)GetProcAddress(hKernel32, \"SetDefaultDllDirectories\");\n\t\tif (pfn)\n\t\t{\n\t\t\t(*pfn)(LOAD_LIBRARY_SEARCH_SYSTEM32);\n\t\t}\n\t}\n\n\tPreloadLibs();\n}\n\nint APIENTRY wWinMain(_In_ HINSTANCE hInstance,\n                      _In_opt_ HINSTANCE hPrevInstance,\n                      _In_ LPWSTR lpCmdLine,\n                      _In_ int nCmdShow)\n{\n\tMitigateDllHijacking();\n\n\tint exitCode = -1;\n\tCString cmdLine(lpCmdLine);\n\n\tif (cmdLine.Find(L\"--checkInstall\") >= 0) {\n\t\t// If we're already installed, exit as fast as possible\n\t\tif (!MachineInstaller::ShouldSilentInstall()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Make sure update.exe gets silent\n\t\twcscat(lpCmdLine, L\" --silent\");\n\t}\n\n\tHRESULT hr = ::CoInitialize(NULL);\n\tATLASSERT(SUCCEEDED(hr));\n\n\tAtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);\n\t_Module = new CAppModule();\n\thr = _Module->Init(NULL, hInstance);\n\n\tbool isQuiet = (cmdLine.Find(L\"-s\") >= 0);\n\tbool weAreUACElevated = CUpdateRunner::AreWeUACElevated() == S_OK;\n\tbool attemptingToRerun = (cmdLine.Find(L\"--rerunningWithoutUAC\") >= 0);\n\n\tif (weAreUACElevated && attemptingToRerun) {\n\t\tCUpdateRunner::DisplayErrorMessage(CString(L\"Please re-run this installer as a normal user instead of \\\"Run as Administrator\\\".\"), NULL);\n\t\texitCode = E_FAIL;\n\t\tgoto out;\n\t}\n\n\tif (!CFxHelper::CanInstallDotNet4_5()) {\n\t\t// Explain this as nicely as possible and give up.\n\t\tMessageBox(0L, L\"This program cannot run on Windows XP or before; it requires a later version of Windows.\", L\"Incompatible Operating System\", 0);\n\t\texitCode = E_FAIL;\n\t\tgoto out;\n\t}\n\n\tNetVersion requiredVersion = CFxHelper::GetRequiredDotNetVersion();\n\n\tif (!CFxHelper::IsDotNetInstalled(requiredVersion)) {\n\t\thr = CFxHelper::InstallDotNetFramework(requiredVersion, isQuiet);\n\t\tif (FAILED(hr)) {\n\t\t\texitCode = hr; // #yolo\n\t\t\tCUpdateRunner::DisplayErrorMessage(CString(L\"Failed to install the .NET Framework, try installing the latest version manually\"), NULL);\n\t\t\tgoto out;\n\t\t}\n\t\n\t\t// S_FALSE isn't failure, but we still shouldn't try to install\n\t\tif (hr != S_OK) {\n\t\t\texitCode = 0;\n\t\t\tgoto out;\n\t\t}\n\t}\n\n\t// If we're UAC-elevated, we shouldn't be because it will give us permissions\n\t// problems later. Just silently rerun ourselves.\n\t// (Skip this check in Wine, which always reports admin privileges)\n\tif (weAreUACElevated && CUpdateRunner::AreWeInWine() != S_OK) {\n\t\twchar_t buf[4096];\n\t\tHMODULE hMod = GetModuleHandle(NULL);\n\t\tGetModuleFileNameW(hMod, buf, 4096);\n\t\twcscat(lpCmdLine, L\" --rerunningWithoutUAC\");\n\n\t\tCUpdateRunner::ShellExecuteFromExplorer(buf, lpCmdLine);\n\t\texitCode = 0;\n\t\tgoto out;\n\t}\n\n\texitCode = CUpdateRunner::ExtractUpdaterAndRun(lpCmdLine, false);\n\nout:\n\t_Module->Term();\n\treturn exitCode;\n}\n"
  },
  {
    "path": "src/Setup/wtl90/atlapp.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\t0x0900\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 int SizeOf_REBARBANDINFO()\n\t{\n\t\tint nSize = sizeof(REBARBANDINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!(IsVista() && IsCommCtrl6()))\n\t\t\tnSize = REBARBANDINFO_V6_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn nSize;\n\t}\n\n#if (_WIN32_WINNT >= 0x501)\n  \tinline int SizeOf_LVGROUP()\n\t{\n\t\tint nSize = sizeof(LVGROUP);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tnSize = LVGROUP_V5_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn nSize;\n\t}\n\n\tinline int SizeOf_LVTILEINFO()\n\t{\n\t\tint nSize = sizeof(LVTILEINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tnSize = LVTILEINFO_V5_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0600)\n\t\treturn nSize;\n\t}\n#endif // (_WIN32_WINNT >= 0x501)\n\n\tinline int SizeOf_MCHITTESTINFO()\n\t{\n\t\tint nSize = 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\tnSize = MCHITTESTINFO_V1_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)\n\t\treturn nSize;\n\t}\n\n#ifndef _WIN32_WCE\n\tinline int SizeOf_NONCLIENTMETRICS()\n\t{\n\t\tint nSize = sizeof(NONCLIENTMETRICS);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)\n\t\tif(!IsVista())\n\t\t\tnSize = NONCLIENTMETRICS_V1_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (WINVER >= 0x0600)\n\t\treturn nSize;\n\t}\n\n\tinline int SizeOf_TOOLINFO()\n\t{\n\t\tint nSize = sizeof(TOOLINFO);\n#if !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501)\n\t\tif(!IsVista())\n\t\t\tnSize = TTTOOLINFO_V2_SIZE;\n#endif // !defined(_WTL_NO_RUNTIME_STRUCT_SIZE) && (_WIN32_WINNT >= 0x0501)\n\t\treturn nSize;\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\t\tWNDCLASSEX wc = { sizeof(WNDCLASSEX) };\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\t\tATOM atom = ::RegisterClassEx(&wc);\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\tLONG Unlock()\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": "src/Setup/wtl90/atlcrack.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\thWnd; \\\n\t\tuMsg; \\\n\t\twParam; \\\n\t\tlParam; \\\n\t\tlResult; \\\n\t\tbHandled; \\\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": "src/Setup/wtl90/atlctrls.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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, nMax;\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\tint nMin = 0, nMax = 0;\n\t\t::GetScrollRange(m_hWnd, SB_CTL, &nMin, &nMax);\n\t\tSCROLLINFO info = { sizeof(SCROLLINFO), SIF_PAGE };\n\t\tif(::GetScrollInfo(m_hWnd, SB_CTL, &info))\n\t\t\tnMax -= ((info.nPage - 1) > 0) ? (info.nPage - 1) : 0;\n\n\t\treturn 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\tATLASSERT(m_hImageList == NULL);\n\t\tATLASSERT(hImageList != NULL);\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 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 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 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 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 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 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#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 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 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 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 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 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\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\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\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\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": "src/Setup/wtl90/atlctrlw.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\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(wParam != VK_SPACE)\n\t\t\tbHandled = FALSE;\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(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_GETKEYBOARDCUES\n\t\tconst UINT SPI_SETKEYBOARDCUES = 0x100B;\n#endif // !SPI_GETKEYBOARDCUES\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\tfor(int i = 0; i < lstrlen(lpstrText); 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#ifndef TMSCHEMA_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 // TMSCHEMA_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": "src/Setup/wtl90/atlctrlx.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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, 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\t0x00000001\n#define PANECNT_VERTICAL\t0x00000002\n#define PANECNT_FLATBORDER\t0x00000004\n#define PANECNT_NOBORDER\t0x00000008\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\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\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->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\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\tdc.FillRect(&rc, COLOR_3DFACE);\n\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, 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, 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;\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;\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\t\tdc.FillRect(&rect, COLOR_3DFACE);\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\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, 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\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, 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": "src/Setup/wtl90/atlddx.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\tbSaveAndValidate; \\\n\t\tnCtlID;\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": "src/Setup/wtl90/atldlgs.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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(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(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, 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, (WORD)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, (WORD)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, 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, (WORD)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, (WORD)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 dwCommonButtons)\n\t{\n\t\tthis->dwCommonButtons = dwCommonButtons;\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* pButtons, UINT cButtons, int nDefaultButton = 0)\n\t{\n\t\tthis->pButtons = pButtons;\n\t\tthis->cButtons = cButtons;\n\t\tif(nDefaultButton != 0)\n\t\t\tthis->nDefaultButton = nDefaultButton;\n\t}\n\n\tvoid SetDefaultButton(int nDefaultButton)\n\t{\n\t\tthis->nDefaultButton = nDefaultButton;\n\t}\n\n\t// radio buttons\n\tvoid SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)\n\t{\n\t\tthis->pRadioButtons = pRadioButtons;\n\t\tthis->cRadioButtons = cRadioButtons;\n\t\tif(nDefaultRadioButton != 0)\n\t\t\tthis->nDefaultRadioButton = nDefaultRadioButton;\n\t}\n\n\tvoid SetDefaultRadioButton(int nDefaultRadioButton)\n\t{\n\t\tthis->nDefaultRadioButton = nDefaultRadioButton;\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 cxWidth)\n\t{\n\t\tthis->cxWidth = cxWidth;\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": "src/Setup/wtl90/atldwm.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Setup/wtl90/atlfind.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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, m_sFindNext, 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\t// We use DLLVERSIONINFO_private so we don't have to depend on shlwapi.h\n\t\t\t\t\ttypedef struct _DLLVERSIONINFO_private\n\t\t\t\t\t{\n\t\t\t\t\t\tDWORD cbSize;\n\t\t\t\t\t\tDWORD dwMajorVersion;\n\t\t\t\t\t\tDWORD dwMinorVersion;\n\t\t\t\t\t\tDWORD dwBuildNumber;\n\t\t\t\t\t\tDWORD dwPlatformID;\n\t\t\t\t\t} DLLVERSIONINFO_private;\n\n\t\t\t\t\tHMODULE hModule = ::LoadLibrary(\"comctl32.dll\");\n\t\t\t\t\tif(hModule != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\ttypedef HRESULT (CALLBACK *LPFN_DllGetVersion)(DLLVERSIONINFO_private *);\n\t\t\t\t\t\tLPFN_DllGetVersion fnDllGetVersion = (LPFN_DllGetVersion)::GetProcAddress(hModule, \"DllGetVersion\");\n\t\t\t\t\t\tif(fnDllGetVersion != NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDLLVERSIONINFO_private version = { sizeof(DLLVERSIONINFO_private) };\n\t\t\t\t\t\t\tif(SUCCEEDED(fnDllGetVersion(&version)))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif(version.dwMajorVersion >= 6)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tpThisNoConst->m_bShadowBufferNeeded = TRUE;\n\n\t\t\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\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\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::FreeLibrary(hModule);\n\t\t\t\t\t\thModule = NULL;\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": "src/Setup/wtl90/atlframe.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);\n\t\t\t\t\t\tm_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, 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(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, 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\tLPTSTR 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 || lstrlen(szBuff) == 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\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": "src/Setup/wtl90/atlgdi.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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, 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": "src/Setup/wtl90/atlmisc.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\tif(!bRet)\n\t\treturn false;\n\tTCHAR szSlash[2] = { chSlash, 0 };\n\tSecureHelper::strcat_x(lpstrOut, cchLen, szSlash);\n\tif(!bRet)\n\t\treturn false;\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": "src/Setup/wtl90/atlprint.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Setup/wtl90/atlres.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Setup/wtl90/atlresce.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Setup/wtl90/atlribbon.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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\tCopyMemory(this, &cf, sizeof CHARFORMAT2);\n\t}\n\n\t// Assign operator\n\tCharFormat& operator =(const CharFormat& cf)\n\t{\n\t\tCopyMemory(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_MaskEffect<CFM_BOLD, CFE_BOLD, UI_PKEY_FontProperties_Bold>,\n\t\t\t&CharFormat::Getk_MaskEffect<CFM_ITALIC, CFE_ITALIC, UI_PKEY_FontProperties_Italic>,\n\t\t\t&CharFormat::Getk_MaskEffect<CFM_UNDERLINE, CFE_UNDERLINE, UI_PKEY_FontProperties_Underline>,\n\t\t\t&CharFormat::Getk_MaskEffect<CFM_STRIKEOUT, CFE_STRIKEOUT, UI_PKEY_FontProperties_Strikethrough>,\n\t\t\t&CharFormat::Getk_VerticalPositioning, \n\t\t\t&CharFormat::Getk_Color<CFM_COLOR, UI_PKEY_FontProperties_ForegroundColor>, \n\t\t\t&CharFormat::Getk_Color<CFM_BACKCOLOR, UI_PKEY_FontProperties_BackgroundColor>, \n\t\t\t&CharFormat::Getk_ColorType<CFM_COLOR, CFE_AUTOCOLOR, UI_SWATCHCOLORTYPE_AUTOMATIC, UI_PKEY_FontProperties_ForegroundColorType>,\n\t\t\t&CharFormat::Getk_ColorType<CFM_BACKCOLOR, CFE_AUTOBACKCOLOR, UI_SWATCHCOLORTYPE_NOCOLOR, UI_PKEY_FontProperties_BackgroundColorType>,\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\ttemplate <DWORD t_dwMask, DWORD t_dwEffects, REFPROPERTYKEY key>\n\tvoid Getk_MaskEffect(IPropertyStore* pStore)\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 |= t_dwMask;\n\t\t\t\tdwEffects |= ((UI_FONTPROPERTIES) uValue == UI_FONTPROPERTIES_SET) ? t_dwEffects : 0;\n\t\t\t}\n\t\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\ttemplate <DWORD t_dwMask, REFPROPERTYKEY key>\n\tvoid Getk_Color(IPropertyStore* pStore)\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 |= t_dwMask;\n\n\t\t\tif (t_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\ttemplate <DWORD t_dwMask, DWORD t_dwEffects, UI_SWATCHCOLORTYPE t_type, REFPROPERTYKEY key>\n\tvoid Getk_ColorType(IPropertyStore* pStore)\n\t{\n\t\tif (SUCCEEDED(pStore->GetValue(key, &propvar)))\n\t\t{\n\t\t\tUIPropertyToUInt32(key, propvar, &uValue);\n\t\t\tif (t_type == (UI_SWATCHCOLORTYPE)uValue)\n\t\t\t{\n\t\t\t\tdwMask |= t_dwMask;\n\t\t\t\tdwEffects |= t_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 propvar;\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, &propvar);\n\t\tpStore->SetValue(key, propvar);\n\t}\n\n\tvoid PutVerticalPos(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT propvar;\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, &propvar);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_VerticalPositioning, propvar);\n\t}\n\n\tvoid PutFace(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT propvar;\n\t\tSetPropertyVal(UI_PKEY_FontProperties_Family, \n\t\t\tdwMask & CFM_FACE ? szFaceName : L\"\", &propvar);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_Family, propvar);\n\t}\n\n\tvoid PutSize(IPropertyStore* pStore)\n\t{\n\t\tPROPVARIANT propvar;\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, &propvar);\n\t\tpStore->SetValue(UI_PKEY_FontProperties_Size, propvar);\n\t}\n\n\tvoid PutColor(IPropertyStore* pStore)\n\t{\n\t\tif ((dwMask & CFM_COLOR) != 0)\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}\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\tFillMemory(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\tZeroMemory(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\tZeroMemory(m_auCmd, sizeof m_auCmd);\n\t\tZeroMemory(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": "src/Setup/wtl90/atlscrl.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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, 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": "src/Setup/wtl90/atlsplit.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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 wotk 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\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 GetSplitterPos() const\n\t{\n\t\treturn m_xySplitterPos;\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 false;\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_bFullDrag || (m_xySplitterPos != m_xySplitterPosNew))\n\t\t{\n\t\t\tm_xySplitterPos = m_xySplitterPosNew;\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": "src/Setup/wtl90/atltheme.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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#ifndef _UXTHEME_H_\n  #include <uxtheme.h>\n#endif\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": "src/Setup/wtl90/atluser.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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 Type, ATL::_U_STRINGorID ID, WORD wLanguage)\n\t{\n\t\tATLASSERT(m_hResource == NULL);\n\t\tATLASSERT(m_hGlobal == NULL);\n\n\t\tm_hResource = ::FindResourceEx(ModuleHelper::GetResourceInstance(), ID.m_lpstr, Type.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 = (WORD)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 = (WORD)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 = (WORD)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": "src/Setup/wtl90/atlwince.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Setup/wtl90/atlwinx.h",
    "content": "// Windows Template Library - WTL version 9.0\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// Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)\n// which can be found in the file CPL.TXT at the root of this distribution.\n// By using this software in any fashion, you are agreeing to be bound by\n// the terms of this license. You must not remove this notice, or\n// any other, from this software.\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": "src/Squirrel/ApplyReleasesProgress.cs",
    "content": "﻿namespace Squirrel\n{\n    using System;\n\n    internal class ApplyReleasesProgress : Progress<int>\n    {\n        private readonly int _releasesToApply;\n        private int _appliedReleases;\n        private int _currentReleaseProgress;\n\n        public ApplyReleasesProgress(int releasesToApply, Action<int> handler)\n            : base(handler)\n        {\n            _releasesToApply = releasesToApply;\n        }\n\n        public void ReportReleaseProgress(int progressOfCurrentRelease)\n        {\n            _currentReleaseProgress = progressOfCurrentRelease;\n\n            CalculateProgress();\n        }\n\n        public void FinishRelease()\n        {\n            _appliedReleases++;\n            _currentReleaseProgress = 0;\n\n            CalculateProgress();\n        }\n\n        private void CalculateProgress()\n        {\n            // Per release progress\n            var perReleaseProgressRange = 100 / _releasesToApply;\n\n            var appliedReleases = Math.Min(_appliedReleases, _releasesToApply);\n            var basePercentage = appliedReleases * perReleaseProgressRange;\n\n            var currentReleasePercentage = (perReleaseProgressRange / 100d) * _currentReleaseProgress;\n\n            var percentage = basePercentage + currentReleasePercentage;\n            OnReport((int)percentage);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/BinaryPatchUtility.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Threading;\nusing SharpCompress.Compressors;\nusing SharpCompress.Compressors.BZip2;\n\n// Adapted from https://github.com/LogosBible/bsdiff.net/blob/master/src/bsdiff/BinaryPatchUtility.cs\n\nnamespace Squirrel.Bsdiff\n{\n    /*\n    The original bsdiff.c source code (http://www.daemonology.net/bsdiff/) is\n    distributed under the following license:\n\n    Copyright 2003-2005 Colin Percival\n    All rights reserved\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted providing that the following conditions\n    are met:\n    1. Redistributions of source code must retain the above copyright\n        notice, this list of conditions and the following disclaimer.\n    2. Redistributions in binary form must reproduce the above copyright\n        notice, this list of conditions and the following disclaimer in the\n        documentation and/or other materials provided with the distribution.\n\n    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n    */\n    class BinaryPatchUtility\n    {\n        /// <summary>\n        /// Creates a binary patch (in <a href=\"http://www.daemonology.net/bsdiff/\">bsdiff</a> format) that can be used\n        /// (by <see cref=\"Apply\"/>) to transform <paramref name=\"oldData\"/> into <paramref name=\"newData\"/>.\n        /// </summary>\n        /// <param name=\"oldData\">The original binary data.</param>\n        /// <param name=\"newData\">The new binary data.</param>\n        /// <param name=\"output\">A <see cref=\"Stream\"/> to which the patch will be written.</param>\n        public static void Create(byte[] oldData, byte[] newData, Stream output)\n        {\n            // NB: If you diff a file big enough, we blow the stack. This doesn't \n            // solve it, just buys us more space. The solution is to rewrite Split\n            // using iteration instead of recursion, but that's Hard(tm).\n            var ex = default(Exception);\n            var t = new Thread(() =>\n            {\n                try\n                {\n                    CreateInternal(oldData, newData, output);\n                }\n                catch (Exception exc)\n                {\n                    ex = exc;\n                }\n            }, 40 * 1048576);\n\n            t.Start();\n            t.Join();\n\n            if (ex != null) throw ex;\n        }\n\n        static void CreateInternal(byte[] oldData, byte[] newData, Stream output)\n        {\n            // check arguments\n            if (oldData == null)\n                throw new ArgumentNullException(\"oldData\");\n            if (newData == null)\n                throw new ArgumentNullException(\"newData\");\n            if (output == null)\n                throw new ArgumentNullException(\"output\");\n            if (!output.CanSeek)\n                throw new ArgumentException(\"Output stream must be seekable.\", \"output\");\n            if (!output.CanWrite)\n                throw new ArgumentException(\"Output stream must be writable.\", \"output\");\n\n            /* Header is\n                0   8    \"BSDIFF40\"\n                8   8   length of bzip2ed ctrl block\n                16  8   length of bzip2ed diff block\n                24  8   length of new file */\n            /* File is\n                0   32  Header\n                32  ??  Bzip2ed ctrl block\n                ??  ??  Bzip2ed diff block\n                ??  ??  Bzip2ed extra block */\n            byte[] header = new byte[c_headerSize];\n            WriteInt64(c_fileSignature, header, 0); // \"BSDIFF40\"\n            WriteInt64(0, header, 8);\n            WriteInt64(0, header, 16);\n            WriteInt64(newData.Length, header, 24);\n\n            long startPosition = output.Position;\n            output.Write(header, 0, header.Length);\n\n            int[] I = SuffixSort(oldData);\n\n            byte[] db = new byte[newData.Length];\n            byte[] eb = new byte[newData.Length];\n\n            int dblen = 0;\n            int eblen = 0;\n\n            using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))\n            using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))\n            {\n                // compute the differences, writing ctrl as we go\n                int scan = 0;\n                int pos = 0;\n                int len = 0;\n                int lastscan = 0;\n                int lastpos = 0;\n                int lastoffset = 0;\n                while (scan < newData.Length)\n                {\n                    int oldscore = 0;\n\n                    for (int scsc = scan += len; scan < newData.Length; scan++)\n                    {\n                        len = Search(I, oldData, newData, scan, 0, oldData.Length, out pos);\n\n                        for (; scsc < scan + len; scsc++)\n                        {\n                            if ((scsc + lastoffset < oldData.Length) && (oldData[scsc + lastoffset] == newData[scsc]))\n                                oldscore++;\n                        }\n\n                        if ((len == oldscore && len != 0) || (len > oldscore + 8))\n                            break;\n\n                        if ((scan + lastoffset < oldData.Length) && (oldData[scan + lastoffset] == newData[scan]))\n                            oldscore--;\n                    }\n\n                    if (len != oldscore || scan == newData.Length)\n                    {\n                        int s = 0;\n                        int sf = 0;\n                        int lenf = 0;\n                        for (int i = 0; (lastscan + i < scan) && (lastpos + i < oldData.Length); )\n                        {\n                            if (oldData[lastpos + i] == newData[lastscan + i])\n                                s++;\n                            i++;\n                            if (s * 2 - i > sf * 2 - lenf)\n                            {\n                                sf = s;\n                                lenf = i;\n                            }\n                        }\n\n                        int lenb = 0;\n                        if (scan < newData.Length)\n                        {\n                            s = 0;\n                            int sb = 0;\n                            for (int i = 1; (scan >= lastscan + i) && (pos >= i); i++)\n                            {\n                                if (oldData[pos - i] == newData[scan - i])\n                                    s++;\n                                if (s * 2 - i > sb * 2 - lenb)\n                                {\n                                    sb = s;\n                                    lenb = i;\n                                }\n                            }\n                        }\n\n                        if (lastscan + lenf > scan - lenb)\n                        {\n                            int overlap = (lastscan + lenf) - (scan - lenb);\n                            s = 0;\n                            int ss = 0;\n                            int lens = 0;\n                            for (int i = 0; i < overlap; i++)\n                            {\n                                if (newData[lastscan + lenf - overlap + i] == oldData[lastpos + lenf - overlap + i])\n                                    s++;\n                                if (newData[scan - lenb + i] == oldData[pos - lenb + i])\n                                    s--;\n                                if (s > ss)\n                                {\n                                    ss = s;\n                                    lens = i + 1;\n                                }\n                            }\n\n                            lenf += lens - overlap;\n                            lenb -= lens;\n                        }\n\n                        for (int i = 0; i < lenf; i++)\n                            db[dblen + i] = (byte)(newData[lastscan + i] - oldData[lastpos + i]);\n                        for (int i = 0; i < (scan - lenb) - (lastscan + lenf); i++)\n                            eb[eblen + i] = newData[lastscan + lenf + i];\n\n                        dblen += lenf;\n                        eblen += (scan - lenb) - (lastscan + lenf);\n\n                        byte[] buf = new byte[8];\n                        WriteInt64(lenf, buf, 0);\n                        bz2Stream.Write(buf, 0, 8);\n\n                        WriteInt64((scan - lenb) - (lastscan + lenf), buf, 0);\n                        bz2Stream.Write(buf, 0, 8);\n\n                        WriteInt64((pos - lenb) - (lastpos + lenf), buf, 0);\n                        bz2Stream.Write(buf, 0, 8);\n\n                        lastscan = scan - lenb;\n                        lastpos = pos - lenb;\n                        lastoffset = pos - scan;\n                    }\n                }\n            }\n\n            // compute size of compressed ctrl data\n            long controlEndPosition = output.Position;\n            WriteInt64(controlEndPosition - startPosition - c_headerSize, header, 8);\n\n            // write compressed diff data\n            using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))\n            using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))\n            {\n                bz2Stream.Write(db, 0, dblen);\n            }\n\n            // compute size of compressed diff data\n            long diffEndPosition = output.Position;\n            WriteInt64(diffEndPosition - controlEndPosition, header, 16);\n\n            // write compressed extra data, if any\n            if (eblen > 0)\n            {\n                using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))\n                using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))\n                {\n                    bz2Stream.Write(eb, 0, eblen);\n                }\n            }\n\n            // seek to the beginning, write the header, then seek back to end\n            long endPosition = output.Position;\n            output.Position = startPosition;\n            output.Write(header, 0, header.Length);\n            output.Position = endPosition;\n        }\n\n        /// <summary>\n        /// Applies a binary patch (in <a href=\"http://www.daemonology.net/bsdiff/\">bsdiff</a> format) to the data in\n        /// <paramref name=\"input\"/> and writes the results of patching to <paramref name=\"output\"/>.\n        /// </summary>\n        /// <param name=\"input\">A <see cref=\"Stream\"/> containing the input data.</param>\n        /// <param name=\"openPatchStream\">A func that can open a <see cref=\"Stream\"/> positioned at the start of the patch data.\n        /// This stream must support reading and seeking, and <paramref name=\"openPatchStream\"/> must allow multiple streams on\n        /// the patch to be opened concurrently.</param>\n        /// <param name=\"output\">A <see cref=\"Stream\"/> to which the patched data is written.</param>\n        public static void Apply(Stream input, Func<Stream> openPatchStream, Stream output)\n        {\n            // check arguments\n            if (input == null)\n                throw new ArgumentNullException(\"input\");\n            if (openPatchStream == null)\n                throw new ArgumentNullException(\"openPatchStream\");\n            if (output == null)\n                throw new ArgumentNullException(\"output\");\n\n            /*\n            File format:\n                0   8   \"BSDIFF40\"\n                8   8   X\n                16  8   Y\n                24  8   sizeof(newfile)\n                32  X   bzip2(control block)\n                32+X    Y   bzip2(diff block)\n                32+X+Y  ??? bzip2(extra block)\n            with control block a set of triples (x,y,z) meaning \"add x bytes\n            from oldfile to x bytes from the diff block; copy y bytes from the\n            extra block; seek forwards in oldfile by z bytes\".\n            */\n            // read header\n            long controlLength, diffLength, newSize;\n            using (Stream patchStream = openPatchStream())\n            {\n                // check patch stream capabilities\n                if (!patchStream.CanRead)\n                    throw new ArgumentException(\"Patch stream must be readable.\", \"openPatchStream\");\n                if (!patchStream.CanSeek)\n                    throw new ArgumentException(\"Patch stream must be seekable.\", \"openPatchStream\");\n\n                byte[] header = patchStream.ReadExactly(c_headerSize);\n\n                // check for appropriate magic\n                long signature = ReadInt64(header, 0);\n                if (signature != c_fileSignature)\n                    throw new InvalidOperationException(\"Corrupt patch.\");\n\n                // read lengths from header\n                controlLength = ReadInt64(header, 8);\n                diffLength = ReadInt64(header, 16);\n                newSize = ReadInt64(header, 24);\n                if (controlLength < 0 || diffLength < 0 || newSize < 0)\n                    throw new InvalidOperationException(\"Corrupt patch.\");\n            }\n\n            // preallocate buffers for reading and writing\n            const int c_bufferSize = 1048576;\n            byte[] newData = new byte[c_bufferSize];\n            byte[] oldData = new byte[c_bufferSize];\n\n            // prepare to read three parts of the patch in parallel\n            using (Stream compressedControlStream = openPatchStream())\n            using (Stream compressedDiffStream = openPatchStream())\n            using (Stream compressedExtraStream = openPatchStream())\n            {\n                // seek to the start of each part\n                compressedControlStream.Seek(c_headerSize, SeekOrigin.Current);\n                compressedDiffStream.Seek(c_headerSize + controlLength, SeekOrigin.Current);\n                compressedExtraStream.Seek(c_headerSize + controlLength + diffLength, SeekOrigin.Current);\n\n                // the stream might end here if there is no extra data\n                var hasExtraData = compressedExtraStream.Position < compressedExtraStream.Length;\n\n                // decompress each part (to read it)\n                using (var controlStream = new BZip2Stream(compressedControlStream, CompressionMode.Decompress))\n                using (var diffStream = new BZip2Stream(compressedDiffStream, CompressionMode.Decompress))\n                using (var extraStream = hasExtraData ? new BZip2Stream(compressedExtraStream, CompressionMode.Decompress) : null)\n                {\n                    long[] control = new long[3];\n                    byte[] buffer = new byte[8];\n\n                    int oldPosition = 0;\n                    int newPosition = 0;\n                    while (newPosition < newSize)\n                    {\n                        // read control data\n                        for (int i = 0; i < 3; i++)\n                        {\n                            controlStream.ReadExactly(buffer, 0, 8);\n                            control[i] = ReadInt64(buffer, 0);\n                        }\n\n                        // sanity-check\n                        if (newPosition + control[0] > newSize)\n                            throw new InvalidOperationException(\"Corrupt patch.\");\n\n                        // seek old file to the position that the new data is diffed against\n                        input.Position = oldPosition;\n\n                        int bytesToCopy = (int)control[0];\n                        while (bytesToCopy > 0)\n                        {\n                            int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize);\n\n                            // read diff string\n                            diffStream.ReadExactly(newData, 0, actualBytesToCopy);\n\n                            // add old data to diff string\n                            int availableInputBytes = Math.Min(actualBytesToCopy, (int)(input.Length - input.Position));\n                            input.ReadExactly(oldData, 0, availableInputBytes);\n\n                            for (int index = 0; index < availableInputBytes; index++)\n                                newData[index] += oldData[index];\n\n                            output.Write(newData, 0, actualBytesToCopy);\n\n                            // adjust counters\n                            newPosition += actualBytesToCopy;\n                            oldPosition += actualBytesToCopy;\n                            bytesToCopy -= actualBytesToCopy;\n                        }\n\n                        // sanity-check\n                        if (newPosition + control[1] > newSize)\n                            throw new InvalidOperationException(\"Corrupt patch.\");\n\n                        // read extra string\n                        bytesToCopy = (int)control[1];\n                        while (bytesToCopy > 0)\n                        {\n                            int actualBytesToCopy = Math.Min(bytesToCopy, c_bufferSize);\n\n                            extraStream.ReadExactly(newData, 0, actualBytesToCopy);\n                            output.Write(newData, 0, actualBytesToCopy);\n\n                            newPosition += actualBytesToCopy;\n                            bytesToCopy -= actualBytesToCopy;\n                        }\n\n                        // adjust position\n                        oldPosition = (int)(oldPosition + control[2]);\n                    }\n                }\n            }\n        }\n\n        private static int CompareBytes(byte[] left, int leftOffset, byte[] right, int rightOffset)\n        {\n            for (int index = 0; index < left.Length - leftOffset && index < right.Length - rightOffset; index++)\n            {\n                int diff = left[index + leftOffset] - right[index + rightOffset];\n                if (diff != 0)\n                    return diff;\n            }\n            return 0;\n        }\n\n        private static int MatchLength(byte[] oldData, int oldOffset, byte[] newData, int newOffset)\n        {\n            int i;\n            for (i = 0; i < oldData.Length - oldOffset && i < newData.Length - newOffset; i++)\n            {\n                if (oldData[i + oldOffset] != newData[i + newOffset])\n                    break;\n            }\n            return i;\n        }\n\n        private static int Search(int[] I, byte[] oldData, byte[] newData, int newOffset, int start, int end, out int pos)\n        {\n            if (end - start < 2)\n            {\n                int startLength = MatchLength(oldData, I[start], newData, newOffset);\n                int endLength = MatchLength(oldData, I[end], newData, newOffset);\n\n                if (startLength > endLength)\n                {\n                    pos = I[start];\n                    return startLength;\n                }\n                else\n                {\n                    pos = I[end];\n                    return endLength;\n                }\n            }\n            else\n            {\n                int midPoint = start + (end - start) / 2;\n                return CompareBytes(oldData, I[midPoint], newData, newOffset) < 0 ?\n                    Search(I, oldData, newData, newOffset, midPoint, end, out pos) :\n                    Search(I, oldData, newData, newOffset, start, midPoint, out pos);\n            }\n        }\n\n        private static void Split(int[] I, int[] v, int start, int len, int h)\n        {\n            if (len < 16)\n            {\n                int j;\n                for (int k = start; k < start + len; k += j)\n                {\n                    j = 1;\n                    int x = v[I[k] + h];\n                    for (int i = 1; k + i < start + len; i++)\n                    {\n                        if (v[I[k + i] + h] < x)\n                        {\n                            x = v[I[k + i] + h];\n                            j = 0;\n                        }\n                        if (v[I[k + i] + h] == x)\n                        {\n                            Swap(ref I[k + j], ref I[k + i]);\n                            j++;\n                        }\n                    }\n                    for (int i = 0; i < j; i++)\n                        v[I[k + i]] = k + j - 1;\n                    if (j == 1)\n                        I[k] = -1;\n                }\n            }\n            else\n            {\n                int x = v[I[start + len / 2] + h];\n                int jj = 0;\n                int kk = 0;\n                for (int i2 = start; i2 < start + len; i2++)\n                {\n                    if (v[I[i2] + h] < x)\n                        jj++;\n                    if (v[I[i2] + h] == x)\n                        kk++;\n                }\n                jj += start;\n                kk += jj;\n\n                int i = start;\n                int j = 0;\n                int k = 0;\n                while (i < jj)\n                {\n                    if (v[I[i] + h] < x)\n                    {\n                        i++;\n                    }\n                    else if (v[I[i] + h] == x)\n                    {\n                        Swap(ref I[i], ref I[jj + j]);\n                        j++;\n                    }\n                    else\n                    {\n                        Swap(ref I[i], ref I[kk + k]);\n                        k++;\n                    }\n                }\n\n                while (jj + j < kk)\n                {\n                    if (v[I[jj + j] + h] == x)\n                    {\n                        j++;\n                    }\n                    else\n                    {\n                        Swap(ref I[jj + j], ref I[kk + k]);\n                        k++;\n                    }\n                }\n\n                if (jj > start)\n                    Split(I, v, start, jj - start, h);\n\n                for (i = 0; i < kk - jj; i++)\n                    v[I[jj + i]] = kk - 1;\n                if (jj == kk - 1)\n                    I[jj] = -1;\n\n                if (start + len > kk)\n                    Split(I, v, kk, start + len - kk, h);\n            }\n        }\n\n        private static int[] SuffixSort(byte[] oldData)\n        {\n            int[] buckets = new int[256];\n\n            foreach (byte oldByte in oldData)\n                buckets[oldByte]++;\n            for (int i = 1; i < 256; i++)\n                buckets[i] += buckets[i - 1];\n            for (int i = 255; i > 0; i--)\n                buckets[i] = buckets[i - 1];\n            buckets[0] = 0;\n\n            int[] I = new int[oldData.Length + 1];\n            for (int i = 0; i < oldData.Length; i++)\n                I[++buckets[oldData[i]]] = i;\n\n            int[] v = new int[oldData.Length + 1];\n            for (int i = 0; i < oldData.Length; i++)\n                v[i] = buckets[oldData[i]];\n\n            for (int i = 1; i < 256; i++)\n            {\n                if (buckets[i] == buckets[i - 1] + 1)\n                    I[buckets[i]] = -1;\n            }\n            I[0] = -1;\n\n            for (int h = 1; I[0] != -(oldData.Length + 1); h += h)\n            {\n                int len = 0;\n                int i = 0;\n                while (i < oldData.Length + 1)\n                {\n                    if (I[i] < 0)\n                    {\n                        len -= I[i];\n                        i -= I[i];\n                    }\n                    else\n                    {\n                        if (len != 0)\n                            I[i - len] = -len;\n                        len = v[I[i]] + 1 - i;\n                        Split(I, v, i, len, h);\n                        i += len;\n                        len = 0;\n                    }\n                }\n\n                if (len != 0)\n                    I[i - len] = -len;\n            }\n\n            for (int i = 0; i < oldData.Length + 1; i++)\n                I[v[i]] = i;\n\n            return I;\n        }\n\n        private static void Swap(ref int first, ref int second)\n        {\n            int temp = first;\n            first = second;\n            second = temp;\n        }\n\n        private static long ReadInt64(byte[] buf, int offset)\n        {\n            long value = buf[offset + 7] & 0x7F;\n\n            for (int index = 6; index >= 0; index--)\n            {\n                value *= 256;\n                value += buf[offset + index];\n            }\n\n            if ((buf[offset + 7] & 0x80) != 0)\n                value = -value;\n\n            return value;\n        }\n\n        private static void WriteInt64(long value, byte[] buf, int offset)\n        {\n            long valueToWrite = value < 0 ? -value : value;\n\n            for (int byteIndex = 0; byteIndex < 8; byteIndex++)\n            {\n                buf[offset + byteIndex] = (byte)(valueToWrite % 256);\n                valueToWrite -= buf[offset + byteIndex];\n                valueToWrite /= 256;\n            }\n\n            if (value < 0)\n                buf[offset + 7] |= 0x80;\n        }\n\n        const long c_fileSignature = 0x3034464649445342L;\n        const int c_headerSize = 32;\n    }\n\n    /// <summary>\n    /// A <see cref=\"Stream\"/> that wraps another stream. One major feature of <see cref=\"WrappingStream\"/> is that it does not dispose the\n    /// underlying stream when it is disposed if Ownership.None is used; this is useful when using classes such as <see cref=\"BinaryReader\"/> and\n    /// <see cref=\"System.Security.Cryptography.CryptoStream\"/> that take ownership of the stream passed to their constructors.\n    /// </summary>\n    /// <remarks>See <a href=\"http://code.logos.com/blog/2009/05/wrappingstream_implementation.html\">WrappingStream Implementation</a>.</remarks>\n    public class WrappingStream : Stream\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"WrappingStream\"/> class.\n        /// </summary>\n        /// <param name=\"streamBase\">The wrapped stream.</param>\n        /// <param name=\"ownership\">Use Owns if the wrapped stream should be disposed when this stream is disposed.</param>\n        public WrappingStream(Stream streamBase, Ownership ownership)\n        {\n            // check parameters\n            if (streamBase == null)\n                throw new ArgumentNullException(\"streamBase\");\n\n            m_streamBase = streamBase;\n            m_ownership = ownership;\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether the current stream supports reading.\n        /// </summary>\n        /// <returns><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</returns>\n        public override bool CanRead\n        {\n            get { return m_streamBase == null ? false : m_streamBase.CanRead; }\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether the current stream supports seeking.\n        /// </summary>\n        /// <returns><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</returns>\n        public override bool CanSeek\n        {\n            get { return m_streamBase == null ? false : m_streamBase.CanSeek; }\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether the current stream supports writing.\n        /// </summary>\n        /// <returns><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</returns>\n        public override bool CanWrite\n        {\n            get { return m_streamBase == null ? false : m_streamBase.CanWrite; }\n        }\n\n        /// <summary>\n        /// Gets the length in bytes of the stream.\n        /// </summary>\n        public override long Length\n        {\n            get { ThrowIfDisposed(); return m_streamBase.Length; }\n        }\n\n        /// <summary>\n        /// Gets or sets the position within the current stream.\n        /// </summary>\n        public override long Position\n        {\n            get { ThrowIfDisposed(); return m_streamBase.Position; }\n            set { ThrowIfDisposed(); m_streamBase.Position = value; }\n        }\n\n        /// <summary>\n        /// Begins an asynchronous read operation.\n        /// </summary>\n        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)\n        {\n            ThrowIfDisposed();\n            return m_streamBase.BeginRead(buffer, offset, count, callback, state);\n        }\n\n        /// <summary>\n        /// Begins an asynchronous write operation.\n        /// </summary>\n        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)\n        {\n            ThrowIfDisposed();\n            return m_streamBase.BeginWrite(buffer, offset, count, callback, state);\n        }\n\n        /// <summary>\n        /// Waits for the pending asynchronous read to complete.\n        /// </summary>\n        public override int EndRead(IAsyncResult asyncResult)\n        {\n            ThrowIfDisposed();\n            return m_streamBase.EndRead(asyncResult);\n        }\n\n        /// <summary>\n        /// Ends an asynchronous write operation.\n        /// </summary>\n        public override void EndWrite(IAsyncResult asyncResult)\n        {\n            ThrowIfDisposed();\n            m_streamBase.EndWrite(asyncResult);\n        }\n\n        /// <summary>\n        /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.\n        /// </summary>\n        public override void Flush()\n        {\n            ThrowIfDisposed();\n            m_streamBase.Flush();\n        }\n\n        /// <summary>\n        /// Reads a sequence of bytes from the current stream and advances the position\n        /// within the stream by the number of bytes read.\n        /// </summary>\n        public override int Read(byte[] buffer, int offset, int count)\n        {\n            ThrowIfDisposed();\n            return m_streamBase.Read(buffer, offset, count);\n        }\n\n        /// <summary>\n        /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.\n        /// </summary>\n        public override int ReadByte()\n        {\n            ThrowIfDisposed();\n            return m_streamBase.ReadByte();\n        }\n\n        /// <summary>\n        /// Sets the position within the current stream.\n        /// </summary>\n        /// <param name=\"offset\">A byte offset relative to the <paramref name=\"origin\"/> parameter.</param>\n        /// <param name=\"origin\">A value of type <see cref=\"T:System.IO.SeekOrigin\"/> indicating the reference point used to obtain the new position.</param>\n        /// <returns>The new position within the current stream.</returns>\n        public override long Seek(long offset, SeekOrigin origin)\n        {\n            ThrowIfDisposed();\n            return m_streamBase.Seek(offset, origin);\n        }\n\n        /// <summary>\n        /// Sets the length of the current stream.\n        /// </summary>\n        /// <param name=\"value\">The desired length of the current stream in bytes.</param>\n        public override void SetLength(long value)\n        {\n            ThrowIfDisposed();\n            m_streamBase.SetLength(value);\n        }\n\n        /// <summary>\n        /// Writes a sequence of bytes to the current stream and advances the current position\n        /// within this stream by the number of bytes written.\n        /// </summary>\n        public override void Write(byte[] buffer, int offset, int count)\n        {\n            ThrowIfDisposed();\n            m_streamBase.Write(buffer, offset, count);\n        }\n\n        /// <summary>\n        /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.\n        /// </summary>\n        public override void WriteByte(byte value)\n        {\n            ThrowIfDisposed();\n            m_streamBase.WriteByte(value);\n        }\n\n        /// <summary>\n        /// Gets the wrapped stream.\n        /// </summary>\n        /// <value>The wrapped stream.</value>\n        protected Stream WrappedStream\n        {\n            get { return m_streamBase; }\n        }\n\n        /// <summary>\n        /// Releases the unmanaged resources used by the <see cref=\"WrappingStream\"/> and optionally releases the managed resources.\n        /// </summary>\n        /// <param name=\"disposing\">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>\n        protected override void Dispose(bool disposing)\n        {\n            try\n            {\n                // doesn't close the base stream, but just prevents access to it through this WrappingStream\n                if (disposing)\n                {\n                    if (m_streamBase != null && m_ownership == Ownership.Owns)\n                        m_streamBase.Dispose();\n                    m_streamBase = null;\n                }\n            }\n            finally\n            {\n                base.Dispose(disposing);\n            }\n        }\n\n        private void ThrowIfDisposed()\n        {\n            // throws an ObjectDisposedException if this object has been disposed\n            if (m_streamBase == null)\n                throw new ObjectDisposedException(GetType().Name);\n        }\n\n        Stream m_streamBase;\n        readonly Ownership m_ownership;\n    }\n\n    /// <summary>\n    /// Indicates whether an object takes ownership of an item.\n    /// </summary>\n    public enum Ownership\n    {\n        /// <summary>\n        /// The object does not own this item.\n        /// </summary>\n        None,\n\n        /// <summary>\n        /// The object owns this item, and is responsible for releasing it.\n        /// </summary>\n        Owns\n    }\n\n    /// <summary>\n    /// Provides helper methods for working with <see cref=\"Stream\"/>.\n    /// </summary>\n    public static class StreamUtility\n    {\n        /// <summary>\n        /// Reads exactly <paramref name=\"count\"/> bytes from <paramref name=\"stream\"/>.\n        /// </summary>\n        /// <param name=\"stream\">The stream to read from.</param>\n        /// <param name=\"count\">The count of bytes to read.</param>\n        /// <returns>A new byte array containing the data read from the stream.</returns>\n        public static byte[] ReadExactly(this Stream stream, int count)\n        {\n            if (count < 0)\n                throw new ArgumentOutOfRangeException(\"count\");\n            byte[] buffer = new byte[count];\n            ReadExactly(stream, buffer, 0, count);\n            return buffer;\n        }\n\n        /// <summary>\n        /// Reads exactly <paramref name=\"count\"/> bytes from <paramref name=\"stream\"/> into\n        /// <paramref name=\"buffer\"/>, starting at the byte given by <paramref name=\"offset\"/>.\n        /// </summary>\n        /// <param name=\"stream\">The stream to read from.</param>\n        /// <param name=\"buffer\">The buffer to read data into.</param>\n        /// <param name=\"offset\">The offset within the buffer at which data is first written.</param>\n        /// <param name=\"count\">The count of bytes to read.</param>\n        public static void ReadExactly(this Stream stream, byte[] buffer, int offset, int count)\n        {\n            // check arguments\n            if (stream == null)\n                throw new ArgumentNullException(\"stream\");\n            if (buffer == null)\n                throw new ArgumentNullException(\"buffer\");\n            if (offset < 0 || offset > buffer.Length)\n                throw new ArgumentOutOfRangeException(\"offset\");\n            if (count < 0 || buffer.Length - offset < count)\n                throw new ArgumentOutOfRangeException(\"count\");\n\n            while (count > 0)\n            {\n                // read data\n                int bytesRead = stream.Read(buffer, offset, count);\n\n                // check for failure to read\n                if (bytesRead == 0)\n                    throw new EndOfStreamException();\n\n                // move to next block\n                offset += bytesRead;\n                count -= bytesRead;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Squirrel/ContentType.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Xml;\n\nnamespace Squirrel\n{\n    internal static class ContentType\n    {\n        public static void Clean(XmlDocument doc)\n        {\n            var typesElement = doc.FirstChild.NextSibling;\n            if (typesElement.Name.ToLowerInvariant() != \"types\") {\n                throw new Exception(\"Invalid ContentTypes file, expected root node should be 'Types'\");\n            }\n\n            var children = typesElement.ChildNodes.OfType<XmlElement>();\n\n            foreach (var child in children) {\n                if (child.GetAttribute(\"Extension\") == \"\") {\n                    typesElement.RemoveChild(child);\n                }\n            }\n        }\n\n        public static void Merge(XmlDocument doc)\n        {\n            var elements = new [] {\n                Tuple.Create(\"Default\", \"diff\", \"application/octet\" ),\n                Tuple.Create(\"Default\", \"bsdiff\", \"application/octet\" ),\n                Tuple.Create(\"Default\", \"exe\", \"application/octet\" ),\n                Tuple.Create(\"Default\", \"dll\", \"application/octet\" ),\n                Tuple.Create(\"Default\", \"shasum\", \"text/plain\" ),\n            };\n\n            var typesElement = doc.FirstChild.NextSibling;\n            if (typesElement.Name.ToLowerInvariant() != \"types\") {\n                throw new Exception(\"Invalid ContentTypes file, expected root node should be 'Types'\");\n            }\n\n            var existingTypes = typesElement.ChildNodes.OfType<XmlElement>()\n                .Select(k => Tuple.Create(k.Name,\n                    k.GetAttribute(\"Extension\").ToLowerInvariant(),\n                    k.GetAttribute(\"ContentType\").ToLowerInvariant()));\n\n            var toAdd = elements\n                .Where(x => existingTypes.All(t => t.Item2 != x.Item2.ToLowerInvariant()))\n                .Select(element => {\n                    var ret = doc.CreateElement(element.Item1, typesElement.NamespaceURI);\n\n                    var ext = doc.CreateAttribute(\"Extension\"); ext.Value = element.Item2;\n                    var ct = doc.CreateAttribute(\"ContentType\"); ct.Value = element.Item3;\n\n                    ret.Attributes.Append(ext);\n                    ret.Attributes.Append(ct);\n\n                    return ret;\n                });\n\n            foreach (var v in toAdd) typesElement.AppendChild(v);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/DeltaPackage.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Squirrel.SimpleSplat;\nusing System.ComponentModel;\nusing Squirrel.Bsdiff;\nusing SharpCompress.Archives;\nusing SharpCompress.Archives.Zip;\nusing SharpCompress.Writers;\nusing SharpCompress.Common;\nusing SharpCompress.Readers;\nusing SharpCompress.Compressors.Deflate;\n\nnamespace Squirrel\n{\n    public interface IDeltaPackageBuilder\n    {\n        ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile);\n        ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile);\n    }\n\n    public class DeltaPackageBuilder : IEnableLogger, IDeltaPackageBuilder\n    {\n        readonly string localAppDirectory;\n        public DeltaPackageBuilder(string localAppDataOverride = null)\n        {\n            this.localAppDirectory = localAppDataOverride;\n        }\n\n        public ReleasePackage CreateDeltaPackage(ReleasePackage basePackage, ReleasePackage newPackage, string outputFile)\n        {\n            Contract.Requires(basePackage != null);\n            Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile));\n\n            if (basePackage.Version > newPackage.Version) {\n                var message = String.Format(\n                    \"You cannot create a delta package based on version {0} as it is a later version than {1}\",\n                    basePackage.Version,\n                    newPackage.Version);\n                throw new InvalidOperationException(message);\n            }\n\n            if (basePackage.ReleasePackageFile == null) {\n                throw new ArgumentException(\"The base package's release file is null\", \"basePackage\");\n            }\n\n            if (!File.Exists(basePackage.ReleasePackageFile)) {\n                throw new FileNotFoundException(\"The base package release does not exist\", basePackage.ReleasePackageFile);\n            }\n\n            if (!File.Exists(newPackage.ReleasePackageFile)) {\n                throw new FileNotFoundException(\"The new package release does not exist\", newPackage.ReleasePackageFile);\n            }\n\n            string baseTempPath = null;\n            string tempPath = null;\n\n            using (Utility.WithTempDirectory(out baseTempPath, null))\n            using (Utility.WithTempDirectory(out tempPath, null)) {\n                var baseTempInfo = new DirectoryInfo(baseTempPath);\n                var tempInfo = new DirectoryInfo(tempPath);\n\n                this.Log().Info(\"Extracting {0} and {1} into {2}\", \n                    basePackage.ReleasePackageFile, newPackage.ReleasePackageFile, tempPath);\n\n                Utility.ExtractZipToDirectory(basePackage.ReleasePackageFile, baseTempInfo.FullName).Wait();\n                Utility.ExtractZipToDirectory(newPackage.ReleasePackageFile, tempInfo.FullName).Wait();\n\n                // Collect a list of relative paths under 'lib' and map them\n                // to their full name. We'll use this later to determine in\n                // the new version of the package whether the file exists or\n                // not.\n                var baseLibFiles = baseTempInfo.GetAllFilesRecursively()\n                    .Where(x => x.FullName.ToLowerInvariant().Contains(\"lib\" + Path.DirectorySeparatorChar))\n                    .ToDictionary(k => k.FullName.Replace(baseTempInfo.FullName, \"\"), v => v.FullName);\n\n                var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == \"lib\");\n\n                foreach (var libFile in newLibDir.GetAllFilesRecursively()) {\n                    createDeltaForSingleFile(libFile, tempInfo, baseLibFiles);\n                }\n\n                ReleasePackage.addDeltaFilesToContentTypes(tempInfo.FullName);\n                Utility.CreateZipFromDirectory(outputFile, tempInfo.FullName).Wait();\n            }\n\n            return new ReleasePackage(outputFile);\n        }\n\n        public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile)\n        {\n            return ApplyDeltaPackage(basePackage, deltaPackage, outputFile, x => { });\n        }\n\n        public ReleasePackage ApplyDeltaPackage(ReleasePackage basePackage, ReleasePackage deltaPackage, string outputFile, Action<int> progress)\n        {\n            Contract.Requires(deltaPackage != null);\n            Contract.Requires(!String.IsNullOrEmpty(outputFile) && !File.Exists(outputFile));\n\n            string workingPath;\n            string deltaPath;\n\n            using (Utility.WithTempDirectory(out deltaPath, localAppDirectory))\n            using (Utility.WithTempDirectory(out workingPath, localAppDirectory)) {\n                var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true };\n\n                using (var za = ZipArchive.Open(deltaPackage.InputPackageFile))\n                using (var reader = za.ExtractAllEntries()) {\n                    reader.WriteAllToDirectory(deltaPath, opts);\n                }\n\n                progress(25);\n\n                using (var za = ZipArchive.Open(basePackage.InputPackageFile))\n                using (var reader = za.ExtractAllEntries()) {\n                    reader.WriteAllToDirectory(workingPath, opts);\n                }\n\n                progress(50);\n\n                var pathsVisited = new List<string>();\n\n                var deltaPathRelativePaths = new DirectoryInfo(deltaPath).GetAllFilesRecursively()\n                    .Select(x => x.FullName.Replace(deltaPath + Path.DirectorySeparatorChar, \"\"))\n                    .ToArray();\n\n                // Apply all of the .diff files\n                deltaPathRelativePaths\n                    .Where(x => x.StartsWith(\"lib\", StringComparison.InvariantCultureIgnoreCase))\n                    .Where(x => !x.EndsWith(\".shasum\", StringComparison.InvariantCultureIgnoreCase))\n                    .Where(x => !x.EndsWith(\".diff\", StringComparison.InvariantCultureIgnoreCase) ||\n                                !deltaPathRelativePaths.Contains(x.Replace(\".diff\", \".bsdiff\")))\n                    .ForEach(file => {\n                        pathsVisited.Add(Regex.Replace(file, @\"\\.(bs)?diff$\", \"\").ToLowerInvariant());\n                        applyDiffToFile(deltaPath, file, workingPath);\n                    });\n\n                progress(75);\n\n                // Delete all of the files that were in the old package but\n                // not in the new one.\n                new DirectoryInfo(workingPath).GetAllFilesRecursively()\n                    .Select(x => x.FullName.Replace(workingPath + Path.DirectorySeparatorChar, \"\").ToLowerInvariant())\n                    .Where(x => x.StartsWith(\"lib\", StringComparison.InvariantCultureIgnoreCase) && !pathsVisited.Contains(x))\n                    .ForEach(x => {\n                        this.Log().Info(\"{0} was in old package but not in new one, deleting\", x);\n                        File.Delete(Path.Combine(workingPath, x));\n                    });\n\n                progress(80);\n\n                // Update all the files that aren't in 'lib' with the delta\n                // package's versions (i.e. the nuspec file, etc etc).\n                deltaPathRelativePaths\n                    .Where(x => !x.StartsWith(\"lib\", StringComparison.InvariantCultureIgnoreCase))\n                    .ForEach(x => {\n                        this.Log().Info(\"Updating metadata file: {0}\", x);\n                        File.Copy(Path.Combine(deltaPath, x), Path.Combine(workingPath, x), true);\n                    });\n\n                this.Log().Info(\"Repacking into full package: {0}\", outputFile);\n                using (var za = ZipArchive.Create())\n                using (var tgt = File.OpenWrite(outputFile)) {\n                    za.DeflateCompressionLevel = CompressionLevel.BestSpeed;\n                    za.AddAllFromDirectory(workingPath);\n                    za.SaveTo(tgt);\n                }\n\n                progress(100);\n            }\n\n            return new ReleasePackage(outputFile);\n        }\n\n        void createDeltaForSingleFile(FileInfo targetFile, DirectoryInfo workingDirectory, Dictionary<string, string> baseFileListing)\n        {\n            // NB: There are three cases here that we'll handle:\n            //\n            // 1. Exists only in new => leave it alone, we'll use it directly.\n            // 2. Exists in both old and new => write a dummy file so we know\n            //    to keep it.\n            // 3. Exists in old but changed in new => create a delta file\n            //\n            // The fourth case of \"Exists only in old => delete it in new\"\n            // is handled when we apply the delta package\n            var relativePath = targetFile.FullName.Replace(workingDirectory.FullName, \"\");\n\n            if (!baseFileListing.ContainsKey(relativePath)) {\n                this.Log().Info(\"{0} not found in base package, marking as new\", relativePath);\n                return;\n            }\n\n            var oldData = File.ReadAllBytes(baseFileListing[relativePath]);\n            var newData = File.ReadAllBytes(targetFile.FullName);\n\n            if (bytesAreIdentical(oldData, newData)) {\n                this.Log().Info(\"{0} hasn't changed, writing dummy file\", relativePath);\n\n                File.Create(targetFile.FullName + \".diff\").Dispose();\n                File.Create(targetFile.FullName + \".shasum\").Dispose();\n                targetFile.Delete();\n                return;\n            }\n\n            this.Log().Info(\"Delta patching {0} => {1}\", baseFileListing[relativePath], targetFile.FullName);\n            var msDelta = new MsDeltaCompression();\n\n            if (targetFile.Extension.Equals(\".exe\", StringComparison.OrdinalIgnoreCase) || \n                targetFile.Extension.Equals(\".dll\", StringComparison.OrdinalIgnoreCase) ||\n                targetFile.Extension.Equals(\".node\", StringComparison.OrdinalIgnoreCase)) {\n                try {\n                    msDelta.CreateDelta(baseFileListing[relativePath], targetFile.FullName, targetFile.FullName + \".diff\");\n                    goto exit;\n                } catch (Exception) {\n                    this.Log().Warn(\"We couldn't create a delta for {0}, attempting to create bsdiff\", targetFile.Name);\n                }\n            }\n            \n            try {\n                using (FileStream of = File.Create(targetFile.FullName + \".bsdiff\")) {\n                    BinaryPatchUtility.Create(oldData, newData, of);\n\n                    // NB: Create a dummy corrupt .diff file so that older \n                    // versions which don't understand bsdiff will fail out\n                    // until they get upgraded, instead of seeing the missing\n                    // file and just removing it.\n                    File.WriteAllText(targetFile.FullName + \".diff\", \"1\");\n                }\n            } catch (Exception ex) {\n                this.Log().WarnException(String.Format(\"We really couldn't create a delta for {0}\", targetFile.Name), ex);\n\n                Utility.DeleteFileHarder(targetFile.FullName + \".bsdiff\", true);\n                Utility.DeleteFileHarder(targetFile.FullName + \".diff\", true);\n                return;\n            }\n\n        exit:\n\n            var rl = ReleaseEntry.GenerateFromFile(new MemoryStream(newData), targetFile.Name + \".shasum\");\n            File.WriteAllText(targetFile.FullName + \".shasum\", rl.EntryAsString, Encoding.UTF8);\n            targetFile.Delete();\n        }\n\n\n        void applyDiffToFile(string deltaPath, string relativeFilePath, string workingDirectory)\n        {\n            var inputFile = Path.Combine(deltaPath, relativeFilePath);\n            var finalTarget = Path.Combine(workingDirectory, Regex.Replace(relativeFilePath, @\"\\.(bs)?diff$\", \"\"));\n\n            var tempTargetFile = default(string);\n            Utility.WithTempFile(out tempTargetFile, localAppDirectory);\n\n            try {\n                // NB: Zero-length diffs indicate the file hasn't actually changed\n                if (new FileInfo(inputFile).Length == 0) {\n                    this.Log().Info(\"{0} exists unchanged, skipping\", relativeFilePath);\n                    return;\n                }\n\n                 if (relativeFilePath.EndsWith(\".bsdiff\", StringComparison.InvariantCultureIgnoreCase)) {\n                    using (var of = File.OpenWrite(tempTargetFile))\n                    using (var inf = File.OpenRead(finalTarget)) {\n                        this.Log().Info(\"Applying BSDiff to {0}\", relativeFilePath);\n                        BinaryPatchUtility.Apply(inf, () => File.OpenRead(inputFile), of);\n                    }\n\n                    verifyPatchedFile(relativeFilePath, inputFile, tempTargetFile);\n                 } else if (relativeFilePath.EndsWith(\".diff\", StringComparison.InvariantCultureIgnoreCase)) {\n                    this.Log().Info(\"Applying MSDiff to {0}\", relativeFilePath);\n                    var msDelta = new MsDeltaCompression();\n                    msDelta.ApplyDelta(inputFile, finalTarget, tempTargetFile);\n\n                    verifyPatchedFile(relativeFilePath, inputFile, tempTargetFile);\n                } else {\n                    using (var of = File.OpenWrite(tempTargetFile))\n                    using (var inf = File.OpenRead(inputFile)) {\n                        this.Log().Info(\"Adding new file: {0}\", relativeFilePath);\n                        inf.CopyTo(of);\n                    }\n                }\n\n                if (File.Exists(finalTarget)) File.Delete(finalTarget);\n\n                var targetPath = Directory.GetParent(finalTarget);\n                if (!targetPath.Exists) targetPath.Create();\n\n                File.Move(tempTargetFile, finalTarget);\n            } finally {\n                if (File.Exists(tempTargetFile)) Utility.DeleteFileHarder(tempTargetFile, true);\n            }\n        }\n\n        void verifyPatchedFile(string relativeFilePath, string inputFile, string tempTargetFile)\n        {\n            var shaFile = Regex.Replace(inputFile, @\"\\.(bs)?diff$\", \".shasum\");\n            var expectedReleaseEntry = ReleaseEntry.ParseReleaseEntry(File.ReadAllText(shaFile, Encoding.UTF8));\n            var actualReleaseEntry = ReleaseEntry.GenerateFromFile(tempTargetFile);\n\n            if (expectedReleaseEntry.Filesize != actualReleaseEntry.Filesize) {\n                this.Log().Warn(\"Patched file {0} has incorrect size, expected {1}, got {2}\", relativeFilePath,\n                    expectedReleaseEntry.Filesize, actualReleaseEntry.Filesize);\n                throw new ChecksumFailedException() {Filename = relativeFilePath};\n            }\n\n            if (expectedReleaseEntry.SHA1 != actualReleaseEntry.SHA1) {\n                this.Log().Warn(\"Patched file {0} has incorrect SHA1, expected {1}, got {2}\", relativeFilePath,\n                    expectedReleaseEntry.SHA1, actualReleaseEntry.SHA1);\n                throw new ChecksumFailedException() {Filename = relativeFilePath};\n            }\n        }\n\n        bool bytesAreIdentical(byte[] oldData, byte[] newData)\n        {\n            if (oldData == null || newData == null) {\n                return oldData == newData;\n            }\n            if (oldData.LongLength != newData.LongLength) {\n                return false;\n            }\n\n            for(long i = 0; i < newData.LongLength; i++) {\n                if (oldData[i] != newData[i]) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/EnumerableExtensions.cs",
    "content": "﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt\n\nusing System;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Squirrel\n{\n    internal static class EnumerableExtensions\n    {\n        public static IEnumerable<T> Return<T>(T value)\n        {\n            yield return value;\n        }\n\n        /// <summary>\n        /// Enumerates the sequence and invokes the given action for each value in the sequence.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"onNext\">Action to invoke for each element.</param>\n        public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)\n        {\n            if (source == null)\n                throw new ArgumentNullException(\"source\");\n            if (onNext == null)\n                throw new ArgumentNullException(\"onNext\");\n\n            foreach (var item in source) onNext(item);\n        }\n\n        /// <summary>\n        /// Returns the elements with the maximum key value by using the default comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector used to extract the key for each element in the sequence.</param>\n        /// <returns>List with the elements that share the same maximum key value.</returns>\n        public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)\n        {\n            if (source == null)\n                throw new ArgumentNullException(\"source\");\n            if (keySelector == null)\n                throw new ArgumentNullException(\"keySelector\");\n\n            return MaxBy(source, keySelector, Comparer<TKey>.Default);\n        }\n\n        /// <summary>\n        /// Returns the elements with the minimum key value by using the specified comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector used to extract the key for each element in the sequence.</param>\n        /// <param name=\"comparer\">Comparer used to determine the maximum key value.</param>\n        /// <returns>List with the elements that share the same maximum key value.</returns>\n        public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (keySelector == null) throw new ArgumentNullException(\"keySelector\");\n            if (comparer == null) throw new ArgumentNullException(\"comparer\");\n\n            return ExtremaBy(source, keySelector, (key, minValue) => comparer.Compare(key, minValue));\n        }\n\n        private static IList<TSource> ExtremaBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, TKey, int> compare)\n        {\n            var result = new List<TSource>();\n\n            using (var e = source.GetEnumerator()) {\n                if (!e.MoveNext()) throw new InvalidOperationException(\"Source sequence doesn't contain any elements.\");\n\n                var current = e.Current;\n                var resKey = keySelector(current);\n                result.Add(current);\n\n                while (e.MoveNext()) {\n                    var cur = e.Current;\n                    var key = keySelector(cur);\n\n                    var cmp = compare(key, resKey);\n                    if (cmp == 0) {\n                        result.Add(cur);\n                    } else if (cmp > 0) {\n                        result = new List<TSource> { cur };\n                        resKey = key;\n                    }\n                }\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Lazily invokes an action for each value in the sequence.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"onNext\">Action to invoke for each element.</param>\n        /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>\n        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (onNext == null) throw new ArgumentNullException(\"onNext\");\n\n            return DoHelper(source, onNext, _ => { }, () => { });\n        }\n\n        /// <summary>\n        /// Lazily invokes an action for each value in the sequence, and executes an action for successful termination.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"onNext\">Action to invoke for each element.</param>\n        /// <param name=\"onCompleted\">Action to invoke on successful termination of the sequence.</param>\n        /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>\n        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (onNext == null) throw new ArgumentNullException(\"onNext\");\n            if (onCompleted == null) throw new ArgumentNullException(\"onCompleted\");\n\n            return DoHelper(source, onNext, _ => { }, onCompleted);\n        }\n\n        /// <summary>\n        /// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"onNext\">Action to invoke for each element.</param>\n        /// <param name=\"onError\">Action to invoke on exceptional termination of the sequence.</param>\n        /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>\n        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (onNext == null) throw new ArgumentNullException(\"onNext\");\n            if (onError == null) throw new ArgumentNullException(\"onError\");\n\n            return DoHelper(source, onNext, onError, () => { });\n        }\n\n        /// <summary>\n        /// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional termination.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"onNext\">Action to invoke for each element.</param>\n        /// <param name=\"onError\">Action to invoke on exceptional termination of the sequence.</param>\n        /// <param name=\"onCompleted\">Action to invoke on successful termination of the sequence.</param>\n        /// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>\n        public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (onNext == null) throw new ArgumentNullException(\"onNext\");\n            if (onError == null) throw new ArgumentNullException(\"onError\");\n            if (onCompleted == null) throw new ArgumentNullException(\"onCompleted\");\n\n            return DoHelper(source, onNext, onError, onCompleted);\n        }\n\n        private static IEnumerable<TSource> DoHelper<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)\n        {\n            using (var e = source.GetEnumerator()) {\n                while (true) {\n                    var current = default(TSource);\n                    try {\n                        if (!e.MoveNext())\n                            break;\n\n                        current = e.Current;\n                    } catch (Exception ex) {\n                        onError(ex);\n                        throw;\n                    }\n\n                    onNext(current);\n                    yield return current;\n                }\n\n                onCompleted();\n            }\n        }\n\n        /// <summary>\n        /// Returns the source sequence prefixed with the specified value.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"values\">Values to prefix the sequence with.</param>\n        /// <returns>Sequence starting with the specified prefix value, followed by the source sequence.</returns>\n        public static IEnumerable<TSource> StartWith<TSource>(this IEnumerable<TSource> source, params TSource[] values)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n\n            return source.StartWith_(values);\n        }\n\n        static IEnumerable<TSource> StartWith_<TSource>(this IEnumerable<TSource> source, params TSource[] values)\n        {\n            foreach (var x in values) yield return x;\n\n            foreach (var item in source) yield return item;\n        }\n\n        /// <summary>\n        /// Returns elements with a distinct key value by using the default equality comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector.</param>\n        /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>\n        public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (keySelector == null) throw new ArgumentNullException(\"keySelector\");\n\n            return source.Distinct_(keySelector, EqualityComparer<TKey>.Default);\n        }\n\n        /// <summary>\n        /// Returns elements with a distinct key value by using the specified equality comparer to compare key values.\n        /// </summary>\n        /// <typeparam name=\"TSource\">Source sequence element type.</typeparam>\n        /// <typeparam name=\"TKey\">Key type.</typeparam>\n        /// <param name=\"source\">Source sequence.</param>\n        /// <param name=\"keySelector\">Key selector.</param>\n        /// <param name=\"comparer\">Comparer used to compare key values.</param>\n        /// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>\n        public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)\n        {\n            if (source == null) throw new ArgumentNullException(\"source\");\n            if (keySelector == null) throw new ArgumentNullException(\"keySelector\");\n            if (comparer == null) throw new ArgumentNullException(\"comparer\");\n\n            return source.Distinct_(keySelector, comparer);\n        }\n\n        static IEnumerable<TSource> Distinct_<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)\n        {\n            var set = new HashSet<TKey>(comparer);\n\n            foreach (var item in source) {\n                var key = keySelector(item);\n\n                if (set.Add(key)) yield return item;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/FileDownloader.cs",
    "content": "﻿using System;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    public interface IFileDownloader\n    {\n        Task DownloadFile(string url, string targetFile, Action<int> progress);\n        Task<byte[]> DownloadUrl(string url);\n    }\n\n    public class FileDownloader : IFileDownloader, IEnableLogger\n    {\n        private readonly WebClient _providedClient;\n\n        public FileDownloader(WebClient providedClient = null)\n        {\n            _providedClient = providedClient;\n        }\n\n        public async Task DownloadFile(string url, string targetFile, Action<int> progress)\n        {\n            using (var wc = _providedClient ?? Utility.CreateWebClient()) {\n                var failedUrl = default(string);\n\n                var lastSignalled = DateTime.MinValue;\n                wc.DownloadProgressChanged += (sender, args) => {\n                    var now = DateTime.Now;\n\n                    if (now - lastSignalled > TimeSpan.FromMilliseconds(500)) {\n                        lastSignalled = now;\n                        progress(args.ProgressPercentage);\n                    }\n                };\n\n            retry:\n                try {\n                    this.Log().Info(\"Downloading file: \" + (failedUrl ?? url));\n\n                    await this.WarnIfThrows(\n                        async () => {\n                            await wc.DownloadFileTaskAsync(failedUrl ?? url, targetFile);\n                            progress(100);\n                        },\n                        \"Failed downloading URL: \" + (failedUrl ?? url));\n                } catch (Exception) {\n                    // NB: Some super brain-dead services are case-sensitive yet \n                    // corrupt case on upload. I can't even.\n                    if (failedUrl != null) throw;\n\n                    failedUrl = url.ToLower();\n                    progress(0);\n                    goto retry;\n                }\n            }\n        }\n\n        public async Task<byte[]> DownloadUrl(string url)\n        {\n            using (var wc = _providedClient ?? Utility.CreateWebClient()) {\n            var failedUrl = default(string);\n\n        retry:\n            try {\n                this.Log().Info(\"Downloading url: \" + (failedUrl ?? url));\n\n                return await this.WarnIfThrows(() => wc.DownloadDataTaskAsync(failedUrl ?? url),\n                    \"Failed to download url: \" + (failedUrl ?? url));\n            } catch (Exception) {\n                // NB: Some super brain-dead services are case-sensitive yet \n                // corrupt case on upload. I can't even.\n                if (failedUrl != null) throw;\n\n                failedUrl = url.ToLower();\n                goto retry;\n            }\n        }\n    }\n}\n}\n"
  },
  {
    "path": "src/Squirrel/IUpdateManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Win32;\nusing Squirrel.SimpleSplat;\nusing NuGet;\n\nnamespace Squirrel\n{\n    [Flags]\n    public enum ShortcutLocation {\n        StartMenu = 1 << 0,\n        Desktop = 1 << 1,\n        Startup = 1 << 2,\n        /// <summary>\n        /// A shortcut in the application folder, useful for portable applications.\n        /// </summary>\n        AppRoot = 1 << 3\n    }\n\n    public enum UpdaterIntention {\n        Install,\n        Update\n    }\n\n    public interface IUpdateManager : IDisposable, IEnableLogger\n    {\n        /// <summary>\n        /// Fetch the remote store for updates and compare against the current \n        /// version to determine what updates to download.\n        /// </summary>\n        /// <param name=\"intention\">Indicates whether the UpdateManager is used\n        /// in a Install or Update scenario.</param>\n        /// <param name=\"ignoreDeltaUpdates\">Set this flag if applying a release\n        /// fails to fall back to a full release, which takes longer to download\n        /// but is less error-prone.</param>\n        /// <param name=\"progress\">A Observer which can be used to report Progress - \n        /// will return values from 0-100 and Complete, or Throw</param>\n        /// <returns>An UpdateInfo object representing the updates to install.\n        /// </returns>\n        Task<UpdateInfo> CheckForUpdate(bool ignoreDeltaUpdates = false, Action<int> progress = null, UpdaterIntention intention = UpdaterIntention.Update);\n\n        /// <summary>\n        /// Download a list of releases into the local package directory.\n        /// </summary>\n        /// <param name=\"releasesToDownload\">The list of releases to download, \n        /// almost always from UpdateInfo.ReleasesToApply.</param>\n        /// <param name=\"progress\">A Observer which can be used to report Progress - \n        /// will return values from 0-100 and Complete, or Throw</param>\n        /// <returns>A completion Observable - either returns a single \n        /// Unit.Default then Complete, or Throw</returns>\n        Task DownloadReleases(IEnumerable<ReleaseEntry> releasesToDownload, Action<int> progress = null);\n\n        /// <summary>\n        /// Take an already downloaded set of releases and apply them, \n        /// copying in the new files from the NuGet package and rewriting \n        /// the application shortcuts.\n        /// </summary>\n        /// <param name=\"updateInfo\">The UpdateInfo instance acquired from \n        /// CheckForUpdate</param>\n        /// <param name=\"progress\">A Observer which can be used to report Progress - \n        /// will return values from 0-100 and Complete, or Throw</param>\n        /// <returns>The path to the installed application (i.e. the path where\n        /// your package's contents ended up</returns>\n        Task<string> ApplyReleases(UpdateInfo updateInfo, Action<int> progress = null);\n\n        /// <summary>\n        /// Completely Installs a targeted app\n        /// </summary>\n        /// <param name=\"silentInstall\">If true, don't run the app once install completes.</param>\n        /// <param name=\"progress\">A Observer which can be used to report Progress - \n        /// will return values from 0-100 and Complete, or Throw</param>\n        /// <returns>Completion</returns>\n        Task FullInstall(bool silentInstall, Action<int> progress = null);\n\n        /// <summary>\n        /// Completely uninstalls the targeted app\n        /// </summary>\n        /// <returns>Completion</returns>\n        Task FullUninstall();\n\n        /// <summary>\n        /// Gets the currently installed version of the given executable, or if\n        /// not given, the currently running assembly\n        /// </summary>\n        /// <param name=\"executable\">The executable to check, or null for this \n        /// executable</param>\n        /// <returns>The running version, or null if this is not a Squirrel\n        /// installed app (i.e. you're running from VS)</returns>\n        SemanticVersion CurrentlyInstalledVersion(string executable = null);\n\n        /// <summary>\n        /// Creates an entry in Programs and Features based on the currently \n        /// applied package\n        /// </summary>\n        /// <param name=\"uninstallCmd\">The command to run to uninstall, usually update.exe --uninstall</param>\n        /// <param name=\"quietSwitch\">The switch for silent uninstall, usually --silent</param>\n        /// <returns>The registry key that was created</returns>\n        Task<RegistryKey> CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch);\n\n        /// <summary>\n        /// Creates an entry in Programs and Features based on the currently \n        /// applied package. Uses the built-in Update.exe to handle uninstall.\n        /// </summary>\n        /// <returns>The registry key that was created</returns>\n        Task<RegistryKey> CreateUninstallerRegistryEntry();\n\n        /// <summary>\n        /// Removes the entry in Programs and Features created via \n        /// CreateUninstallerRegistryEntry\n        /// </summary>\n        void RemoveUninstallerRegistryEntry();\n\n        /// <summary>\n        /// Create a shortcut on the Desktop / Start Menu for the given \n        /// executable. Metadata from the currently installed NuGet package \n        /// and information from the Version Header of the EXE will be used\n        /// to construct the shortcut folder / name.\n        /// </summary>\n        /// <param name=\"exeName\">The name of the executable, relative to the \n        /// app install directory.</param>\n        /// <param name=\"locations\">The locations to install the shortcut</param>\n        /// <param name=\"updateOnly\">Set to false during initial install, true \n        /// during app update.</param>\n        /// <param name=\"programArguments\">The arguments to code into the shortcut</param>\n        /// <param name=\"icon\">The shortcut icon</param>\n        void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly, string programArguments, string icon);\n\n        /// <summary>\n        /// Removes shortcuts created by CreateShortcutsForExecutable\n        /// </summary>\n        /// <param name=\"exeName\">The name of the executable, relative to the\n        /// app install directory.</param>\n        /// <param name=\"locations\">The locations to install the shortcut</param>\n        void RemoveShortcutsForExecutable(string exeName, ShortcutLocation locations);\n    }\n\n    public static class EasyModeMixin\n    {\n        public static async Task<ReleaseEntry> UpdateApp(this IUpdateManager This, Action<int> progress = null)\n        {\n            progress = progress ?? (_ => {});\n            This.Log().Info(\"Starting automatic update\");\n\n            bool ignoreDeltaUpdates = false;\n\n        retry:\n            var updateInfo = default(UpdateInfo);\n\n            try {\n                updateInfo = await This.ErrorIfThrows(() => This.CheckForUpdate(ignoreDeltaUpdates, x => progress(x / 3)),\n                    \"Failed to check for updates\");\n\n                await This.ErrorIfThrows(() =>\n                    This.DownloadReleases(updateInfo.ReleasesToApply, x => progress(x / 3 + 33)),\n                    \"Failed to download updates\");\n\n                await This.ErrorIfThrows(() =>\n                    This.ApplyReleases(updateInfo, x => progress(x / 3 + 66)),\n                    \"Failed to apply updates\");\n\n                await This.ErrorIfThrows(() => \n                    This.CreateUninstallerRegistryEntry(),\n                    \"Failed to set up uninstaller\");\n            } catch {\n                if (ignoreDeltaUpdates == false) {\n                    ignoreDeltaUpdates = true;\n                    goto retry;\n                }\n\n                throw;\n            }\n\n            return updateInfo.ReleasesToApply.Any() ?\n                updateInfo.ReleasesToApply.MaxBy(x => x.Version).Last() :\n                default(ReleaseEntry);\n        }\n\n        public static void CreateShortcutForThisExe(this IUpdateManager This)\n        {\n            string entrypoint = Assembly.GetEntryAssembly().Location;\n            if (String.Equals(Path.GetExtension(entrypoint), \".dll\", StringComparison.OrdinalIgnoreCase)) {\n                // This happens in .NET Core apps. A shortcut to a .dll doesn't work, so replace with the .exe.\n                string candidateExe = Path.Combine(Path.GetDirectoryName(entrypoint), Path.GetFileNameWithoutExtension(entrypoint)) + \".exe\";\n                if (File.Exists(candidateExe)) {\n                    entrypoint = candidateExe;\n                }\n            }\n\n            This.CreateShortcutsForExecutable(\n                Path.GetFileName(entrypoint),\n                ShortcutLocation.Desktop | ShortcutLocation.StartMenu, \n                Environment.CommandLine.Contains(\"squirrel-install\") == false,\n                null, null);\n        }\n\n        public static void RemoveShortcutForThisExe(this IUpdateManager This)\n        {\n            This.RemoveShortcutsForExecutable(\n                Path.GetFileName(Assembly.GetEntryAssembly().Location),\n                ShortcutLocation.Desktop | ShortcutLocation.StartMenu);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/MarkdownSharp.cs",
    "content": "﻿/*\n * MarkdownSharp\n * -------------\n * a C# Markdown processor\n *\n * Markdown is a text-to-HTML conversion tool for web writers\n * Copyright (c) 2004 John Gruber\n * http://daringfireball.net/projects/markdown/\n *\n * Markdown.NET\n * Copyright (c) 2004-2009 Milan Negovan\n * http://www.aspnetresources.com\n * http://aspnetresources.com/blog/markdown_announced.aspx\n *\n * MarkdownSharp\n * Copyright (c) 2009-2011 Jeff Atwood\n * http://stackoverflow.com\n * http://www.codinghorror.com/blog/\n * http://code.google.com/p/markdownsharp/\n *\n * History: Milan ported the Markdown processor to C#. He granted license to me so I can open source it\n * and let the community contribute to and improve MarkdownSharp.\n *\n */\n\n#region Copyright and license\n\n/*\n\nCopyright (c) 2009 - 2010 Jeff Atwood\n\nhttp://www.opensource.org/licenses/mit-license.php\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\nCopyright (c) 2003-2004 John Gruber\n<http://daringfireball.net/>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n* Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in the\n  documentation and/or other materials provided with the distribution.\n\n* Neither the name \"Markdown\" nor the names of its contributors may\n  be used to endorse or promote products derived from this software\n  without specific prior written permission.\n\nThis software is provided by the copyright holders and contributors \"as\nis\" and any express or implied warranties, including, but not limited\nto, the implied warranties of merchantability and fitness for a\nparticular purpose are disclaimed. In no event shall the copyright owner\nor contributors be liable for any direct, indirect, incidental, special,\nexemplary, or consequential damages (including, but not limited to,\nprocurement of substitute goods or services; loss of use, data, or\nprofits; or business interruption) however caused and on any theory of\nliability, whether in contract, strict liability, or tort (including\nnegligence or otherwise) arising in any way out of the use of this\nsoftware, even if advised of the possibility of such damage.\n*/\n\n#endregion\n\nusing System;\nusing System.Collections.Generic;\nusing System.Configuration;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace MarkdownSharp\n{\n\n    public class MarkdownOptions\n    {\n        /// <summary>\n        /// when true, (most) bare plain URLs are auto-hyperlinked\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool AutoHyperlink { get; set; }\n        /// <summary>\n        /// when true, RETURN becomes a literal newline\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool AutoNewlines { get; set; }\n        /// <summary>\n        /// use \">\" for HTML output, or \" />\" for XHTML output\n        /// </summary>\n        public string EmptyElementSuffix { get; set; }\n        /// <summary>\n        /// when true, problematic URL characters like [, ], (, and so forth will be encoded\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool EncodeProblemUrlCharacters { get; set; }\n        /// <summary>\n        /// when false, email addresses will never be auto-linked\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool LinkEmails { get; set; }\n        /// <summary>\n        /// when true, bold and italic require non-word characters on either side\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool StrictBoldItalic { get; set; }\n    }\n\n\n    /// <summary>\n    /// Markdown is a text-to-HTML conversion tool for web writers.\n    /// Markdown allows you to write using an easy-to-read, easy-to-write plain text format,\n    /// then convert it to structurally valid XHTML (or HTML).\n    /// </summary>\n    public class Markdown\n    {\n        private const string _version = \"1.13\";\n\n        #region Constructors and Options\n\n        /// <summary>\n        /// Create a new Markdown instance using default options\n        /// </summary>\n        public Markdown()\n        {\n        }\n\n        /// <summary>\n        /// Create a new Markdown instance and set the options from the MarkdownOptions object.\n        /// </summary>\n        public Markdown(MarkdownOptions options)\n        {\n            _autoHyperlink = options.AutoHyperlink;\n            _autoNewlines = options.AutoNewlines;\n            _emptyElementSuffix = options.EmptyElementSuffix;\n            _encodeProblemUrlCharacters = options.EncodeProblemUrlCharacters;\n            _linkEmails = options.LinkEmails;\n            _strictBoldItalic = options.StrictBoldItalic;\n        }\n\n\n        /// <summary>\n        /// use \">\" for HTML output, or \" />\" for XHTML output\n        /// </summary>\n        public string EmptyElementSuffix\n        {\n            get { return _emptyElementSuffix; }\n            set { _emptyElementSuffix = value; }\n        }\n        private string _emptyElementSuffix = \" />\";\n\n        /// <summary>\n        /// when false, email addresses will never be auto-linked\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool LinkEmails\n        {\n            get { return _linkEmails; }\n            set { _linkEmails = value; }\n        }\n        private bool _linkEmails = true;\n\n        /// <summary>\n        /// when true, bold and italic require non-word characters on either side\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool StrictBoldItalic\n        {\n            get { return _strictBoldItalic; }\n            set { _strictBoldItalic = value; }\n        }\n        private bool _strictBoldItalic = false;\n\n        /// <summary>\n        /// when true, RETURN becomes a literal newline\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool AutoNewLines\n        {\n            get { return _autoNewlines; }\n            set { _autoNewlines = value; }\n        }\n        private bool _autoNewlines = false;\n\n        /// <summary>\n        /// when true, (most) bare plain URLs are auto-hyperlinked\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool AutoHyperlink\n        {\n            get { return _autoHyperlink; }\n            set { _autoHyperlink = value; }\n        }\n        private bool _autoHyperlink = false;\n\n        /// <summary>\n        /// when true, problematic URL characters like [, ], (, and so forth will be encoded\n        /// WARNING: this is a significant deviation from the markdown spec\n        /// </summary>\n        public bool EncodeProblemUrlCharacters\n        {\n            get { return _encodeProblemUrlCharacters; }\n            set { _encodeProblemUrlCharacters = value; }\n        }\n        private bool _encodeProblemUrlCharacters = false;\n\n        #endregion\n\n        private enum TokenType { Text, Tag }\n\n        private struct Token\n        {\n            public Token(TokenType type, string value)\n            {\n                this.Type = type;\n                this.Value = value;\n            }\n            public TokenType Type;\n            public string Value;\n        }\n\n        /// <summary>\n        /// maximum nested depth of [] and () supported by the transform; implementation detail\n        /// </summary>\n        private const int _nestDepth = 6;\n\n        /// <summary>\n        /// Tabs are automatically converted to spaces as part of the transform\n        /// this constant determines how \"wide\" those tabs become in spaces\n        /// </summary>\n        private const int _tabWidth = 4;\n\n        private const string _markerUL = @\"[*+-]\";\n        private const string _markerOL = @\"\\d+[.]\";\n\n        private static readonly Dictionary<string, string> _escapeTable;\n        private static readonly Dictionary<string, string> _invertedEscapeTable;\n        private static readonly Dictionary<string, string> _backslashEscapeTable;\n\n        private readonly Dictionary<string, string> _urls = new Dictionary<string, string>();\n        private readonly Dictionary<string, string> _titles = new Dictionary<string, string>();\n        private readonly Dictionary<string, string> _htmlBlocks = new Dictionary<string, string>();\n\n        private int _listLevel;\n        private static string AutoLinkPreventionMarker = \"\\x1AP\"; // temporarily replaces \"://\" where auto-linking shouldn't happen;\n\n        /// <summary>\n        /// In the static constuctor we'll initialize what stays the same across all transforms.\n        /// </summary>\n        static Markdown()\n        {\n            // Table of hash values for escaped characters:\n            _escapeTable = new Dictionary<string, string>();\n            _invertedEscapeTable = new Dictionary<string, string>();\n            // Table of hash value for backslash escaped characters:\n            _backslashEscapeTable = new Dictionary<string, string>();\n\n            string backslashPattern = \"\";\n\n            foreach (char c in @\"\\`*_{}[]()>#+-.!/\")\n            {\n                string key = c.ToString();\n                string hash = GetHashKey(key, isHtmlBlock: false);\n                _escapeTable.Add(key, hash);\n                _invertedEscapeTable.Add(hash, key);\n                _backslashEscapeTable.Add(@\"\\\" + key, hash);\n                backslashPattern += Regex.Escape(@\"\\\" + key) + \"|\";\n            }\n\n            _backslashEscapes = new Regex(backslashPattern.Substring(0, backslashPattern.Length - 1), RegexOptions.Compiled);\n        }\n\n        /// <summary>\n        /// current version of MarkdownSharp;\n        /// see http://code.google.com/p/markdownsharp/ for the latest code or to contribute\n        /// </summary>\n        public string Version\n        {\n            get { return _version; }\n        }\n\n        /// <summary>\n        /// Transforms the provided Markdown-formatted text to HTML;\n        /// see http://en.wikipedia.org/wiki/Markdown\n        /// </summary>\n        /// <remarks>\n        /// The order in which other subs are called here is\n        /// essential. Link and image substitutions need to happen before\n        /// EscapeSpecialChars(), so that any *'s or _'s in the a\n        /// and img tags get encoded.\n        /// </remarks>\n        public string Transform(string text)\n        {\n            if (String.IsNullOrEmpty(text)) return \"\";\n\n            Setup();\n\n            text = Normalize(text);\n\n            text = HashHTMLBlocks(text);\n            text = StripLinkDefinitions(text);\n            text = RunBlockGamut(text);\n            text = Unescape(text);\n\n            Cleanup();\n\n            return text + \"\\n\";\n        }\n\n\n        /// <summary>\n        /// Perform transformations that form block-level tags like paragraphs, headers, and list items.\n        /// </summary>\n        private string RunBlockGamut(string text, bool unhash = true)\n        {\n            text = DoHeaders(text);\n            text = DoHorizontalRules(text);\n            text = DoLists(text);\n            text = DoCodeBlocks(text);\n            text = DoBlockQuotes(text);\n\n            // We already ran HashHTMLBlocks() before, in Markdown(), but that\n            // was to escape raw HTML in the original Markdown source. This time,\n            // we're escaping the markup we've just created, so that we don't wrap\n            // <p> tags around block-level tags.\n            text = HashHTMLBlocks(text);\n\n            text = FormParagraphs(text, unhash: unhash);\n\n            return text;\n        }\n\n\n        /// <summary>\n        /// Perform transformations that occur *within* block-level tags like paragraphs, headers, and list items.\n        /// </summary>\n        private string RunSpanGamut(string text)\n        {\n            text = DoCodeSpans(text);\n            text = EscapeSpecialCharsWithinTagAttributes(text);\n            text = EscapeBackslashes(text);\n\n            // Images must come first, because ![foo][f] looks like an anchor.\n            text = DoImages(text);\n            text = DoAnchors(text);\n\n            // Must come after DoAnchors(), because you can use < and >\n            // delimiters in inline links like [this](<url>).\n            text = DoAutoLinks(text);\n\n            text = text.Replace(AutoLinkPreventionMarker, \"://\");\n\n            text = EncodeAmpsAndAngles(text);\n            text = DoItalicsAndBold(text);\n            text = DoHardBreaks(text);\n\n            return text;\n        }\n\n        private static Regex _newlinesLeadingTrailing = new Regex(@\"^\\n+|\\n+\\z\", RegexOptions.Compiled);\n        private static Regex _newlinesMultiple = new Regex(@\"\\n{2,}\", RegexOptions.Compiled);\n        private static Regex _leadingWhitespace = new Regex(@\"^[ ]*\", RegexOptions.Compiled);\n\n        private static Regex _htmlBlockHash = new Regex(\"\\x1AH\\\\d+H\", RegexOptions.Compiled);\n\n        /// <summary>\n        /// splits on two or more newlines, to form \"paragraphs\";\n        /// each paragraph is then unhashed (if it is a hash and unhashing isn't turned off) or wrapped in HTML p tag\n        /// </summary>\n        private string FormParagraphs(string text, bool unhash = true)\n        {\n            // split on two or more newlines\n            string[] grafs = _newlinesMultiple.Split(_newlinesLeadingTrailing.Replace(text, \"\"));\n\n            for (int i = 0; i < grafs.Length; i++)\n            {\n                if (grafs[i].StartsWith(\"\\x1AH\"))\n                {\n                    // unhashify HTML blocks\n                    if (unhash)\n                    {\n                        int sanityCheck = 50; // just for safety, guard against an infinite loop\n                        bool keepGoing = true; // as long as replacements where made, keep going\n                        while (keepGoing && sanityCheck > 0)\n                        {\n                            keepGoing = false;\n                            grafs[i] = _htmlBlockHash.Replace(grafs[i], match =>\n                            {\n                                keepGoing = true;\n                                return _htmlBlocks[match.Value];\n                            });\n                            sanityCheck--;\n                        }\n                        /* if (keepGoing)\n                        {\n                            // Logging of an infinite loop goes here.\n                            // If such a thing should happen, please open a new issue on http://code.google.com/p/markdownsharp/\n                            // with the input that caused it.\n                        }*/\n                    }\n                }\n                else\n                {\n                    // do span level processing inside the block, then wrap result in <p> tags\n                    grafs[i] = _leadingWhitespace.Replace(RunSpanGamut(grafs[i]), \"<p>\") + \"</p>\";\n                }\n            }\n\n            return string.Join(\"\\n\\n\", grafs);\n        }\n\n\n        private void Setup()\n        {\n            // Clear the global hashes. If we don't clear these, you get conflicts\n            // from other articles when generating a page which contains more than\n            // one article (e.g. an index page that shows the N most recent\n            // articles):\n            _urls.Clear();\n            _titles.Clear();\n            _htmlBlocks.Clear();\n            _listLevel = 0;\n        }\n\n        private void Cleanup()\n        {\n            Setup();\n        }\n\n        private static string _nestedBracketsPattern;\n\n        /// <summary>\n        /// Reusable pattern to match balanced [brackets]. See Friedl's\n        /// \"Mastering Regular Expressions\", 2nd Ed., pp. 328-331.\n        /// </summary>\n        private static string GetNestedBracketsPattern()\n        {\n            // in other words [this] and [this[also]] and [this[also[too]]]\n            // up to _nestDepth\n            if (_nestedBracketsPattern == null)\n                _nestedBracketsPattern =\n                    RepeatString(@\"\n                    (?>              # Atomic matching\n                       [^\\[\\]]+      # Anything other than brackets\n                     |\n                       \\[\n                           \", _nestDepth) + RepeatString(\n                    @\" \\]\n                    )*\"\n                    , _nestDepth);\n            return _nestedBracketsPattern;\n        }\n\n        private static string _nestedParensPattern;\n\n        /// <summary>\n        /// Reusable pattern to match balanced (parens). See Friedl's\n        /// \"Mastering Regular Expressions\", 2nd Ed., pp. 328-331.\n        /// </summary>\n        private static string GetNestedParensPattern()\n        {\n            // in other words (this) and (this(also)) and (this(also(too)))\n            // up to _nestDepth\n            if (_nestedParensPattern == null)\n                _nestedParensPattern =\n                    RepeatString(@\"\n                    (?>              # Atomic matching\n                       [^()\\s]+      # Anything other than parens or whitespace\n                     |\n                       \\(\n                           \", _nestDepth) + RepeatString(\n                    @\" \\)\n                    )*\"\n                    , _nestDepth);\n            return _nestedParensPattern;\n        }\n\n        private static Regex _linkDef = new Regex(string.Format(@\"\n                        ^[ ]{{0,{0}}}\\[([^\\[\\]]+)\\]:  # id = $1\n                          [ ]*\n                          \\n?                   # maybe *one* newline\n                          [ ]*\n                        <?(\\S+?)>?              # url = $2\n                          [ ]*\n                          \\n?                   # maybe one newline\n                          [ ]*\n                        (?:\n                            (?<=\\s)             # lookbehind for whitespace\n                            [\"\"(]\n                            (.+?)               # title = $3\n                            [\"\")]\n                            [ ]*\n                        )?                      # title is optional\n                        (?:\\n+|\\Z)\", _tabWidth - 1), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Strips link definitions from text, stores the URLs and titles in hash references.\n        /// </summary>\n        /// <remarks>\n        /// ^[id]: url \"optional title\"\n        /// </remarks>\n        private string StripLinkDefinitions(string text)\n        {\n            return _linkDef.Replace(text, new MatchEvaluator(LinkEvaluator));\n        }\n\n        private string LinkEvaluator(Match match)\n        {\n            string linkID = match.Groups[1].Value.ToLowerInvariant();\n            _urls[linkID] = EncodeAmpsAndAngles(match.Groups[2].Value);\n\n            if (match.Groups[3] != null && match.Groups[3].Length > 0)\n                _titles[linkID] = match.Groups[3].Value.Replace(\"\\\"\", \"&quot;\");\n\n            return \"\";\n        }\n\n        // compiling this monster regex results in worse performance. trust me.\n        private static Regex _blocksHtml = new Regex(GetBlockPattern(), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);\n\n\n        /// <summary>\n        /// derived pretty much verbatim from PHP Markdown\n        /// </summary>\n        private static string GetBlockPattern()\n        {\n\n            // Hashify HTML blocks:\n            // We only want to do this for block-level HTML tags, such as headers,\n            // lists, and tables. That's because we still want to wrap <p>s around\n            // \"paragraphs\" that are wrapped in non-block-level tags, such as anchors,\n            // phrase emphasis, and spans. The list of tags we're looking for is\n            // hard-coded:\n            //\n            // *  List \"a\" is made of tags which can be both inline or block-level.\n            //    These will be treated block-level when the start tag is alone on\n            //    its line, otherwise they're not matched here and will be taken as\n            //    inline later.\n            // *  List \"b\" is made of tags which are always block-level;\n            //\n            string blockTagsA = \"ins|del\";\n            string blockTagsB = \"p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|script|noscript|form|fieldset|iframe|math\";\n\n            // Regular expression for the content of a block tag.\n            string attr = @\"\n            (?>﻿  ﻿  ﻿  ﻿              # optional tag attributes\n              \\s﻿  ﻿  ﻿              # starts with whitespace\n              (?>\n                [^>\"\"/]+﻿              # text outside quotes\n              |\n                /+(?!>)﻿  ﻿              # slash not followed by >\n              |\n                \"\"[^\"\"]*\"\"﻿  ﻿          # text inside double quotes (tolerate >)\n              |\n                '[^']*'﻿                  # text inside single quotes (tolerate >)\n              )*\n            )?﻿\n            \";\n\n            string content = RepeatString(@\"\n                (?>\n                  [^<]+﻿  ﻿  ﻿          # content without tag\n                |\n                  <\\2﻿  ﻿  ﻿          # nested opening tag\n                    \" + attr + @\"       # attributes\n                  (?>\n                      />\n                  |\n                      >\", _nestDepth) +   // end of opening tag\n                      \".*?\" +             // last level nested tag content\n            RepeatString(@\"\n                      </\\2\\s*>﻿          # closing nested tag\n                  )\n                  |﻿  ﻿  ﻿  ﻿\n                  <(?!/\\2\\s*>           # other tags with a different name\n                  )\n                )*\", _nestDepth);\n\n            string content2 = content.Replace(@\"\\2\", @\"\\3\");\n\n            // First, look for nested blocks, e.g.:\n            // ﻿  <div>\n            // ﻿  ﻿  <div>\n            // ﻿  ﻿  tags for inner block must be indented.\n            // ﻿  ﻿  </div>\n            // ﻿  </div>\n            //\n            // The outermost tags must start at the left margin for this to match, and\n            // the inner nested divs must be indented.\n            // We need to do this before the next, more liberal match, because the next\n            // match will start at the first `<div>` and stop at the first `</div>`.\n            string pattern = @\"\n            (?>\n                  (?>\n                    (?<=\\n)     # Starting at the beginning of a line\n                    |           # or\n                    \\A\\n?       # the beginning of the doc\n                  )\n                  (             # save in $1\n\n                    # Match from `\\n<tag>` to `</tag>\\n`, handling nested tags\n                    # in between.\n\n                        <($block_tags_b_re)   # start tag = $2\n                        $attr>                # attributes followed by > and \\n\n                        $content              # content, support nesting\n                        </\\2>                 # the matching end tag\n                        [ ]*                  # trailing spaces\n                        (?=\\n+|\\Z)            # followed by a newline or end of document\n\n                  | # Special version for tags of group a.\n\n                        <($block_tags_a_re)   # start tag = $3\n                        $attr>[ ]*\\n          # attributes followed by >\n                        $content2             # content, support nesting\n                        </\\3>                 # the matching end tag\n                        [ ]*                  # trailing spaces\n                        (?=\\n+|\\Z)            # followed by a newline or end of document\n\n                  | # Special case just for <hr />. It was easier to make a special\n                    # case than to make the other regex more complicated.\n\n                        [ ]{0,$less_than_tab}\n                        <hr\n                        $attr                 # attributes\n                        /?>                   # the matching end tag\n                        [ ]*\n                        (?=\\n{2,}|\\Z)         # followed by a blank line or end of document\n\n                  | # Special case for standalone HTML comments:\n\n                      (?<=\\n\\n|\\A)            # preceded by a blank line or start of document\n                      [ ]{0,$less_than_tab}\n                      (?s:\n                        <!--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)-->\n                      )\n                      [ ]*\n                      (?=\\n{2,}|\\Z)            # followed by a blank line or end of document\n\n                  | # PHP and ASP-style processor instructions (<? and <%)\n\n                      [ ]{0,$less_than_tab}\n                      (?s:\n                        <([?%])                # $4\n                        .*?\n                        \\4>\n                      )\n                      [ ]*\n                      (?=\\n{2,}|\\Z)            # followed by a blank line or end of document\n\n                  )\n            )\";\n\n            pattern = pattern.Replace(\"$less_than_tab\", (_tabWidth - 1).ToString());\n            pattern = pattern.Replace(\"$block_tags_b_re\", blockTagsB);\n            pattern = pattern.Replace(\"$block_tags_a_re\", blockTagsA);\n            pattern = pattern.Replace(\"$attr\", attr);\n            pattern = pattern.Replace(\"$content2\", content2);\n            pattern = pattern.Replace(\"$content\", content);\n\n            return pattern;\n        }\n\n        /// <summary>\n        /// replaces any block-level HTML blocks with hash entries\n        /// </summary>\n        private string HashHTMLBlocks(string text)\n        {\n            return _blocksHtml.Replace(text, new MatchEvaluator(HtmlEvaluator));\n        }\n\n        private string HtmlEvaluator(Match match)\n        {\n            string text = match.Groups[1].Value;\n            string key = GetHashKey(text, isHtmlBlock: true);\n            _htmlBlocks[key] = text;\n\n            return string.Concat(\"\\n\\n\", key, \"\\n\\n\");\n        }\n\n        private static string GetHashKey(string s, bool isHtmlBlock)\n        {\n            var delim = isHtmlBlock ? 'H' : 'E';\n            return \"\\x1A\" + delim +  Math.Abs(s.GetHashCode()).ToString() + delim;\n        }\n\n        private static Regex _htmlTokens = new Regex(@\"\n            (<!--(?:|(?:[^>-]|-[^>])(?:[^-]|-[^-])*)-->)|        # match <!-- foo -->\n            (<\\?.*?\\?>)|                 # match <?foo?> \" +\n            RepeatString(@\"\n            (<[A-Za-z\\/!$](?:[^<>]|\", _nestDepth) + RepeatString(@\")*>)\", _nestDepth) +\n                                       \" # match <tag> and </tag>\",\n            RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// returns an array of HTML tokens comprising the input string. Each token is\n        /// either a tag (possibly with nested, tags contained therein, such\n        /// as &lt;a href=\"&lt;MTFoo&gt;\"&gt;, or a run of text between tags. Each element of the\n        /// array is a two-element array; the first is either 'tag' or 'text'; the second is\n        /// the actual value.\n        /// </summary>\n        private List<Token> TokenizeHTML(string text)\n        {\n            int pos = 0;\n            int tagStart = 0;\n            var tokens = new List<Token>();\n\n            // this regex is derived from the _tokenize() subroutine in Brad Choate's MTRegex plugin.\n            // http://www.bradchoate.com/past/mtregex.php\n            foreach (Match m in _htmlTokens.Matches(text))\n            {\n                tagStart = m.Index;\n\n                if (pos < tagStart)\n                    tokens.Add(new Token(TokenType.Text, text.Substring(pos, tagStart - pos)));\n\n                tokens.Add(new Token(TokenType.Tag, m.Value));\n                pos = tagStart + m.Length;\n            }\n\n            if (pos < text.Length)\n                tokens.Add(new Token(TokenType.Text, text.Substring(pos, text.Length - pos)));\n\n            return tokens;\n        }\n\n\n        private static Regex _anchorRef = new Regex(string.Format(@\"\n            (                               # wrap whole match in $1\n                \\[\n                    ({0})                   # link text = $2\n                \\]\n\n                [ ]?                        # one optional space\n                (?:\\n[ ]*)?                 # one optional newline followed by spaces\n\n                \\[\n                    (.*?)                   # id = $3\n                \\]\n            )\", GetNestedBracketsPattern()), RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        private static Regex _anchorInline = new Regex(string.Format(@\"\n                (                           # wrap whole match in $1\n                    \\[\n                        ({0})               # link text = $2\n                    \\]\n                    \\(                      # literal paren\n                        [ ]*\n                        ({1})               # href = $3\n                        [ ]*\n                        (                   # $4\n                        (['\"\"])           # quote char = $5\n                        (.*?)               # title = $6\n                        \\5                  # matching quote\n                        [ ]*                # ignore any spaces between closing quote and )\n                        )?                  # title is optional\n                    \\)\n                )\", GetNestedBracketsPattern(), GetNestedParensPattern()),\n                  RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        private static Regex _anchorRefShortcut = new Regex(@\"\n            (                               # wrap whole match in $1\n              \\[\n                 ([^\\[\\]]+)                 # link text = $2; can't contain [ or ]\n              \\]\n            )\", RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown link shortcuts into HTML anchor tags\n        /// </summary>\n        /// <remarks>\n        /// [link text](url \"title\")\n        /// [link text][id]\n        /// [id]\n        /// </remarks>\n        private string DoAnchors(string text)\n        {\n            // First, handle reference-style links: [link text] [id]\n            text = _anchorRef.Replace(text, new MatchEvaluator(AnchorRefEvaluator));\n\n            // Next, inline-style links: [link text](url \"optional title\") or [link text](url \"optional title\")\n            text = _anchorInline.Replace(text, new MatchEvaluator(AnchorInlineEvaluator));\n\n            //  Last, handle reference-style shortcuts: [link text]\n            //  These must come last in case you've also got [link test][1]\n            //  or [link test](/foo)\n            text = _anchorRefShortcut.Replace(text, new MatchEvaluator(AnchorRefShortcutEvaluator));\n            return text;\n        }\n\n        private string SaveFromAutoLinking(string s)\n        {\n            return s.Replace(\"://\", AutoLinkPreventionMarker);\n        }\n\n        private string AnchorRefEvaluator(Match match)\n        {\n            string wholeMatch = match.Groups[1].Value;\n            string linkText = SaveFromAutoLinking(match.Groups[2].Value);\n            string linkID = match.Groups[3].Value.ToLowerInvariant();\n\n            string result;\n\n            // for shortcut links like [this][].\n            if (linkID == \"\")\n                linkID = linkText.ToLowerInvariant();\n\n            if (_urls.ContainsKey(linkID))\n            {\n                string url = _urls[linkID];\n\n                url = EncodeProblemUrlChars(url);\n                url = EscapeBoldItalic(url);\n                result = \"<a href=\\\"\" + url + \"\\\"\";\n\n                if (_titles.ContainsKey(linkID))\n                {\n                    string title = AttributeEncode(_titles[linkID]);\n                    title = AttributeEncode(EscapeBoldItalic(title));\n                    result += \" title=\\\"\" + title + \"\\\"\";\n                }\n\n                result += \">\" + linkText + \"</a>\";\n            }\n            else\n                result = wholeMatch;\n\n            return result;\n        }\n\n        private string AnchorRefShortcutEvaluator(Match match)\n        {\n            string wholeMatch = match.Groups[1].Value;\n            string linkText = SaveFromAutoLinking(match.Groups[2].Value);\n            string linkID = Regex.Replace(linkText.ToLowerInvariant(), @\"[ ]*\\n[ ]*\", \" \");  // lower case and remove newlines / extra spaces\n\n            string result;\n\n            if (_urls.ContainsKey(linkID))\n            {\n                string url = _urls[linkID];\n\n                url = EncodeProblemUrlChars(url);\n                url = EscapeBoldItalic(url);\n                result = \"<a href=\\\"\" + url + \"\\\"\";\n\n                if (_titles.ContainsKey(linkID))\n                {\n                    string title = AttributeEncode(_titles[linkID]);\n                    title = EscapeBoldItalic(title);\n                    result += \" title=\\\"\" + title + \"\\\"\";\n                }\n\n                result += \">\" + linkText + \"</a>\";\n            }\n            else\n                result = wholeMatch;\n\n            return result;\n        }\n\n\n        private string AnchorInlineEvaluator(Match match)\n        {\n            string linkText = SaveFromAutoLinking(match.Groups[2].Value);\n            string url = match.Groups[3].Value;\n            string title = match.Groups[6].Value;\n            string result;\n\n            url = EncodeProblemUrlChars(url);\n            url = EscapeBoldItalic(url);\n            if (url.StartsWith(\"<\") && url.EndsWith(\">\"))\n                url = url.Substring(1, url.Length - 2); // remove <>'s surrounding URL, if present\n\n            result = string.Format(\"<a href=\\\"{0}\\\"\", url);\n\n            if (!String.IsNullOrEmpty(title))\n            {\n                title = AttributeEncode(title);\n                title = EscapeBoldItalic(title);\n                result += string.Format(\" title=\\\"{0}\\\"\", title);\n            }\n\n            result += string.Format(\">{0}</a>\", linkText);\n            return result;\n        }\n\n        private static Regex _imagesRef = new Regex(@\"\n                    (               # wrap whole match in $1\n                    !\\[\n                        (.*?)       # alt text = $2\n                    \\]\n\n                    [ ]?            # one optional space\n                    (?:\\n[ ]*)?     # one optional newline followed by spaces\n\n                    \\[\n                        (.*?)       # id = $3\n                    \\]\n\n                    )\", RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled);\n\n        private static Regex _imagesInline = new Regex(String.Format(@\"\n              (                     # wrap whole match in $1\n                !\\[\n                    (.*?)           # alt text = $2\n                \\]\n                \\s?                 # one optional whitespace character\n                \\(                  # literal paren\n                    [ ]*\n                    ({0})           # href = $3\n                    [ ]*\n                    (               # $4\n                    (['\"\"])       # quote char = $5\n                    (.*?)           # title = $6\n                    \\5              # matching quote\n                    [ ]*\n                    )?              # title is optional\n                \\)\n              )\", GetNestedParensPattern()),\n                  RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown image shortcuts into HTML img tags.\n        /// </summary>\n        /// <remarks>\n        /// ![alt text][id]\n        /// ![alt text](url \"optional title\")\n        /// </remarks>\n        private string DoImages(string text)\n        {\n            // First, handle reference-style labeled images: ![alt text][id]\n            text = _imagesRef.Replace(text, new MatchEvaluator(ImageReferenceEvaluator));\n\n            // Next, handle inline images:  ![alt text](url \"optional title\")\n            // Don't forget: encode * and _\n            text = _imagesInline.Replace(text, new MatchEvaluator(ImageInlineEvaluator));\n\n            return text;\n        }\n\n        // This prevents the creation of horribly broken HTML when some syntax ambiguities\n        // collide. It likely still doesn't do what the user meant, but at least we're not\n        // outputting garbage.\n        private string EscapeImageAltText(string s)\n        {\n            s = EscapeBoldItalic(s);\n            s = Regex.Replace(s, @\"[\\[\\]()]\", m => _escapeTable[m.ToString()]);\n            return s;\n        }\n\n        private string ImageReferenceEvaluator(Match match)\n        {\n            string wholeMatch = match.Groups[1].Value;\n            string altText = match.Groups[2].Value;\n            string linkID = match.Groups[3].Value.ToLowerInvariant();\n\n            // for shortcut links like ![this][].\n            if (linkID == \"\")\n                linkID = altText.ToLowerInvariant();\n\n            if (_urls.ContainsKey(linkID))\n            {\n                string url = _urls[linkID];\n                string title = null;\n\n                if (_titles.ContainsKey(linkID))\n                    title = _titles[linkID];\n\n                return ImageTag(url, altText, title);\n            }\n            else\n            {\n                // If there's no such link ID, leave intact:\n                return wholeMatch;\n            }\n        }\n\n        private string ImageInlineEvaluator(Match match)\n        {\n            string alt = match.Groups[2].Value;\n            string url = match.Groups[3].Value;\n            string title = match.Groups[6].Value;\n\n            if (url.StartsWith(\"<\") && url.EndsWith(\">\"))\n                url = url.Substring(1, url.Length - 2);    // Remove <>'s surrounding URL, if present\n\n            return ImageTag(url, alt, title);\n        }\n\n        private string ImageTag(string url, string altText, string title)\n        {\n            altText = EscapeImageAltText(AttributeEncode(altText));\n            url = EncodeProblemUrlChars(url);\n            url = EscapeBoldItalic(url);\n            var result = string.Format(\"<img src=\\\"{0}\\\" alt=\\\"{1}\\\"\", url, altText);\n            if (!String.IsNullOrEmpty(title))\n            {\n                title = AttributeEncode(EscapeBoldItalic(title));\n                result += string.Format(\" title=\\\"{0}\\\"\", title);\n            }\n            result += _emptyElementSuffix;\n            return result;\n        }\n\n        private static Regex _headerSetext = new Regex(@\"\n                ^(.+?)\n                [ ]*\n                \\n\n                (=+|-+)     # $1 = string of ='s or -'s\n                [ ]*\n                \\n+\",\n            RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        private static Regex _headerAtx = new Regex(@\"\n                ^(\\#{1,6})  # $1 = string of #'s\n                [ ]*\n                (.+?)       # $2 = Header text\n                [ ]*\n                \\#*         # optional closing #'s (not counted)\n                \\n+\",\n            RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown headers into HTML header tags\n        /// </summary>\n        /// <remarks>\n        /// Header 1\n        /// ========\n        ///\n        /// Header 2\n        /// --------\n        ///\n        /// # Header 1\n        /// ## Header 2\n        /// ## Header 2 with closing hashes ##\n        /// ...\n        /// ###### Header 6\n        /// </remarks>\n        private string DoHeaders(string text)\n        {\n            text = _headerSetext.Replace(text, new MatchEvaluator(SetextHeaderEvaluator));\n            text = _headerAtx.Replace(text, new MatchEvaluator(AtxHeaderEvaluator));\n            return text;\n        }\n\n        private string SetextHeaderEvaluator(Match match)\n        {\n            string header = match.Groups[1].Value;\n            int level = match.Groups[2].Value.StartsWith(\"=\") ? 1 : 2;\n            return string.Format(\"<h{1}>{0}</h{1}>\\n\\n\", RunSpanGamut(header), level);\n        }\n\n        private string AtxHeaderEvaluator(Match match)\n        {\n            string header = match.Groups[2].Value;\n            int level = match.Groups[1].Value.Length;\n            return string.Format(\"<h{1}>{0}</h{1}>\\n\\n\", RunSpanGamut(header), level);\n        }\n\n\n        private static Regex _horizontalRules = new Regex(@\"\n            ^[ ]{0,3}         # Leading space\n                ([-*_])       # $1: First marker\n                (?>           # Repeated marker group\n                    [ ]{0,2}  # Zero, one, or two spaces.\n                    \\1        # Marker character\n                ){2,}         # Group repeated at least twice\n                [ ]*          # Trailing spaces\n                $             # End of line.\n            \", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown horizontal rules into HTML hr tags\n        /// </summary>\n        /// <remarks>\n        /// ***\n        /// * * *\n        /// ---\n        /// - - -\n        /// </remarks>\n        private string DoHorizontalRules(string text)\n        {\n            return _horizontalRules.Replace(text, \"<hr\" + _emptyElementSuffix + \"\\n\");\n        }\n\n        private static string _wholeList = string.Format(@\"\n            (                               # $1 = whole list\n              (                             # $2\n                [ ]{{0,{1}}}\n                ({0})                       # $3 = first list item marker\n                [ ]+\n              )\n              (?s:.+?)\n              (                             # $4\n                  \\z\n                |\n                  \\n{{2,}}\n                  (?=\\S)\n                  (?!                       # Negative lookahead for another list item marker\n                    [ ]*\n                    {0}[ ]+\n                  )\n              )\n            )\", string.Format(\"(?:{0}|{1})\", _markerUL, _markerOL), _tabWidth - 1);\n\n        private static Regex _listNested = new Regex(@\"^\" + _wholeList,\n            RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        private static Regex _listTopLevel = new Regex(@\"(?:(?<=\\n\\n)|\\A\\n?)\" + _wholeList,\n            RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown lists into HTML ul and ol and li tags\n        /// </summary>\n        private string DoLists(string text, bool isInsideParagraphlessListItem = false)\n        {\n            // We use a different prefix before nested lists than top-level lists.\n            // See extended comment in _ProcessListItems().\n            if (_listLevel > 0)\n                text = _listNested.Replace(text, GetListEvaluator(isInsideParagraphlessListItem));\n            else\n                text = _listTopLevel.Replace(text, GetListEvaluator(false));\n\n            return text;\n        }\n\n        private MatchEvaluator GetListEvaluator(bool isInsideParagraphlessListItem = false)\n        {\n            return new MatchEvaluator(match =>\n                {\n                    string list = match.Groups[1].Value;\n                    string listType = Regex.IsMatch(match.Groups[3].Value, _markerUL) ? \"ul\" : \"ol\";\n                    string result;\n\n                    result = ProcessListItems(list, listType == \"ul\" ? _markerUL : _markerOL, isInsideParagraphlessListItem);\n\n                    result = string.Format(\"<{0}>\\n{1}</{0}>\\n\", listType, result);\n                    return result;\n                });\n        }\n\n        /// <summary>\n        /// Process the contents of a single ordered or unordered list, splitting it\n        /// into individual list items.\n        /// </summary>\n        private string ProcessListItems(string list, string marker, bool isInsideParagraphlessListItem = false)\n        {\n            // The listLevel global keeps track of when we're inside a list.\n            // Each time we enter a list, we increment it; when we leave a list,\n            // we decrement. If it's zero, we're not in a list anymore.\n\n            // We do this because when we're not inside a list, we want to treat\n            // something like this:\n\n            //    I recommend upgrading to version\n            //    8. Oops, now this line is treated\n            //    as a sub-list.\n\n            // As a single paragraph, despite the fact that the second line starts\n            // with a digit-period-space sequence.\n\n            // Whereas when we're inside a list (or sub-list), that line will be\n            // treated as the start of a sub-list. What a kludge, huh? This is\n            // an aspect of Markdown's syntax that's hard to parse perfectly\n            // without resorting to mind-reading. Perhaps the solution is to\n            // change the syntax rules such that sub-lists must start with a\n            // starting cardinal number; e.g. \"1.\" or \"a.\".\n\n            _listLevel++;\n\n            // Trim trailing blank lines:\n            list = Regex.Replace(list, @\"\\n{2,}\\z\", \"\\n\");\n\n            string pattern = string.Format(\n              @\"(^[ ]*)                    # leading whitespace = $1\n                ({0}) [ ]+                 # list marker = $2\n                ((?s:.+?)                  # list item text = $3\n                (\\n+))\n                (?= (\\z | \\1 ({0}) [ ]+))\", marker);\n\n            bool lastItemHadADoubleNewline = false;\n\n            // has to be a closure, so subsequent invocations can share the bool\n            MatchEvaluator ListItemEvaluator = (Match match) =>\n            {\n                string item = match.Groups[3].Value;\n\n                bool endsWithDoubleNewline = item.EndsWith(\"\\n\\n\");\n                bool containsDoubleNewline = endsWithDoubleNewline || item.Contains(\"\\n\\n\");\n\n                if (containsDoubleNewline || lastItemHadADoubleNewline)\n                    // we could correct any bad indentation here..\n                    item = RunBlockGamut(Outdent(item) + \"\\n\", unhash: false);\n                else\n                {\n                    // recursion for sub-lists\n                    item = DoLists(Outdent(item), isInsideParagraphlessListItem: true);\n                    item = item.TrimEnd('\\n');\n                    if (!isInsideParagraphlessListItem) // only the outer-most item should run this, otherwise it's run multiple times for the inner ones\n                        item = RunSpanGamut(item);\n                }\n                lastItemHadADoubleNewline = endsWithDoubleNewline;\n                return string.Format(\"<li>{0}</li>\\n\", item);\n            };\n\n            list = Regex.Replace(list, pattern, new MatchEvaluator(ListItemEvaluator),\n                                  RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);\n            _listLevel--;\n            return list;\n        }\n\n        private static Regex _codeBlock = new Regex(string.Format(@\"\n                    (?:\\n\\n|\\A\\n?)\n                    (                        # $1 = the code block -- one or more lines, starting with a space\n                    (?:\n                        (?:[ ]{{{0}}})       # Lines must start with a tab-width of spaces\n                        .*\\n+\n                    )+\n                    )\n                    ((?=^[ ]{{0,{0}}}[^ \\t\\n])|\\Z) # Lookahead for non-space at line-start, or end of doc\",\n                    _tabWidth), RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);\n\n        /// <summary>\n        /// /// Turn Markdown 4-space indented code into HTML pre code blocks\n        /// </summary>\n        private string DoCodeBlocks(string text)\n        {\n            text = _codeBlock.Replace(text, new MatchEvaluator(CodeBlockEvaluator));\n            return text;\n        }\n\n        private string CodeBlockEvaluator(Match match)\n        {\n            string codeBlock = match.Groups[1].Value;\n\n            codeBlock = EncodeCode(Outdent(codeBlock));\n            codeBlock = _newlinesLeadingTrailing.Replace(codeBlock, \"\");\n\n            return string.Concat(\"\\n\\n<pre><code>\", codeBlock, \"\\n</code></pre>\\n\\n\");\n        }\n\n        private static Regex _codeSpan = new Regex(@\"\n                    (?<![\\\\`])   # Character before opening ` can't be a backslash or backtick\n                    (`+)      # $1 = Opening run of `\n                    (?!`)     # and no more backticks -- match the full run\n                    (.+?)     # $2 = The code block\n                    (?<!`)\n                    \\1\n                    (?!`)\", RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown `code spans` into HTML code tags\n        /// </summary>\n        private string DoCodeSpans(string text)\n        {\n            //    * You can use multiple backticks as the delimiters if you want to\n            //        include literal backticks in the code span. So, this input:\n            //\n            //        Just type ``foo `bar` baz`` at the prompt.\n            //\n            //        Will translate to:\n            //\n            //          <p>Just type <code>foo `bar` baz</code> at the prompt.</p>\n            //\n            //        There's no arbitrary limit to the number of backticks you\n            //        can use as delimters. If you need three consecutive backticks\n            //        in your code, use four for delimiters, etc.\n            //\n            //    * You can use spaces to get literal backticks at the edges:\n            //\n            //          ... type `` `bar` `` ...\n            //\n            //        Turns to:\n            //\n            //          ... type <code>`bar`</code> ...\n            //\n\n            return _codeSpan.Replace(text, new MatchEvaluator(CodeSpanEvaluator));\n        }\n\n        private string CodeSpanEvaluator(Match match)\n        {\n            string span = match.Groups[2].Value;\n            span = Regex.Replace(span, @\"^[ ]*\", \"\"); // leading whitespace\n            span = Regex.Replace(span, @\"[ ]*$\", \"\"); // trailing whitespace\n            span = EncodeCode(span);\n            span = SaveFromAutoLinking(span); // to prevent auto-linking. Not necessary in code *blocks*, but in code spans.\n\n            return string.Concat(\"<code>\", span, \"</code>\");\n        }\n\n\n        private static Regex _bold = new Regex(@\"(\\*\\*|__) (?=\\S) (.+?[*_]*) (?<=\\S) \\1\",\n            RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled);\n        private static Regex _strictBold = new Regex(@\"(^|[\\W_])(?:(?!\\1)|(?=^))(\\*|_)\\2(?=\\S)(.*?\\S)\\2\\2(?!\\2)(?=[\\W_]|$)\",\n            RegexOptions.Singleline | RegexOptions.Compiled);\n\n        private static Regex _italic = new Regex(@\"(\\*|_) (?=\\S) (.+?) (?<=\\S) \\1\",\n            RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.Compiled);\n        private static Regex _strictItalic = new Regex(@\"(^|[\\W_])(?:(?!\\1)|(?=^))(\\*|_)(?=\\S)((?:(?!\\2).)*?\\S)\\2(?!\\2)(?=[\\W_]|$)\",\n            RegexOptions.Singleline | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown *italics* and **bold** into HTML strong and em tags\n        /// </summary>\n        private string DoItalicsAndBold(string text)\n        {\n\n            // <strong> must go first, then <em>\n            if (_strictBoldItalic)\n            {\n                text = _strictBold.Replace(text, \"$1<strong>$3</strong>\");\n                text = _strictItalic.Replace(text, \"$1<em>$3</em>\");\n            }\n            else\n            {\n                text = _bold.Replace(text, \"<strong>$2</strong>\");\n                text = _italic.Replace(text, \"<em>$2</em>\");\n            }\n            return text;\n        }\n\n        /// <summary>\n        /// Turn markdown line breaks (two space at end of line) into HTML break tags\n        /// </summary>\n        private string DoHardBreaks(string text)\n        {\n            if (_autoNewlines)\n                text = Regex.Replace(text, @\"\\n\", string.Format(\"<br{0}\\n\", _emptyElementSuffix));\n            else\n                text = Regex.Replace(text, @\" {2,}\\n\", string.Format(\"<br{0}\\n\", _emptyElementSuffix));\n            return text;\n        }\n\n        private static Regex _blockquote = new Regex(@\"\n            (                           # Wrap whole match in $1\n                (\n                ^[ ]*>[ ]?              # '>' at the start of a line\n                    .+\\n                # rest of the first line\n                (.+\\n)*                 # subsequent consecutive lines\n                \\n*                     # blanks\n                )+\n            )\", RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Turn Markdown > quoted blocks into HTML blockquote blocks\n        /// </summary>\n        private string DoBlockQuotes(string text)\n        {\n            return _blockquote.Replace(text, new MatchEvaluator(BlockQuoteEvaluator));\n        }\n\n        private string BlockQuoteEvaluator(Match match)\n        {\n            string bq = match.Groups[1].Value;\n\n            bq = Regex.Replace(bq, @\"^[ ]*>[ ]?\", \"\", RegexOptions.Multiline);       // trim one level of quoting\n            bq = Regex.Replace(bq, @\"^[ ]+$\", \"\", RegexOptions.Multiline);           // trim whitespace-only lines\n            bq = RunBlockGamut(bq);                                                  // recurse\n\n            bq = Regex.Replace(bq, @\"^\", \"  \", RegexOptions.Multiline);\n\n            // These leading spaces screw with <pre> content, so we need to fix that:\n            bq = Regex.Replace(bq, @\"(\\s*<pre>.+?</pre>)\", new MatchEvaluator(BlockQuoteEvaluator2), RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);\n\n            bq = string.Format(\"<blockquote>\\n{0}\\n</blockquote>\", bq);\n            string key = GetHashKey(bq, isHtmlBlock: true);\n            _htmlBlocks[key] = bq;\n\n            return \"\\n\\n\" + key + \"\\n\\n\";\n        }\n\n        private string BlockQuoteEvaluator2(Match match)\n        {\n            return Regex.Replace(match.Groups[1].Value, @\"^  \", \"\", RegexOptions.Multiline);\n        }\n\n        private const string _charInsideUrl = @\"[-A-Z0-9+&@#/%?=~_|\\[\\]\\(\\)!:,\\.;\" + \"\\x1a]\";\n        private const string _charEndingUrl = \"[-A-Z0-9+&@#/%=~_|\\\\[\\\\])]\";\n\n        private static Regex _autolinkBare = new Regex(@\"(<|=\"\")?\\b(https?|ftp)(://\" + _charInsideUrl + \"*\" + _charEndingUrl + \")(?=$|\\\\W)\",\n            RegexOptions.IgnoreCase | RegexOptions.Compiled);\n\n        private static Regex _endCharRegex = new Regex(_charEndingUrl, RegexOptions.IgnoreCase | RegexOptions.Compiled);\n\n        private static string handleTrailingParens(Match match)\n        {\n            // The first group is essentially a negative lookbehind -- if there's a < or a =\", we don't touch this.\n            // We're not using a *real* lookbehind, because of links with in links, like <a href=\"http://web.archive.org/web/20121130000728/http://www.google.com/\">\n            // With a real lookbehind, the full link would never be matched, and thus the http://www.google.com *would* be matched.\n            // With the simulated lookbehind, the full link *is* matched (just not handled, because of this early return), causing\n            // the google link to not be matched again.\n            if (match.Groups[1].Success)\n                return match.Value;\n\n            var protocol = match.Groups[2].Value;\n            var link = match.Groups[3].Value;\n            if (!link.EndsWith(\")\"))\n                return \"<\" + protocol + link + \">\";\n            var level = 0;\n            foreach (Match c in Regex.Matches(link, \"[()]\"))\n            {\n                if (c.Value == \"(\")\n                {\n                    if (level <= 0)\n                        level = 1;\n                    else\n                        level++;\n                }\n                else\n                {\n                    level--;\n                }\n            }\n            var tail = \"\";\n            if (level < 0)\n            {\n                link = Regex.Replace(link, @\"\\){1,\" + (-level) + \"}$\", m => { tail = m.Value; return \"\"; });\n            }\n            if (tail.Length > 0)\n            {\n                var lastChar = link[link.Length - 1];\n                if (!_endCharRegex.IsMatch(lastChar.ToString()))\n                {\n                    tail = lastChar + tail;\n                    link = link.Substring(0, link.Length - 1);\n                }\n            }\n            return \"<\" + protocol + link + \">\" + tail;\n        }\n\n        /// <summary>\n        /// Turn angle-delimited URLs into HTML anchor tags\n        /// </summary>\n        /// <remarks>\n        /// &lt;http://www.example.com&gt;\n        /// </remarks>\n        private string DoAutoLinks(string text)\n        {\n\n            if (_autoHyperlink)\n            {\n                // fixup arbitrary URLs by adding Markdown < > so they get linked as well\n                // note that at this point, all other URL in the text are already hyperlinked as <a href=\"\"></a>\n                // *except* for the <http://www.foo.com> case\n                text = _autolinkBare.Replace(text, handleTrailingParens);\n            }\n\n            // Hyperlinks: <http://foo.com>\n            text = Regex.Replace(text, \"<((https?|ftp):[^'\\\">\\\\s]+)>\", new MatchEvaluator(HyperlinkEvaluator));\n\n            if (_linkEmails)\n            {\n                // Email addresses: <address@domain.foo>\n                string pattern =\n                    @\"<\n                      (?:mailto:)?\n                      (\n                        [-.\\w]+\n                        \\@\n                        [-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+\n                      )\n                      >\";\n                text = Regex.Replace(text, pattern, new MatchEvaluator(EmailEvaluator), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);\n            }\n\n            return text;\n        }\n\n        private string HyperlinkEvaluator(Match match)\n        {\n            string link = match.Groups[1].Value;\n            return string.Format(\"<a href=\\\"{0}\\\">{1}</a>\", EscapeBoldItalic(EncodeProblemUrlChars(link)), link);\n        }\n\n        private string EmailEvaluator(Match match)\n        {\n            string email = Unescape(match.Groups[1].Value);\n\n            //\n            //    Input: an email address, e.g. \"foo@example.com\"\n            //\n            //    Output: the email address as a mailto link, with each character\n            //            of the address encoded as either a decimal or hex entity, in\n            //            the hopes of foiling most address harvesting spam bots. E.g.:\n            //\n            //      <a href=\"&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;\n            //        x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;\">&#102;&#111;&#111;\n            //        &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>\n            //\n            //    Based by a filter by Matthew Wickline, posted to the BBEdit-Talk\n            //    mailing list: <http://tinyurl.com/yu7ue>\n            //\n            email = \"mailto:\" + email;\n\n            // leave ':' alone (to spot mailto: later)\n            email = EncodeEmailAddress(email);\n\n            email = string.Format(\"<a href=\\\"{0}\\\">{0}</a>\", email);\n\n            // strip the mailto: from the visible part\n            email = Regex.Replace(email, \"\\\">.+?:\", \"\\\">\");\n            return email;\n        }\n\n\n        private static Regex _outDent = new Regex(@\"^[ ]{1,\" + _tabWidth + @\"}\", RegexOptions.Multiline | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Remove one level of line-leading spaces\n        /// </summary>\n        private string Outdent(string block)\n        {\n            return _outDent.Replace(block, \"\");\n        }\n\n\n        #region Encoding and Normalization\n\n\n        /// <summary>\n        /// encodes email address randomly\n        /// roughly 10% raw, 45% hex, 45% dec\n        /// note that @ is always encoded and : never is\n        /// </summary>\n        private string EncodeEmailAddress(string addr)\n        {\n            var sb = new StringBuilder(addr.Length * 5);\n            var rand = new Random();\n            int r;\n            foreach (char c in addr)\n            {\n                r = rand.Next(1, 100);\n                if ((r > 90 || c == ':') && c != '@')\n                    sb.Append(c);                         // m\n                else if (r < 45)\n                    sb.AppendFormat(\"&#x{0:x};\", (int)c); // &#x6D\n                else\n                    sb.AppendFormat(\"&#{0};\", (int)c);    // &#109\n            }\n            return sb.ToString();\n        }\n\n        private static Regex _codeEncoder = new Regex(@\"&|<|>|\\\\|\\*|_|\\{|\\}|\\[|\\]\", RegexOptions.Compiled);\n\n        /// <summary>\n        /// Encode/escape certain Markdown characters inside code blocks and spans where they are literals\n        /// </summary>\n        private string EncodeCode(string code)\n        {\n            return _codeEncoder.Replace(code, EncodeCodeEvaluator);\n        }\n        private string EncodeCodeEvaluator(Match match)\n        {\n            switch (match.Value)\n            {\n                // Encode all ampersands; HTML entities are not\n                // entities within a Markdown code span.\n                case \"&\":\n                    return \"&amp;\";\n                // Do the angle bracket song and dance\n                case \"<\":\n                    return \"&lt;\";\n                case \">\":\n                    return \"&gt;\";\n                // escape characters that are magic in Markdown\n                default:\n                    return _escapeTable[match.Value];\n            }\n        }\n\n\n        private static Regex _amps = new Regex(@\"&(?!((#[0-9]+)|(#[xX][a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9]*));)\", RegexOptions.ExplicitCapture | RegexOptions.Compiled);\n        private static Regex _angles = new Regex(@\"<(?![A-Za-z/?\\$!])\", RegexOptions.ExplicitCapture | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Encode any ampersands (that aren't part of an HTML entity) and left or right angle brackets\n        /// </summary>\n        private string EncodeAmpsAndAngles(string s)\n        {\n            s = _amps.Replace(s, \"&amp;\");\n            s = _angles.Replace(s, \"&lt;\");\n            return s;\n        }\n\n        private static Regex _backslashEscapes;\n\n        /// <summary>\n        /// Encodes any escaped characters such as \\`, \\*, \\[ etc\n        /// </summary>\n        private string EscapeBackslashes(string s)\n        {\n            return _backslashEscapes.Replace(s, new MatchEvaluator(EscapeBackslashesEvaluator));\n        }\n        private string EscapeBackslashesEvaluator(Match match)\n        {\n            return _backslashEscapeTable[match.Value];\n        }\n\n        private static Regex _unescapes = new Regex(\"\\x1A\" + \"E\\\\d+E\", RegexOptions.Compiled);\n\n        /// <summary>\n        /// swap back in all the special characters we've hidden\n        /// </summary>\n        private string Unescape(string s)\n        {\n            return _unescapes.Replace(s, new MatchEvaluator(UnescapeEvaluator));\n        }\n        private string UnescapeEvaluator(Match match)\n        {\n            return _invertedEscapeTable[match.Value];\n        }\n\n\n        /// <summary>\n        /// escapes Bold [ * ] and Italic [ _ ] characters\n        /// </summary>\n        private string EscapeBoldItalic(string s)\n        {\n            s = s.Replace(\"*\", _escapeTable[\"*\"]);\n            s = s.Replace(\"_\", _escapeTable[\"_\"]);\n            return s;\n        }\n\n        private static string AttributeEncode(string s)\n        {\n            return s.Replace(\">\", \"&gt;\").Replace(\"<\", \"&lt;\").Replace(\"\\\"\", \"&quot;\");\n        }\n\n        private static readonly char[] _problemUrlChars = @\"\"\"'*()[]$:\".ToCharArray();\n\n        /// <summary>\n        /// hex-encodes some unusual \"problem\" chars in URLs to avoid URL detection problems\n        /// </summary>\n        private string EncodeProblemUrlChars(string url)\n        {\n            if (!_encodeProblemUrlCharacters) return url;\n\n            var sb = new StringBuilder(url.Length);\n            bool encode;\n            char c;\n\n            for (int i = 0; i < url.Length; i++)\n            {\n                c = url[i];\n                encode = Array.IndexOf(_problemUrlChars, c) != -1;\n                if (encode && c == ':' && i < url.Length - 1)\n                    encode = !(url[i + 1] == '/') && !(url[i + 1] >= '0' && url[i + 1] <= '9');\n\n                if (encode)\n                    sb.Append(\"%\" + String.Format(\"{0:x}\", (byte)c));\n                else\n                    sb.Append(c);\n            }\n\n            return sb.ToString();\n        }\n\n\n        /// <summary>\n        /// Within tags -- meaning between &lt; and &gt; -- encode [\\ ` * _] so they\n        /// don't conflict with their use in Markdown for code, italics and strong.\n        /// We're replacing each such character with its corresponding hash\n        /// value; this is likely overkill, but it should prevent us from colliding\n        /// with the escape values by accident.\n        /// </summary>\n        private string EscapeSpecialCharsWithinTagAttributes(string text)\n        {\n            var tokens = TokenizeHTML(text);\n\n            // now, rebuild text from the tokens\n            var sb = new StringBuilder(text.Length);\n\n            foreach (var token in tokens)\n            {\n                string value = token.Value;\n\n                if (token.Type == TokenType.Tag)\n                {\n                    value = value.Replace(@\"\\\", _escapeTable[@\"\\\"]);\n\n                    if (_autoHyperlink && value.StartsWith(\"<!\")) // escape slashes in comments to prevent autolinking there -- http://meta.stackoverflow.com/questions/95987/html-comment-containing-url-breaks-if-followed-by-another-html-comment\n                        value = value.Replace(\"/\", _escapeTable[\"/\"]);\n\n                    value = Regex.Replace(value, \"(?<=.)</?code>(?=.)\", _escapeTable[@\"`\"]);\n                    value = EscapeBoldItalic(value);\n                }\n\n                sb.Append(value);\n            }\n\n            return sb.ToString();\n        }\n\n        /// <summary>\n        /// convert all tabs to _tabWidth spaces;\n        /// standardizes line endings from DOS (CR LF) or Mac (CR) to UNIX (LF);\n        /// makes sure text ends with a couple of newlines;\n        /// removes any blank lines (only spaces) in the text\n        /// </summary>\n        private string Normalize(string text)\n        {\n            var output = new StringBuilder(text.Length);\n            var line = new StringBuilder();\n            bool valid = false;\n\n            for (int i = 0; i < text.Length; i++)\n            {\n                switch (text[i])\n                {\n                    case '\\n':\n                        if (valid) output.Append(line);\n                        output.Append('\\n');\n                        line.Length = 0; valid = false;\n                        break;\n                    case '\\r':\n                        if ((i < text.Length - 1) && (text[i + 1] != '\\n'))\n                        {\n                            if (valid) output.Append(line);\n                            output.Append('\\n');\n                            line.Length = 0; valid = false;\n                        }\n                        break;\n                    case '\\t':\n                        int width = (_tabWidth - line.Length % _tabWidth);\n                        for (int k = 0; k < width; k++)\n                            line.Append(' ');\n                        break;\n                    case '\\x1A':\n                        break;\n                    default:\n                        if (!valid && text[i] != ' ') valid = true;\n                        line.Append(text[i]);\n                        break;\n                }\n            }\n\n            if (valid) output.Append(line);\n            output.Append('\\n');\n\n            // add two newlines to the end before return\n            return output.Append(\"\\n\\n\").ToString();\n        }\n\n        #endregion\n\n        /// <summary>\n        /// this is to emulate what's evailable in PHP\n        /// </summary>\n        private static string RepeatString(string text, int count)\n        {\n            var sb = new StringBuilder(text.Length * count);\n            for (int i = 0; i < count; i++)\n                sb.Append(text);\n            return sb.ToString();\n        }\n\n    }\n}"
  },
  {
    "path": "src/Squirrel/MsDeltaCompression.cs",
    "content": "﻿#nullable enable\n\nusing System;\nusing System.ComponentModel;\n\nnamespace Squirrel\n{\n    internal class MsDeltaCompression\n    {\n        public void CreateDelta(string oldFilePath, string newFilePath, string deltaFilePath)\n        {\n            const string? sourceOptionsName = null;\n            const string? targetOptionsName = null;\n            var globalOptions = new DeltaInput();\n            var targetFileTime = IntPtr.Zero;\n\n            if (!NativeMethods.CreateDelta(\n                FileTypeSet.Executables, CreateFlags.IgnoreFileSizeLimit, CreateFlags.None, oldFilePath, newFilePath,\n                sourceOptionsName, targetOptionsName, globalOptions, targetFileTime, HashAlgId.Crc32, deltaFilePath))\n            {\n                throw new Win32Exception();\n            }\n        }\n\n        public void ApplyDelta(string deltaFilePath, string oldFilePath, string newFilePath)\n        {\n            if (!NativeMethods.ApplyDelta(ApplyFlags.AllowLegacy, oldFilePath, deltaFilePath, newFilePath))\n                throw new Win32Exception();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/NativeMethods.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Squirrel\n{\n    public static class NativeMethods\n    {\n        public static int GetParentProcessId()\n        {\n            var pbi = new PROCESS_BASIC_INFORMATION();\n\n            //Get a handle to our own process\n            IntPtr hProc = OpenProcess((ProcessAccess)0x001F0FFF, false, Process.GetCurrentProcess().Id);\n\n            try {\n                int sizeInfoReturned;\n                int queryStatus = NtQueryInformationProcess(hProc, (PROCESSINFOCLASS)0, ref pbi, pbi.Size, out sizeInfoReturned);\n            } finally {\n                if (!hProc.Equals(IntPtr.Zero)) {\n                    //Close handle and free allocated memory\n                    CloseHandle(hProc);\n                    hProc = IntPtr.Zero;\n                }\n            }\n\n            return (int)pbi.InheritedFromUniqueProcessId;\n        }\n\n\n        [DllImport(\"version.dll\", SetLastError = true)]\n        [return:MarshalAs(UnmanagedType.Bool)] internal static extern bool GetFileVersionInfo(\n            string lpszFileName, \n            int dwHandleIgnored,\n            int dwLen, \n            [MarshalAs(UnmanagedType.LPArray)] byte[] lpData);\n\n        [DllImport(\"version.dll\", SetLastError = true)]\n        internal static extern int GetFileVersionInfoSize(\n            string lpszFileName,\n            IntPtr dwHandleIgnored);\n\n        [DllImport(\"version.dll\")]\n        [return:MarshalAs(UnmanagedType.Bool)] internal static extern bool VerQueryValue(\n            byte[] pBlock, \n            string pSubBlock, \n            out IntPtr pValue, \n            out int len);\n\n        [DllImport(\"psapi.dll\", SetLastError=true)]\n        internal static extern bool EnumProcesses(\n            IntPtr pProcessIds, // pointer to allocated DWORD array\n            int cb,\n            out int pBytesReturned);\n\n        [DllImport(\"kernel32.dll\", SetLastError=true)]\n        internal static extern bool QueryFullProcessImageName(\n            IntPtr hProcess, \n            [In] int justPassZeroHere,\n            [Out] StringBuilder lpImageFileName, \n            [In] [MarshalAs(UnmanagedType.U4)] ref int nSize);\n\n        [DllImport(\"kernel32.dll\", SetLastError=true)]\n        internal static extern IntPtr OpenProcess(\n            ProcessAccess processAccess,\n            bool bInheritHandle,\n            int processId);\n\n        [DllImport(\"kernel32.dll\", SetLastError = true)]\n        internal static extern bool CloseHandle(IntPtr hHandle);\n\n        [DllImport(\"NTDLL.DLL\", SetLastError=true)]\n        internal static extern int NtQueryInformationProcess(IntPtr hProcess, PROCESSINFOCLASS pic, ref PROCESS_BASIC_INFORMATION pbi, int cb, out int pSize);\n\n        [DllImport(\"kernel32.dll\", SetLastError=true)]\n        internal static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);\n\n        [DllImport(\"kernel32.dll\", EntryPoint = \"GetStdHandle\")]\n        internal static extern IntPtr GetStdHandle(StandardHandles nStdHandle);\n\n        [DllImport(\"kernel32.dll\", EntryPoint = \"AllocConsole\")]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        internal static extern bool AllocConsole();\n \n        [DllImport(\"kernel32.dll\")]\n        internal static extern bool AttachConsole(int pid);\n\n        [DllImport(\"Kernel32.dll\", SetLastError=true)]\n        internal static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);\n\n        [DllImport(\"Kernel32.dll\", SetLastError=true)]\n        internal static extern bool UpdateResource(IntPtr handle, string pType, IntPtr pName, short language, [MarshalAs(UnmanagedType.LPArray)] byte[] pData, int dwSize);\n\n        [DllImport(\"Kernel32.dll\", SetLastError=true)]\n        internal static extern bool EndUpdateResource(IntPtr handle, bool discard);\n\n#nullable enable\n        /// <summary>\n        ///     The ApplyDelta function use the specified delta and source files to create a new copy of the target file.\n        /// </summary>\n        /// <param name=\"applyFlags\">Either DELTA_FLAG_NONE or DELTA_APPLY_FLAG_ALLOW_PA19.</param>\n        /// <param name=\"sourceName\">The name of the source file to which the delta is to be applied.</param>\n        /// <param name=\"deltaName\">The name of the delta to be applied to the source file.</param>\n        /// <param name=\"targetName\">The name of the target file that is to be created.</param>\n        /// <returns>\n        ///     Returns TRUE on success or FALSE otherwise.\n        /// </returns>\n        /// <remarks>\n        ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#applydeltaaw\n        /// </remarks>\n        [DllImport(\"msdelta.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        internal static extern bool ApplyDelta(\n            [MarshalAs(UnmanagedType.I8)] ApplyFlags applyFlags,\n            string sourceName,\n            string deltaName,\n            string targetName);\n\n        /// <summary>\n        ///     The CreateDelta function creates a delta from the specified source and target files and write the output delta to the designated file name.\n        /// </summary>\n        /// <param name=\"fileTypeSet\">The file type set used for Create.</param>\n        /// <param name=\"setFlags\">The file type set used for Create.</param>\n        /// <param name=\"resetFlags\">The file type set used for Create.</param>\n        /// <param name=\"sourceName\">The file type set used for Create.</param>\n        /// <param name=\"targetName\">The name of the target against which the source is compared.</param>\n        /// <param name=\"sourceOptionsName\">Reserved. Pass NULL.</param>\n        /// <param name=\"targetOptionsName\">Reserved. Pass NULL.</param>\n        /// <param name=\"globalOptions\">Reserved. Pass a DELTA_INPUT structure with lpStart set to NULL and uSize set to 0.</param>\n        /// <param name=\"targetFileTime\">The time stamp set on the target file after delta Apply. If NULL, the timestamp of the target file during delta Create will be used.</param>\n        /// <param name=\"hashAlgId\">ALG_ID of the algorithm to be used to generate the target signature.</param>\n        /// <param name=\"deltaName\">The name of the delta file to be created.</param>\n        /// <returns>\n        ///     Returns TRUE on success or FALSE otherwise.\n        /// </returns>\n        /// <remarks>\n        ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#createdeltaaw\n        /// </remarks>\n        [DllImport(\"msdelta.dll\", CharSet = CharSet.Unicode, SetLastError = true)]\n        [return: MarshalAs(UnmanagedType.Bool)]\n        internal static extern bool CreateDelta(\n            [MarshalAs(UnmanagedType.I8)] FileTypeSet fileTypeSet,\n            [MarshalAs(UnmanagedType.I8)] CreateFlags setFlags,\n            [MarshalAs(UnmanagedType.I8)] CreateFlags resetFlags,\n            string sourceName,\n            string targetName,\n            string? sourceOptionsName,\n            string? targetOptionsName,\n            DeltaInput globalOptions,\n            IntPtr targetFileTime,\n            [MarshalAs(UnmanagedType.U4)] HashAlgId hashAlgId,\n            string deltaName);\n#nullable restore\n    }\n\n    [Flags]\n    public enum ProcessAccess : uint {\n        All = 0x001F0FFF,\n        Terminate = 0x00000001,\n        CreateThread = 0x00000002,\n        VirtualMemoryOperation = 0x00000008,\n        VirtualMemoryRead = 0x00000010,\n        VirtualMemoryWrite = 0x00000020,\n        DuplicateHandle = 0x00000040,\n        CreateProcess = 0x000000080,\n        SetQuota = 0x00000100,\n        SetInformation = 0x00000200,\n        QueryInformation = 0x00000400,\n        QueryLimitedInformation = 0x00001000,\n        Synchronize = 0x00100000\n    }\n\n    public enum PROCESSINFOCLASS : int {\n        ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION\n        ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX\n        ProcessIoCounters, // q: IO_COUNTERS\n        ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX\n        ProcessTimes, // q: KERNEL_USER_TIMES\n        ProcessBasePriority, // s: KPRIORITY\n        ProcessRaisePriority, // s: ULONG\n        ProcessDebugPort, // q: HANDLE\n        ProcessExceptionPort, // s: HANDLE\n        ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN\n        ProcessLdtInformation, // 10\n        ProcessLdtSize,\n        ProcessDefaultHardErrorMode, // qs: ULONG\n        ProcessIoPortHandlers, // (kernel-mode only)\n        ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS\n        ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void\n        ProcessUserModeIOPL,\n        ProcessEnableAlignmentFaultFixup, // s: BOOLEAN\n        ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS\n        ProcessWx86Information,\n        ProcessHandleCount, // 20, q: ULONG, PROCESS_HANDLE_INFORMATION\n        ProcessAffinityMask, // s: KAFFINITY\n        ProcessPriorityBoost, // qs: ULONG\n        ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX\n        ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION\n        ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND\n        ProcessWow64Information, // q: ULONG_PTR\n        ProcessImageFileName, // q: UNICODE_STRING\n        ProcessLUIDDeviceMapsEnabled, // q: ULONG\n        ProcessBreakOnTermination, // qs: ULONG\n        ProcessDebugObjectHandle, // 30, q: HANDLE\n        ProcessDebugFlags, // qs: ULONG\n        ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables\n        ProcessIoPriority, // qs: ULONG\n        ProcessExecuteFlags, // qs: ULONG\n        ProcessResourceManagement,\n        ProcessCookie, // q: ULONG\n        ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION\n        ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION\n        ProcessPagePriority, // q: ULONG\n        ProcessInstrumentationCallback, // 40\n        ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX\n        ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]\n        ProcessImageFileNameWin32, // q: UNICODE_STRING\n        ProcessImageFileMapping, // q: HANDLE (input)\n        ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE\n        ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE\n        ProcessGroupInformation, // q: USHORT[]\n        ProcessTokenVirtualizationEnabled, // s: ULONG\n        ProcessConsoleHostProcess, // q: ULONG_PTR\n        ProcessWindowInformation, // 50, q: PROCESS_WINDOW_INFORMATION\n        ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8\n        ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION\n        ProcessDynamicFunctionTableInformation,\n        ProcessHandleCheckingMode,\n        ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION\n        ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION\n        MaxProcessInfoClass\n    };\n\n    [StructLayout(LayoutKind.Sequential, Pack = 1)]\n    public struct PROCESS_BASIC_INFORMATION {\n        public IntPtr ExitStatus;\n        public IntPtr PebBaseAddress;\n        public IntPtr AffinityMask;\n        public IntPtr BasePriority;\n        public UIntPtr UniqueProcessId;\n        public IntPtr InheritedFromUniqueProcessId;\n\n        public int Size {\n            get { return (int)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); }\n        }\n    }\n\n    public enum StandardHandles : int {\n        STD_INPUT_HANDLE = -10,\n        STD_OUTPUT_HANDLE = -11,\n        STD_ERROR_HANDLE = -12,\n    }\n\n    /// <remarks>\n    ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#deltaflagtypeflags\n    /// </remarks>\n    internal enum ApplyFlags : long\n    {\n        /// <summary>Indicates no special handling.</summary>\n        None = 0,\n\n        /// <summary>Allow MSDelta to apply deltas created using PatchAPI.</summary>\n        AllowLegacy = 1,\n    }\n\n    /// <remarks>\n    ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#filetypesets\n    /// </remarks>\n    [Flags]\n    internal enum FileTypeSet : long\n    {\n        /// <summary>\n        ///     File type set that includes I386, IA64 and AMD64 Portable Executable (PE) files. Others are treated as raw.\n        /// </summary>\n        Executables = 0x0FL,\n    }\n\n    /// <remarks>\n    ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#deltaflagtypeflags\n    /// </remarks>\n    internal enum CreateFlags : long\n    {\n        /// <summary>Indicates no special handling.</summary>\n        None = 0,\n\n        /// <summary>Allow the source, target and delta files to exceed the default size limit.</summary>\n        IgnoreFileSizeLimit = 1 << 17,\n    }\n\n    /// <remarks>\n    ///     http://msdn.microsoft.com/en-us/library/bb417345.aspx#deltainputstructure\n    /// </remarks>\n    [StructLayout(LayoutKind.Sequential)]\n    internal struct DeltaInput\n    {\n        /// <summary>Memory address non-editable input buffer.</summary>\n        public IntPtr Start;\n\n        /// <summary>Size of the memory buffer in bytes.</summary>\n        public IntPtr Size;\n\n        /// <summary>\n        ///     Defines whether MSDelta is allowed to edit the input buffer. If you make the input editable, the buffer will\n        ///     be zeroed at function return. However this will cause most MSDelta functions to use less memory.\n        /// </summary>\n        [MarshalAs(UnmanagedType.Bool)] public bool Editable;\n    }\n\n    internal enum HashAlgId\n    {\n        /// <summary>No signature.</summary>\n        None = 0,\n\n        /// <summary>32-bit CRC defined in msdelta.dll.</summary>\n        Crc32 = 32,\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n[assembly: ComVisible(false)]\n[assembly: InternalsVisibleTo(\"Squirrel.Tests\")]\n[assembly: InternalsVisibleTo(\"Update\")]\n[assembly: InternalsVisibleTo(\"Update-Mono\")]\n[assembly: InternalsVisibleTo(\"SyncReleases\")]\n"
  },
  {
    "path": "src/Squirrel/ReleaseEntry.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing NuGet;\nusing Squirrel.SimpleSplat;\nusing System.Runtime.Serialization;\nusing System.Threading.Tasks;\nusing System.Collections.Concurrent;\n\nnamespace Squirrel\n{\n    public interface IReleaseEntry\n    {\n        string SHA1 { get; }\n        string Filename { get; }\n        long Filesize { get; }\n        bool IsDelta { get; }\n        string EntryAsString { get; }\n        SemanticVersion Version { get; }\n        string PackageName { get; }\n        float? StagingPercentage { get; }\n\n        string GetReleaseNotes(string packageDirectory);\n        Uri GetIconUrl(string packageDirectory);\n    }\n\n    [DataContract]\n    public class ReleaseEntry : IEnableLogger, IReleaseEntry\n    {\n        [DataMember] public string SHA1 { get; protected set; }\n        [DataMember] public string BaseUrl { get; protected set; }\n        [DataMember] public string Filename { get; protected set; }\n        [DataMember] public string Query { get; protected set; }\n        [DataMember] public long Filesize { get; protected set; }\n        [DataMember] public bool IsDelta { get; protected set; }\n        [DataMember] public float? StagingPercentage { get; protected set; }\n\n        protected ReleaseEntry(string sha1, string filename, long filesize, bool isDelta, string baseUrl = null, string query = null, float? stagingPercentage = null)\n        {\n            Contract.Requires(sha1 != null && sha1.Length == 40);\n            Contract.Requires(filename != null);\n            Contract.Requires(filename.Contains(Path.DirectorySeparatorChar) == false);\n            Contract.Requires(filesize > 0);\n\n            SHA1 = sha1; BaseUrl = baseUrl;  Filename = filename; Query = query; Filesize = filesize; IsDelta = isDelta; StagingPercentage = stagingPercentage;\n        }\n\n        [IgnoreDataMember]\n        public string EntryAsString {\n            get {\n                if (StagingPercentage != null) {\n                    return String.Format(\"{0} {1}{2} {3} # {4}\", SHA1, BaseUrl, Filename, Filesize, stagingPercentageAsString(StagingPercentage.Value));\n                } else {\n                    return String.Format(\"{0} {1}{2} {3}\", SHA1, BaseUrl, Filename, Filesize);\n                }\n            }\n        }\n\n        [IgnoreDataMember]\n        public SemanticVersion Version { get { return Filename.ToSemanticVersion(); } }\n\n        static readonly Regex packageNameRegex = new Regex(@\"^([\\w-]+)-\\d+\\..+\\.nupkg$\");\n        [IgnoreDataMember]\n        public string PackageName {\n            get {\n                var match = packageNameRegex.Match(Filename);\n                return match.Success ? \n                    match.Groups[1].Value : \n                    Filename.Substring(0, Filename.IndexOfAny(new[] { '-', '.' }));\n            }\n        }\n\n        public string GetReleaseNotes(string packageDirectory)\n        {\n            var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));\n            var t = zp.Id;\n\n            if (String.IsNullOrWhiteSpace(zp.ReleaseNotes)) {\n                throw new Exception(String.Format(\"Invalid 'ReleaseNotes' value in nuspec file at '{0}'\", Path.Combine(packageDirectory, Filename)));\n            }\n\n            return zp.ReleaseNotes;\n        }\n\n        public Uri GetIconUrl(string packageDirectory)\n        {\n            var zp = new ZipPackage(Path.Combine(packageDirectory, Filename));\n            return zp.IconUrl;\n        }\n\n        static readonly Regex entryRegex = new Regex(@\"^([0-9a-fA-F]{40})\\s+(\\S+)\\s+(\\d+)[\\r]*$\");\n        static readonly Regex commentRegex = new Regex(@\"\\s*#.*$\");\n        static readonly Regex stagingRegex = new Regex(@\"#\\s+(\\d{1,3})%$\");\n        public static ReleaseEntry ParseReleaseEntry(string entry)\n        {\n            Contract.Requires(entry != null);\n\n            float? stagingPercentage = null;\n            var m = stagingRegex.Match(entry);\n            if (m != null && m.Success) {\n                stagingPercentage = Single.Parse(m.Groups[1].Value) / 100.0f;\n            }\n\n            entry = commentRegex.Replace(entry, \"\");\n            if (String.IsNullOrWhiteSpace(entry)) {\n                return null;\n            }\n\n            m = entryRegex.Match(entry);\n            if (!m.Success) {\n                throw new Exception(\"Invalid release entry: \" + entry);\n            }\n\n            if (m.Groups.Count != 4) {\n                throw new Exception(\"Invalid release entry: \" + entry);\n            }\n\n            string filename = m.Groups[2].Value;\n\n            // Split the base URL and the filename if an URI is provided,\n            // throws if a path is provided\n            string baseUrl = null;\n            string query = null;\n\n            if(Utility.IsHttpUrl(filename)) {\n                var uri = new Uri(filename);\n                var path = uri.LocalPath;\n                var authority = uri.GetLeftPart(UriPartial.Authority);\n\n                if (String.IsNullOrEmpty(path) || String.IsNullOrEmpty(authority)) {\n                    throw new Exception(\"Invalid URL\");\n                }\n\n                var indexOfLastPathSeparator = path.LastIndexOf(\"/\") + 1;\n                baseUrl = authority + path.Substring(0, indexOfLastPathSeparator);\n                filename = path.Substring(indexOfLastPathSeparator);\n\n                if (!String.IsNullOrEmpty(uri.Query)) {\n                    query = uri.Query;\n                }\n            }\n\n            if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) > -1) {\n                throw new Exception(\"Filename can either be an absolute HTTP[s] URL, *or* a file name\");\n            }\n\n            long size = Int64.Parse(m.Groups[3].Value);\n            bool isDelta = filenameIsDeltaFile(filename);\n\n            return new ReleaseEntry(m.Groups[1].Value, filename, size, isDelta, baseUrl, query, stagingPercentage);\n        }\n\n        public bool IsStagingMatch(Guid? userId)\n        {\n            // A \"Staging match\" is when a user falls into the affirmative\n            // bucket - i.e. if the staging is at 10%, this user is the one out\n            // of ten case.\n            if (!StagingPercentage.HasValue) return true;\n            if (!userId.HasValue) return false;\n\n            uint val = BitConverter.ToUInt32(userId.Value.ToByteArray(), 12);\n\n            double percentage = ((double)val / (double)UInt32.MaxValue);\n            return percentage < StagingPercentage.Value;\n        }\n\n        public static IEnumerable<ReleaseEntry> ParseReleaseFile(string fileContents)\n        {\n            if (String.IsNullOrEmpty(fileContents)) {\n                return new ReleaseEntry[0];\n            }\n\n            fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);\n\n            var ret = fileContents.Split('\\n')\n                .Where(x => !String.IsNullOrWhiteSpace(x))\n                .Select(ParseReleaseEntry)\n                .Where(x => x != null)\n                .ToArray();\n\n            return ret.Any(x => x == null) ? null : ret;\n        }\n\n        public static IEnumerable<ReleaseEntry> ParseReleaseFileAndApplyStaging(string fileContents, Guid? userToken)\n        {\n            if (String.IsNullOrEmpty(fileContents)) {\n                return new ReleaseEntry[0];\n            }\n\n            fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);\n\n            var ret = fileContents.Split('\\n')\n                .Where(x => !String.IsNullOrWhiteSpace(x))\n                .Select(ParseReleaseEntry)\n                .Where(x => x != null && x.IsStagingMatch(userToken))\n                .ToArray();\n\n            return ret.Any(x => x == null) ? null : ret;\n        }\n\n\n        public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, Stream stream)\n        {\n            Contract.Requires(releaseEntries != null && releaseEntries.Any());\n            Contract.Requires(stream != null);\n\n            using (var sw = new StreamWriter(stream, Encoding.UTF8)) {\n                sw.Write(String.Join(\"\\n\", releaseEntries\n                    .OrderBy(x => x.Version)\n                    .ThenByDescending(x => x.IsDelta)\n                    .Select(x => x.EntryAsString)));\n            }\n        }\n\n        public static void WriteReleaseFile(IEnumerable<ReleaseEntry> releaseEntries, string path)\n        {\n            Contract.Requires(releaseEntries != null && releaseEntries.Any());\n            Contract.Requires(!String.IsNullOrEmpty(path));\n\n            using (var f = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {\n                WriteReleaseFile(releaseEntries, f);\n            }\n        }\n\n        public static ReleaseEntry GenerateFromFile(Stream file, string filename, string baseUrl = null)\n        {\n            Contract.Requires(file != null && file.CanRead);\n            Contract.Requires(!String.IsNullOrEmpty(filename));\n\n            var hash = Utility.CalculateStreamSHA1(file);\n            return new ReleaseEntry(hash, filename, file.Length, filenameIsDeltaFile(filename), baseUrl);\n        }\n\n        public static ReleaseEntry GenerateFromFile(string path, string baseUrl = null)\n        {\n            using (var inf = File.OpenRead(path)) {\n                return GenerateFromFile(inf, Path.GetFileName(path), baseUrl);\n            }\n        }\n\n        public static List<ReleaseEntry> BuildReleasesFile(string releasePackagesDir)\n        {\n            var packagesDir = new DirectoryInfo(releasePackagesDir);\n\n            // Generate release entries for all of the local packages\n            var entriesQueue = new ConcurrentQueue<ReleaseEntry>();\n            Parallel.ForEach(packagesDir.GetFiles(\"*.nupkg\"), x => {\n                using (var file = x.OpenRead()) {\n                    entriesQueue.Enqueue(GenerateFromFile(file, x.Name));\n                }\n            });\n\n            // Write the new RELEASES file to a temp file then move it into\n            // place\n            var entries = entriesQueue.ToList();\n            var tempFile = default(string);\n            Utility.WithTempFile(out tempFile, releasePackagesDir);\n\n            try {\n                using (var of = File.OpenWrite(tempFile)) {\n                    if (entries.Count > 0) WriteReleaseFile(entries, of);\n                }\n\n                var target = Path.Combine(packagesDir.FullName, \"RELEASES\");\n                if (File.Exists(target)) {\n                    File.Delete(target);\n                }\n\n                File.Move(tempFile, target);\n            } finally {\n                if (File.Exists(tempFile)) Utility.DeleteFileHarder(tempFile, true);\n            }\n\n            return entries;\n        }\n\n        static string stagingPercentageAsString(float percentage)\n        {\n            return String.Format(\"{0:F0}%\", percentage * 100.0);\n        }\n\n        static bool filenameIsDeltaFile(string filename)\n        {\n            return filename.EndsWith(\"-delta.nupkg\", StringComparison.InvariantCultureIgnoreCase);\n        }\n\n        public static ReleasePackage GetPreviousRelease(IEnumerable<ReleaseEntry> releaseEntries, IReleasePackage package, string targetDir)\n        {\n            if (releaseEntries == null || !releaseEntries.Any()) return null;\n\n            return releaseEntries\n                .Where(x => x.IsDelta == false)\n                .Where(x => x.Version < package.ToSemanticVersion())\n                .OrderByDescending(x => x.Version)\n                .Select(x => new ReleasePackage(Path.Combine(targetDir, x.Filename), true))\n                .FirstOrDefault();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/ReleaseExtensions.cs",
    "content": "﻿using NuGet;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Squirrel\n{\n    public static class VersionExtensions\n    {\n        static readonly Regex _suffixRegex = new Regex(@\"(-full|-delta)?\\.nupkg$\", RegexOptions.Compiled);\n        static readonly Regex _versionRegex = new Regex(@\"\\d+(\\.\\d+){0,3}(-[A-Za-z][0-9A-Za-z-]*)?$\", RegexOptions.Compiled);\n\n        public static SemanticVersion ToSemanticVersion(this IReleasePackage package)\n        {\n            return package.InputPackageFile.ToSemanticVersion();\n        }\n\n        public static SemanticVersion ToSemanticVersion(this string fileName)\n        {\n            var name = _suffixRegex.Replace(fileName, \"\");\n            var version = _versionRegex.Match(name).Value;\n            return new SemanticVersion(version);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/ReleasePackage.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.Design;\nusing System.Diagnostics.Contracts;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.Versioning;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Xml;\nusing MarkdownSharp;\nusing NuGet;\nusing Squirrel.SimpleSplat;\nusing System.Threading.Tasks;\nusing SharpCompress.Archives.Zip;\nusing SharpCompress.Readers;\n\nnamespace Squirrel\n{\n    internal static class FrameworkTargetVersion\n    {\n        public static FrameworkName Net40 = new FrameworkName(\".NETFramework,Version=v4.0\");\n        public static FrameworkName Net45 = new FrameworkName(\".NETFramework,Version=v4.5\");\n    }\n\n    public interface IReleasePackage\n    {\n        string InputPackageFile { get; }\n        string ReleasePackageFile { get; }\n        string SuggestedReleaseFileName { get; }\n\n        string CreateReleasePackage(string outputFile, string packagesRootDir = null, Func<string, string> releaseNotesProcessor = null, Action<string> contentsPostProcessHook = null);\n    }\n\n    public static class VersionComparer\n    {\n        public static bool Matches(IVersionSpec versionSpec, SemanticVersion version)\n        {\n            if (versionSpec == null)\n                return true; // I CAN'T DEAL WITH THIS\n\n            bool minVersion;\n            if (versionSpec.MinVersion == null) {\n                minVersion = true; // no preconditon? LET'S DO IT\n            } else if (versionSpec.IsMinInclusive) {\n                minVersion = version >= versionSpec.MinVersion;\n            } else {\n                minVersion = version > versionSpec.MinVersion;\n            }\n\n            bool maxVersion;\n            if (versionSpec.MaxVersion == null) {\n                maxVersion = true; // no preconditon? LET'S DO IT\n            } else if (versionSpec.IsMaxInclusive) {\n                maxVersion = version <= versionSpec.MaxVersion;\n            } else {\n                maxVersion = version < versionSpec.MaxVersion;\n            }\n\n            return maxVersion && minVersion;\n        }\n    }\n\n    public class ReleasePackage : IEnableLogger, IReleasePackage\n    {\n        public ReleasePackage(string inputPackageFile, bool isReleasePackage = false)\n        {\n            InputPackageFile = inputPackageFile;\n\n            if (isReleasePackage) {\n                ReleasePackageFile = inputPackageFile;\n            }\n        }\n\n        public string InputPackageFile { get; protected set; }\n        public string ReleasePackageFile { get; protected set; }\n\n        public string SuggestedReleaseFileName {\n            get {\n                var zp = new ZipPackage(InputPackageFile);\n                return String.Format(\"{0}-{1}-full.nupkg\", zp.Id, zp.Version);\n            }\n        }\n\n        public SemanticVersion Version { get { return InputPackageFile.ToSemanticVersion(); } }\n\n        public string CreateReleasePackage(string outputFile, string packagesRootDir = null, Func<string, string> releaseNotesProcessor = null, Action<string> contentsPostProcessHook = null)\n        {\n            Contract.Requires(!String.IsNullOrEmpty(outputFile));\n            releaseNotesProcessor = releaseNotesProcessor ?? (x => (new Markdown()).Transform(x));\n\n            if (ReleasePackageFile != null) {\n                return ReleasePackageFile;\n            }\n\n            var package = new ZipPackage(InputPackageFile);\n\n            var dontcare = default(SemanticVersion);\n\n            // NB: Our test fixtures use packages that aren't SemVer compliant, \n            // we don't really care that they aren't valid\n            if (!ModeDetector.InUnitTestRunner() && !SemanticVersion.TryParseStrict(package.Version.ToString(), out dontcare)) {\n                throw new Exception(\n                    String.Format(\n                        \"Your package version is currently {0}, which is *not* SemVer-compatible, change this to be a SemVer version number\",\n                        package.Version.ToString()));\n            }\n\n            // we can tell from here what platform(s) the package targets\n            // but given this is a simple package we only\n            // ever expect one entry here (crash hard otherwise)\n            var frameworks = package.GetSupportedFrameworks();\n            if (frameworks.Count() > 1) {\n                var platforms = frameworks\n                    .Aggregate(new StringBuilder(), (sb, f) => sb.Append(f.ToString() + \"; \"));\n\n                throw new InvalidOperationException(String.Format(\n                    \"The input package file {0} targets multiple platforms - {1} - and cannot be transformed into a release package.\", InputPackageFile, platforms));\n\n            } else if (!frameworks.Any()) {\n                throw new InvalidOperationException(String.Format(\n                    \"The input package file {0} targets no platform and cannot be transformed into a release package.\", InputPackageFile));\n            }\n\n            var targetFramework = frameworks.Single();\n\n            // Recursively walk the dependency tree and extract all of the\n            // dependent packages into the a temporary directory\n            this.Log().Info(\"Creating release package: {0} => {1}\", InputPackageFile, outputFile);\n            var dependencies = findAllDependentPackages(\n                package,\n                new LocalPackageRepository(packagesRootDir),\n                frameworkName: targetFramework)\n                .ToArray();\n\n            string tempPath = null;\n\n            using (Utility.WithTempDirectory(out tempPath, null)) {\n                var tempDir = new DirectoryInfo(tempPath);\n\n                extractZipWithEscaping(InputPackageFile, tempPath).Wait();\n\n                this.Log().Info(\"Extracting dependent packages: [{0}]\", String.Join(\",\", dependencies.Select(x => x.Id)));\n                extractDependentPackages(dependencies, tempDir, targetFramework);\n\n                var specPath = tempDir.GetFiles(\"*.nuspec\").First().FullName;\n\n                this.Log().Info(\"Removing unnecessary data\");\n                removeDependenciesFromPackageSpec(specPath);\n\n                if (releaseNotesProcessor != null) {\n                    renderReleaseNotesMarkdown(specPath, releaseNotesProcessor);\n                }\n\n                addDeltaFilesToContentTypes(tempDir.FullName);\n\n                contentsPostProcessHook?.Invoke(tempPath);\n\n                Utility.CreateZipFromDirectory(outputFile, tempPath).Wait();\n\n                ReleasePackageFile = outputFile;\n                return ReleasePackageFile;\n            }\n        }\n\n        static Task extractZipWithEscaping(string zipFilePath, string outFolder)\n        {\n            return Task.Run(() => {\n                using (var za = ZipArchive.Open(zipFilePath))\n                using (var reader = za.ExtractAllEntries()) {\n                    while (reader.MoveToNextEntry()) {\n                        var parts = reader.Entry.Key.Split('\\\\', '/').Select(x => Uri.UnescapeDataString(x));\n                        var decoded = String.Join(Path.DirectorySeparatorChar.ToString(), parts);\n\n                        var fullTargetFile = Path.Combine(outFolder, decoded);\n                        var fullTargetDir = Path.GetDirectoryName(fullTargetFile);\n                        Directory.CreateDirectory(fullTargetDir);\n\n                        Utility.Retry(() => {\n                            if (reader.Entry.IsDirectory) {\n                                Directory.CreateDirectory(Path.Combine(outFolder, decoded));\n                            } else {\n                                reader.WriteEntryToFile(Path.Combine(outFolder, decoded));\n                            }\n                        }, 5);\n                    }\n                }\n            });\n        }\n\n        public static Task ExtractZipForInstall(string zipFilePath, string outFolder, string rootPackageFolder)\n        {\n            return ExtractZipForInstall(zipFilePath, outFolder, rootPackageFolder, x => { });\n        }\n\n        public static Task ExtractZipForInstall(string zipFilePath, string outFolder, string rootPackageFolder, Action<int> progress)\n        {\n            var re = new Regex(@\"lib[\\\\\\/][^\\\\\\/]*[\\\\\\/]\", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);\n\n            return Task.Run(() => {\n                using (var za = ZipArchive.Open(zipFilePath))\n                using (var reader = za.ExtractAllEntries()) {\n                    var totalItems = za.Entries.Count;\n                    var currentItem = 0;\n\n                    while (reader.MoveToNextEntry()) {\n                        // Report progress early since we might be need to continue for non-matches\n                        currentItem++;\n                        var percentage = (currentItem * 100d) / totalItems;\n                        progress((int)percentage);\n\n                        var parts = reader.Entry.Key.Split('\\\\', '/');\n                        var decoded = String.Join(Path.DirectorySeparatorChar.ToString(), parts);\n\n                        if (!re.IsMatch(decoded)) continue;\n                        decoded = re.Replace(decoded, \"\", 1);\n\n                        var fullTargetFile = Path.Combine(outFolder, decoded);\n                        var fullTargetDir = Path.GetDirectoryName(fullTargetFile);\n                        Directory.CreateDirectory(fullTargetDir);\n\n                        var failureIsOkay = false;\n                        if (!reader.Entry.IsDirectory && decoded.Contains(\"_ExecutionStub.exe\")) {\n                            // NB: On upgrade, many of these stubs will be in-use, nbd tho.\n                            failureIsOkay = true;\n\n                            fullTargetFile = Path.Combine(\n                                rootPackageFolder,\n                                Path.GetFileName(decoded).Replace(\"_ExecutionStub.exe\", \".exe\"));\n\n                            LogHost.Default.Info(\"Rigging execution stub for {0} to {1}\", decoded, fullTargetFile);\n                        }\n\n                        try {\n                            Utility.Retry(() => {\n                                if (reader.Entry.IsDirectory) {\n                                    Directory.CreateDirectory(fullTargetFile);\n                                } else {\n                                    reader.WriteEntryToFile(fullTargetFile);\n                                }\n                            }, 5);\n                        } catch (Exception e) {\n                            if (!failureIsOkay) throw;\n                            LogHost.Default.WarnException(\"Can't write execution stub, probably in use\", e);\n                        }\n                    }\n                }\n\n                progress(100);\n            });\n        }\n\n        void extractDependentPackages(IEnumerable<IPackage> dependencies, DirectoryInfo tempPath, FrameworkName framework)\n        {\n            dependencies.ForEach(pkg => {\n                this.Log().Info(\"Scanning {0}\", pkg.Id);\n\n                pkg.GetLibFiles().ForEach(file => {\n                    var outPath = new FileInfo(Path.Combine(tempPath.FullName, file.Path));\n\n                    if (!VersionUtility.IsCompatible(framework , new[] { file.TargetFramework }))\n                    {\n                        this.Log().Info(\"Ignoring {0} as the target framework is not compatible\", outPath);\n                        return;\n                    }\n\n                    Directory.CreateDirectory(outPath.Directory.FullName);\n\n                    using (var of = File.Create(outPath.FullName)) {\n                        this.Log().Info(\"Writing {0} to {1}\", file.Path, outPath);\n                        file.GetStream().CopyTo(of);\n                    }\n                });\n            });\n        }\n\n        void renderReleaseNotesMarkdown(string specPath, Func<string, string> releaseNotesProcessor)\n        {\n            var doc = new XmlDocument();\n            doc.Load(specPath);\n\n            // XXX: This code looks full tart\n            var metadata = doc.DocumentElement.ChildNodes\n                .OfType<XmlElement>()\n                .First(x => x.Name.ToLowerInvariant() == \"metadata\");\n\n            var releaseNotes = metadata.ChildNodes\n                .OfType<XmlElement>()\n                .FirstOrDefault(x => x.Name.ToLowerInvariant() == \"releasenotes\");\n\n            if (releaseNotes == null) {\n                this.Log().Info(\"No release notes found in {0}\", specPath);\n                return;\n            }\n\n            releaseNotes.InnerText = String.Format(\"<![CDATA[\\n\" + \"{0}\\n\" + \"]]>\",\n                releaseNotesProcessor(releaseNotes.InnerText));\n\n            doc.Save(specPath);\n        }\n\n        void removeDependenciesFromPackageSpec(string specPath)\n        {\n            var xdoc = new XmlDocument();\n            xdoc.Load(specPath);\n\n            var metadata = xdoc.DocumentElement.FirstChild;\n            var dependenciesNode = metadata.ChildNodes.OfType<XmlElement>().FirstOrDefault(x => x.Name.ToLowerInvariant() == \"dependencies\");\n            if (dependenciesNode != null) {\n                metadata.RemoveChild(dependenciesNode);\n            }\n\n            xdoc.Save(specPath);\n        }\n\n        internal IEnumerable<IPackage> findAllDependentPackages(\n            IPackage package = null,\n            IPackageRepository packageRepository = null,\n            HashSet<string> packageCache = null,\n            FrameworkName frameworkName = null)\n        {\n            package = package ?? new ZipPackage(InputPackageFile);\n            packageCache = packageCache ?? new HashSet<string>();\n\n            var deps = package.DependencySets\n                .Where(x => x.TargetFramework == null\n                            || x.TargetFramework == frameworkName)\n                .SelectMany(x => x.Dependencies);\n\n            return deps.SelectMany(dependency => {\n                var ret = matchPackage(packageRepository, dependency.Id, dependency.VersionSpec);\n\n                if (ret == null) {\n                    var message = String.Format(\"Couldn't find file for package in {1}: {0}\", dependency.Id, packageRepository.Source);\n                    this.Log().Error(message);\n                    throw new Exception(message);\n                }\n\n                if (packageCache.Contains(ret.GetFullName())) {\n                    return Enumerable.Empty<IPackage>();\n                }\n\n                packageCache.Add(ret.GetFullName());\n\n                return findAllDependentPackages(ret, packageRepository, packageCache, frameworkName).StartWith(ret).Distinct(y => y.GetFullName());\n            }).ToArray();\n        }\n\n        IPackage matchPackage(IPackageRepository packageRepository, string id, IVersionSpec version)\n        {\n            return packageRepository.FindPackagesById(id).FirstOrDefault(x => VersionComparer.Matches(version, x.Version));\n        }\n\n\n        static internal void addDeltaFilesToContentTypes(string rootDirectory)\n        {\n            var doc = new XmlDocument();\n            var path = Path.Combine(rootDirectory, \"[Content_Types].xml\");\n            doc.Load(path);\n\n            ContentType.Merge(doc);\n            ContentType.Clean(doc);\n\n            using (var sw = new StreamWriter(path, false, Encoding.UTF8)) {\n                doc.Save(sw);\n            }\n        }\n    }\n\n    public class ChecksumFailedException : Exception\n    {\n        public string Filename { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/ShellFile.cs",
    "content": "﻿using System;\nusing System.Drawing;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\n// All of this code is from http://vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Creating_and_Modifying_Shortcuts/article.asp\n\nnamespace Squirrel.Shell\n{\n    /// <summary>\n    /// Summary description for ShellLink.\n    /// </summary>\n    public class ShellLink : IDisposable\n    {\n        [ComImport()]\n        [Guid(\"0000010C-0000-0000-C000-000000000046\")]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        interface IPersist\n        {\n            [PreserveSig]\n            //[helpstring(\"Returns the class identifier for the component object\")]\n            void GetClassID(out Guid pClassID);\n        }\n\n        [ComImport()]\n        [Guid(\"0000010B-0000-0000-C000-000000000046\")]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        interface IPersistFile\n        {\n            // can't get this to go if I extend IPersist, so put it here:\n            [PreserveSig]\n            void GetClassID(out Guid pClassID);\n\n            //[helpstring(\"Checks for changes since last file write\")]      \n            void IsDirty();\n\n            //[helpstring(\"Opens the specified file and initializes the object from its contents\")]      \n            void Load(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszFileName,\n                uint dwMode);\n\n            //[helpstring(\"Saves the object into the specified file\")]      \n            void Save(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszFileName,\n                [MarshalAs(UnmanagedType.Bool)] bool fRemember);\n\n            //[helpstring(\"Notifies the object that save is completed\")]      \n            void SaveCompleted(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszFileName);\n\n            //[helpstring(\"Gets the current name of the file associated with the object\")]      \n            void GetCurFile(\n                [MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName);\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct PropVariant\n        {\n            public short variantType;\n            public short Reserved1, Reserved2, Reserved3;\n            public IntPtr pointerValue;\n\n            public static PropVariant FromString(string str)\n            {\n                var pv = new PropVariant() {\n                    variantType = 31,  // VT_LPWSTR\n                    pointerValue = Marshal.StringToCoTaskMemUni(str),\n                };\n\n                return pv;\n            }\n\n            public static PropVariant FromGuid(Guid guid)\n            {\n                byte[] bytes = guid.ToByteArray();\n                var pv = new PropVariant() {\n                    variantType = 72,  // VT_CLSID\n                    pointerValue = Marshal.AllocCoTaskMem(bytes.Length),\n                };\n                Marshal.Copy(bytes, 0, pv.pointerValue, bytes.Length);\n\n                return pv;\n            }\n\n            /// <summary>\n            /// Called to properly clean up the memory referenced by a PropVariant instance.\n            /// </summary>\n            [DllImport(\"ole32.dll\")]\n            private extern static int PropVariantClear(ref PropVariant pvar);\n\n            /// <summary>\n            /// Called to clear the PropVariant's referenced and local memory.\n            /// </summary>\n            /// <remarks>\n            /// You must call Clear to avoid memory leaks.\n            /// </remarks>\n            public void Clear()\n            {\n                // Can't pass \"this\" by ref, so make a copy to call PropVariantClear with\n                PropVariant tmp = this;\n                PropVariantClear(ref tmp);\n\n                // Since we couldn't pass \"this\" by ref, we need to clear the member fields manually\n                // NOTE: PropVariantClear already freed heap data for us, so we are just setting\n                //       our references to null.\n                variantType = (short)VarEnum.VT_EMPTY;\n                Reserved1 = Reserved2 = Reserved3 = 0;\n                pointerValue = IntPtr.Zero;\n            }\n        }\n\n        [StructLayout(LayoutKind.Sequential)]\n        public struct PROPERTYKEY\n        {\n            public Guid fmtid;\n            public UIntPtr pid;\n\n            public static PROPERTYKEY PKEY_AppUserModel_ID {\n                get {\n                    return new PROPERTYKEY() {\n                        fmtid = Guid.ParseExact(\"{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}\", \"B\"),\n                        pid = new UIntPtr(5),\n                    };\n                }\n            }\n\n            public static PROPERTYKEY PKEY_AppUserModel_ToastActivatorCLSID {\n                get {\n                    return new PROPERTYKEY() {\n                        fmtid = Guid.ParseExact(\"{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}\", \"B\"),\n                        pid = new UIntPtr(26),\n                    };\n                }\n            }\n        }\n\n        [ComImport]\n        [Guid(\"886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99\")]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        interface IPropertyStore\n        {\n            [PreserveSig]\n            int GetCount([Out] out uint cProps);\n            [PreserveSig]\n            int GetAt([In] uint iProp, out PROPERTYKEY pkey);\n            [PreserveSig]\n            int GetValue([In] ref PROPERTYKEY key, out PropVariant pv);\n            [PreserveSig]\n            int SetValue([In] ref PROPERTYKEY key, [In] ref PropVariant pv);\n            [PreserveSig]\n            int Commit();\n        }\n\n        [ComImport()]\n        [Guid(\"000214EE-0000-0000-C000-000000000046\")]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        interface IShellLinkA\n        {\n            //[helpstring(\"Retrieves the path and filename of a shell link object\")]\n            void GetPath(\n                [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile,\n                int cchMaxPath,\n                ref _WIN32_FIND_DATAA pfd,\n                uint fFlags);\n\n            //[helpstring(\"Retrieves the list of shell link item identifiers\")]\n            void GetIDList(out IntPtr ppidl);\n\n            //[helpstring(\"Sets the list of shell link item identifiers\")]\n            void SetIDList(IntPtr pidl);\n\n            //[helpstring(\"Retrieves the shell link description string\")]\n            void GetDescription(\n                [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile,\n                int cchMaxName);\n\n            //[helpstring(\"Sets the shell link description string\")]\n            void SetDescription(\n                [MarshalAs(UnmanagedType.LPStr)] string pszName);\n\n            //[helpstring(\"Retrieves the name of the shell link working directory\")]\n            void GetWorkingDirectory(\n                [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir,\n                int cchMaxPath);\n\n            //[helpstring(\"Sets the name of the shell link working directory\")]\n            void SetWorkingDirectory(\n                [MarshalAs(UnmanagedType.LPStr)] string pszDir);\n\n            //[helpstring(\"Retrieves the shell link command-line arguments\")]\n            void GetArguments(\n                [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs,\n                int cchMaxPath);\n\n            //[helpstring(\"Sets the shell link command-line arguments\")]\n            void SetArguments(\n                [MarshalAs(UnmanagedType.LPStr)] string pszArgs);\n\n            //[propget, helpstring(\"Retrieves or sets the shell link hot key\")]\n            void GetHotkey(out short pwHotkey);\n            //[propput, helpstring(\"Retrieves or sets the shell link hot key\")]\n            void SetHotkey(short pwHotkey);\n\n            //[propget, helpstring(\"Retrieves or sets the shell link show command\")]\n            void GetShowCmd(out uint piShowCmd);\n            //[propput, helpstring(\"Retrieves or sets the shell link show command\")]\n            void SetShowCmd(uint piShowCmd);\n\n            //[helpstring(\"Retrieves the location (path and index) of the shell link icon\")]\n            void GetIconLocation(\n                [Out(), MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath,\n                int cchIconPath,\n                out int piIcon);\n\n            //[helpstring(\"Sets the location (path and index) of the shell link icon\")]\n            void SetIconLocation(\n                [MarshalAs(UnmanagedType.LPStr)] string pszIconPath,\n                int iIcon);\n\n            //[helpstring(\"Sets the shell link relative path\")]\n            void SetRelativePath(\n                [MarshalAs(UnmanagedType.LPStr)] string pszPathRel,\n                uint dwReserved);\n\n            //[helpstring(\"Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)\")]\n            void Resolve(\n                IntPtr hWnd,\n                uint fFlags);\n\n            //[helpstring(\"Sets the shell link path and filename\")]\n            void SetPath(\n                [MarshalAs(UnmanagedType.LPStr)] string pszFile);\n        }\n\n        [ComImport()]\n        [Guid(\"000214F9-0000-0000-C000-000000000046\")]\n        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n        interface IShellLinkW\n        {\n            //[helpstring(\"Retrieves the path and filename of a shell link object\")]\n            void GetPath(\n                [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,\n                int cchMaxPath,\n                ref _WIN32_FIND_DATAW pfd,\n                uint fFlags);\n\n            //[helpstring(\"Retrieves the list of shell link item identifiers\")]\n            void GetIDList(out IntPtr ppidl);\n\n            //[helpstring(\"Sets the list of shell link item identifiers\")]\n            void SetIDList(IntPtr pidl);\n\n            //[helpstring(\"Retrieves the shell link description string\")]\n            void GetDescription(\n                [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,\n                int cchMaxName);\n\n            //[helpstring(\"Sets the shell link description string\")]\n            void SetDescription(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszName);\n\n            //[helpstring(\"Retrieves the name of the shell link working directory\")]\n            void GetWorkingDirectory(\n                [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,\n                int cchMaxPath);\n\n            //[helpstring(\"Sets the name of the shell link working directory\")]\n            void SetWorkingDirectory(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszDir);\n\n            //[helpstring(\"Retrieves the shell link command-line arguments\")]\n            void GetArguments(\n                [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,\n                int cchMaxPath);\n\n            //[helpstring(\"Sets the shell link command-line arguments\")]\n            void SetArguments(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszArgs);\n\n            //[propget, helpstring(\"Retrieves or sets the shell link hot key\")]\n            void GetHotkey(out short pwHotkey);\n            //[propput, helpstring(\"Retrieves or sets the shell link hot key\")]\n            void SetHotkey(short pwHotkey);\n\n            //[propget, helpstring(\"Retrieves or sets the shell link show command\")]\n            void GetShowCmd(out uint piShowCmd);\n            //[propput, helpstring(\"Retrieves or sets the shell link show command\")]\n            void SetShowCmd(uint piShowCmd);\n\n            //[helpstring(\"Retrieves the location (path and index) of the shell link icon\")]\n            void GetIconLocation(\n                [Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,\n                int cchIconPath,\n                out int piIcon);\n\n            //[helpstring(\"Sets the location (path and index) of the shell link icon\")]\n            void SetIconLocation(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszIconPath,\n                int iIcon);\n\n            //[helpstring(\"Sets the shell link relative path\")]\n            void SetRelativePath(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszPathRel,\n                uint dwReserved);\n\n            //[helpstring(\"Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary)\")]\n            void Resolve(\n                IntPtr hWnd,\n                uint fFlags);\n\n            //[helpstring(\"Sets the shell link path and filename\")]\n            void SetPath(\n                [MarshalAs(UnmanagedType.LPWStr)] string pszFile);\n        }\n\n        [Guid(\"00021401-0000-0000-C000-000000000046\")]\n        [ClassInterface(ClassInterfaceType.None)]\n        [ComImport()]\n        class CShellLink\n        {\n        }\n\n        enum EShellLinkGP : uint\n        {\n            SLGP_SHORTPATH = 1,\n            SLGP_UNCPRIORITY = 2\n        }\n\n        [Flags]\n        enum EShowWindowFlags : uint\n        {\n            SW_HIDE = 0,\n            SW_SHOWNORMAL = 1,\n            SW_NORMAL = 1,\n            SW_SHOWMINIMIZED = 2,\n            SW_SHOWMAXIMIZED = 3,\n            SW_MAXIMIZE = 3,\n            SW_SHOWNOACTIVATE = 4,\n            SW_SHOW = 5,\n            SW_MINIMIZE = 6,\n            SW_SHOWMINNOACTIVE = 7,\n            SW_SHOWNA = 8,\n            SW_RESTORE = 9,\n            SW_SHOWDEFAULT = 10,\n            SW_MAX = 10\n        }\n\n        [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0,\n            CharSet = CharSet.Unicode)]\n        struct _WIN32_FIND_DATAW\n        {\n            public uint dwFileAttributes;\n            public _FILETIME ftCreationTime;\n            public _FILETIME ftLastAccessTime;\n            public _FILETIME ftLastWriteTime;\n            public uint nFileSizeHigh;\n            public uint nFileSizeLow;\n            public uint dwReserved0;\n            public uint dwReserved1;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH\n                public string cFileName;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]\n            public string cAlternateFileName;\n        }\n\n        [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0,\n            CharSet = CharSet.Ansi)]\n        struct _WIN32_FIND_DATAA\n        {\n            public uint dwFileAttributes;\n            public _FILETIME ftCreationTime;\n            public _FILETIME ftLastAccessTime;\n            public _FILETIME ftLastWriteTime;\n            public uint nFileSizeHigh;\n            public uint nFileSizeLow;\n            public uint dwReserved0;\n            public uint dwReserved1;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] // MAX_PATH\n                public string cFileName;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]\n            public string cAlternateFileName;\n        }\n\n        [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0)]\n        struct _FILETIME\n        {\n            public uint dwLowDateTime;\n            public uint dwHighDateTime;\n        }\n\n        class UnManagedMethods\n        {\n            [DllImport(\"Shell32\", CharSet = CharSet.Auto)]\n            internal static extern int ExtractIconEx(\n                [MarshalAs(UnmanagedType.LPTStr)] string lpszFile,\n                int nIconIndex,\n                IntPtr[] phIconLarge,\n                IntPtr[] phIconSmall,\n                int nIcons);\n\n            [DllImport(\"user32\")]\n            internal static extern int DestroyIcon(IntPtr hIcon);\n        }\n\n        /// <summary>\n        /// Flags determining how the links with missing\n        /// targets are resolved.\n        /// </summary>\n        [Flags]\n        public enum EShellLinkResolveFlags : uint\n        {\n            /// <summary>\n            /// Allow any match during resolution.  Has no effect\n            /// on ME/2000 or above, use the other flags instead.\n            /// </summary>\n            SLR_ANY_MATCH = 0x2,\n\n            /// <summary>\n            /// Call the Microsoft Windows Installer. \n            /// </summary>\n            SLR_INVOKE_MSI = 0x80,\n\n            /// <summary>\n            /// Disable distributed link tracking. By default, \n            /// distributed link tracking tracks removable media \n            /// across multiple devices based on the volume name. \n            /// It also uses the UNC path to track remote file \n            /// systems whose drive letter has changed. Setting \n            /// SLR_NOLINKINFO disables both types of tracking.\n            /// </summary>\n            SLR_NOLINKINFO = 0x40,\n\n            /// <summary>\n            /// Do not display a dialog box if the link cannot be resolved. \n            /// When SLR_NO_UI is set, a time-out value that specifies the \n            /// maximum amount of time to be spent resolving the link can \n            /// be specified in milliseconds. The function returns if the \n            /// link cannot be resolved within the time-out duration. \n            /// If the timeout is not set, the time-out duration will be \n            /// set to the default value of 3,000 milliseconds (3 seconds). \n            /// </summary>                                  \n            SLR_NO_UI = 0x1,\n\n            /// <summary>\n            /// Not documented in SDK.  Assume same as SLR_NO_UI but \n            /// intended for applications without a hWnd.\n            /// </summary>\n            SLR_NO_UI_WITH_MSG_PUMP = 0x101,\n\n            /// <summary>\n            /// Do not update the link information. \n            /// </summary>\n            SLR_NOUPDATE = 0x8,\n\n            /// <summary>\n            /// Do not execute the search heuristics. \n            /// </summary>                                                        \n            SLR_NOSEARCH = 0x10,\n\n            /// <summary>\n            /// Do not use distributed link tracking. \n            /// </summary>\n            SLR_NOTRACK = 0x20,\n\n            /// <summary>\n            /// If the link object has changed, update its path and list \n            /// of identifiers. If SLR_UPDATE is set, you do not need to \n            /// call IPersistFile::IsDirty to determine whether or not \n            /// the link object has changed. \n            /// </summary>\n            SLR_UPDATE = 0x4\n        }\n\n        public enum LinkDisplayMode : uint\n        {\n            edmNormal = EShowWindowFlags.SW_NORMAL,\n            edmMinimized = EShowWindowFlags.SW_SHOWMINNOACTIVE,\n            edmMaximized = EShowWindowFlags.SW_MAXIMIZE\n        }\n\n        // Use Unicode (W) under NT, otherwise use ANSI      \n        IShellLinkW linkW;\n        IShellLinkA linkA;\n        string shortcutFile = \"\";\n\n        /// <summary>\n        /// Creates an instance of the Shell Link object.\n        /// </summary>\n        public ShellLink()\n        {\n            if (System.Environment.OSVersion.Platform == PlatformID.Win32NT)\n            {\n                linkW = (IShellLinkW)new CShellLink();\n            }\n            else\n            {\n                linkA = (IShellLinkA)new CShellLink();\n            }\n        }\n\n        /// <summary>\n        /// Creates an instance of a Shell Link object\n        /// from the specified link file\n        /// </summary>\n        /// <param name=\"linkFile\">The Shortcut file to open</param>\n        public ShellLink(string linkFile) : this()\n        {\n            Open(linkFile);\n        }\n\n        /// <summary>\n        /// Call dispose just in case it hasn't happened yet\n        /// </summary>\n        ~ShellLink()\n        {\n            Dispose();\n        }\n\n        /// <summary>\n        /// Dispose the object, releasing the COM ShellLink object\n        /// </summary>\n        public void Dispose()\n        {\n            if (linkW != null)\n            {\n                Marshal.ReleaseComObject(linkW);\n                linkW = null;\n            }\n            if (linkA != null)\n            {\n                Marshal.ReleaseComObject(linkA);\n                linkA = null;\n            }\n        }\n\n        public string ShortCutFile\n        {\n            get { return this.shortcutFile; }\n            set { this.shortcutFile = value; }\n        }\n\n        /// <summary>\n        /// Gets a System.Drawing.Icon containing the icon for this\n        /// ShellLink object.\n        /// </summary>\n        public Icon LargeIcon\n        {\n            get { return getIcon(true); }\n        }\n\n        public Icon SmallIcon\n        {\n            get { return getIcon(false); }\n        }\n\n        Icon getIcon(bool large)\n        {\n            // Get icon index and path:\n            int iconIndex = 0;\n            StringBuilder iconPath = new StringBuilder(260, 260);\n            if (linkA == null)\n            {\n                linkW.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex);\n            }\n            else\n            {\n                linkA.GetIconLocation(iconPath, iconPath.Capacity, out iconIndex);\n            }\n            string iconFile = iconPath.ToString();\n\n            // If there are no details set for the icon, then we must use\n            // the shell to get the icon for the target:\n            if (iconFile.Length == 0)\n            {\n                // Use the FileIcon object to get the icon:\n                FileIcon.SHGetFileInfoConstants flags =\n                    FileIcon.SHGetFileInfoConstants.SHGFI_ICON |\n                        FileIcon.SHGetFileInfoConstants.SHGFI_ATTRIBUTES;\n                if (large)\n                {\n                    flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_LARGEICON;\n                }\n                else\n                {\n                    flags = flags | FileIcon.SHGetFileInfoConstants.SHGFI_SMALLICON;\n                }\n                FileIcon fileIcon = new FileIcon(Target, flags);\n                return fileIcon.ShellIcon;\n            }\n            else\n            {\n                // Use ExtractIconEx to get the icon:\n                IntPtr[] hIconEx = new IntPtr[1] { IntPtr.Zero };\n                int iconCount = 0;\n                if (large)\n                {\n                    iconCount = UnManagedMethods.ExtractIconEx(\n                        iconFile,\n                        iconIndex,\n                        hIconEx,\n                        null,\n                        1);\n                }\n                else\n                {\n                    iconCount = UnManagedMethods.ExtractIconEx(\n                        iconFile,\n                        iconIndex,\n                        null,\n                        hIconEx,\n                        1);\n                }\n                // If success then return as a GDI+ object\n                Icon icon = null;\n                if (hIconEx[0] != IntPtr.Zero)\n                {\n                    icon = Icon.FromHandle(hIconEx[0]);\n                    //UnManagedMethods.DestroyIcon(hIconEx[0]);\n                }\n                return icon;\n            }\n        }\n\n        /// <summary>\n        /// Gets the path to the file containing the icon for this shortcut.\n        /// </summary>\n        public string IconPath\n        {\n            get\n            {\n                StringBuilder iconPath = new StringBuilder(260, 260);\n                int iconIndex = 0;\n                if (linkA == null)\n                {\n                    linkW.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                else\n                {\n                    linkA.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                return iconPath.ToString();\n            }\n            set\n            {\n                StringBuilder iconPath = new StringBuilder(260, 260);\n                int iconIndex = 0;\n                if (linkA == null)\n                {\n                    linkW.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                else\n                {\n                    linkA.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                if (linkA == null)\n                {\n                    linkW.SetIconLocation(value, iconIndex);\n                }\n                else\n                {\n                    linkA.SetIconLocation(value, iconIndex);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets the index of this icon within the icon path's resources\n        /// </summary>\n        public int IconIndex\n        {\n            get\n            {\n                StringBuilder iconPath = new StringBuilder(260, 260);\n                int iconIndex = 0;\n                if (linkA == null)\n                {\n                    linkW.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                else\n                {\n                    linkA.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                return iconIndex;\n            }\n            set\n            {\n                StringBuilder iconPath = new StringBuilder(260, 260);\n                int iconIndex = 0;\n                if (linkA == null)\n                {\n                    linkW.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                else\n                {\n                    linkA.GetIconLocation(iconPath, iconPath.Capacity, out\n                        iconIndex);\n                }\n                if (linkA == null)\n                {\n                    linkW.SetIconLocation(iconPath.ToString(), value);\n                }\n                else\n                {\n                    linkA.SetIconLocation(iconPath.ToString(), value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets the fully qualified path to the link's target\n        /// </summary>\n        public string Target\n        {\n            get\n            {\n                StringBuilder target = new StringBuilder(260, 260);\n                if (linkA == null)\n                {\n                    _WIN32_FIND_DATAW fd = new _WIN32_FIND_DATAW();\n                    linkW.GetPath(target, target.Capacity, ref fd,\n                        (uint)EShellLinkGP.SLGP_UNCPRIORITY);\n                }\n                else\n                {\n                    _WIN32_FIND_DATAA fd = new _WIN32_FIND_DATAA();\n                    linkA.GetPath(target, target.Capacity, ref fd,\n                        (uint)EShellLinkGP.SLGP_UNCPRIORITY);\n                }\n                return target.ToString();\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetPath(value);\n                }\n                else\n                {\n                    linkA.SetPath(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets the Working Directory for the Link\n        /// </summary>\n        public string WorkingDirectory\n        {\n            get\n            {\n                StringBuilder path = new StringBuilder(260, 260);\n                if (linkA == null)\n                {\n                    linkW.GetWorkingDirectory(path, path.Capacity);\n                }\n                else\n                {\n                    linkA.GetWorkingDirectory(path, path.Capacity);\n                }\n                return path.ToString();\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetWorkingDirectory(value);\n                }\n                else\n                {\n                    linkA.SetWorkingDirectory(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets the description of the link\n        /// </summary>\n        public string Description\n        {\n            get\n            {\n                StringBuilder description = new StringBuilder(1024, 1024);\n                if (linkA == null)\n                {\n                    linkW.GetDescription(description, description.Capacity);\n                }\n                else\n                {\n                    linkA.GetDescription(description, description.Capacity);\n                }\n                return description.ToString();\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetDescription(value);\n                }\n                else\n                {\n                    linkA.SetDescription(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets any command line arguments associated with the link\n        /// </summary>\n        public string Arguments\n        {\n            get\n            {\n                StringBuilder arguments = new StringBuilder(260, 260);\n                if (linkA == null)\n                {\n                    linkW.GetArguments(arguments, arguments.Capacity);\n                }\n                else\n                {\n                    linkA.GetArguments(arguments, arguments.Capacity);\n                }\n                return arguments.ToString();\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetArguments(value);\n                }\n                else\n                {\n                    linkA.SetArguments(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets the initial display mode when the shortcut is\n        /// run\n        /// </summary>\n        public LinkDisplayMode DisplayMode\n        {\n            get\n            {\n                uint cmd = 0;\n                if (linkA == null)\n                {\n                    linkW.GetShowCmd(out cmd);\n                }\n                else\n                {\n                    linkA.GetShowCmd(out cmd);\n                }\n                return (LinkDisplayMode)cmd;\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetShowCmd((uint)value);\n                }\n                else\n                {\n                    linkA.SetShowCmd((uint)value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Gets/sets the HotKey to start the shortcut (if any)\n        /// </summary>\n        public short HotKey\n        {\n            get\n            {\n                short key = 0;\n                if (linkA == null)\n                {\n                    linkW.GetHotkey(out key);\n                }\n                else\n                {\n                    linkA.GetHotkey(out key);\n                }\n                return key;\n            }\n            set\n            {\n                if (linkA == null)\n                {\n                    linkW.SetHotkey(value);\n                }\n                else\n                {\n                    linkA.SetHotkey(value);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Sets the appUserModelId\n        /// </summary>\n        public void SetAppUserModelId(string appId)\n        {\n            var propStore = (IPropertyStore)linkW;\n            var pkey = PROPERTYKEY.PKEY_AppUserModel_ID;\n            var str = PropVariant.FromString (appId);\n            propStore.SetValue(ref pkey, ref str);\n        }\n\n        /// <summary>\n        /// Sets the ToastActivatorCLSID\n        /// </summary>\n        public void SetToastActivatorCLSID(string clsid)\n        {\n            var guid = Guid.Parse(clsid);\n            SetToastActivatorCLSID(guid);\n        }\n\n        /// <summary>\n        /// Sets the ToastActivatorCLSID\n        /// </summary>\n        public void SetToastActivatorCLSID(Guid clsid)\n        {\n            var propStore = (IPropertyStore)linkW;\n\n            var pkey = PROPERTYKEY.PKEY_AppUserModel_ToastActivatorCLSID;\n\n            var varGuid = PropVariant.FromGuid(clsid);\n            try {\n                int errCode = propStore.SetValue(ref pkey, ref varGuid);\n                Marshal.ThrowExceptionForHR(errCode);\n\n                errCode = propStore.Commit();\n                Marshal.ThrowExceptionForHR(errCode);\n            } finally {\n                varGuid.Clear();\n            }\n        }\n\n        /// <summary>\n        /// Saves the shortcut to ShortCutFile.\n        /// </summary>\n        public void Save()\n        {\n            Save(shortcutFile);\n        }\n\n        /// <summary>\n        /// Saves the shortcut to the specified file\n        /// </summary>\n        /// <param name=\"linkFile\">The shortcut file (.lnk)</param>\n        public void Save(\n            string linkFile\n            )\n        {\n            // Save the object to disk\n            if (linkA == null)\n            {\n                ((IPersistFile)linkW).Save(linkFile, true);\n                shortcutFile = linkFile;\n            }\n            else\n            {\n                ((IPersistFile)linkA).Save(linkFile, true);\n                shortcutFile = linkFile;\n            }\n        }\n\n        /// <summary>\n        /// Loads a shortcut from the specified file\n        /// </summary>\n        /// <param name=\"linkFile\">The shortcut file (.lnk) to load</param>\n        public void Open(\n            string linkFile\n            )\n        {\n            Open(linkFile,\n                IntPtr.Zero,\n                (EShellLinkResolveFlags.SLR_ANY_MATCH |\n                    EShellLinkResolveFlags.SLR_NO_UI),\n                1);\n        }\n\n        /// <summary>\n        /// Loads a shortcut from the specified file, and allows flags controlling\n        /// the UI behaviour if the shortcut's target isn't found to be set.\n        /// </summary>\n        /// <param name=\"linkFile\">The shortcut file (.lnk) to load</param>\n        /// <param name=\"hWnd\">The window handle of the application's UI, if any</param>\n        /// <param name=\"resolveFlags\">Flags controlling resolution behaviour</param>\n        public void Open(\n            string linkFile,\n            IntPtr hWnd,\n            EShellLinkResolveFlags resolveFlags\n            )\n        {\n            Open(linkFile,\n                hWnd,\n                resolveFlags,\n                1);\n        }\n\n        /// <summary>\n        /// Loads a shortcut from the specified file, and allows flags controlling\n        /// the UI behaviour if the shortcut's target isn't found to be set.  If\n        /// no SLR_NO_UI is specified, you can also specify a timeout.\n        /// </summary>\n        /// <param name=\"linkFile\">The shortcut file (.lnk) to load</param>\n        /// <param name=\"hWnd\">The window handle of the application's UI, if any</param>\n        /// <param name=\"resolveFlags\">Flags controlling resolution behaviour</param>\n        /// <param name=\"timeOut\">Timeout if SLR_NO_UI is specified, in ms.</param>\n        public void Open(\n            string linkFile,\n            IntPtr hWnd,\n            EShellLinkResolveFlags resolveFlags,\n            ushort timeOut\n            )\n        {\n            uint flags;\n\n            if ((resolveFlags & EShellLinkResolveFlags.SLR_NO_UI)\n                == EShellLinkResolveFlags.SLR_NO_UI)\n            {\n                flags = (uint)((int)resolveFlags | (timeOut << 16));\n            }\n            else\n            {\n                flags = (uint)resolveFlags;\n            }\n\n            if (linkA == null)\n            {\n                ((IPersistFile)linkW).Load(linkFile, 0); //STGM_DIRECT)\n                linkW.Resolve(hWnd, flags);\n                this.shortcutFile = linkFile;\n            }\n            else\n            {\n                ((IPersistFile)linkA).Load(linkFile, 0); //STGM_DIRECT)\n                linkA.Resolve(hWnd, flags);\n                this.shortcutFile = linkFile;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Enables extraction of icons for any file type from\n    /// the Shell.\n    /// </summary>\n    public class FileIcon\n    {\n        const int MAX_PATH = 260;\n\n        [StructLayout(LayoutKind.Sequential)]\n        struct SHFILEINFO\n        {\n            public IntPtr hIcon;\n            public int iIcon;\n            public int dwAttributes;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]\n            public string szDisplayName;\n\n            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]\n            public string szTypeName;\n        }\n\n        [DllImport(\"shell32\")]\n        static extern IntPtr SHGetFileInfo(\n            string pszPath,\n            int dwFileAttributes,\n            ref SHFILEINFO psfi,\n            uint cbFileInfo,\n            uint uFlags);\n\n        [DllImport(\"user32.dll\")]\n        static extern int DestroyIcon(IntPtr hIcon);\n\n        const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100;\n        const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000;\n        const int FORMAT_MESSAGE_FROM_HMODULE = 0x800;\n        const int FORMAT_MESSAGE_FROM_STRING = 0x400;\n        const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;\n        const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x200;\n        const int FORMAT_MESSAGE_MAX_WIDTH_MASK = 0xFF;\n\n        [DllImport(\"kernel32\")]\n        static extern int FormatMessage(\n            int dwFlags,\n            IntPtr lpSource,\n            int dwMessageId,\n            int dwLanguageId,\n            string lpBuffer,\n            uint nSize,\n            IntPtr argumentsLong);\n\n        [DllImport(\"kernel32\")]\n        static extern int GetLastError();\n\n        string fileName;\n        string displayName;\n        string typeName;\n        SHGetFileInfoConstants flags;\n        Icon fileIcon;\n\n        [Flags]\n        public enum SHGetFileInfoConstants : int\n        {\n            SHGFI_ICON = 0x100, // get icon \n            SHGFI_DISPLAYNAME = 0x200, // get display name \n            SHGFI_TYPENAME = 0x400, // get type name \n            SHGFI_ATTRIBUTES = 0x800, // get attributes \n            SHGFI_ICONLOCATION = 0x1000, // get icon location \n            SHGFI_EXETYPE = 0x2000, // return exe type \n            SHGFI_SYSICONINDEX = 0x4000, // get system icon index \n            SHGFI_LINKOVERLAY = 0x8000, // put a link overlay on icon \n            SHGFI_SELECTED = 0x10000, // show icon in selected state \n            SHGFI_ATTR_SPECIFIED = 0x20000, // get only specified attributes \n            SHGFI_LARGEICON = 0x0, // get large icon \n            SHGFI_SMALLICON = 0x1, // get small icon \n            SHGFI_OPENICON = 0x2, // get open icon \n            SHGFI_SHELLICONSIZE = 0x4, // get shell size icon \n            //SHGFI_PIDL = 0x8,                  // pszPath is a pidl \n            SHGFI_USEFILEATTRIBUTES = 0x10, // use passed dwFileAttribute \n            SHGFI_ADDOVERLAYS = 0x000000020, // apply the appropriate overlays\n            SHGFI_OVERLAYINDEX = 0x000000040 // Get the index of the overlay\n        }\n\n        /// <summary>\n        /// Gets/sets the flags used to extract the icon\n        /// </summary>\n        public FileIcon.SHGetFileInfoConstants Flags\n        {\n            get { return flags; }\n            set { flags = value; }\n        }\n\n        /// <summary>\n        /// Gets/sets the filename to get the icon for\n        /// </summary>\n        public string FileName\n        {\n            get { return fileName; }\n            set { fileName = value; }\n        }\n\n        /// <summary>\n        /// Gets the icon for the chosen file\n        /// </summary>\n        public Icon ShellIcon\n        {\n            get { return fileIcon; }\n        }\n\n        /// <summary>\n        /// Gets the display name for the selected file\n        /// if the SHGFI_DISPLAYNAME flag was set.\n        /// </summary>\n        public string DisplayName\n        {\n            get { return displayName; }\n        }\n\n        /// <summary>\n        /// Gets the type name for the selected file\n        /// if the SHGFI_TYPENAME flag was set.\n        /// </summary>\n        public string TypeName\n        {\n            get { return typeName; }\n        }\n\n        /// <summary>\n        ///  Gets the information for the specified \n        ///  file name and flags.\n        /// </summary>\n        public void GetInfo()\n        {\n            fileIcon = null;\n            typeName = \"\";\n            displayName = \"\";\n\n            SHFILEINFO shfi = new SHFILEINFO();\n            uint shfiSize = (uint)Marshal.SizeOf(shfi.GetType());\n\n            IntPtr ret = SHGetFileInfo(\n                fileName, 0, ref shfi, shfiSize, (uint)(flags));\n            if (ret != IntPtr.Zero)\n            {\n                if (shfi.hIcon != IntPtr.Zero)\n                {\n                    fileIcon = System.Drawing.Icon.FromHandle(shfi.hIcon);\n                    // Now owned by the GDI+ object\n                    //DestroyIcon(shfi.hIcon);\n                }\n                typeName = shfi.szTypeName;\n                displayName = shfi.szDisplayName;\n            }\n            else\n            {\n                int err = GetLastError();\n                Console.WriteLine(\"Error {0}\", err);\n                string txtS = new string('\\0', 256);\n                int len = FormatMessage(\n                    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n                    IntPtr.Zero, err, 0, txtS, 256, IntPtr.Zero);\n                Console.WriteLine(\"Len {0} text {1}\", len, txtS);\n\n                // throw exception\n            }\n        }\n\n        /// <summary>\n        /// Constructs a new, default instance of the FileIcon\n        /// class.  Specify the filename and call GetInfo()\n        /// to retrieve an icon.\n        /// </summary>\n        public FileIcon()\n        {\n            flags = SHGetFileInfoConstants.SHGFI_ICON |\n                SHGetFileInfoConstants.SHGFI_DISPLAYNAME |\n                SHGetFileInfoConstants.SHGFI_TYPENAME |\n                SHGetFileInfoConstants.SHGFI_ATTRIBUTES |\n                SHGetFileInfoConstants.SHGFI_EXETYPE;\n        }\n\n        /// <summary>\n        /// Constructs a new instance of the FileIcon class\n        /// and retrieves the icon, display name and type name\n        /// for the specified file.      \n        /// </summary>\n        /// <param name=\"fileName\">The filename to get the icon, \n        /// display name and type name for</param>\n        public FileIcon(string fileName)\n            : this()\n        {\n            this.fileName = fileName;\n            GetInfo();\n        }\n\n        /// <summary>\n        /// Constructs a new instance of the FileIcon class\n        /// and retrieves the information specified in the \n        /// flags.\n        /// </summary>\n        /// <param name=\"fileName\">The filename to get information\n        /// for</param>\n        /// <param name=\"flags\">The flags to use when extracting the\n        /// icon and other shell information.</param>\n        public FileIcon(string fileName, FileIcon.SHGetFileInfoConstants flags)\n        {\n            this.fileName = fileName;\n            this.flags = flags;\n            GetInfo();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/SimpleJson/SimpleJson.cs",
    "content": "//-----------------------------------------------------------------------\n// <copyright file=\"SimpleJson.cs\" company=\"The Outercurve Foundation\">\n//    Copyright (c) 2011, The Outercurve Foundation.\n//\n//    Licensed under the MIT License (the \"License\");\n//    you may not use this file except in compliance with the License.\n//    You may obtain a copy of the License at\n//      http://www.opensource.org/licenses/mit-license.php\n//\n//    Unless required by applicable law or agreed to in writing, software\n//    distributed under the License is distributed on an \"AS IS\" BASIS,\n//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//    See the License for the specific language governing permissions and\n//    limitations under the License.\n// </copyright>\n// <author>Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)</author>\n// <website>https://github.com/facebook-csharp-sdk/simple-json</website>\n//-----------------------------------------------------------------------\n\n// VERSION: 0.38.0\n\n// NOTE: uncomment the following line to make SimpleJson class internal.\n#define SIMPLE_JSON_INTERNAL\n\n// NOTE: uncomment the following line to make JsonArray and JsonObject class internal.\n//#define SIMPLE_JSON_OBJARRAYINTERNAL\n\n// NOTE: uncomment the following line to enable dynamic support.\n#define SIMPLE_JSON_DYNAMIC\n\n// NOTE: uncomment the following line to enable DataContract support.\n#define SIMPLE_JSON_DATACONTRACT\n\n// NOTE: uncomment the following line to enable IReadOnlyCollection<T> and IReadOnlyList<T> support.\n//#define SIMPLE_JSON_READONLY_COLLECTIONS\n\n// NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke().\n// define if you are using .net framework <= 3.0 or < WP7.5\n//#define SIMPLE_JSON_NO_LINQ_EXPRESSION\n\n// NOTE: uncomment the following line if you are compiling under Window Metro style application/library.\n// usually already defined in properties\n//#define NETFX_CORE;\n\n// If you are targetting WinStore, WP8 and NET4.5+ PCL make sure to #define SIMPLE_JSON_TYPEINFO;\n\n// original json parsing code from http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html\n\n#if NETFX_CORE\n#define SIMPLE_JSON_TYPEINFO\n#endif\n\nusing System;\nusing System.CodeDom.Compiler;\nusing System.Collections;\nusing System.Collections.Generic;\n#if !SIMPLE_JSON_NO_LINQ_EXPRESSION\nusing System.Linq.Expressions;\n#endif\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\n#if SIMPLE_JSON_DYNAMIC\nusing System.Dynamic;\n#endif\nusing System.Globalization;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing Squirrel.Json.Reflection;\n\n// ReSharper disable LoopCanBeConvertedToQuery\n// ReSharper disable RedundantExplicitArrayCreation\n// ReSharper disable SuggestUseVarKeywordEvident\nnamespace Squirrel.Json\n{\n    /// <summary>\n    /// Represents the json array.\n    /// </summary>\n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n    [EditorBrowsable(EditorBrowsableState.Never)]\n    [SuppressMessage(\"Microsoft.Naming\", \"CA1710:IdentifiersShouldHaveCorrectSuffix\")]\n#if SIMPLE_JSON_OBJARRAYINTERNAL\n    internal\n#else\n    public\n#endif\n class JsonArray : List<object>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JsonArray\"/> class. \n        /// </summary>\n        public JsonArray() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JsonArray\"/> class. \n        /// </summary>\n        /// <param name=\"capacity\">The capacity of the json array.</param>\n        public JsonArray(int capacity) : base(capacity) { }\n\n        /// <summary>\n        /// The json representation of the array.\n        /// </summary>\n        /// <returns>The json representation of the array.</returns>\n        public override string ToString()\n        {\n            return SimpleJson.SerializeObject(this) ?? string.Empty;\n        }\n    }\n\n    /// <summary>\n    /// Represents the json object.\n    /// </summary>\n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n    [EditorBrowsable(EditorBrowsableState.Never)]\n    [SuppressMessage(\"Microsoft.Naming\", \"CA1710:IdentifiersShouldHaveCorrectSuffix\")]\n#if SIMPLE_JSON_OBJARRAYINTERNAL\n    internal\n#else\n    public\n#endif\n class JsonObject :\n#if SIMPLE_JSON_DYNAMIC\n DynamicObject,\n#endif\n IDictionary<string, object>\n    {\n        /// <summary>\n        /// The internal member dictionary.\n        /// </summary>\n        private readonly Dictionary<string, object> _members;\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"JsonObject\"/>.\n        /// </summary>\n        public JsonObject()\n        {\n            _members = new Dictionary<string, object>();\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"JsonObject\"/>.\n        /// </summary>\n        /// <param name=\"comparer\">The <see cref=\"T:System.Collections.Generic.IEqualityComparer`1\"/> implementation to use when comparing keys, or null to use the default <see cref=\"T:System.Collections.Generic.EqualityComparer`1\"/> for the type of the key.</param>\n        public JsonObject(IEqualityComparer<string> comparer)\n        {\n            _members = new Dictionary<string, object>(comparer);\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"System.Object\"/> at the specified index.\n        /// </summary>\n        /// <value></value>\n        public object this[int index]\n        {\n            get { return GetAtIndex(_members, index); }\n        }\n\n        internal static object GetAtIndex(IDictionary<string, object> obj, int index)\n        {\n            if (obj == null)\n                throw new ArgumentNullException(\"obj\");\n            if (index >= obj.Count)\n                throw new ArgumentOutOfRangeException(\"index\");\n            int i = 0;\n            foreach (KeyValuePair<string, object> o in obj)\n                if (i++ == index) return o.Value;\n            return null;\n        }\n\n        /// <summary>\n        /// Adds the specified key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value.</param>\n        public void Add(string key, object value)\n        {\n            _members.Add(key, value);\n        }\n\n        /// <summary>\n        /// Determines whether the specified key contains key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <returns>\n        ///     <c>true</c> if the specified key contains key; otherwise, <c>false</c>.\n        /// </returns>\n        public bool ContainsKey(string key)\n        {\n            return _members.ContainsKey(key);\n        }\n\n        /// <summary>\n        /// Gets the keys.\n        /// </summary>\n        /// <value>The keys.</value>\n        public ICollection<string> Keys\n        {\n            get { return _members.Keys; }\n        }\n\n        /// <summary>\n        /// Removes the specified key.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <returns></returns>\n        public bool Remove(string key)\n        {\n            return _members.Remove(key);\n        }\n\n        /// <summary>\n        /// Tries the get value.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <returns></returns>\n        public bool TryGetValue(string key, out object value)\n        {\n            return _members.TryGetValue(key, out value);\n        }\n\n        /// <summary>\n        /// Gets the values.\n        /// </summary>\n        /// <value>The values.</value>\n        public ICollection<object> Values\n        {\n            get { return _members.Values; }\n        }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"System.Object\"/> with the specified key.\n        /// </summary>\n        /// <value></value>\n        public object this[string key]\n        {\n            get { return _members[key]; }\n            set { _members[key] = value; }\n        }\n\n        /// <summary>\n        /// Adds the specified item.\n        /// </summary>\n        /// <param name=\"item\">The item.</param>\n        public void Add(KeyValuePair<string, object> item)\n        {\n            _members.Add(item.Key, item.Value);\n        }\n\n        /// <summary>\n        /// Clears this instance.\n        /// </summary>\n        public void Clear()\n        {\n            _members.Clear();\n        }\n\n        /// <summary>\n        /// Determines whether [contains] [the specified item].\n        /// </summary>\n        /// <param name=\"item\">The item.</param>\n        /// <returns>\n        /// \t<c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.\n        /// </returns>\n        public bool Contains(KeyValuePair<string, object> item)\n        {\n            return _members.ContainsKey(item.Key) && _members[item.Key] == item.Value;\n        }\n\n        /// <summary>\n        /// Copies to.\n        /// </summary>\n        /// <param name=\"array\">The array.</param>\n        /// <param name=\"arrayIndex\">Index of the array.</param>\n        public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)\n        {\n            if (array == null) throw new ArgumentNullException(\"array\");\n            int num = Count;\n            foreach (KeyValuePair<string, object> kvp in this)\n            {\n                array[arrayIndex++] = kvp;\n                if (--num <= 0)\n                    return;\n            }\n        }\n\n        /// <summary>\n        /// Gets the count.\n        /// </summary>\n        /// <value>The count.</value>\n        public int Count\n        {\n            get { return _members.Count; }\n        }\n\n        /// <summary>\n        /// Gets a value indicating whether this instance is read only.\n        /// </summary>\n        /// <value>\n        /// \t<c>true</c> if this instance is read only; otherwise, <c>false</c>.\n        /// </value>\n        public bool IsReadOnly\n        {\n            get { return false; }\n        }\n\n        /// <summary>\n        /// Removes the specified item.\n        /// </summary>\n        /// <param name=\"item\">The item.</param>\n        /// <returns></returns>\n        public bool Remove(KeyValuePair<string, object> item)\n        {\n            return _members.Remove(item.Key);\n        }\n\n        /// <summary>\n        /// Gets the enumerator.\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()\n        {\n            return _members.GetEnumerator();\n        }\n\n        /// <summary>\n        /// Returns an enumerator that iterates through a collection.\n        /// </summary>\n        /// <returns>\n        /// An <see cref=\"T:System.Collections.IEnumerator\"/> object that can be used to iterate through the collection.\n        /// </returns>\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return _members.GetEnumerator();\n        }\n\n        /// <summary>\n        /// Returns a json <see cref=\"T:System.String\"/> that represents the current <see cref=\"T:System.Object\"/>.\n        /// </summary>\n        /// <returns>\n        /// A json <see cref=\"T:System.String\"/> that represents the current <see cref=\"T:System.Object\"/>.\n        /// </returns>\n        public override string ToString()\n        {\n            return SimpleJson.SerializeObject(this);\n        }\n\n#if SIMPLE_JSON_DYNAMIC\n        /// <summary>\n        /// Provides implementation for type conversion operations. Classes derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class can override this method to specify dynamic behavior for operations that convert an object from one type to another.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the conversion operation. The binder.Type property provides the type to which the object must be converted. For example, for the statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic), where sampleObject is an instance of the class derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, binder.Type returns the <see cref=\"T:System.String\"/> type. The binder.Explicit property provides information about the kind of conversion that occurs. It returns true for explicit conversion and false for implicit conversion.</param>\n        /// <param name=\"result\">The result of the type conversion operation.</param>\n        /// <returns>\n        /// Alwasy returns true.\n        /// </returns>\n        public override bool TryConvert(ConvertBinder binder, out object result)\n        {\n            // <pex>\n            if (binder == null)\n                throw new ArgumentNullException(\"binder\");\n            // </pex>\n            Type targetType = binder.Type;\n\n            if ((targetType == typeof(IEnumerable)) ||\n                (targetType == typeof(IEnumerable<KeyValuePair<string, object>>)) ||\n                (targetType == typeof(IDictionary<string, object>)) ||\n                (targetType == typeof(IDictionary)))\n            {\n                result = this;\n                return true;\n            }\n\n            return base.TryConvert(binder, out result);\n        }\n\n        /// <summary>\n        /// Provides the implementation for operations that delete an object member. This method is not intended for use in C# or Visual Basic.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the deletion.</param>\n        /// <returns>\n        /// Alwasy returns true.\n        /// </returns>\n        public override bool TryDeleteMember(DeleteMemberBinder binder)\n        {\n            // <pex>\n            if (binder == null)\n                throw new ArgumentNullException(\"binder\");\n            // </pex>\n            return _members.Remove(binder.Name);\n        }\n\n        /// <summary>\n        /// Provides the implementation for operations that get a value by index. Classes derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class can override this method to specify dynamic behavior for indexing operations.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the operation.</param>\n        /// <param name=\"indexes\">The indexes that are used in the operation. For example, for the sampleObject[3] operation in C# (sampleObject(3) in Visual Basic), where sampleObject is derived from the DynamicObject class, <paramref name=\"indexes\"/> is equal to 3.</param>\n        /// <param name=\"result\">The result of the index operation.</param>\n        /// <returns>\n        /// Alwasy returns true.\n        /// </returns>\n        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)\n        {\n            if (indexes == null) throw new ArgumentNullException(\"indexes\");\n            if (indexes.Length == 1)\n            {\n                result = ((IDictionary<string, object>)this)[(string)indexes[0]];\n                return true;\n            }\n            result = null;\n            return true;\n        }\n\n        /// <summary>\n        /// Provides the implementation for operations that get member values. Classes derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class can override this method to specify dynamic behavior for operations such as getting a value for a property.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, binder.Name returns \"SampleProperty\". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>\n        /// <param name=\"result\">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name=\"result\"/>.</param>\n        /// <returns>\n        /// Alwasy returns true.\n        /// </returns>\n        public override bool TryGetMember(GetMemberBinder binder, out object result)\n        {\n            object value;\n            if (_members.TryGetValue(binder.Name, out value))\n            {\n                result = value;\n                return true;\n            }\n            result = null;\n            return true;\n        }\n\n        /// <summary>\n        /// Provides the implementation for operations that set a value by index. Classes derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class can override this method to specify dynamic behavior for operations that access objects by a specified index.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the operation.</param>\n        /// <param name=\"indexes\">The indexes that are used in the operation. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, <paramref name=\"indexes\"/> is equal to 3.</param>\n        /// <param name=\"value\">The value to set to the object that has the specified index. For example, for the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject is derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, <paramref name=\"value\"/> is equal to 10.</param>\n        /// <returns>\n        /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.\n        /// </returns>\n        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)\n        {\n            if (indexes == null) throw new ArgumentNullException(\"indexes\");\n            if (indexes.Length == 1)\n            {\n                ((IDictionary<string, object>)this)[(string)indexes[0]] = value;\n                return true;\n            }\n            return base.TrySetIndex(binder, indexes, value);\n        }\n\n        /// <summary>\n        /// Provides the implementation for operations that set member values. Classes derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class can override this method to specify dynamic behavior for operations such as setting a value for a property.\n        /// </summary>\n        /// <param name=\"binder\">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member to which the value is being assigned. For example, for the statement sampleObject.SampleProperty = \"Test\", where sampleObject is an instance of the class derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, binder.Name returns \"SampleProperty\". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>\n        /// <param name=\"value\">The value to set to the member. For example, for sampleObject.SampleProperty = \"Test\", where sampleObject is an instance of the class derived from the <see cref=\"T:System.Dynamic.DynamicObject\"/> class, the <paramref name=\"value\"/> is \"Test\".</param>\n        /// <returns>\n        /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a language-specific run-time exception is thrown.)\n        /// </returns>\n        public override bool TrySetMember(SetMemberBinder binder, object value)\n        {\n            // <pex>\n            if (binder == null)\n                throw new ArgumentNullException(\"binder\");\n            // </pex>\n            _members[binder.Name] = value;\n            return true;\n        }\n\n        /// <summary>\n        /// Returns the enumeration of all dynamic member names.\n        /// </summary>\n        /// <returns>\n        /// A sequence that contains dynamic member names.\n        /// </returns>\n        public override IEnumerable<string> GetDynamicMemberNames()\n        {\n            foreach (var key in Keys)\n                yield return key;\n        }\n#endif\n    }\n}\n\nnamespace Squirrel.Json\n{\n    /// <summary>\n    /// This class encodes and decodes JSON strings.\n    /// Spec. details, see http://www.json.org/\n    /// \n    /// JSON uses Arrays and Objects. These correspond here to the datatypes JsonArray(IList&lt;object>) and JsonObject(IDictionary&lt;string,object>).\n    /// All numbers are parsed to doubles.\n    /// </summary>\n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n#if SIMPLE_JSON_INTERNAL\n    internal\n#else\n    public\n#endif\n static class SimpleJson\n    {\n        private const int TOKEN_NONE = 0;\n        private const int TOKEN_CURLY_OPEN = 1;\n        private const int TOKEN_CURLY_CLOSE = 2;\n        private const int TOKEN_SQUARED_OPEN = 3;\n        private const int TOKEN_SQUARED_CLOSE = 4;\n        private const int TOKEN_COLON = 5;\n        private const int TOKEN_COMMA = 6;\n        private const int TOKEN_STRING = 7;\n        private const int TOKEN_NUMBER = 8;\n        private const int TOKEN_TRUE = 9;\n        private const int TOKEN_FALSE = 10;\n        private const int TOKEN_NULL = 11;\n        private const int BUILDER_CAPACITY = 2000;\n\n        private static readonly char[] EscapeTable;\n        private static readonly char[] EscapeCharacters = new char[] { '\"', '\\\\', '\\b', '\\f', '\\n', '\\r', '\\t' };\n        private static readonly string EscapeCharactersString = new string(EscapeCharacters);\n\n        static SimpleJson()\n        {\n            EscapeTable = new char[93];\n            EscapeTable['\"']  = '\"';\n            EscapeTable['\\\\'] = '\\\\';\n            EscapeTable['\\b'] = 'b';\n            EscapeTable['\\f'] = 'f';\n            EscapeTable['\\n'] = 'n';\n            EscapeTable['\\r'] = 'r';\n            EscapeTable['\\t'] = 't';\n        }\n\n        /// <summary>\n        /// Parses the string json into a value\n        /// </summary>\n        /// <param name=\"json\">A JSON string.</param>\n        /// <returns>An IList&lt;object>, a IDictionary&lt;string,object>, a double, a string, null, true, or false</returns>\n        public static object DeserializeObject(string json)\n        {\n            object obj;\n            if (TryDeserializeObject(json, out obj))\n                return obj;\n            throw new SerializationException(\"Invalid JSON string\");\n        }\n\n        /// <summary>\n        /// Try parsing the json string into a value.\n        /// </summary>\n        /// <param name=\"json\">\n        /// A JSON string.\n        /// </param>\n        /// <param name=\"obj\">\n        /// The object.\n        /// </param>\n        /// <returns>\n        /// Returns true if successfull otherwise false.\n        /// </returns>\n        [SuppressMessage(\"Microsoft.Design\", \"CA1007:UseGenericsWhereAppropriate\", Justification=\"Need to support .NET 2\")]\n        public static bool TryDeserializeObject(string json, out object obj)\n        {\n            bool success = true;\n            if (json != null)\n            {\n                char[] charArray = json.ToCharArray();\n                int index = 0;\n                obj = ParseValue(charArray, ref index, ref success);\n            }\n            else\n                obj = null;\n\n            return success;\n        }\n\n        public static object DeserializeObject(string json, Type type, IJsonSerializerStrategy jsonSerializerStrategy)\n        {\n            object jsonObject = DeserializeObject(json);\n            return type == null || jsonObject != null && ReflectionUtils.IsAssignableFrom(jsonObject.GetType(), type)\n                       ? jsonObject\n                       : (jsonSerializerStrategy ?? CurrentJsonSerializerStrategy).DeserializeObject(jsonObject, type);\n        }\n\n        public static object DeserializeObject(string json, Type type)\n        {\n            return DeserializeObject(json, type, null);\n        }\n\n        public static T DeserializeObject<T>(string json, IJsonSerializerStrategy jsonSerializerStrategy)\n        {\n            return (T)DeserializeObject(json, typeof(T), jsonSerializerStrategy);\n        }\n\n        public static T DeserializeObject<T>(string json)\n        {\n            return (T)DeserializeObject(json, typeof(T), null);\n        }\n\n        /// <summary>\n        /// Converts a IDictionary&lt;string,object> / IList&lt;object> object into a JSON string\n        /// </summary>\n        /// <param name=\"json\">A IDictionary&lt;string,object> / IList&lt;object></param>\n        /// <param name=\"jsonSerializerStrategy\">Serializer strategy to use</param>\n        /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>\n        public static string SerializeObject(object json, IJsonSerializerStrategy jsonSerializerStrategy)\n        {\n            StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);\n            bool success = SerializeValue(jsonSerializerStrategy, json, builder);\n            return (success ? builder.ToString() : null);\n        }\n\n        public static string SerializeObject(object json)\n        {\n            return SerializeObject(json, CurrentJsonSerializerStrategy);\n        }\n\n        public static string EscapeToJavascriptString(string jsonString)\n        {\n            if (string.IsNullOrEmpty(jsonString))\n                return jsonString;\n\n            StringBuilder sb = new StringBuilder();\n            char c;\n\n            for (int i = 0; i < jsonString.Length; )\n            {\n                c = jsonString[i++];\n\n                if (c == '\\\\')\n                {\n                    int remainingLength = jsonString.Length - i;\n                    if (remainingLength >= 2)\n                    {\n                        char lookahead = jsonString[i];\n                        if (lookahead == '\\\\')\n                        {\n                            sb.Append('\\\\');\n                            ++i;\n                        }\n                        else if (lookahead == '\"')\n                        {\n                            sb.Append(\"\\\"\");\n                            ++i;\n                        }\n                        else if (lookahead == 't')\n                        {\n                            sb.Append('\\t');\n                            ++i;\n                        }\n                        else if (lookahead == 'b')\n                        {\n                            sb.Append('\\b');\n                            ++i;\n                        }\n                        else if (lookahead == 'n')\n                        {\n                            sb.Append('\\n');\n                            ++i;\n                        }\n                        else if (lookahead == 'r')\n                        {\n                            sb.Append('\\r');\n                            ++i;\n                        }\n                    }\n                }\n                else\n                {\n                    sb.Append(c);\n                }\n            }\n            return sb.ToString();\n        }\n\n        static IDictionary<string, object> ParseObject(char[] json, ref int index, ref bool success)\n        {\n            IDictionary<string, object> table = new JsonObject();\n            int token;\n\n            // {\n            NextToken(json, ref index);\n\n            bool done = false;\n            while (!done)\n            {\n                token = LookAhead(json, index);\n                if (token == TOKEN_NONE)\n                {\n                    success = false;\n                    return null;\n                }\n                else if (token == TOKEN_COMMA)\n                    NextToken(json, ref index);\n                else if (token == TOKEN_CURLY_CLOSE)\n                {\n                    NextToken(json, ref index);\n                    return table;\n                }\n                else\n                {\n                    // name\n                    string name = ParseString(json, ref index, ref success);\n                    if (!success)\n                    {\n                        success = false;\n                        return null;\n                    }\n                    // :\n                    token = NextToken(json, ref index);\n                    if (token != TOKEN_COLON)\n                    {\n                        success = false;\n                        return null;\n                    }\n                    // value\n                    object value = ParseValue(json, ref index, ref success);\n                    if (!success)\n                    {\n                        success = false;\n                        return null;\n                    }\n                    table[name] = value;\n                }\n            }\n            return table;\n        }\n\n        static JsonArray ParseArray(char[] json, ref int index, ref bool success)\n        {\n            JsonArray array = new JsonArray();\n\n            // [\n            NextToken(json, ref index);\n\n            bool done = false;\n            while (!done)\n            {\n                int token = LookAhead(json, index);\n                if (token == TOKEN_NONE)\n                {\n                    success = false;\n                    return null;\n                }\n                else if (token == TOKEN_COMMA)\n                    NextToken(json, ref index);\n                else if (token == TOKEN_SQUARED_CLOSE)\n                {\n                    NextToken(json, ref index);\n                    break;\n                }\n                else\n                {\n                    object value = ParseValue(json, ref index, ref success);\n                    if (!success)\n                        return null;\n                    array.Add(value);\n                }\n            }\n            return array;\n        }\n\n        static object ParseValue(char[] json, ref int index, ref bool success)\n        {\n            switch (LookAhead(json, index))\n            {\n                case TOKEN_STRING:\n                    return ParseString(json, ref index, ref success);\n                case TOKEN_NUMBER:\n                    return ParseNumber(json, ref index, ref success);\n                case TOKEN_CURLY_OPEN:\n                    return ParseObject(json, ref index, ref success);\n                case TOKEN_SQUARED_OPEN:\n                    return ParseArray(json, ref index, ref success);\n                case TOKEN_TRUE:\n                    NextToken(json, ref index);\n                    return true;\n                case TOKEN_FALSE:\n                    NextToken(json, ref index);\n                    return false;\n                case TOKEN_NULL:\n                    NextToken(json, ref index);\n                    return null;\n                case TOKEN_NONE:\n                    break;\n            }\n            success = false;\n            return null;\n        }\n\n        static string ParseString(char[] json, ref int index, ref bool success)\n        {\n            StringBuilder s = new StringBuilder(BUILDER_CAPACITY);\n            char c;\n\n            EatWhitespace(json, ref index);\n\n            // \"\n            c = json[index++];\n            bool complete = false;\n            while (!complete)\n            {\n                if (index == json.Length)\n                    break;\n\n                c = json[index++];\n                if (c == '\"')\n                {\n                    complete = true;\n                    break;\n                }\n                else if (c == '\\\\')\n                {\n                    if (index == json.Length)\n                        break;\n                    c = json[index++];\n                    if (c == '\"')\n                        s.Append('\"');\n                    else if (c == '\\\\')\n                        s.Append('\\\\');\n                    else if (c == '/')\n                        s.Append('/');\n                    else if (c == 'b')\n                        s.Append('\\b');\n                    else if (c == 'f')\n                        s.Append('\\f');\n                    else if (c == 'n')\n                        s.Append('\\n');\n                    else if (c == 'r')\n                        s.Append('\\r');\n                    else if (c == 't')\n                        s.Append('\\t');\n                    else if (c == 'u')\n                    {\n                        int remainingLength = json.Length - index;\n                        if (remainingLength >= 4)\n                        {\n                            // parse the 32 bit hex into an integer codepoint\n                            uint codePoint;\n                            if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint)))\n                                return \"\";\n\n                            // convert the integer codepoint to a unicode char and add to string\n                            if (0xD800 <= codePoint && codePoint <= 0xDBFF)  // if high surrogate\n                            {\n                                index += 4; // skip 4 chars\n                                remainingLength = json.Length - index;\n                                if (remainingLength >= 6)\n                                {\n                                    uint lowCodePoint;\n                                    if (new string(json, index, 2) == \"\\\\u\" && UInt32.TryParse(new string(json, index + 2, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out lowCodePoint))\n                                    {\n                                        if (0xDC00 <= lowCodePoint && lowCodePoint <= 0xDFFF)    // if low surrogate\n                                        {\n                                            s.Append((char)codePoint);\n                                            s.Append((char)lowCodePoint);\n                                            index += 6; // skip 6 chars\n                                            continue;\n                                        }\n                                    }\n                                }\n                                success = false;    // invalid surrogate pair\n                                return \"\";\n                            }\n                            s.Append(ConvertFromUtf32((int)codePoint));\n                            // skip 4 chars\n                            index += 4;\n                        }\n                        else\n                            break;\n                    }\n                }\n                else\n                    s.Append(c);\n            }\n            if (!complete)\n            {\n                success = false;\n                return null;\n            }\n            return s.ToString();\n        }\n\n        private static string ConvertFromUtf32(int utf32)\n        {\n            // http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System/System/Char.cs.htm\n            if (utf32 < 0 || utf32 > 0x10FFFF)\n                throw new ArgumentOutOfRangeException(\"utf32\", \"The argument must be from 0 to 0x10FFFF.\");\n            if (0xD800 <= utf32 && utf32 <= 0xDFFF)\n                throw new ArgumentOutOfRangeException(\"utf32\", \"The argument must not be in surrogate pair range.\");\n            if (utf32 < 0x10000)\n                return new string((char)utf32, 1);\n            utf32 -= 0x10000;\n            return new string(new char[] { (char)((utf32 >> 10) + 0xD800), (char)(utf32 % 0x0400 + 0xDC00) });\n        }\n\n        static object ParseNumber(char[] json, ref int index, ref bool success)\n        {\n            EatWhitespace(json, ref index);\n            int lastIndex = GetLastIndexOfNumber(json, index);\n            int charLength = (lastIndex - index) + 1;\n            object returnNumber;\n            string str = new string(json, index, charLength);\n            if (str.IndexOf(\".\", StringComparison.OrdinalIgnoreCase) != -1 || str.IndexOf(\"e\", StringComparison.OrdinalIgnoreCase) != -1)\n            {\n                double number;\n                success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);\n                returnNumber = number;\n            }\n            else\n            {\n                long number;\n                success = long.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);\n                returnNumber = number;\n            }\n            index = lastIndex + 1;\n            return returnNumber;\n        }\n\n        static int GetLastIndexOfNumber(char[] json, int index)\n        {\n            int lastIndex;\n            for (lastIndex = index; lastIndex < json.Length; lastIndex++)\n                if (\"0123456789+-.eE\".IndexOf(json[lastIndex]) == -1) break;\n            return lastIndex - 1;\n        }\n\n        static void EatWhitespace(char[] json, ref int index)\n        {\n            for (; index < json.Length; index++)\n                if (\" \\t\\n\\r\\b\\f\".IndexOf(json[index]) == -1) break;\n        }\n\n        static int LookAhead(char[] json, int index)\n        {\n            int saveIndex = index;\n            return NextToken(json, ref saveIndex);\n        }\n\n        [SuppressMessage(\"Microsoft.Maintainability\", \"CA1502:AvoidExcessiveComplexity\")]\n        static int NextToken(char[] json, ref int index)\n        {\n            EatWhitespace(json, ref index);\n            if (index == json.Length)\n                return TOKEN_NONE;\n            char c = json[index];\n            index++;\n            switch (c)\n            {\n                case '{':\n                    return TOKEN_CURLY_OPEN;\n                case '}':\n                    return TOKEN_CURLY_CLOSE;\n                case '[':\n                    return TOKEN_SQUARED_OPEN;\n                case ']':\n                    return TOKEN_SQUARED_CLOSE;\n                case ',':\n                    return TOKEN_COMMA;\n                case '\"':\n                    return TOKEN_STRING;\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                    return TOKEN_NUMBER;\n                case ':':\n                    return TOKEN_COLON;\n            }\n            index--;\n            int remainingLength = json.Length - index;\n            // false\n            if (remainingLength >= 5)\n            {\n                if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && json[index + 4] == 'e')\n                {\n                    index += 5;\n                    return TOKEN_FALSE;\n                }\n            }\n            // true\n            if (remainingLength >= 4)\n            {\n                if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e')\n                {\n                    index += 4;\n                    return TOKEN_TRUE;\n                }\n            }\n            // null\n            if (remainingLength >= 4)\n            {\n                if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l')\n                {\n                    index += 4;\n                    return TOKEN_NULL;\n                }\n            }\n            return TOKEN_NONE;\n        }\n\n        static bool SerializeValue(IJsonSerializerStrategy jsonSerializerStrategy, object value, StringBuilder builder)\n        {\n            bool success = true;\n            string stringValue = value as string;\n            if (stringValue != null)\n                success = SerializeString(stringValue, builder);\n            else\n            {\n                IDictionary<string, object> dict = value as IDictionary<string, object>;\n                if (dict != null)\n                {\n                    success = SerializeObject(jsonSerializerStrategy, dict.Keys, dict.Values, builder);\n                }\n                else\n                {\n                    IDictionary<string, string> stringDictionary = value as IDictionary<string, string>;\n                    if (stringDictionary != null)\n                    {\n                        success = SerializeObject(jsonSerializerStrategy, stringDictionary.Keys, stringDictionary.Values, builder);\n                    }\n                    else\n                    {\n                        IEnumerable enumerableValue = value as IEnumerable;\n                        if (enumerableValue != null)\n                            success = SerializeArray(jsonSerializerStrategy, enumerableValue, builder);\n                        else if (IsNumeric(value))\n                            success = SerializeNumber(value, builder);\n                        else if (value is bool)\n                            builder.Append((bool)value ? \"true\" : \"false\");\n                        else if (value == null)\n                            builder.Append(\"null\");\n                        else\n                        {\n                            object serializedObject;\n                            success = jsonSerializerStrategy.TrySerializeNonPrimitiveObject(value, out serializedObject);\n                            if (success)\n                                SerializeValue(jsonSerializerStrategy, serializedObject, builder);\n                        }\n                    }\n                }\n            }\n            return success;\n        }\n\n        static bool SerializeObject(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable keys, IEnumerable values, StringBuilder builder)\n        {\n            builder.Append(\"{\");\n            IEnumerator ke = keys.GetEnumerator();\n            IEnumerator ve = values.GetEnumerator();\n            bool first = true;\n            while (ke.MoveNext() && ve.MoveNext())\n            {\n                object key = ke.Current;\n                object value = ve.Current;\n                if (!first)\n                    builder.Append(\",\");\n                string stringKey = key as string;\n                if (stringKey != null)\n                    SerializeString(stringKey, builder);\n                else\n                    if (!SerializeValue(jsonSerializerStrategy, value, builder)) return false;\n                builder.Append(\":\");\n                if (!SerializeValue(jsonSerializerStrategy, value, builder))\n                    return false;\n                first = false;\n            }\n            builder.Append(\"}\");\n            return true;\n        }\n\n        static bool SerializeArray(IJsonSerializerStrategy jsonSerializerStrategy, IEnumerable anArray, StringBuilder builder)\n        {\n            builder.Append(\"[\");\n            bool first = true;\n            foreach (object value in anArray)\n            {\n                if (!first)\n                    builder.Append(\",\");\n                if (!SerializeValue(jsonSerializerStrategy, value, builder))\n                    return false;\n                first = false;\n            }\n            builder.Append(\"]\");\n            return true;\n        }\n\n        static bool SerializeString(string aString, StringBuilder builder)\n        {\n            // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged)\n            if (aString.IndexOfAny(EscapeCharacters) == -1)\n            {\n                builder.Append('\"');\n                builder.Append(aString);\n                builder.Append('\"');\n\n                return true;\n            }\n\n            builder.Append('\"');\n            int safeCharacterCount = 0;\n            char[] charArray = aString.ToCharArray();\n\n            for (int i = 0; i < charArray.Length; i++)\n            {\n                char c = charArray[i];\n\n                // Non ascii characters are fine, buffer them up and send them to the builder\n                // in larger chunks if possible. The escape table is a 1:1 translation table\n                // with \\0 [default(char)] denoting a safe character.\n                if (c >= EscapeTable.Length || EscapeTable[c] == default(char))\n                {\n                    safeCharacterCount++;\n                }\n                else\n                {\n                    if (safeCharacterCount > 0)\n                    {\n                        builder.Append(charArray, i - safeCharacterCount, safeCharacterCount);\n                        safeCharacterCount = 0;\n                    }\n\n                    builder.Append('\\\\');\n                    builder.Append(EscapeTable[c]);\n                }\n            }\n\n            if (safeCharacterCount > 0)\n            {\n                builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount);\n            }\n\n            builder.Append('\"');\n            return true;\n        }\n\n        static bool SerializeNumber(object number, StringBuilder builder)\n        {\n            if (number is long)\n                builder.Append(((long)number).ToString(CultureInfo.InvariantCulture));\n            else if (number is ulong)\n                builder.Append(((ulong)number).ToString(CultureInfo.InvariantCulture));\n            else if (number is int)\n                builder.Append(((int)number).ToString(CultureInfo.InvariantCulture));\n            else if (number is uint)\n                builder.Append(((uint)number).ToString(CultureInfo.InvariantCulture));\n            else if (number is decimal)\n                builder.Append(((decimal)number).ToString(CultureInfo.InvariantCulture));\n            else if (number is float)\n                builder.Append(((float)number).ToString(CultureInfo.InvariantCulture));\n            else\n                builder.Append(Convert.ToDouble(number, CultureInfo.InvariantCulture).ToString(\"r\", CultureInfo.InvariantCulture));\n            return true;\n        }\n\n        /// <summary>\n        /// Determines if a given object is numeric in any way\n        /// (can be integer, double, null, etc).\n        /// </summary>\n        static bool IsNumeric(object value)\n        {\n            if (value is sbyte) return true;\n            if (value is byte) return true;\n            if (value is short) return true;\n            if (value is ushort) return true;\n            if (value is int) return true;\n            if (value is uint) return true;\n            if (value is long) return true;\n            if (value is ulong) return true;\n            if (value is float) return true;\n            if (value is double) return true;\n            if (value is decimal) return true;\n            return false;\n        }\n\n        private static IJsonSerializerStrategy _currentJsonSerializerStrategy;\n        public static IJsonSerializerStrategy CurrentJsonSerializerStrategy\n        {\n            get\n            {\n                return _currentJsonSerializerStrategy ??\n                    (_currentJsonSerializerStrategy =\n#if SIMPLE_JSON_DATACONTRACT\n DataContractJsonSerializerStrategy\n#else\n PocoJsonSerializerStrategy\n#endif\n);\n            }\n            set\n            {\n                _currentJsonSerializerStrategy = value;\n            }\n        }\n\n        private static PocoJsonSerializerStrategy _pocoJsonSerializerStrategy;\n        [EditorBrowsable(EditorBrowsableState.Advanced)]\n        public static PocoJsonSerializerStrategy PocoJsonSerializerStrategy\n        {\n            get\n            {\n                return _pocoJsonSerializerStrategy ?? (_pocoJsonSerializerStrategy = new PocoJsonSerializerStrategy());\n            }\n        }\n\n#if SIMPLE_JSON_DATACONTRACT\n\n        private static DataContractJsonSerializerStrategy _dataContractJsonSerializerStrategy;\n        [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Advanced)]\n        public static DataContractJsonSerializerStrategy DataContractJsonSerializerStrategy\n        {\n            get\n            {\n                return _dataContractJsonSerializerStrategy ?? (_dataContractJsonSerializerStrategy = new DataContractJsonSerializerStrategy());\n            }\n        }\n\n#endif\n    }\n    \n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n#if SIMPLE_JSON_INTERNAL\n    internal\n#else\n    public\n#endif\n interface IJsonSerializerStrategy\n    {\n        [SuppressMessage(\"Microsoft.Design\", \"CA1007:UseGenericsWhereAppropriate\", Justification=\"Need to support .NET 2\")]\n        bool TrySerializeNonPrimitiveObject(object input, out object output);\n        object DeserializeObject(object value, Type type);\n    }\n\n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n#if SIMPLE_JSON_INTERNAL\n    internal\n#else\n    public\n#endif\n class PocoJsonSerializerStrategy : IJsonSerializerStrategy\n    {\n        internal IDictionary<Type, ReflectionUtils.ConstructorDelegate> ConstructorCache;\n        internal IDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>> GetCache;\n        internal IDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>> SetCache;\n\n        internal static readonly Type[] EmptyTypes = new Type[0];\n        internal static readonly Type[] ArrayConstructorParameterTypes = new Type[] { typeof(int) };\n\n        private static readonly string[] Iso8601Format = new string[]\n                                                             {\n                                                                 @\"yyyy-MM-dd\\THH:mm:ss.FFFFFFF\\Z\",\n                                                                 @\"yyyy-MM-dd\\THH:mm:ss\\Z\",\n                                                                 @\"yyyy-MM-dd\\THH:mm:ssK\"\n                                                             };\n\n        public PocoJsonSerializerStrategy()\n        {\n            ConstructorCache = new ReflectionUtils.ThreadSafeDictionary<Type, ReflectionUtils.ConstructorDelegate>(ContructorDelegateFactory);\n            GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);\n            SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);\n        }\n\n        protected virtual string MapClrMemberNameToJsonFieldName(string clrPropertyName)\n        {\n            return clrPropertyName;\n        }\n\n        internal virtual ReflectionUtils.ConstructorDelegate ContructorDelegateFactory(Type key)\n        {\n            return ReflectionUtils.GetContructor(key, key.IsArray ? ArrayConstructorParameterTypes : EmptyTypes);\n        }\n\n        internal virtual IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)\n        {\n            IDictionary<string, ReflectionUtils.GetDelegate> result = new Dictionary<string, ReflectionUtils.GetDelegate>();\n            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))\n            {\n                if (propertyInfo.CanRead)\n                {\n                    MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);\n                    if (getMethod.IsStatic || !getMethod.IsPublic)\n                        continue;\n                    result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = ReflectionUtils.GetGetMethod(propertyInfo);\n                }\n            }\n            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))\n            {\n                if (fieldInfo.IsStatic || !fieldInfo.IsPublic)\n                    continue;\n                result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = ReflectionUtils.GetGetMethod(fieldInfo);\n            }\n            return result;\n        }\n\n        internal virtual IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)\n        {\n            IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> result = new Dictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>();\n            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))\n            {\n                if (propertyInfo.CanWrite)\n                {\n                    MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);\n                    if (setMethod.IsStatic || !setMethod.IsPublic)\n                        continue;\n                    result[MapClrMemberNameToJsonFieldName(propertyInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));\n                }\n            }\n            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))\n            {\n                if (fieldInfo.IsInitOnly || fieldInfo.IsStatic || !fieldInfo.IsPublic)\n                    continue;\n                result[MapClrMemberNameToJsonFieldName(fieldInfo.Name)] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));\n            }\n            return result;\n        }\n\n        public virtual bool TrySerializeNonPrimitiveObject(object input, out object output)\n        {\n            return TrySerializeKnownTypes(input, out output) || TrySerializeUnknownTypes(input, out output);\n        }\n\n        [SuppressMessage(\"Microsoft.Maintainability\", \"CA1502:AvoidExcessiveComplexity\")]\n        public virtual object DeserializeObject(object value, Type type)\n        {\n            if (type == null) throw new ArgumentNullException(\"type\");\n            string str = value as string;\n\n            if (type == typeof (Guid) && string.IsNullOrEmpty(str))\n                return default(Guid);\n\n            if (value == null)\n                return null;\n            \n            object obj = null;\n\n            if (str != null)\n            {\n                if (str.Length != 0) // We know it can't be null now.\n                {\n                    if (type == typeof(DateTime) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTime)))\n                        return DateTime.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);\n                    if (type == typeof(DateTimeOffset) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(DateTimeOffset)))\n                        return DateTimeOffset.ParseExact(str, Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);\n                    if (type == typeof(Guid) || (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid)))\n                        return new Guid(str);\n                    if (type == typeof(Uri))\n                    {\n                        bool isValid =  Uri.IsWellFormedUriString(str, UriKind.RelativeOrAbsolute);\n\n                        Uri result;\n                        if (isValid && Uri.TryCreate(str, UriKind.RelativeOrAbsolute, out result))\n                            return result;\n\n\t\t\t\t\t\t\t\t\t\t\t\treturn null;\n                    }\n                  \n\t\t\t\t\t\t\t\t\tif (type == typeof(string))  \n\t\t\t\t\t\t\t\t\t\treturn str;\n\n\t\t\t\t\t\t\t\t\treturn Convert.ChangeType(str, type, CultureInfo.InvariantCulture);\n                }\n                else\n                {\n                    if (type == typeof(Guid))\n                        obj = default(Guid);\n                    else if (ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))\n                        obj = null;\n                    else\n                        obj = str;\n                }\n                // Empty string case\n                if (!ReflectionUtils.IsNullableType(type) && Nullable.GetUnderlyingType(type) == typeof(Guid))\n                    return str;\n            }\n            else if (value is bool)\n                return value;\n            \n            bool valueIsLong = value is long;\n            bool valueIsDouble = value is double;\n            if ((valueIsLong && type == typeof(long)) || (valueIsDouble && type == typeof(double)))\n                return value;\n            if ((valueIsDouble && type != typeof(double)) || (valueIsLong && type != typeof(long)))\n            {\n                obj = type == typeof(int) || type == typeof(long) || type == typeof(double) || type == typeof(float) || type == typeof(bool) || type == typeof(decimal) || type == typeof(byte) || type == typeof(short)\n                            ? Convert.ChangeType(value, type, CultureInfo.InvariantCulture)\n                            : value;\n            }\n            else\n            {\n                IDictionary<string, object> objects = value as IDictionary<string, object>;\n                if (objects != null)\n                {\n                    IDictionary<string, object> jsonObject = objects;\n\n                    if (ReflectionUtils.IsTypeDictionary(type))\n                    {\n                        // if dictionary then\n                        Type[] types = ReflectionUtils.GetGenericTypeArguments(type);\n                        Type keyType = types[0];\n                        Type valueType = types[1];\n\n                        Type genericType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);\n\n                        IDictionary dict = (IDictionary)ConstructorCache[genericType]();\n\n                        foreach (KeyValuePair<string, object> kvp in jsonObject)\n                            dict.Add(kvp.Key, DeserializeObject(kvp.Value, valueType));\n\n                        obj = dict;\n                    }\n                    else\n                    {\n                        if (type == typeof(object))\n                            obj = value;\n                        else\n                        {\n                            obj = ConstructorCache[type]();\n                            foreach (KeyValuePair<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> setter in SetCache[type])\n                            {\n                                object jsonValue;\n                                if (jsonObject.TryGetValue(setter.Key, out jsonValue))\n                                {\n                                    jsonValue = DeserializeObject(jsonValue, setter.Value.Key);\n                                    setter.Value.Value(obj, jsonValue);\n                                }\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    IList<object> valueAsList = value as IList<object>;\n                    if (valueAsList != null)\n                    {\n                        IList<object> jsonObject = valueAsList;\n                        IList list = null;\n\n                        if (type.IsArray)\n                        {\n                            list = (IList)ConstructorCache[type](jsonObject.Count);\n                            int i = 0;\n                            foreach (object o in jsonObject)\n                                list[i++] = DeserializeObject(o, type.GetElementType());\n                        }\n                        else if (ReflectionUtils.IsTypeGenericeCollectionInterface(type) || ReflectionUtils.IsAssignableFrom(typeof(IList), type))\n                        {\n                            Type innerType = ReflectionUtils.GetGenericListElementType(type);\n                            list = (IList)(ConstructorCache[type] ?? ConstructorCache[typeof(List<>).MakeGenericType(innerType)])(jsonObject.Count);\n                            foreach (object o in jsonObject)\n                                list.Add(DeserializeObject(o, innerType));\n                        }\n                        obj = list;\n                    }\n                }\n                return obj;\n            }\n            if (ReflectionUtils.IsNullableType(type))\n                return ReflectionUtils.ToNullableType(obj, type);\n            return obj;\n        }\n\n        protected virtual object SerializeEnum(Enum p)\n        {\n            return Convert.ToDouble(p, CultureInfo.InvariantCulture);\n        }\n\n        [SuppressMessage(\"Microsoft.Design\", \"CA1007:UseGenericsWhereAppropriate\", Justification=\"Need to support .NET 2\")]\n        protected virtual bool TrySerializeKnownTypes(object input, out object output)\n        {\n            bool returnValue = true;\n            if (input is DateTime)\n                output = ((DateTime)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);\n            else if (input is DateTimeOffset)\n                output = ((DateTimeOffset)input).ToUniversalTime().ToString(Iso8601Format[0], CultureInfo.InvariantCulture);\n            else if (input is Guid)\n                output = ((Guid)input).ToString(\"D\");\n            else if (input is Uri)\n                output = input.ToString();\n            else\n            {\n                Enum inputEnum = input as Enum;\n                if (inputEnum != null)\n                    output = SerializeEnum(inputEnum);\n                else\n                {\n                    returnValue = false;\n                    output = null;\n                }\n            }\n            return returnValue;\n        }\n        [SuppressMessage(\"Microsoft.Design\", \"CA1007:UseGenericsWhereAppropriate\", Justification=\"Need to support .NET 2\")]\n        protected virtual bool TrySerializeUnknownTypes(object input, out object output)\n        {\n            if (input == null) throw new ArgumentNullException(\"input\");\n            output = null;\n            Type type = input.GetType();\n            if (type.FullName == null)\n                return false;\n            IDictionary<string, object> obj = new JsonObject();\n            IDictionary<string, ReflectionUtils.GetDelegate> getters = GetCache[type];\n            foreach (KeyValuePair<string, ReflectionUtils.GetDelegate> getter in getters)\n            {\n                if (getter.Value != null)\n                    obj.Add(MapClrMemberNameToJsonFieldName(getter.Key), getter.Value(input));\n            }\n            output = obj;\n            return true;\n        }\n    }\n\n#if SIMPLE_JSON_DATACONTRACT\n    [GeneratedCode(\"simple-json\", \"1.0.0\")]\n#if SIMPLE_JSON_INTERNAL\n    internal\n#else\n    public\n#endif\n class DataContractJsonSerializerStrategy : PocoJsonSerializerStrategy\n    {\n        public DataContractJsonSerializerStrategy()\n        {\n            GetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, ReflectionUtils.GetDelegate>>(GetterValueFactory);\n            SetCache = new ReflectionUtils.ThreadSafeDictionary<Type, IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>>(SetterValueFactory);\n        }\n\n        internal override IDictionary<string, ReflectionUtils.GetDelegate> GetterValueFactory(Type type)\n        {\n            bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;\n            if (!hasDataContract)\n                return base.GetterValueFactory(type);\n            string jsonKey;\n            IDictionary<string, ReflectionUtils.GetDelegate> result = new Dictionary<string, ReflectionUtils.GetDelegate>();\n            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))\n            {\n                if (propertyInfo.CanRead)\n                {\n                    MethodInfo getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);\n                    if (!getMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))\n                        result[jsonKey] = ReflectionUtils.GetGetMethod(propertyInfo);\n                }\n            }\n            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))\n            {\n                if (!fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))\n                    result[jsonKey] = ReflectionUtils.GetGetMethod(fieldInfo);\n            }\n            return result;\n        }\n\n        internal override IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> SetterValueFactory(Type type)\n        {\n            bool hasDataContract = ReflectionUtils.GetAttribute(type, typeof(DataContractAttribute)) != null;\n            if (!hasDataContract)\n                return base.SetterValueFactory(type);\n            string jsonKey;\n            IDictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>> result = new Dictionary<string, KeyValuePair<Type, ReflectionUtils.SetDelegate>>();\n            foreach (PropertyInfo propertyInfo in ReflectionUtils.GetProperties(type))\n            {\n                if (propertyInfo.CanWrite)\n                {\n                    MethodInfo setMethod = ReflectionUtils.GetSetterMethodInfo(propertyInfo);\n                    if (!setMethod.IsStatic && CanAdd(propertyInfo, out jsonKey))\n                        result[jsonKey] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(propertyInfo.PropertyType, ReflectionUtils.GetSetMethod(propertyInfo));\n                }\n            }\n            foreach (FieldInfo fieldInfo in ReflectionUtils.GetFields(type))\n            {\n                if (!fieldInfo.IsInitOnly && !fieldInfo.IsStatic && CanAdd(fieldInfo, out jsonKey))\n                    result[jsonKey] = new KeyValuePair<Type, ReflectionUtils.SetDelegate>(fieldInfo.FieldType, ReflectionUtils.GetSetMethod(fieldInfo));\n            }\n            // todo implement sorting for DATACONTRACT.\n            return result;\n        }\n\n        private static bool CanAdd(MemberInfo info, out string jsonKey)\n        {\n            jsonKey = null;\n            if (ReflectionUtils.GetAttribute(info, typeof(IgnoreDataMemberAttribute)) != null)\n                return false;\n            DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)ReflectionUtils.GetAttribute(info, typeof(DataMemberAttribute));\n            if (dataMemberAttribute == null)\n                return false;\n            jsonKey = string.IsNullOrEmpty(dataMemberAttribute.Name) ? info.Name : dataMemberAttribute.Name;\n            return true;\n        }\n    }\n\n#endif\n\n    namespace Reflection\n    {\n        // This class is meant to be copied into other libraries. So we want to exclude it from Code Analysis rules\n \t    // that might be in place in the target project.\n        [GeneratedCode(\"reflection-utils\", \"1.0.0\")]\n#if SIMPLE_JSON_REFLECTION_UTILS_PUBLIC\n        public\n#else\n        internal\n#endif\n class ReflectionUtils\n        {\n            private static readonly object[] EmptyObjects = new object[] { };\n\n            public delegate object GetDelegate(object source);\n            public delegate void SetDelegate(object source, object value);\n            public delegate object ConstructorDelegate(params object[] args);\n\n            public delegate TValue ThreadSafeDictionaryValueFactory<TKey, TValue>(TKey key);\n\n#if SIMPLE_JSON_TYPEINFO\n            public static TypeInfo GetTypeInfo(Type type)\n            {\n                return type.GetTypeInfo();\n            }\n#else\n            public static Type GetTypeInfo(Type type)\n            {\n                return type;\n            }\n#endif\n\n            public static Attribute GetAttribute(MemberInfo info, Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                if (info == null || type == null || !info.IsDefined(type))\n                    return null;\n                return info.GetCustomAttribute(type);\n#else\n                if (info == null || type == null || !Attribute.IsDefined(info, type))\n                    return null;\n                return Attribute.GetCustomAttribute(info, type);\n#endif\n            }\n\n            public static Type GetGenericListElementType(Type type)\n            {\n                IEnumerable<Type> interfaces;\n#if SIMPLE_JSON_TYPEINFO\n                interfaces = type.GetTypeInfo().ImplementedInterfaces;\n#else\n                interfaces = type.GetInterfaces();\n#endif\n                foreach (Type implementedInterface in interfaces)\n                {\n                    if (IsTypeGeneric(implementedInterface) &&\n                        implementedInterface.GetGenericTypeDefinition() == typeof (IList<>))\n                    {\n                        return GetGenericTypeArguments(implementedInterface)[0];\n                    }\n                }\n                return GetGenericTypeArguments(type)[0];\n            }\n\n            public static Attribute GetAttribute(Type objectType, Type attributeType)\n            {\n\n#if SIMPLE_JSON_TYPEINFO\n                if (objectType == null || attributeType == null || !objectType.GetTypeInfo().IsDefined(attributeType))\n                    return null;\n                return objectType.GetTypeInfo().GetCustomAttribute(attributeType);\n#else\n                if (objectType == null || attributeType == null || !Attribute.IsDefined(objectType, attributeType))\n                    return null;\n                return Attribute.GetCustomAttribute(objectType, attributeType);\n#endif\n            }\n\n            public static Type[] GetGenericTypeArguments(Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return type.GetTypeInfo().GenericTypeArguments;\n#else\n                return type.GetGenericArguments();\n#endif\n            }\n\n            public static bool IsTypeGeneric(Type type)\n            {\n                return GetTypeInfo(type).IsGenericType;\n            }\n\n            public static bool IsTypeGenericeCollectionInterface(Type type)\n            {\n                if (!IsTypeGeneric(type))\n                    return false;\n\n                Type genericDefinition = type.GetGenericTypeDefinition();\n\n                return (genericDefinition == typeof(IList<>)\n                    || genericDefinition == typeof(ICollection<>)\n                    || genericDefinition == typeof(IEnumerable<>)\n#if SIMPLE_JSON_READONLY_COLLECTIONS\n                    || genericDefinition == typeof(IReadOnlyCollection<>)\n                    || genericDefinition == typeof(IReadOnlyList<>)\n#endif\n                    );\n            }\n\n            public static bool IsAssignableFrom(Type type1, Type type2)\n            {\n                return GetTypeInfo(type1).IsAssignableFrom(GetTypeInfo(type2));\n            }\n\n            public static bool IsTypeDictionary(Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                if (typeof(IDictionary<,>).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))\n                    return true;\n#else\n                if (typeof(System.Collections.IDictionary).IsAssignableFrom(type))\n                    return true;\n#endif\n                if (!GetTypeInfo(type).IsGenericType)\n                    return false;\n\n                Type genericDefinition = type.GetGenericTypeDefinition();\n                return genericDefinition == typeof(IDictionary<,>);\n            }\n\n            public static bool IsNullableType(Type type)\n            {\n                return GetTypeInfo(type).IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);\n            }\n\n            public static object ToNullableType(object obj, Type nullableType)\n            {\n                return obj == null ? null : Convert.ChangeType(obj, Nullable.GetUnderlyingType(nullableType), CultureInfo.InvariantCulture);\n            }\n\n            public static bool IsValueType(Type type)\n            {\n                return GetTypeInfo(type).IsValueType;\n            }\n\n            public static IEnumerable<ConstructorInfo> GetConstructors(Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return type.GetTypeInfo().DeclaredConstructors;\n#else\n                return type.GetConstructors();\n#endif\n            }\n\n            public static ConstructorInfo GetConstructorInfo(Type type, params Type[] argsType)\n            {\n                IEnumerable<ConstructorInfo> constructorInfos = GetConstructors(type);\n                int i;\n                bool matches;\n                foreach (ConstructorInfo constructorInfo in constructorInfos)\n                {\n                    ParameterInfo[] parameters = constructorInfo.GetParameters();\n                    if (argsType.Length != parameters.Length)\n                        continue;\n\n                    i = 0;\n                    matches = true;\n                    foreach (ParameterInfo parameterInfo in constructorInfo.GetParameters())\n                    {\n                        if (parameterInfo.ParameterType != argsType[i])\n                        {\n                            matches = false;\n                            break;\n                        }\n                    }\n\n                    if (matches)\n                        return constructorInfo;\n                }\n\n                return null;\n            }\n\n            public static IEnumerable<PropertyInfo> GetProperties(Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return type.GetRuntimeProperties();\n#else\n                return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);\n#endif\n            }\n\n            public static IEnumerable<FieldInfo> GetFields(Type type)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return type.GetRuntimeFields();\n#else\n                return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);\n#endif\n            }\n\n            public static MethodInfo GetGetterMethodInfo(PropertyInfo propertyInfo)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return propertyInfo.GetMethod;\n#else\n                return propertyInfo.GetGetMethod(true);\n#endif\n            }\n\n            public static MethodInfo GetSetterMethodInfo(PropertyInfo propertyInfo)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return propertyInfo.SetMethod;\n#else\n                return propertyInfo.GetSetMethod(true);\n#endif\n            }\n\n            public static ConstructorDelegate GetContructor(ConstructorInfo constructorInfo)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetConstructorByReflection(constructorInfo);\n#else\n                return GetConstructorByExpression(constructorInfo);\n#endif\n            }\n\n            public static ConstructorDelegate GetContructor(Type type, params Type[] argsType)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetConstructorByReflection(type, argsType);\n#else\n                return GetConstructorByExpression(type, argsType);\n#endif\n            }\n\n            public static ConstructorDelegate GetConstructorByReflection(ConstructorInfo constructorInfo)\n            {\n                return delegate(object[] args) { return constructorInfo.Invoke(args); };\n            }\n\n            public static ConstructorDelegate GetConstructorByReflection(Type type, params Type[] argsType)\n            {\n                ConstructorInfo constructorInfo = GetConstructorInfo(type, argsType);\n                return constructorInfo == null ? null : GetConstructorByReflection(constructorInfo);\n            }\n\n#if !SIMPLE_JSON_NO_LINQ_EXPRESSION\n\n            public static ConstructorDelegate GetConstructorByExpression(ConstructorInfo constructorInfo)\n            {\n                ParameterInfo[] paramsInfo = constructorInfo.GetParameters();\n                ParameterExpression param = Expression.Parameter(typeof(object[]), \"args\");\n                Expression[] argsExp = new Expression[paramsInfo.Length];\n                for (int i = 0; i < paramsInfo.Length; i++)\n                {\n                    Expression index = Expression.Constant(i);\n                    Type paramType = paramsInfo[i].ParameterType;\n                    Expression paramAccessorExp = Expression.ArrayIndex(param, index);\n                    Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);\n                    argsExp[i] = paramCastExp;\n                }\n                NewExpression newExp = Expression.New(constructorInfo, argsExp);\n                Expression<Func<object[], object>> lambda = Expression.Lambda<Func<object[], object>>(newExp, param);\n                Func<object[], object> compiledLambda = lambda.Compile();\n                return delegate(object[] args) { return compiledLambda(args); };\n            }\n\n            public static ConstructorDelegate GetConstructorByExpression(Type type, params Type[] argsType)\n            {\n                ConstructorInfo constructorInfo = GetConstructorInfo(type, argsType);\n                return constructorInfo == null ? null : GetConstructorByExpression(constructorInfo);\n            }\n\n#endif\n\n            public static GetDelegate GetGetMethod(PropertyInfo propertyInfo)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetGetMethodByReflection(propertyInfo);\n#else\n                return GetGetMethodByExpression(propertyInfo);\n#endif\n            }\n\n            public static GetDelegate GetGetMethod(FieldInfo fieldInfo)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetGetMethodByReflection(fieldInfo);\n#else\n                return GetGetMethodByExpression(fieldInfo);\n#endif\n            }\n\n            public static GetDelegate GetGetMethodByReflection(PropertyInfo propertyInfo)\n            {\n                MethodInfo methodInfo = GetGetterMethodInfo(propertyInfo);\n                return delegate(object source) { return methodInfo.Invoke(source, EmptyObjects); };\n            }\n\n            public static GetDelegate GetGetMethodByReflection(FieldInfo fieldInfo)\n            {\n                return delegate(object source) { return fieldInfo.GetValue(source); };\n            }\n\n#if !SIMPLE_JSON_NO_LINQ_EXPRESSION\n\n            public static GetDelegate GetGetMethodByExpression(PropertyInfo propertyInfo)\n            {\n                MethodInfo getMethodInfo = GetGetterMethodInfo(propertyInfo);\n                ParameterExpression instance = Expression.Parameter(typeof(object), \"instance\");\n                UnaryExpression instanceCast = (!IsValueType(propertyInfo.DeclaringType)) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType);\n                Func<object, object> compiled = Expression.Lambda<Func<object, object>>(Expression.TypeAs(Expression.Call(instanceCast, getMethodInfo), typeof(object)), instance).Compile();\n                return delegate(object source) { return compiled(source); };\n            }\n\n            public static GetDelegate GetGetMethodByExpression(FieldInfo fieldInfo)\n            {\n                ParameterExpression instance = Expression.Parameter(typeof(object), \"instance\");\n                MemberExpression member = Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo);\n                GetDelegate compiled = Expression.Lambda<GetDelegate>(Expression.Convert(member, typeof(object)), instance).Compile();\n                return delegate(object source) { return compiled(source); };\n            }\n\n#endif\n\n            public static SetDelegate GetSetMethod(PropertyInfo propertyInfo)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetSetMethodByReflection(propertyInfo);\n#else\n                return GetSetMethodByExpression(propertyInfo);\n#endif\n            }\n\n            public static SetDelegate GetSetMethod(FieldInfo fieldInfo)\n            {\n#if SIMPLE_JSON_NO_LINQ_EXPRESSION\n                return GetSetMethodByReflection(fieldInfo);\n#else\n                return GetSetMethodByExpression(fieldInfo);\n#endif\n            }\n\n            public static SetDelegate GetSetMethodByReflection(PropertyInfo propertyInfo)\n            {\n                MethodInfo methodInfo = GetSetterMethodInfo(propertyInfo);\n                return delegate(object source, object value) { methodInfo.Invoke(source, new object[] { value }); };\n            }\n\n            public static SetDelegate GetSetMethodByReflection(FieldInfo fieldInfo)\n            {\n                return delegate(object source, object value) { fieldInfo.SetValue(source, value); };\n            }\n\n#if !SIMPLE_JSON_NO_LINQ_EXPRESSION\n\n            public static SetDelegate GetSetMethodByExpression(PropertyInfo propertyInfo)\n            {\n                MethodInfo setMethodInfo = GetSetterMethodInfo(propertyInfo);\n                ParameterExpression instance = Expression.Parameter(typeof(object), \"instance\");\n                ParameterExpression value = Expression.Parameter(typeof(object), \"value\");\n                UnaryExpression instanceCast = (!IsValueType(propertyInfo.DeclaringType)) ? Expression.TypeAs(instance, propertyInfo.DeclaringType) : Expression.Convert(instance, propertyInfo.DeclaringType);\n                UnaryExpression valueCast = (!IsValueType(propertyInfo.PropertyType)) ? Expression.TypeAs(value, propertyInfo.PropertyType) : Expression.Convert(value, propertyInfo.PropertyType);\n                Action<object, object> compiled = Expression.Lambda<Action<object, object>>(Expression.Call(instanceCast, setMethodInfo, valueCast), new ParameterExpression[] { instance, value }).Compile();\n                return delegate(object source, object val) { compiled(source, val); };\n            }\n\n            public static SetDelegate GetSetMethodByExpression(FieldInfo fieldInfo)\n            {\n                ParameterExpression instance = Expression.Parameter(typeof(object), \"instance\");\n                ParameterExpression value = Expression.Parameter(typeof(object), \"value\");\n                Action<object, object> compiled = Expression.Lambda<Action<object, object>>(\n                    Assign(Expression.Field(Expression.Convert(instance, fieldInfo.DeclaringType), fieldInfo), Expression.Convert(value, fieldInfo.FieldType)), instance, value).Compile();\n                return delegate(object source, object val) { compiled(source, val); };\n            }\n\n            public static BinaryExpression Assign(Expression left, Expression right)\n            {\n#if SIMPLE_JSON_TYPEINFO\n                return Expression.Assign(left, right);\n#else\n                MethodInfo assign = typeof(Assigner<>).MakeGenericType(left.Type).GetMethod(\"Assign\");\n                BinaryExpression assignExpr = Expression.Add(left, right, assign);\n                return assignExpr;\n#endif\n            }\n\n            private static class Assigner<T>\n            {\n                public static T Assign(ref T left, T right)\n                {\n                    return (left = right);\n                }\n            }\n\n#endif\n\n            public sealed class ThreadSafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>\n            {\n                private readonly object _lock = new object();\n                private readonly ThreadSafeDictionaryValueFactory<TKey, TValue> _valueFactory;\n                private Dictionary<TKey, TValue> _dictionary;\n\n                public ThreadSafeDictionary(ThreadSafeDictionaryValueFactory<TKey, TValue> valueFactory)\n                {\n                    _valueFactory = valueFactory;\n                }\n\n                private TValue Get(TKey key)\n                {\n                    if (_dictionary == null)\n                        return AddValue(key);\n                    TValue value;\n                    if (!_dictionary.TryGetValue(key, out value))\n                        return AddValue(key);\n                    return value;\n                }\n\n                private TValue AddValue(TKey key)\n                {\n                    TValue value = _valueFactory(key);\n                    lock (_lock)\n                    {\n                        if (_dictionary == null)\n                        {\n                            _dictionary = new Dictionary<TKey, TValue>();\n                            _dictionary[key] = value;\n                        }\n                        else\n                        {\n                            TValue val;\n                            if (_dictionary.TryGetValue(key, out val))\n                                return val;\n                            Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>(_dictionary);\n                            dict[key] = value;\n                            _dictionary = dict;\n                        }\n                    }\n                    return value;\n                }\n\n                public void Add(TKey key, TValue value)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public bool ContainsKey(TKey key)\n                {\n                    return _dictionary.ContainsKey(key);\n                }\n\n                public ICollection<TKey> Keys\n                {\n                    get { return _dictionary.Keys; }\n                }\n\n                public bool Remove(TKey key)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public bool TryGetValue(TKey key, out TValue value)\n                {\n                    value = this[key];\n                    return true;\n                }\n\n                public ICollection<TValue> Values\n                {\n                    get { return _dictionary.Values; }\n                }\n\n                public TValue this[TKey key]\n                {\n                    get { return Get(key); }\n                    set { throw new NotImplementedException(); }\n                }\n\n                public void Add(KeyValuePair<TKey, TValue> item)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public void Clear()\n                {\n                    throw new NotImplementedException();\n                }\n\n                public bool Contains(KeyValuePair<TKey, TValue> item)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public int Count\n                {\n                    get { return _dictionary.Count; }\n                }\n\n                public bool IsReadOnly\n                {\n                    get { throw new NotImplementedException(); }\n                }\n\n                public bool Remove(KeyValuePair<TKey, TValue> item)\n                {\n                    throw new NotImplementedException();\n                }\n\n                public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()\n                {\n                    return _dictionary.GetEnumerator();\n                }\n\n                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n                {\n                    return _dictionary.GetEnumerator();\n                }\n            }\n\n        }\n    }\n}\n// ReSharper restore LoopCanBeConvertedToQuery\n// ReSharper restore RedundantExplicitArrayCreation\n// ReSharper restore SuggestUseVarKeywordEvident\n"
  },
  {
    "path": "src/Squirrel/SimpleSplat/AssemblyFinder.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Squirrel.SimpleSplat\n{\n    static class AssemblyFinder\n    {\n        public static T AttemptToLoadType<T>(string fullTypeName)\n        {\n            var thisType = typeof(AssemblyFinder);\n\n            var toSearch = new[] {\n                thisType.AssemblyQualifiedName.Replace(thisType.FullName + \", \", \"\"),\n                thisType.AssemblyQualifiedName.Replace(thisType.FullName + \", \", \"\").Replace(\".Portable\", \"\"),\n            }.Select(x => new AssemblyName(x)).ToArray();\n\n            foreach (var assembly in toSearch) {\n                var fullName = fullTypeName + \", \" + assembly.FullName; \n                var type = Type.GetType(fullName, false);\n                if (type == null) continue;\n\n                return (T)Activator.CreateInstance(type);\n            }\n\n            return default(T);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/SimpleSplat/Logging.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Reflection;\nusing System.Globalization;\nusing System.Text;\nusing System.Threading;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\n\nnamespace Squirrel.SimpleSplat\n{\n    /*    \n     * Interfaces\n     */\n\n    public enum LogLevel {\n        Debug = 1, Info, Warn, Error, Fatal,\n    }\n\n    public interface ILogger\n    {\n        void Write([Localizable(false)] string message, LogLevel logLevel);\n        LogLevel Level { get; set; }\n    }\n\n    public interface IFullLogger : ILogger\n    {\n        void Debug<T>(T value);\n        void Debug<T>(IFormatProvider formatProvider, T value);\n        void DebugException([Localizable(false)] string message, Exception exception);\n        void Debug(IFormatProvider formatProvider, [Localizable(false)] string message, params object[] args);\n        void Debug([Localizable(false)] string message);\n        void Debug([Localizable(false)] string message, params object[] args);\n        void Debug<TArgument>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument argument);\n        void Debug<TArgument>([Localizable(false)] string message, TArgument argument);\n        void Debug<TArgument1, TArgument2>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Debug<TArgument1, TArgument2>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Debug<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n        void Debug<TArgument1, TArgument2, TArgument3>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n\n        void Info<T>(T value);\n        void Info<T>(IFormatProvider formatProvider, T value);\n        void InfoException([Localizable(false)] string message, Exception exception);\n        void Info(IFormatProvider formatProvider, [Localizable(false)] string message, params object[] args);\n        void Info([Localizable(false)] string message);\n        void Info([Localizable(false)] string message, params object[] args);\n        void Info<TArgument>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument argument);\n        void Info<TArgument>([Localizable(false)] string message, TArgument argument);\n        void Info<TArgument1, TArgument2>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Info<TArgument1, TArgument2>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Info<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n        void Info<TArgument1, TArgument2, TArgument3>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n\n        void Warn<T>(T value);\n        void Warn<T>(IFormatProvider formatProvider, T value);\n        void WarnException([Localizable(false)] string message, Exception exception);\n        void Warn(IFormatProvider formatProvider, [Localizable(false)] string message, params object[] args);\n        void Warn([Localizable(false)] string message);\n        void Warn([Localizable(false)] string message, params object[] args);\n        void Warn<TArgument>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument argument);\n        void Warn<TArgument>([Localizable(false)] string message, TArgument argument);\n        void Warn<TArgument1, TArgument2>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Warn<TArgument1, TArgument2>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Warn<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n        void Warn<TArgument1, TArgument2, TArgument3>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n\n        void Error<T>(T value);\n        void Error<T>(IFormatProvider formatProvider, T value);\n        void ErrorException([Localizable(false)] string message, Exception exception);\n        void Error(IFormatProvider formatProvider, [Localizable(false)] string message, params object[] args);\n        void Error([Localizable(false)] string message);\n        void Error([Localizable(false)] string message, params object[] args);\n        void Error<TArgument>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument argument);\n        void Error<TArgument>([Localizable(false)] string message, TArgument argument);\n        void Error<TArgument1, TArgument2>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Error<TArgument1, TArgument2>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Error<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n        void Error<TArgument1, TArgument2, TArgument3>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n\n        void Fatal<T>(T value);\n        void Fatal<T>(IFormatProvider formatProvider, T value);\n        void FatalException([Localizable(false)] string message, Exception exception);\n        void Fatal(IFormatProvider formatProvider, [Localizable(false)] string message, params object[] args);\n        void Fatal([Localizable(false)] string message);\n        void Fatal([Localizable(false)] string message, params object[] args);\n        void Fatal<TArgument>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument argument);\n        void Fatal<TArgument>([Localizable(false)] string message, TArgument argument);\n        void Fatal<TArgument1, TArgument2>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Fatal<TArgument1, TArgument2>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2);\n        void Fatal<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, [Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n        void Fatal<TArgument1, TArgument2, TArgument3>([Localizable(false)] string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3);\n    }\n\n    public interface ILogManager\n    {\n        IFullLogger GetLogger(Type type);\n    }\n\n    public class DefaultLogManager : ILogManager\n    {\n        readonly MemoizingMRUCache<Type, IFullLogger> loggerCache;\n\n        public DefaultLogManager(IDependencyResolver dependencyResolver = null)\n        {\n            dependencyResolver = dependencyResolver ?? SquirrelLocator.Current;\n\n            loggerCache = new MemoizingMRUCache<Type, IFullLogger>((type, _) => {\n                var ret = dependencyResolver.GetService<ILogger>();\n                if (ret == null) {\n                    throw new Exception(\"Couldn't find an ILogger. This should never happen, your dependency resolver is probably broken.\");\n                }\n\n                return new WrappingFullLogger(ret, type);\n            }, 64);\n        }\n\n        static readonly IFullLogger nullLogger = new WrappingFullLogger(new NullLogger(), typeof(MemoizingMRUCache<Type, IFullLogger>));\n        public IFullLogger GetLogger(Type type)\n        {\n            if (LogHost.suppressLogging) return nullLogger;\n            if (type == typeof(MemoizingMRUCache<Type, IFullLogger>)) return nullLogger;\n\n            lock (loggerCache) {\n                return loggerCache.Get(type);\n            }\n        }\n    }\n\n    public class FuncLogManager : ILogManager\n    {\n        readonly Func<Type, IFullLogger> _inner;\n        public FuncLogManager(Func<Type, IFullLogger> getLogger)\n        {\n            _inner = getLogger;\n        }\n\n        public IFullLogger GetLogger(Type type)\n        {\n            return _inner(type);\n        }\n    }\n\n    public static class LogManagerMixin\n    {\n        public static IFullLogger GetLogger<T>(this ILogManager This)\n        {\n            return This.GetLogger(typeof(T));\n        }\n    }\n\n    public class NullLogger : ILogger\n    {\n        public void Write(string message, LogLevel logLevel) {}\n        public LogLevel Level { get; set; }\n    }\n\n    public class DebugLogger : ILogger\n    {\n        public void Write(string message, LogLevel logLevel)\n        {\n            if ((int)logLevel < (int)Level) return;\n            Debug.WriteLine(message);\n        }\n\n        public LogLevel Level { get; set; }\n    }\n\n\n    /*    \n     * LogHost / Logging Mixin\n     */\n\n    /// <summary>\n    /// \"Implement\" this interface in your class to get access to the Log() \n    /// Mixin, which will give you a Logger that includes the class name in the\n    /// log.\n    /// </summary>\n    [System.Runtime.InteropServices.ComVisible(false)]\n    public interface IEnableLogger { }\n\n    public static class LogHost\n    {\n        static internal bool suppressLogging = false;\n        static readonly IFullLogger nullLogger = new WrappingFullLogger(new NullLogger(), typeof(string));\n\n        /// <summary>\n        /// Use this logger inside miscellaneous static methods where creating\n        /// a class-specific logger isn't really worth it.\n        /// </summary>\n        public static IFullLogger Default {\n            get {\n                if (suppressLogging) return nullLogger;\n\n                var factory = SquirrelLocator.Current.GetService<ILogManager>();\n                if (factory == null) {\n                    throw new Exception(\"ILogManager is null. This should never happen, your dependency resolver is broken\");\n                }\n                return factory.GetLogger(typeof(LogHost));\n            }\n        }\n\n        /// <summary>\n        /// Call this method to write log entries on behalf of the current \n        /// class.\n        /// </summary>\n        public static IFullLogger Log<T>(this T This) where T : IEnableLogger\n        {\n            if (suppressLogging) return nullLogger;\n\n            var factory = SquirrelLocator.Current.GetService<ILogManager>();\n            if (factory == null) {\n                throw new Exception(\"ILogManager is null. This should never happen, your dependency resolver is broken\");\n            }\n\n            return factory.GetLogger<T>();\n        }\n    }\n\n    #region Extremely Dull Code Ahead\n    public class WrappingFullLogger : IFullLogger\n    {\n        readonly ILogger _inner;\n        readonly string prefix;\n        readonly MethodInfo stringFormat;\n\n        public WrappingFullLogger(ILogger inner, Type callingType)\n        {\n            _inner = inner;\n            prefix = String.Format(CultureInfo.InvariantCulture, \"{0}: \", callingType.Name);\n\n            stringFormat = typeof (String).GetMethod(\"Format\", new[] {typeof (IFormatProvider), typeof (string), typeof (object[])});\n            Contract.Requires(inner != null);\n            Contract.Requires(stringFormat != null);\n        }\n\n        string InvokeStringFormat(IFormatProvider formatProvider, string message, object[] args)\n        {\n            var sfArgs = new object[3];\n            sfArgs[0] = formatProvider;\n            sfArgs[1] = message;\n            sfArgs[2] = args;\n            return (string) stringFormat.Invoke(null, sfArgs);\n        }\n\n        public void Debug<T>(T value)\n        {\n            _inner.Write(prefix + value, LogLevel.Debug);\n        }\n\n        public void Debug<T>(IFormatProvider formatProvider, T value)\n        {\n            _inner.Write(String.Format(formatProvider, \"{0}{1}\", prefix, value), LogLevel.Debug);\n        }\n\n        public void DebugException(string message, Exception exception)\n        {\n            _inner.Write(String.Format(\"{0}{1}: {2}\", prefix, message, exception), LogLevel.Debug);\n        }\n\n        public void Debug(IFormatProvider formatProvider, string message, params object[] args)\n        {\n            var result = InvokeStringFormat(formatProvider, message, args);\n\n            _inner.Write(prefix + result, LogLevel.Debug);\n        }\n\n\n        public void Debug(string message)\n        {\n            _inner.Write(prefix + message, LogLevel.Debug);\n        }\n\n        public void Debug(string message, params object[] args)\n        {\n            var result = InvokeStringFormat(CultureInfo.InvariantCulture, message, args);\n            _inner.Write(prefix + result, LogLevel.Debug);\n        }\n\n        public void Debug<TArgument>(IFormatProvider formatProvider, string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument), LogLevel.Debug);\n        }\n\n        public void Debug<TArgument>(string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument), LogLevel.Debug);\n        }\n\n        public void Debug<TArgument1, TArgument2>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2), LogLevel.Debug);\n        }\n\n        public void Debug<TArgument1, TArgument2>(string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2), LogLevel.Debug);\n        }\n\n        public void Debug<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2, argument3), LogLevel.Debug);\n        }\n\n        public void Debug<TArgument1, TArgument2, TArgument3>(string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2, argument3), LogLevel.Debug);\n        }\n\n        public void Info<T>(T value)\n        {\n            _inner.Write(prefix + value, LogLevel.Info);\n        }\n\n        public void Info<T>(IFormatProvider formatProvider, T value)\n        {\n            _inner.Write(String.Format(formatProvider, \"{0}{1}\", prefix, value), LogLevel.Info);\n        }\n\n        public void InfoException(string message, Exception exception)\n        {\n            _inner.Write(String.Format(\"{0}{1}: {2}\", prefix, message, exception), LogLevel.Info);\n        }\n\n        public void Info(IFormatProvider formatProvider, string message, params object[] args)\n        {\n            var result = InvokeStringFormat(formatProvider, message, args);\n            _inner.Write(prefix + result, LogLevel.Info);\n        }\n\n        public void Info(string message)\n        {\n            _inner.Write(prefix + message, LogLevel.Info);\n        }\n\n        public void Info(string message, params object[] args)\n        {\n            var result = InvokeStringFormat(CultureInfo.InvariantCulture, message, args);\n            _inner.Write(prefix + result, LogLevel.Info);\n        }\n\n        public void Info<TArgument>(IFormatProvider formatProvider, string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument), LogLevel.Info);\n        }\n\n        public void Info<TArgument>(string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument), LogLevel.Info);\n        }\n\n        public void Info<TArgument1, TArgument2>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2), LogLevel.Info);\n        }\n\n        public void Info<TArgument1, TArgument2>(string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2), LogLevel.Info);\n        }\n\n        public void Info<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2, argument3), LogLevel.Info);\n        }\n\n        public void Info<TArgument1, TArgument2, TArgument3>(string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2, argument3), LogLevel.Info);\n        }\n\n        public void Warn<T>(T value)\n        {\n            _inner.Write(prefix + value, LogLevel.Warn);\n        }\n\n        public void Warn<T>(IFormatProvider formatProvider, T value)\n        {\n            _inner.Write(String.Format(formatProvider, \"{0}{1}\", prefix, value), LogLevel.Warn);\n        }\n\n        public void WarnException(string message, Exception exception)\n        {\n            _inner.Write(String.Format(\"{0}{1}: {2}\", prefix, message, exception), LogLevel.Warn);\n        }\n\n        public void Warn(IFormatProvider formatProvider, string message, params object[] args)\n        {\n            var result = InvokeStringFormat(formatProvider, message, args);\n            _inner.Write(prefix + result, LogLevel.Warn);\n        }\n\n        public void Warn(string message)\n        {\n            _inner.Write(prefix + message, LogLevel.Warn);\n        }\n\n        public void Warn(string message, params object[] args)\n        {\n            var result = InvokeStringFormat(CultureInfo.InvariantCulture, message, args);\n            _inner.Write(prefix + result, LogLevel.Warn);\n        }\n\n        public void Warn<TArgument>(IFormatProvider formatProvider, string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument), LogLevel.Warn);\n        }\n\n        public void Warn<TArgument>(string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument), LogLevel.Warn);\n        }\n\n        public void Warn<TArgument1, TArgument2>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2), LogLevel.Warn);\n        }\n\n        public void Warn<TArgument1, TArgument2>(string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2), LogLevel.Warn);\n        }\n\n        public void Warn<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2, argument3), LogLevel.Warn);\n        }\n\n        public void Warn<TArgument1, TArgument2, TArgument3>(string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2, argument3), LogLevel.Warn);\n        }\n\n\n        public void Error<T>(T value)\n        {\n            _inner.Write(prefix + value, LogLevel.Error);\n        }\n\n        public void Error<T>(IFormatProvider formatProvider, T value)\n        {\n            _inner.Write(String.Format(formatProvider, \"{0}{1}\", prefix, value), LogLevel.Error);\n        }\n\n        public void ErrorException(string message, Exception exception)\n        {\n            _inner.Write(String.Format(\"{0}{1}: {2}\", prefix, message, exception), LogLevel.Error);\n        }\n\n        public void Error(IFormatProvider formatProvider, string message, params object[] args)\n        {\n            var result = InvokeStringFormat(formatProvider, message, args);\n            _inner.Write(prefix + result, LogLevel.Error);\n        }\n\n        public void Error(string message)\n        {\n            _inner.Write(prefix + message, LogLevel.Error);\n        }\n\n        public void Error(string message, params object[] args)\n        {\n            var result = InvokeStringFormat(CultureInfo.InvariantCulture, message, args);\n            _inner.Write(prefix + result, LogLevel.Error);\n        }\n\n        public void Error<TArgument>(IFormatProvider formatProvider, string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument), LogLevel.Error);\n        }\n\n        public void Error<TArgument>(string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument), LogLevel.Error);\n        }\n\n        public void Error<TArgument1, TArgument2>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2), LogLevel.Error);\n        }\n\n        public void Error<TArgument1, TArgument2>(string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2), LogLevel.Error);\n        }\n\n        public void Error<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2, argument3), LogLevel.Error);\n        }\n\n        public void Error<TArgument1, TArgument2, TArgument3>(string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2, argument3), LogLevel.Error);\n        }\n\n\n        public void Fatal<T>(T value)\n        {\n            _inner.Write(prefix + value, LogLevel.Fatal);\n        }\n\n        public void Fatal<T>(IFormatProvider formatProvider, T value)\n        {\n            _inner.Write(String.Format(formatProvider, \"{0}{1}\", prefix, value), LogLevel.Fatal);\n        }\n\n        public void FatalException(string message, Exception exception)\n        {\n            _inner.Write(String.Format(\"{0}{1}: {2}\", prefix, message, exception), LogLevel.Fatal);\n        }\n\n        public void Fatal(IFormatProvider formatProvider, string message, params object[] args)\n        {\n            var result = InvokeStringFormat(formatProvider, message, args);\n            _inner.Write(prefix + result, LogLevel.Fatal);\n        }\n\n        public void Fatal(string message)\n        {\n            _inner.Write(prefix + message, LogLevel.Fatal);\n        }\n\n        public void Fatal(string message, params object[] args)\n        {\n            var result = InvokeStringFormat(CultureInfo.InvariantCulture, message, args);\n            _inner.Write(prefix + result, LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument>(IFormatProvider formatProvider, string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument), LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument>(string message, TArgument argument)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument), LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument1, TArgument2>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2), LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument1, TArgument2>(string message, TArgument1 argument1, TArgument2 argument2)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2), LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument1, TArgument2, TArgument3>(IFormatProvider formatProvider, string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(formatProvider, message, argument1, argument2, argument3), LogLevel.Fatal);\n        }\n\n        public void Fatal<TArgument1, TArgument2, TArgument3>(string message, TArgument1 argument1, TArgument2 argument2, TArgument3 argument3)\n        {\n            _inner.Write(prefix + String.Format(CultureInfo.InvariantCulture, message, argument1, argument2, argument3), LogLevel.Fatal);\n        }\n\n        public void Write([Localizable(false)] string message, LogLevel logLevel)\n        {\n            _inner.Write(message, logLevel);\n        }\n\n        public LogLevel Level {\n            get { return _inner.Level; }\n            set { _inner.Level = value; }\n        }\n    }\n    #endregion\n\n    #if PORTABLE || WINDOWS_PHONE || NETFX_CORE\n    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]\n    public sealed class LocalizableAttribute : Attribute\n    {\n        public LocalizableAttribute(bool isLocalizable) { }\n    }\n    #endif\n}\n\n// vim: tw=120 ts=4 sw=4 et :\n"
  },
  {
    "path": "src/Squirrel/SimpleSplat/MemoizingMRUCache.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Diagnostics.Contracts;\n\nnamespace Squirrel.SimpleSplat\n{\n    /// <summary>\n    /// This data structure is a representation of a memoizing cache - i.e. a\n    /// class that will evaluate a function, but keep a cache of recently\n    /// evaluated parameters.\n    ///\n    /// Since this is a memoizing cache, it is important that this function be a\n    /// \"pure\" function in the mathematical sense - that a key *always* maps to\n    /// a corresponding return value.\n    /// </summary>\n    /// <typeparam name=\"TParam\">The type of the parameter to the calculation function.</typeparam>\n    /// <typeparam name=\"TVal\">The type of the value returned by the calculation\n    /// function.</typeparam>\n    public class MemoizingMRUCache<TParam, TVal>\n    {\n        private readonly Func<TParam, object, TVal> calculationFunction;\n        private readonly Action<TVal> releaseFunction;\n        private readonly int maxCacheSize;\n\n        private LinkedList<TParam> cacheMRUList;\n        private Dictionary<TParam, Tuple<LinkedListNode<TParam>, TVal>> cacheEntries;\n\n        /// <summary>\n        /// Constructor\n        /// </summary>\n        /// <param name=\"calculationFunc\">The function whose results you want to cache,\n        /// which is provided the key value, and an Tag object that is\n        /// user-defined</param>\n        /// <param name=\"maxSize\">The size of the cache to maintain, after which old\n        /// items will start to be thrown out.</param>\n        /// <param name=\"onRelease\">A function to call when a result gets\n        /// evicted from the cache (i.e. because Invalidate was called or the\n        /// cache is full)</param>\n        public MemoizingMRUCache(Func<TParam, object, TVal> calculationFunc, int maxSize, Action<TVal> onRelease = null)\n        {\n            Contract.Requires(calculationFunc != null);\n            Contract.Requires(maxSize > 0);\n\n            calculationFunction = calculationFunc;\n            releaseFunction = onRelease;\n            maxCacheSize = maxSize;\n            InvalidateAll();\n        }\n\n        public TVal Get(TParam key) { return Get(key, null); }\n\n        /// <summary>\n        /// Evaluates the function provided, returning the cached value if possible\n        /// </summary>\n        /// <param name=\"key\">The value to pass to the calculation function.</param>\n        /// <param name=\"context\">An additional optional user-specific parameter.</param>\n        /// <returns></returns>\n        public TVal Get(TParam key, object context = null)\n        {\n            Contract.Requires(key != null);\n\n            if (cacheEntries.ContainsKey(key)) {\n                var found = cacheEntries[key];\n                cacheMRUList.Remove(found.Item1);\n                cacheMRUList.AddFirst(found.Item1);\n                return found.Item2;\n            }\n\n            var result = calculationFunction(key, context);\n\n            var node = new LinkedListNode<TParam>(key);\n            cacheMRUList.AddFirst(node);\n            cacheEntries[key] = new Tuple<LinkedListNode<TParam>, TVal>(node, result);\n            maintainCache();\n\n            return result;\n        }\n\n        public bool TryGet(TParam key, out TVal result)\n        {\n            Contract.Requires(key != null);\n\n            Tuple<LinkedListNode<TParam>, TVal> output;\n            var ret = cacheEntries.TryGetValue(key, out output);\n            if (ret && output != null) {\n                cacheMRUList.Remove(output.Item1);\n                cacheMRUList.AddFirst(output.Item1);\n                result = output.Item2;\n            } else {\n                result = default(TVal);\n            }\n            return ret;\n        }\n\n        /// <summary>\n        /// Ensure that the next time this key is queried, the calculation\n        /// function will be called.\n        /// </summary>\n        public void Invalidate(TParam key)\n        {\n            Contract.Requires(key != null);\n\n            if (!cacheEntries.ContainsKey(key))\n                return;\n\n            var to_remove = cacheEntries[key];\n            if (releaseFunction != null)\n                releaseFunction(to_remove.Item2);\n\n            cacheMRUList.Remove(to_remove.Item1);\n            cacheEntries.Remove(key);\n        }\n\n        /// <summary>\n        /// Invalidate all items in the cache\n        /// </summary>\n        public void InvalidateAll()\n        {\n            if (releaseFunction == null || cacheEntries == null) {\n                cacheMRUList = new LinkedList<TParam>();\n                cacheEntries = new Dictionary<TParam, Tuple<LinkedListNode<TParam>, TVal>>();\n                return;\n            }\n\n            if (cacheEntries.Count == 0)\n                return;\n\n            /*             We have to remove them one-by-one to call the release function\n             * We ToArray() this so we don't get a \"modifying collection while\n             * enumerating\" exception. */\n            foreach (var v in cacheEntries.Keys.ToArray()) { Invalidate(v); }\n        }\n\n        /// <summary>\n        /// Returns all values currently in the cache\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerable<TVal> CachedValues()\n        {\n            return cacheEntries.Select(x => x.Value.Item2);\n        }\n\n        void maintainCache()\n        {\n            while (cacheMRUList.Count > maxCacheSize) {\n                var to_remove = cacheMRUList.Last.Value;\n                if (releaseFunction != null)\n                    releaseFunction(cacheEntries[to_remove].Item2);\n\n                cacheEntries.Remove(cacheMRUList.Last.Value);\n                cacheMRUList.RemoveLast();\n            }\n        }\n\n        [ContractInvariantMethod]\n        void Invariants()\n        {\n            Contract.Invariant(cacheEntries.Count == cacheMRUList.Count);\n            Contract.Invariant(cacheEntries.Count <= maxCacheSize);\n        }\n    }\n}\n\n// vim: tw=120 ts=4 sw=4 et :"
  },
  {
    "path": "src/Squirrel/SimpleSplat/ModeDetector.cs",
    "content": "using System;\n\nnamespace Squirrel.SimpleSplat\n{\n    public interface IModeDetector\n    {\n        bool? InUnitTestRunner();\n        bool? InDesignMode();\n    }\n\n    public static class ModeDetector\n    {\n        static ModeDetector()\n        {\n            var platModeDetector = AssemblyFinder.AttemptToLoadType<IModeDetector>(\"Squirrel.SimpleSplat.PlatformModeDetector\");\n            current = platModeDetector;\n        }\n\n        static IModeDetector current { get; set; }\n\n        public static void OverrideModeDetector(IModeDetector modeDetector)\n        {\n            current = modeDetector;\n            cachedInDesignModeResult = null;\n            cachedInUnitTestRunnerResult = null;\n        }\n\n        static bool? cachedInUnitTestRunnerResult;\n        public static bool InUnitTestRunner() \n        {\n            if (cachedInUnitTestRunnerResult.HasValue) return cachedInUnitTestRunnerResult.Value;\n\n            if (current != null) {\n                cachedInUnitTestRunnerResult = current.InUnitTestRunner();\n                if (cachedInUnitTestRunnerResult.HasValue) return cachedInUnitTestRunnerResult.Value;\n            }\n\n            // We have no sane platform-independent way to detect a unit test \n            // runner :-/\n            return false;\n        }\n                \n        static bool? cachedInDesignModeResult;\n        public static bool InDesignMode()\n        {\n            if (cachedInDesignModeResult.HasValue) return cachedInDesignModeResult.Value;\n\n            if (current != null) {\n                cachedInDesignModeResult = current.InDesignMode();\n                if (cachedInDesignModeResult.HasValue) return cachedInDesignModeResult.Value;\n            }\n            \n            // Check Silverlight / WP8 Design Mode\n            var type = Type.GetType(\"System.ComponentModel.DesignerProperties, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\", false);\n            if (type != null) {\n                var mInfo = type.GetMethod(\"GetIsInDesignMode\");\n                var dependencyObject = Type.GetType(\"System.Windows.Controls.Border, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\", false);\n\n                if (dependencyObject != null) {\n                    cachedInDesignModeResult = (bool)mInfo.Invoke(null, new object[] { Activator.CreateInstance(dependencyObject) });\n                }\n            } else if((type = Type.GetType(\"System.ComponentModel.DesignerProperties, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\", false)) != null) {\n                // loaded the assembly, could be .net \n                var mInfo = type.GetMethod(\"GetIsInDesignMode\");\n                Type dependencyObject = Type.GetType(\"System.Windows.DependencyObject, WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\", false);\n                if (dependencyObject != null) {\n                    cachedInDesignModeResult = (bool)mInfo.Invoke(null, new object[] { Activator.CreateInstance(dependencyObject) });\n                }\n            } else if ((type = Type.GetType(\"Windows.ApplicationModel.DesignMode, Windows, ContentType=WindowsRuntime\", false)) != null) {\n                // check WinRT next\n                cachedInDesignModeResult = (bool)type.GetProperty(\"DesignModeEnabled\").GetMethod.Invoke(null, null);\n            } else {\n                cachedInDesignModeResult = false;\n            }\n\n            return cachedInDesignModeResult.GetValueOrDefault();\n        }\n    }\n}"
  },
  {
    "path": "src/Squirrel/SimpleSplat/PlatformModeDetector.cs",
    "content": "using System;\nusing System.IO;\nusing System.Reflection;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\n#if SILVERLIGHT\nusing System.Windows;\n#elif NETFX_CORE\nusing Windows.ApplicationModel;\n#endif\n\nnamespace Squirrel.SimpleSplat\n{\n    public class PlatformModeDetector : IModeDetector\n    {\n        public bool? InUnitTestRunner()\n        {\n            var testAssemblies = new[] {\n                \"CSUNIT\",\n                \"NUNIT\",\n                \"XUNIT\",\n                \"MBUNIT\",\n                \"NBEHAVE\",\n            };\n\n            try {\n                return searchForAssembly(testAssemblies);\n            } catch (Exception) {\n                return null;\n            }\n        }\n\n        public bool? InDesignMode()\n        {\n#if SILVERLIGHT\n            if (Application.Current.RootVisual != null) {\n                return System.ComponentModel.DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual);\n            }\n\n            return false;\n#elif NETFX_CORE\n            return DesignMode.DesignModeEnabled;\n#else\n            var designEnvironments = new[] {\n                \"BLEND.EXE\",\n                \"XDESPROC.EXE\",\n            };\n\n            var entry = Assembly.GetEntryAssembly();\n            if (entry != null) {\n                var exeName = (new FileInfo(entry.Location)).Name.ToUpperInvariant();\n\n                if (designEnvironments.Any(x => x.Contains(exeName))) {\n                    return true;\n                }\n            }\n\n            return false;\n#endif\n        }\n        \n        static bool searchForAssembly(IEnumerable<string> assemblyList)\n        {\n#if SILVERLIGHT\n            return Deployment.Current.Parts.Any(x => assemblyList.Any(name => x.Source.ToUpperInvariant().Contains(name)));\n#elif NETFX_CORE\n            var depPackages = Package.Current.Dependencies.Select(x => x.Id.FullName);\n            if (depPackages.Any(x => assemblyList.Any(name => x.ToUpperInvariant().Contains(name)))) return true;\n\n            var fileTask = Task.Factory.StartNew(async () => {\n                var files = await Package.Current.InstalledLocation.GetFilesAsync();\n                return files.Select(x => x.Path).ToArray();\n            }, TaskCreationOptions.HideScheduler).Unwrap();\n\n            return fileTask.Result.Any(x => assemblyList.Any(name => x.ToUpperInvariant().Contains(name)));\n#else\n            return AppDomain.CurrentDomain.GetAssemblies()\n                .Any(x => assemblyList.Any(name => x.FullName.ToUpperInvariant().Contains(name)));\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/SimpleSplat/ServiceLocation.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\n\nnamespace Squirrel.SimpleSplat\n{\n    public static class SquirrelLocator\n    {\n        [ThreadStatic] static IDependencyResolver unitTestDependencyResolver;\n        static IDependencyResolver dependencyResolver;\n\n        static readonly List<Action> resolverChanged = new List<Action>();\n\n        static SquirrelLocator()\n        {\n            var r = new ModernDependencyResolver();\n            dependencyResolver = r;\n\n            RegisterResolverCallbackChanged(() => {\n                if (SquirrelLocator.CurrentMutable == null) return;\n                SquirrelLocator.CurrentMutable.InitializeSplat();\n            });\n        }\n\n        /// <summary>\n        /// Gets or sets the dependency resolver. This class is used throughout\n        /// libraries for many internal operations as well as for general use\n        /// by applications. If this isn't assigned on startup, a default, highly\n        /// capable implementation will be used, and it is advised for most people\n        /// to simply use the default implementation.\n        /// </summary>\n        /// <value>The dependency resolver.</value>\n        public static IDependencyResolver Current {\n            get {\n                return unitTestDependencyResolver ?? dependencyResolver;\n            }\n            set {\n                if (ModeDetector.InUnitTestRunner()) {\n                    unitTestDependencyResolver = value;\n                    dependencyResolver = dependencyResolver ?? value;\n                } else {\n                    dependencyResolver = value;\n                }\n\n                var currentCallbacks = default(Action[]);\n                lock (resolverChanged) {\n                    // NB: Prevent deadlocks should we reenter this setter from \n                    // the callbacks\n                    currentCallbacks = resolverChanged.ToArray();\n                }\n\n                foreach (var block in currentCallbacks) block();\n            }\n        }\n\n        /// <summary>\n        /// Convenience property to return the DependencyResolver cast to a\n        /// MutableDependencyResolver. The default resolver is also a mutable\n        /// resolver, so this will be non-null. Use this to register new types\n        /// on startup if you are using the default resolver\n        /// </summary>\n        public static IMutableDependencyResolver CurrentMutable {\n            get { return Current as IMutableDependencyResolver; }\n            set { Current = value; }\n        }\n\n        /// <summary>\n        /// This method allows libraries to register themselves to be set up\n        /// whenever the dependency resolver changes. Applications should avoid\n        /// this method, it is usually used for libraries that depend on service\n        /// location.\n        /// </summary>\n        /// <param name=\"callback\">A callback that is invoked when the \n        /// resolver is changed. This callback is also invoked immediately,\n        /// to configure the current resolver.</param>\n        /// <returns>When disposed, removes the callback. You probably can \n        /// ignore this.</returns>\n        public static IDisposable RegisterResolverCallbackChanged(Action callback)\n        {\n            lock (resolverChanged) {\n                resolverChanged.Add(callback);\n            }\n\n            // NB: We always immediately invoke the callback to set up the \n            // current resolver with whatever we've got\n            callback();\n\n            return new ActionDisposable(() => {\n                lock (resolverChanged) resolverChanged.Remove(callback);\n            });\n        }\n    }\n\n    /// <summary>\n    /// Represents a dependency resolver, a service to look up global class \n    /// instances or types.\n    /// </summary>\n    public interface IDependencyResolver : IDisposable\n    {\n        /// <summary>\n        /// Gets an instance of the given <paramref name=\"serviceType\"/>. Must return <c>null</c>\n        /// if the service is not available (must not throw).\n        /// </summary>\n        /// <param name=\"serviceType\">The object type.</param>\n        /// <returns>The requested object, if found; <c>null</c> otherwise.</returns>\n        object GetService(Type serviceType, string contract = null);\n\n        /// <summary>\n        /// Gets all instances of the given <paramref name=\"serviceType\"/>. Must return an empty\n        /// collection if the service is not available (must not return <c>null</c> or throw).\n        /// </summary>\n        /// <param name=\"serviceType\">The object type.</param>\n        /// <returns>A sequence of instances of the requested <paramref name=\"serviceType\"/>. The sequence\n        /// should be empty (not <c>null</c>) if no objects of the given type are available.</returns>\n        IEnumerable<object> GetServices(Type serviceType, string contract = null);\n    }\n\n    /// <summary>\n    /// Represents a dependency resolver where types can be registered after \n    /// setup.\n    /// </summary>\n    public interface IMutableDependencyResolver : IDependencyResolver\n    {\n        void Register(Func<object> factory, Type serviceType, string contract = null);\n\n        /// <summary>\n        /// Register a callback to be called when a new service matching the type \n        /// and contract is registered.\n        /// \n        /// When registered, the callback is also called for each currently matching \n        /// service.\n        /// </summary>\n        /// <returns>When disposed removes the callback</returns>\n        /// <param name=\"serviceType\">Service type.</param>\n        /// <param name=\"contract\">Contract.</param>\n        /// <param name=\"callback\">Callback.</param>\n        IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action<IDisposable> callback);\n    }\n\n    public static class DependencyResolverMixins\n    {\n        /// <summary>\n        /// Gets an instance of the given <paramref name=\"serviceType\"/>. Must return <c>null</c>\n        /// if the service is not available (must not throw).\n        /// </summary>\n        /// <param name=\"serviceType\">The object type.</param>\n        /// <returns>The requested object, if found; <c>null</c> otherwise.</returns>\n        public static T GetService<T>(this IDependencyResolver This, string contract = null)\n        {\n            return (T)This.GetService(typeof(T), contract);\n        }\n\n        /// <summary>\n        /// Gets all instances of the given <paramref name=\"serviceType\"/>. Must return an empty\n        /// collection if the service is not available (must not return <c>null</c> or throw).\n        /// </summary>\n        /// <param name=\"serviceType\">The object type.</param>\n        /// <returns>A sequence of instances of the requested <paramref name=\"serviceType\"/>. The sequence\n        /// should be empty (not <c>null</c>) if no objects of the given type are available.</returns>\n        public static IEnumerable<T> GetServices<T>(this IDependencyResolver This, string contract = null)\n        {\n            return This.GetServices(typeof(T), contract).Cast<T>();\n        }\n\n        public static IDisposable ServiceRegistrationCallback(this IMutableDependencyResolver This, Type serviceType, Action<IDisposable> callback)\n        {\n            return This.ServiceRegistrationCallback(serviceType, null, callback);\n        }\n\n        /// <summary>\n        /// Override the default Dependency Resolver until the object returned \n        /// is disposed.\n        /// </summary>\n        /// <param name=\"resolver\">The test resolver to use.</param>\n        public static IDisposable WithResolver(this IDependencyResolver resolver)\n        {\n            var origResolver = SquirrelLocator.Current;\n            SquirrelLocator.Current = resolver;\n\n            return new ActionDisposable(() => SquirrelLocator.Current = origResolver);\n        }\n                \n        public static void RegisterConstant(this IMutableDependencyResolver This, object value, Type serviceType, string contract = null)\n        {\n            This.Register(() => value, serviceType, contract);\n        }\n\n        public static void RegisterLazySingleton(this IMutableDependencyResolver This, Func<object> valueFactory, Type serviceType, string contract = null)\n        {\n            var val = new Lazy<object>(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication);\n            This.Register(() => val.Value, serviceType, contract);\n        }\n\n        public static void InitializeSplat(this IMutableDependencyResolver This)\n        {\n            This.Register(() => new DefaultLogManager(), typeof(ILogManager));\n            This.Register(() => new DebugLogger(), typeof(ILogger));\n        }\n    }\n\n    /// <summary>\n    /// This class is a dependency resolver written for modern C# 5.0 times. \n    /// It implements all registrations via a Factory method. With the power\n    /// of Closures, you can actually implement most lifetime styles (i.e.\n    /// construct per call, lazy construct, singleton) using this.\n    ///\n    /// Unless you have a very compelling reason not to, this is the only class\n    /// you need in order to do dependency resolution, don't bother with using\n    /// a full IoC container.\n    /// </summary>\n    public class ModernDependencyResolver : IMutableDependencyResolver\n    {\n        Dictionary<Tuple<Type, string>, List<Func<object>>> _registry;\n        Dictionary<Tuple<Type, string>, List<Action<IDisposable>>> _callbackRegistry;\n\n        public ModernDependencyResolver() : this(null) { }\n\n        protected ModernDependencyResolver(Dictionary<Tuple<Type, string>, List<Func<object>>> registry)\n        {\n            _registry = registry != null ? \n                registry.ToDictionary(k => k.Key, v => v.Value.ToList()) :\n                new Dictionary<Tuple<Type, string>, List<Func<object>>>();\n\n            _callbackRegistry = new Dictionary<Tuple<Type, string>, List<Action<IDisposable>>>();\n        }\n\n        public void Register(Func<object> factory, Type serviceType, string contract = null)\n        {\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n            if (!_registry.ContainsKey(pair)) {\n                _registry[pair] = new List<Func<object>>();\n            }\n\n            _registry[pair].Add(factory);\n\n            if (_callbackRegistry.ContainsKey(pair)) {\n                List<Action<IDisposable>> toRemove = null;\n\n                foreach (var callback in _callbackRegistry[pair]) {\n                    var remove = false;\n                    var disp = new ActionDisposable(() => {\n                        remove = true;\n                    });\n\n                    callback(disp);\n\n                    if (remove) {\n                        if (toRemove == null) {\n                            toRemove = new List<Action<IDisposable>>();\n                        }\n\n                        toRemove.Add(callback);\n                    }\n                }\n\n                if (toRemove != null) {\n                    foreach (var c in toRemove) {\n                        _callbackRegistry[pair].Remove(c);\n                    }\n                }\n            }\n        }\n\n        public object GetService(Type serviceType, string contract = null)\n        {\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n            if (!_registry.ContainsKey(pair)) return default(object);\n\n            var ret = _registry[pair].Last();\n            return ret();\n        }\n\n        public IEnumerable<object> GetServices(Type serviceType, string contract = null)\n        {\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n            if (!_registry.ContainsKey(pair)) return Enumerable.Empty<object>();\n\n            return _registry[pair].Select(x => x()).ToList();\n        }\n\n        public IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action<IDisposable> callback)\n        {\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n\n            if (!_callbackRegistry.ContainsKey(pair)) {\n                _callbackRegistry[pair] = new List<Action<IDisposable>>();\n            }\n\n            _callbackRegistry[pair].Add(callback);\n\n            var disp = new ActionDisposable(() => {\n                _callbackRegistry[pair].Remove(callback);\n            });\n\n            if (_registry.ContainsKey(pair)) {\n                foreach (var s in _registry[pair]) {\n                    callback(disp);\n                }\n            }\n\n            return disp;\n        }\n\n        public ModernDependencyResolver Duplicate()\n        {\n            return new ModernDependencyResolver(_registry);\n        }\n\n        public void Dispose()\n        {\n            _registry = null;\n        }\n    }\n\n    /// <summary>\n    /// A simple dependency resolver which takes Funcs for all its actions.\n    /// GetService is always implemented via GetServices().LastOrDefault()\n    /// </summary>\n    public class FuncDependencyResolver : IMutableDependencyResolver\n    {\n        readonly Func<Type, string, IEnumerable<object>> innerGetServices;\n        readonly Action<Func<object>, Type, string> innerRegister;\n        readonly Dictionary<Tuple<Type, string>, List<Action<IDisposable>>> _callbackRegistry = \n            new Dictionary<Tuple<Type, string>, List<Action<IDisposable>>>();\n\n        IDisposable inner;\n\n        public FuncDependencyResolver(\n            Func<Type, string, IEnumerable<object>> getAllServices, \n            Action<Func<object>, Type, string> register = null, \n            IDisposable toDispose = null)\n        {\n            innerGetServices = getAllServices;\n            innerRegister = register;\n            inner = toDispose ?? ActionDisposable.Empty;\n        }\n\n        public object GetService(Type serviceType, string contract = null)\n        {\n            return (GetServices(serviceType, contract) ?? Enumerable.Empty<object>()).LastOrDefault();\n        }\n\n        public IEnumerable<object> GetServices(Type serviceType, string contract = null)\n        {\n            return innerGetServices(serviceType, contract);\n        }\n\n        public void Dispose() \n        { \n            Interlocked.Exchange(ref inner, ActionDisposable.Empty).Dispose();\n        }\n\n        public void Register(Func<object> factory, Type serviceType, string contract = null)\n        {\n            if (innerRegister == null) throw new NotImplementedException();\n            innerRegister(factory, serviceType, contract);\n\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n\n            if (_callbackRegistry.ContainsKey(pair)) {\n                List<Action<IDisposable>> toRemove = null;\n\n                foreach (var callback in _callbackRegistry[pair]) {\n                    var remove = false;\n                    var disp = new ActionDisposable(() => {\n                        remove = true;\n                    });\n\n                    callback(disp);\n\n                    if (remove) {\n                        if (toRemove == null) {\n                            toRemove = new List<Action<IDisposable>>();\n                        }\n\n                        toRemove.Add(callback);\n                    }\n                }\n\n                if (toRemove != null) {\n                    foreach (var c in toRemove) {\n                        _callbackRegistry[pair].Remove(c);\n                    }\n                }\n            }\n        }\n\n        public IDisposable ServiceRegistrationCallback(Type serviceType, string contract, Action<IDisposable> callback)\n        {\n            var pair = Tuple.Create(serviceType, contract ?? string.Empty);\n\n            if (!_callbackRegistry.ContainsKey(pair)) {\n                _callbackRegistry[pair] = new List<Action<IDisposable>>();\n            }\n\n            _callbackRegistry[pair].Add(callback);\n\n            return new ActionDisposable(() => {\n                _callbackRegistry[pair].Remove(callback);\n            });\n        }\n    }\n\n    sealed class ActionDisposable : IDisposable\n    {\n        Action block;\n\n        public static IDisposable Empty {\n            get { return new ActionDisposable(() => {}); }\n        }\n\n        public ActionDisposable(Action block)\n        {\n            this.block = block;\n        }\n\n        public void Dispose()\n        {\n            Interlocked.Exchange(ref block, () => {})();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/Squirrel.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>net45;netstandard2.0</TargetFrameworks>\n    <LangVersion>9</LangVersion>\n    <Description>Squirrel</Description>\n    <Title>Squirrel</Title>\n    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\vendor\\nuget\\src\\Core\\Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.CSharp\" Version=\"4.7.0\" />\n    <PackageReference Include=\"Microsoft.Web.Xdt\" Version=\"3.1.0\" />\n    <PackageReference Include=\"Mono.Cecil\" Version=\"0.11.2\" />\n    <PackageReference Include=\"SharpCompress\" Version=\"0.17.1.0\" />\n    <PackageReference Include=\"System.Net.Http\" Version=\"4.3.4\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'netstandard2.0'\">\n    <PackageReference Include=\"Microsoft.Win32.Registry\" Version=\"5.0.0\" />\n    <PackageReference Include=\"System.Drawing.Common\" Version=\"5.0.2\" />\n  </ItemGroup>\n\n  <ItemGroup Condition=\"'$(TargetFramework)' == 'net45'\">\n    <Reference Include=\"System.Web\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Squirrel/SquirrelAwareApp.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    /// <summary>\n    /// SquirrelAwareApp helps you to handle Squirrel app activation events\n    /// correctly.\n    /// </summary>\n    public static class SquirrelAwareApp\n    {\n        /// <summary>\n        /// Call this method as early as possible in app startup. This method\n        /// will dispatch to your methods to set up your app. Depending on the\n        /// parameter, your app will exit after this method is called, which \n        /// is required by Squirrel. UpdateManager has methods to help you to\n        /// do this, such as CreateShortcutForThisExe.\n        /// </summary>\n        /// <param name=\"onInitialInstall\">Called when your app is initially\n        /// installed. Set up app shortcuts here as well as file associations.\n        /// </param>\n        /// <param name=\"onAppUpdate\">Called when your app is updated to a new\n        /// version.</param>\n        /// <param name=\"onAppObsoleted\">Called when your app is no longer the\n        /// latest version (i.e. they have installed a new version and your app\n        /// is now the old version)</param>\n        /// <param name=\"onAppUninstall\">Called when your app is uninstalled \n        /// via Programs and Features. Remove all of the things that you created\n        /// in onInitialInstall.</param>\n        /// <param name=\"onFirstRun\">Called the first time an app is run after\n        /// being installed. Your application will **not** exit after this is\n        /// dispatched, you should use this as a hint (i.e. show a 'Welcome' \n        /// screen, etc etc.</param>\n        /// <param name=\"arguments\">Use in a unit-test runner to mock the \n        /// arguments. In your app, leave this as null.</param>\n        public static void HandleEvents(\n            Action<Version> onInitialInstall = null,\n            Action<Version> onAppUpdate = null,\n            Action<Version> onAppObsoleted = null,\n            Action<Version> onAppUninstall = null,\n            Action onFirstRun = null,\n            string[] arguments = null)\n        {\n            Action<Version> defaultBlock = (v => { });\n            var args = arguments ?? Environment.GetCommandLineArgs().Skip(1).ToArray();\n            if (args.Length == 0) return;\n\n            var lookup = new[] {\n                new { Key = \"--squirrel-install\", Value = onInitialInstall ?? defaultBlock },\n                new { Key = \"--squirrel-updated\", Value = onAppUpdate ?? defaultBlock },\n                new { Key = \"--squirrel-obsolete\", Value = onAppObsoleted ?? defaultBlock },\n                new { Key = \"--squirrel-uninstall\", Value = onAppUninstall ?? defaultBlock },\n            }.ToDictionary(k => k.Key, v => v.Value);\n\n            if (args[0] == \"--squirrel-firstrun\") {\n                (onFirstRun ?? (() => {}))();\n                return;\n            }\n\n            if (args.Length != 2) return;\n\n            if (!lookup.ContainsKey(args[0])) return;\n            var version = args[1].ToSemanticVersion().Version;\n\n            try {\n                lookup[args[0]](version);\n                if (!ModeDetector.InUnitTestRunner()) Environment.Exit(0);\n            } catch (Exception ex) {\n                LogHost.Default.ErrorException(\"Failed to handle Squirrel events\", ex);\n                if (!ModeDetector.InUnitTestRunner()) Environment.Exit(-1);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Squirrel/SquirrelAwareExecutableDetector.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Mono.Cecil;\n\nnamespace Squirrel\n{\n    static class SquirrelAwareExecutableDetector\n    {\n        public static List<string> GetAllSquirrelAwareApps(string directory, int minimumVersion = 1)\n        {\n            var di = new DirectoryInfo(directory);\n\n            return di.EnumerateFiles()\n                .Where(x => x.Name.EndsWith(\".exe\", StringComparison.OrdinalIgnoreCase))\n                .Select(x => x.FullName)\n                .Where(x => (GetPESquirrelAwareVersion(x) ?? -1) >= minimumVersion)\n                .ToList();\n        }\n\n        public static int? GetPESquirrelAwareVersion(string executable)\n        {\n            if (!File.Exists(executable)) return null;\n            var fullname = Path.GetFullPath(executable);\n\n            return Utility.Retry<int?>(() => \n                GetAssemblySquirrelAwareVersion(fullname) ?? GetVersionBlockSquirrelAwareValue(fullname));\n        }\n\n        static int? GetAssemblySquirrelAwareVersion(string executable)\n        {\n            try {\n                using (var assembly = AssemblyDefinition.ReadAssembly(executable)) {\n                    if (!assembly.HasCustomAttributes) return null;\n\n                    var attrs = assembly.CustomAttributes;\n                    var attribute = attrs.FirstOrDefault(x => {\n                        if (x.AttributeType.FullName != typeof(AssemblyMetadataAttribute).FullName) return false;\n                        if (x.ConstructorArguments.Count != 2) return false;\n                        return x.ConstructorArguments[0].Value.ToString() == \"SquirrelAwareVersion\";\n                    });\n\n                    if (attribute == null) return null;\n\n                    int result;\n                    if (!Int32.TryParse(attribute.ConstructorArguments[1].Value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture, out result)) {\n                        return null;\n                    }\n\n                    return result;\n                }\n            }\n            catch (FileLoadException) { return null; }\n            catch (BadImageFormatException) { return null; }\n        }\n\n        static int? GetVersionBlockSquirrelAwareValue(string executable)\n        {\n            int size = NativeMethods.GetFileVersionInfoSize(executable, IntPtr.Zero);\n\n            // Nice try, buffer overflow\n            if (size <= 0 || size > 4096) return null;\n\n            var buf = new byte[size];\n            if (!NativeMethods.GetFileVersionInfo(executable, 0, size, buf)) return null;\n\n            const string englishUS = \"040904B0\";\n            const string neutral = \"000004B0\";\n            var supportedLanguageCodes = new[] {englishUS, neutral};\n\n            IntPtr result;\n            int resultSize;\n            if (!supportedLanguageCodes.Any(\n                languageCode =>\n                    NativeMethods.VerQueryValue(\n                        buf,\n                        $\"\\\\StringFileInfo\\\\{languageCode}\\\\SquirrelAwareVersion\",\n                        out result, out resultSize\n                    )\n            ))\n            {\n                return null;\n            }\n\n            // NB: I have **no** idea why, but Atom.exe won't return the version\n            // number \"1\" despite it being in the resource file and being 100% \n            // identical to the version block that actually works. I've got stuff\n            // to ship, so we're just going to return '1' if we find the name in \n            // the block at all. I hate myself for this.\n            return 1;\n\n#if __NOT__DEFINED_EVAR__\n            int ret;\n            string resultData = Marshal.PtrToStringAnsi(result, resultSize-1 /* Subtract one for null terminator */);\n            if (!Int32.TryParse(resultData, NumberStyles.Integer, CultureInfo.CurrentCulture, out ret)) return null;\n\n            return ret;\n#endif\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/TaskbarHelper.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\n\nnamespace Squirrel.Shell\n{\n    public static class TaskbarHelper \n    {\n        public static bool IsPinnedToTaskbar(string executablePath) \n        {\n            var taskbarPath = Path.Combine(\n                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\n                \"Microsoft\\\\Internet Explorer\\\\Quick Launch\\\\User Pinned\\\\TaskBar\");\n\n            return Directory\n                .GetFiles(taskbarPath, \"*.lnk\")\n                .Select(pinnedShortcut => new ShellLink(pinnedShortcut))\n                .Any(shortcut => String.Equals(shortcut.Target, executablePath, StringComparison.OrdinalIgnoreCase));\n        }\n\n        public static void PinToTaskbar(string executablePath) \n        {\n            pinUnpin(executablePath, \"pin to taskbar\");\n\n            if (!IsPinnedToTaskbar(executablePath)) {\n                throw new Exception(\"Pinning executable to taskbar failed.\");\n            }\n        }\n\n        public static void UnpinFromTaskbar(string executablePath) \n        {\n            pinUnpin(executablePath, \"unpin from taskbar\");\n\n            if (IsPinnedToTaskbar(executablePath)) {\n                throw new Exception(\"Executable is still pinned to taskbar.\");\n            }\n        }\n\n        static void pinUnpin(string executablePath, string verbToExecute) \n        {\n            if (!File.Exists(executablePath)) {\n                throw new FileNotFoundException(executablePath);\n            }\n\n            dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID(\"Shell.Application\"));\n\n            try {\n                var path = Path.GetDirectoryName(executablePath);\n                var fileName = Path.GetFileName(executablePath);\n\n                dynamic directory = shellApplication.NameSpace(path);\n                dynamic link = directory.ParseName(fileName);\n\n                dynamic verbs = link.Verbs();\n\n                for (var i = 0; i < verbs.Count(); i++) {\n                    dynamic verb = verbs.Item(i);\n                    string verbName = verb.Name.Replace(@\"&\", String.Empty).ToLower();\n\n                    if (verbName.Equals(verbToExecute)) {\n                        verb.DoIt();\n                    }\n                }\n            } finally {\n                Marshal.ReleaseComObject(shellApplication);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/TrayHelper.cs",
    "content": "﻿using Microsoft.Win32;\nusing Squirrel.SimpleSplat;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Squirrel\n{\n    public class TrayStateChanger : IEnableLogger\n    {\n        public List<NOTIFYITEM> GetTrayItems()\n        {\n            var instance = new TrayNotify();\n            try {\n                if (useLegacyInterface()) {\n                    return getTrayItemsWin7(instance);\n                } else {\n                    return getTrayItems(instance);\n                }\n            } finally {\n                Marshal.ReleaseComObject(instance);\n            }\n        }\n\n        public void PromoteTrayItem(string exeToPromote)\n        {\n            var instance = new TrayNotify();\n\n            try {\n                var items = default(List<NOTIFYITEM>);\n                var legacy = useLegacyInterface();\n\n                if (legacy) {\n                    items = getTrayItemsWin7(instance);\n                } else {\n                    items = getTrayItems(instance);\n                }\n\n                exeToPromote = exeToPromote.ToLowerInvariant();\n\n                for (int i = 0; i < items.Count; i++) {\n                    var item = items[i];\n                    var exeName = item.exe_name.ToLowerInvariant();\n\n                    if (!exeName.Contains(exeToPromote)) continue;\n\n                    if (item.preference != NOTIFYITEM_PREFERENCE.PREFERENCE_SHOW_WHEN_ACTIVE) continue;\n                    item.preference = NOTIFYITEM_PREFERENCE.PREFERENCE_SHOW_ALWAYS;\n\n                    var writable = NOTIFYITEM_Writable.fromNotifyItem(item);\n                    if (legacy) {\n                        var notifier = (ITrayNotifyWin7)instance;\n                        notifier.SetPreference(ref writable);\n                    } else {\n                        var notifier = (ITrayNotify)instance;\n                        notifier.SetPreference(ref writable);\n                    }\n                }\n            } catch (Exception ex) {\n                Console.WriteLine(\"Failed to promote Tray icon: \" + ex.ToString());\n            } finally {\n                Marshal.ReleaseComObject(instance);\n            }\n        }\n\n        public unsafe void RemoveDeadEntries(List<string> executablesInPackage, string rootAppDirectory, string currentAppVersion)\n        {\n            var iconStreamData = default(byte[]);\n            try {\n                iconStreamData = (byte[])Registry.GetValue(\"HKEY_CURRENT_USER\\\\Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\TrayNotify\", \"IconStreams\", new byte[] { 00 });\n            } catch (Exception ex) {\n                Console.WriteLine(\"Couldn't load IconStreams key, bailing: \" + ex.ToString());\n                return;\n            }\n\n            if (iconStreamData == null || iconStreamData.Length < 20) return;\n            var toKeep = new List<byte[]>();\n            var header = default(IconStreamsHeader);\n\n            fixed (byte* b = iconStreamData) {\n                header = (IconStreamsHeader)Marshal.PtrToStructure((IntPtr)b, typeof(IconStreamsHeader));\n                byte* current;\n\n                if (header.count <= 1) return;\n\n                for (int i=0; i < header.count; i++) {\n                    var offset = Marshal.SizeOf(typeof(IconStreamsHeader)) + (i * Marshal.SizeOf(typeof(IconStreamsItem)));\n                    if (offset > iconStreamData.Length) {\n                        this.Log().Error(\"Corrupted IconStreams regkey, bailing\");\n                        return;\n                    }\n\n                    current = b + offset;\n\n                    var item = (IconStreamsItem)Marshal.PtrToStructure((IntPtr)current, typeof(IconStreamsItem));\n\n                    try {\n                        var path = item.ExePath.ToLowerInvariant();\n\n                        // Someone completely unrelated? Keep it!\n                        if (!executablesInPackage.Any(exe => path.Contains(exe.ToLowerInvariant()))) {\n                            goto keepItem;\n                        }\n                        \n                        // Not an installed app? Keep it!\n                        if (!path.StartsWith(rootAppDirectory, StringComparison.Ordinal)) {\n                            goto keepItem;\n                        }\n\n                        // The current version? Keep it!\n                        if (path.Contains(\"app-\" + currentAppVersion)) {\n                            goto keepItem;\n                        }\n\n                        // Don't keep this item, remove it from IconStreams\n                        continue;\n\n                    keepItem:\n\n                        var newItem = new byte[Marshal.SizeOf(typeof(IconStreamsItem))];\n                        Array.Copy(iconStreamData, offset, newItem, 0, newItem.Length);\n                        toKeep.Add(newItem);\n                    } catch (Exception ex) {\n                        this.Log().ErrorException(\"Failed to parse IconStreams regkey\", ex);\n                        return;\n                    }\n                }\n\n                if (header.count == toKeep.Count) {\n                    return;\n                }\n\n                header.count = (uint)toKeep.Count;\n                Marshal.StructureToPtr(header, (IntPtr)b, false);\n\n                current = b + Marshal.SizeOf(typeof(IconStreamsHeader));\n                for(int i = 0; i < toKeep.Count; i++) {\n                    Marshal.Copy(toKeep[i], 0, (IntPtr)current, toKeep[i].Length);\n                    current += toKeep[i].Length;\n                }\n            }\n\n            try {\n                var newSize = Marshal.SizeOf(typeof(IconStreamsHeader)) + (toKeep.Count * Marshal.SizeOf(typeof(IconStreamsItem)));\n                var toSave = new byte[newSize];\n                Array.Copy(iconStreamData, toSave, newSize);\n                Registry.SetValue(\"HKEY_CURRENT_USER\\\\Software\\\\Classes\\\\Local Settings\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\TrayNotify\", \"IconStreams\", toSave);\n            } catch (Exception ex) {\n                Console.WriteLine(\"Failed to write new IconStreams regkey: \" + ex.ToString());\n            }\n\n            return;\n        }\n\n        static List<NOTIFYITEM> getTrayItems(TrayNotify instance)\n        {\n            var notifier = (ITrayNotify)instance;\n            var callback = new NotificationCb();\n            var handle = default(ulong);\n\n            notifier.RegisterCallback(callback, out handle);\n            notifier.UnregisterCallback(handle);\n            return callback.items;\n        }\n\n        static List<NOTIFYITEM> getTrayItemsWin7(TrayNotify instance)\n        {\n            var notifier = (ITrayNotifyWin7)instance;\n            var callback = new NotificationCb();\n\n            notifier.RegisterCallback(callback);\n            notifier.RegisterCallback(null);\n            return callback.items;\n        }\n\n        class NotificationCb : INotificationCb\n        {\n            public readonly List<NOTIFYITEM> items = new List<NOTIFYITEM>();\n\n            public void Notify([In] uint nEvent, [In] ref NOTIFYITEM notifyItem)\n            {\n                items.Add(notifyItem);\n            }\n        }\n\n        static bool useLegacyInterface()\n        {\n            var ver = Environment.OSVersion.Version;\n            if (ver.Major < 6) return true;\n            if (ver.Major > 6) return false;\n\n            // Windows 6.2 and higher use new interface\n            return ver.Minor <= 1;\n        }\n    }\n\n    // The known values for NOTIFYITEM's dwPreference member.\n    public enum NOTIFYITEM_PREFERENCE\n    {\n        // In Windows UI: \"Only show notifications.\"\n        PREFERENCE_SHOW_WHEN_ACTIVE = 0,\n        // In Windows UI: \"Hide icon and notifications.\"\n        PREFERENCE_SHOW_NEVER = 1,\n        // In Windows UI: \"Show icon and notifications.\"\n        PREFERENCE_SHOW_ALWAYS = 2\n    };\n\n    // NOTIFYITEM describes an entry in Explorer's registry of status icons.\n    // Explorer keeps entries around for a process even after it exits.\n    public struct NOTIFYITEM\n    {\n        [MarshalAs(UnmanagedType.LPWStr)]\n        public string exe_name;    // The file name of the creating executable.\n\n        [MarshalAs(UnmanagedType.LPWStr)]\n        public string tip;         // The last hover-text value associated with this status\n                                   // item.\n\n        public IntPtr icon;       // The icon associated with this status item.\n        public IntPtr hwnd;       // The HWND associated with the status item.\n        public NOTIFYITEM_PREFERENCE preference;  // Determines the behavior of the icon with respect to\n                                                  // the taskbar\n        public uint id;    // The ID specified by the application.  (hWnd, uID) is\n                           // unique.\n        public Guid guid;  // The GUID specified by the application, alternative to\n                           // uID.\n    };\n    public struct NOTIFYITEM_Writable\n    {\n        public IntPtr exe_name;    // The file name of the creating executable.\n\n        public IntPtr tip;         // The last hover-text value associated with this status\n                                   // item.\n\n        public IntPtr icon;       // The icon associated with this status item.\n        public IntPtr hwnd;       // The HWND associated with the status item.\n        public NOTIFYITEM_PREFERENCE preference;  // Determines the behavior of the icon with respect to\n                                                  // the taskbar\n        public uint id;    // The ID specified by the application.  (hWnd, uID) is\n                           // unique.\n        public Guid guid;  // The GUID specified by the application, alternative to\n                           // uID.\n\n        public static NOTIFYITEM_Writable fromNotifyItem(NOTIFYITEM item)\n        {\n            return new NOTIFYITEM_Writable {\n                exe_name = Marshal.StringToCoTaskMemAuto(item.exe_name),\n                tip = Marshal.StringToCoTaskMemAuto(item.tip),\n                icon = item.icon,\n                hwnd = item.hwnd,\n                preference = item.preference,\n                id = item.id,\n                guid = item.guid\n            };\n        }\n    };\n\n    [ComImport]\n    [Guid(\"D782CCBA-AFB0-43F1-94DB-FDA3779EACCB\")]\n    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n    interface INotificationCb\n    {\n        void Notify([In]uint nEvent, [In] ref NOTIFYITEM notifyItem);\n    }\n\n    [ComImport]\n    [Guid(\"FB852B2C-6BAD-4605-9551-F15F87830935\")]\n    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n    interface ITrayNotifyWin7\n    {\n        void RegisterCallback([MarshalAs(UnmanagedType.Interface)]INotificationCb callback);\n        void SetPreference([In] ref NOTIFYITEM_Writable notifyItem);\n        void EnableAutoTray([In] bool enabled);\n    }\n\n    [ComImport]\n    [Guid(\"D133CE13-3537-48BA-93A7-AFCD5D2053B4\")]\n    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\n    interface ITrayNotify\n    {\n        void RegisterCallback([MarshalAs(UnmanagedType.Interface)]INotificationCb callback, [Out] out ulong handle);\n        void UnregisterCallback([In] ulong handle);\n        void SetPreference([In] ref NOTIFYITEM_Writable notifyItem);\n        void EnableAutoTray([In] bool enabled);\n        void DoAction([In] bool enabled);\n    }\n\n    [ComImport, Guid(\"25DEAD04-1EAC-4911-9E3A-AD0A4AB560FD\")]\n    class TrayNotify { }\n\n    public struct IconStreamsHeader {\n        public uint cbSize;\n        public uint unknown1;\n        public uint unknown2;\n        public uint count;\n        public uint unknown3;\n    }\n\n    public struct IconStreamsItem {\n        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 528)]\n        public byte[] exe_path;\n\n        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1112)]\n        public byte[] dontcare;\n\n        public unsafe string ExePath {\n            get {\n                byte[] exeCopy = new byte[exe_path.Length];\n\n                // https://raw.githubusercontent.com/lestert2005/SystemTrayModder/b1061f3758f8ff9c43d77157c7a62c7e5cc6885d/source/Program.cs\n                for (int i=0; i < exe_path.Length; i++) {\n                    var b = exe_path[i];\n                    if (b > 64 && b < 91) {\n                        exeCopy[i] = (byte)((b - 64 + 13) % 26 + 64);\n                        continue;\n                    }\n\n                    if (b > 96 && b < 123) {\n                        exeCopy[i] = (byte)((b - 96 + 13) % 26 + 96);\n                        continue;\n                    }\n\n                    exeCopy[i] = b;\n                }\n\n                fixed (byte* b = exeCopy) {\n                    return Marshal.PtrToStringUni((IntPtr)b);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateInfo.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Runtime.Serialization;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    [DataContract]\n    public class UpdateInfo : IEnableLogger\n    {\n        [DataMember] public ReleaseEntry CurrentlyInstalledVersion { get; protected set; }\n        [DataMember] public ReleaseEntry FutureReleaseEntry { get; protected set; }\n        [DataMember] public List<ReleaseEntry> ReleasesToApply { get; protected set; }\n\n        [IgnoreDataMember]\n        public bool IsBootstrapping {\n            get { return CurrentlyInstalledVersion == null;  }\n        }\n\n        [IgnoreDataMember]\n        public string PackageDirectory { get; protected set; }\n\n        protected UpdateInfo(ReleaseEntry currentlyInstalledVersion, IEnumerable<ReleaseEntry> releasesToApply, string packageDirectory)\n        {\n            // NB: When bootstrapping, CurrentlyInstalledVersion is null!\n            CurrentlyInstalledVersion = currentlyInstalledVersion;\n            ReleasesToApply = (releasesToApply ?? Enumerable.Empty<ReleaseEntry>()).ToList();\n            FutureReleaseEntry = ReleasesToApply.Any() ?\n                ReleasesToApply.MaxBy(x => x.Version).FirstOrDefault() :\n                CurrentlyInstalledVersion;\n\n            this.PackageDirectory = packageDirectory;\n        }\n\n        public Dictionary<ReleaseEntry, string> FetchReleaseNotes()\n        {\n            return ReleasesToApply\n                .SelectMany(x => {\n                    try {\n                        var releaseNotes = x.GetReleaseNotes(PackageDirectory);\n                        return EnumerableExtensions.Return(Tuple.Create(x, releaseNotes));\n                    } catch (Exception ex) {\n                        this.Log().WarnException(\"Couldn't get release notes for:\" + x.Filename, ex);\n                        return Enumerable.Empty<Tuple<ReleaseEntry, string>>();\n                    }\n                })\n                .ToDictionary(k => k.Item1, v => v.Item2);\n        }\n\n        public static UpdateInfo Create(ReleaseEntry currentVersion, IEnumerable<ReleaseEntry> availableReleases, string packageDirectory)\n        {\n            Contract.Requires(availableReleases != null);\n            Contract.Requires(!String.IsNullOrEmpty(packageDirectory));\n\n            var latestFull = availableReleases.MaxBy(x => x.Version).FirstOrDefault(x => !x.IsDelta);\n            if (latestFull == null) {\n                throw new Exception(\"There should always be at least one full release\");\n            }\n\n            if (currentVersion == null) {\n                return new UpdateInfo(null, new[] { latestFull }, packageDirectory);\n            }\n\n            if (currentVersion.Version >= latestFull.Version) {\n                return new UpdateInfo(currentVersion, Enumerable.Empty<ReleaseEntry>(), packageDirectory);\n            }\n\n            var newerThanUs = availableReleases\n                .Where(x => x.Version > currentVersion.Version)\n                .OrderBy(v => v.Version);\n\n            var deltasSize = newerThanUs.Where(x => x.IsDelta).Sum(x => x.Filesize);\n\n            return (deltasSize < latestFull.Filesize && deltasSize > 0) ? \n                new UpdateInfo(currentVersion, newerThanUs.Where(x => x.IsDelta).ToArray(), packageDirectory) : \n                new UpdateInfo(currentVersion, new[] { latestFull }, packageDirectory);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateManager.ApplyReleases.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading.Tasks;\nusing NuGet;\nusing Squirrel.SimpleSplat;\nusing System.Threading;\nusing Squirrel.Shell;\nusing Microsoft.Win32;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager\n    {\n        internal class ApplyReleasesImpl : IEnableLogger\n        {\n            readonly string rootAppDirectory;\n\n            public ApplyReleasesImpl(string rootAppDirectory)\n            {\n                this.rootAppDirectory = rootAppDirectory;\n            }\n\n            public async Task<string> ApplyReleases(UpdateInfo updateInfo, bool silentInstall, bool attemptingFullInstall, Action<int> progress = null)\n            {\n                progress = progress ?? (_ => { });\n\n                progress(0);\n\n                // Progress range: 00 -> 40\n                var release = await createFullPackagesFromDeltas(updateInfo.ReleasesToApply, updateInfo.CurrentlyInstalledVersion, new ApplyReleasesProgress(updateInfo.ReleasesToApply.Count, x => progress(CalculateProgress(x, 0, 40))));\n\n                progress(40);\n\n                if (release == null) {\n                    if (attemptingFullInstall) {\n                        this.Log().Info(\"No release to install, running the app\");\n                        await invokePostInstall(updateInfo.CurrentlyInstalledVersion.Version, false, true, silentInstall);\n                    }\n\n                    progress(100);\n                    return getDirectoryForRelease(updateInfo.CurrentlyInstalledVersion.Version).FullName;\n                }\n\n                // Progress range: 40 -> 80\n                var ret = await this.ErrorIfThrows(() => installPackageToAppDir(updateInfo, release, x => progress(CalculateProgress(x, 40, 80))), \n                    \"Failed to install package to app dir\");\n\n                progress(80);\n\n                var currentReleases = await this.ErrorIfThrows(() => updateLocalReleasesFile(),\n                    \"Failed to update local releases file\");\n\n                progress(85);\n\n                var newVersion = currentReleases.MaxBy(x => x.Version).First().Version;\n                executeSelfUpdate(newVersion);\n\n                progress(90);\n\n                await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInstall, false, silentInstall),\n                    \"Failed to invoke post-install\");\n\n                progress(95);\n\n                this.Log().Info(\"Starting fixPinnedExecutables\");\n\n                this.ErrorIfThrows(() => fixPinnedExecutables(updateInfo.FutureReleaseEntry.Version));\n\n                progress(96);\n\n                this.Log().Info(\"Fixing up tray icons\");\n\n                var trayFixer = new TrayStateChanger();\n                var appDir = new DirectoryInfo(Utility.AppDirForRelease(rootAppDirectory, updateInfo.FutureReleaseEntry));\n                var allExes = appDir.GetFiles(\"*.exe\").Select(x => x.Name).ToList();\n\n                this.ErrorIfThrows(() => trayFixer.RemoveDeadEntries(allExes, rootAppDirectory, updateInfo.FutureReleaseEntry.Version.ToString()));\n\n                progress(97);\n\n                unshimOurselves();\n\n                progress(98);\n\n                try {\n                    var currentVersion = updateInfo.CurrentlyInstalledVersion != null ?\n                        updateInfo.CurrentlyInstalledVersion.Version : null;\n\n                    await cleanDeadVersions(currentVersion, newVersion);\n                } catch (Exception ex) {\n                    this.Log().WarnException(\"Failed to clean dead versions, continuing anyways\", ex);\n                }\n\n                progress(100);\n\n                return ret;\n            }\n\n            public async Task FullUninstall()\n            {\n                var currentRelease = getReleases().MaxBy(x => x.Name.ToSemanticVersion()).FirstOrDefault();\n\n                this.Log().Info(\"Starting full uninstall\");\n                if (currentRelease.Exists) {\n                    var version = currentRelease.Name.ToSemanticVersion();\n\n                    try {\n                        var squirrelAwareApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(currentRelease.FullName);\n\n                        if (isAppFolderDead(currentRelease.FullName)) throw new Exception(\"App folder is dead, but we're trying to uninstall it?\");\n\n                        var allApps = currentRelease.EnumerateFiles()\n                            .Where(x => x.Name.EndsWith(\".exe\", StringComparison.OrdinalIgnoreCase))\n                            .Where(x => !x.Name.StartsWith(\"squirrel.\", StringComparison.OrdinalIgnoreCase) && !x.Name.StartsWith(\"update.\", StringComparison.OrdinalIgnoreCase))\n                            .ToList();\n\n                        if (squirrelAwareApps.Count > 0) {\n                            await squirrelAwareApps.ForEachAsync(async exe => {\n                                using (var cts = new CancellationTokenSource()) { \n                                    cts.CancelAfter(10 * 1000);\n\n                                    try {\n                                        await Utility.InvokeProcessAsync(exe, String.Format(\"--squirrel-uninstall {0}\", version), cts.Token);\n                                    } catch (Exception ex) {\n                                        this.Log().ErrorException(\"Failed to run cleanup hook, continuing: \" + exe, ex);\n                                    }\n                                }\n                            }, 1 /*at a time*/);\n                        } else {\n                            allApps.ForEach(x => RemoveShortcutsForExecutable(x.Name, ShortcutLocation.StartMenu | ShortcutLocation.Desktop));\n                        }\n                    } catch (Exception ex) {\n                        this.Log().WarnException(\"Failed to run pre-uninstall hooks, uninstalling anyways\", ex);\n                    }\n                }\n\n                try {\n                    this.ErrorIfThrows(() => fixPinnedExecutables(new SemanticVersion(255, 255, 255, 255), true));\n                } catch { }\n\n                await this.ErrorIfThrows(() => Utility.DeleteDirectoryOrJustGiveUp(rootAppDirectory),\n                    \"Failed to delete app directory: \" + rootAppDirectory);\n\n                // NB: We drop this file here so that --checkInstall will ignore \n                // this folder - if we don't do this, users who \"accidentally\" run as \n                // administrator will find the app reinstalling itself on every\n                // reboot\n                if (!Directory.Exists(rootAppDirectory)) {\n                    Directory.CreateDirectory(rootAppDirectory);\n                }\n\n                File.WriteAllText(Path.Combine(rootAppDirectory, \".dead\"), \" \");\n            }\n\n            public Dictionary<ShortcutLocation, ShellLink> GetShortcutsForExecutable(string exeName, ShortcutLocation locations, string programArguments)\n            {\n                this.Log().Info(\"About to create shortcuts for {0}, rootAppDir {1}\", exeName, rootAppDirectory);\n\n                var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory));\n                var thisRelease = Utility.FindCurrentVersion(releases);\n\n                var zf = new ZipPackage(Path.Combine(\n                    Utility.PackageDirectoryForAppDir(rootAppDirectory),\n                    thisRelease.Filename));\n\n                var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName);\n                var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath);\n\n                var ret = new Dictionary<ShortcutLocation, ShellLink>();\n                foreach (var f in (ShortcutLocation[]) Enum.GetValues(typeof(ShortcutLocation))) {\n                    if (!locations.HasFlag(f)) continue;\n\n                    var file = linkTargetForVersionInfo(f, zf, fileVerInfo);\n                    var appUserModelId = String.Format(\"com.squirrel.{0}.{1}\", zf.Id.Replace(\" \", \"\"), exeName.Replace(\".exe\", \"\").Replace(\" \", \"\"));\n                    var toastActivatorCLSDID = Utility.CreateGuidFromHash(appUserModelId).ToString();\n\n                    this.Log().Info(\"Creating shortcut for {0} => {1}\", exeName, file);\n                    this.Log().Info(\"appUserModelId: {0} | toastActivatorCLSID: {1}\", appUserModelId, toastActivatorCLSDID);\n\n                    var target = Path.Combine(rootAppDirectory, exeName);\n                    var sl = new ShellLink {\n                        Target = target,\n                        IconPath = target,\n                        IconIndex = 0,\n                        WorkingDirectory = Path.GetDirectoryName(exePath),\n                        Description = zf.Description,\n                    };\n\n                    if (!String.IsNullOrWhiteSpace(programArguments)) {\n                        sl.Arguments += String.Format(\" -a \\\"{0}\\\"\", programArguments);\n                    }\n\n                    sl.SetAppUserModelId(appUserModelId);\n                    sl.SetToastActivatorCLSID(toastActivatorCLSDID);\n\n                    ret.Add(f, sl);\n                }\n\n                return ret;\n            }\n\n            public void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly, string programArguments, string icon)\n            {\n                this.Log().Info(\"About to create shortcuts for {0}, rootAppDir {1}\", exeName, rootAppDirectory);\n\n                var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory));\n                var thisRelease = Utility.FindCurrentVersion(releases);\n\n                var zf = new ZipPackage(Path.Combine(\n                    Utility.PackageDirectoryForAppDir(rootAppDirectory),\n                    thisRelease.Filename));\n\n                var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName);\n                var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath);\n\n                foreach (var f in (ShortcutLocation[]) Enum.GetValues(typeof(ShortcutLocation))) {\n                    if (!locations.HasFlag(f)) continue;\n\n                    var file = linkTargetForVersionInfo(f, zf, fileVerInfo);\n                    var fileExists = File.Exists(file);\n\n                    // NB: If we've already installed the app, but the shortcut\n                    // is no longer there, we have to assume that the user didn't\n                    // want it there and explicitly deleted it, so we shouldn't\n                    // annoy them by recreating it.\n                    if (!fileExists && updateOnly) {\n                        this.Log().Warn(\"Wanted to update shortcut {0} but it appears user deleted it\", file);\n                        continue;\n                    }\n\n                    this.Log().Info(\"Creating shortcut for {0} => {1}\", exeName, file);\n\n                    ShellLink sl;\n                    this.ErrorIfThrows(() => Utility.Retry(() => {\n                        File.Delete(file);\n\n                        var target = Path.Combine(rootAppDirectory, exeName);\n                        sl = new ShellLink {\n                            Target = target,\n                            IconPath = icon ?? target,\n                            IconIndex = 0,\n                            WorkingDirectory = Path.GetDirectoryName(exePath),\n                            Description = zf.Description,\n                        };\n\n                        if (!String.IsNullOrWhiteSpace(programArguments)) {\n                            sl.Arguments += String.Format(\" -a \\\"{0}\\\"\", programArguments);\n                        }\n\n                        var appUserModelId = String.Format(\"com.squirrel.{0}.{1}\", zf.Id.Replace(\" \", \"\"), exeName.Replace(\".exe\", \"\").Replace(\" \", \"\"));\n                        var toastActivatorCLSID = Utility.CreateGuidFromHash(appUserModelId).ToString();\n\n                        sl.SetAppUserModelId(appUserModelId);\n                        sl.SetToastActivatorCLSID(toastActivatorCLSID);\n\n                        this.Log().Info(\"About to save shortcut: {0} (target {1}, workingDir {2}, args {3}, toastActivatorCSLID {4})\", file, sl.Target, sl.WorkingDirectory, sl.Arguments, toastActivatorCLSID);\n                        if (ModeDetector.InUnitTestRunner() == false) sl.Save(file);\n                    }, 4), \"Can't write shortcut: \" + file);\n                }\n\n                fixPinnedExecutables(zf.Version);\n            }\n\n            public void RemoveShortcutsForExecutable(string exeName, ShortcutLocation locations)\n            {\n                var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory));\n                var thisRelease = Utility.FindCurrentVersion(releases);\n\n                var zf = new ZipPackage(Path.Combine(\n                    Utility.PackageDirectoryForAppDir(rootAppDirectory),\n                    thisRelease.Filename));\n\n                var fileVerInfo = FileVersionInfo.GetVersionInfo(\n                    Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName));\n\n                foreach (var f in (ShortcutLocation[]) Enum.GetValues(typeof(ShortcutLocation))) {\n                    if (!locations.HasFlag(f)) continue;\n\n                    var file = linkTargetForVersionInfo(f, zf, fileVerInfo);\n\n                    this.Log().Info(\"Removing shortcut for {0} => {1}\", exeName, file);\n\n                    this.ErrorIfThrows(() => {\n                        if (File.Exists(file)) File.Delete(file);\n                    }, \"Couldn't delete shortcut: \" + file);\n                }\n\n                fixPinnedExecutables(zf.Version);\n            }\n\n            Task<string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release, Action<int> progressCallback)\n            {\n                return Task.Run(async () => {\n                    var target = getDirectoryForRelease(release.Version);\n\n                    // NB: This might happen if we got killed partially through applying the release\n                    if (target.Exists) {\n                        this.Log().Warn(\"Found partially applied release folder, killing it: \" + target.FullName);\n                        await Utility.DeleteDirectory(target.FullName);\n                    }\n\n                    target.Create();\n\n                    // Create the .not-finished file before extraction is started\n                    var notFinishedFilePath = Path.Combine(target.FullName, \".not-finished\");\n                    File.WriteAllText(notFinishedFilePath, \"\");\n\n                    this.Log().Info(\"Writing files to app directory: {0}\", target.FullName);\n                    await ReleasePackage.ExtractZipForInstall(\n                        Path.Combine(updateInfo.PackageDirectory, release.Filename),\n                        target.FullName,\n                        rootAppDirectory,\n                        progressCallback);\n\n                    // Delete the .not-finished file after extraction is completed\n                    this.ErrorIfThrows(() => {\n                        File.Delete(notFinishedFilePath);\n                    }, \"Couldn't delete file: \" + notFinishedFilePath);\n\n                    return target.FullName;\n                });\n            }\n\n            async Task<ReleaseEntry> createFullPackagesFromDeltas(IEnumerable<ReleaseEntry> releasesToApply, ReleaseEntry currentVersion, ApplyReleasesProgress progress)\n            {\n                Contract.Requires(releasesToApply != null);\n\n                progress = progress ?? new ApplyReleasesProgress(releasesToApply.Count(), x => { });\n\n                // If there are no remote releases at all, bail\n                if (!releasesToApply.Any()) {\n                    return null;\n                }\n\n                // If there are no deltas in our list, we're already done\n                if (releasesToApply.All(x => !x.IsDelta)) {\n                    return releasesToApply.MaxBy(x => x.Version).FirstOrDefault();\n                }\n\n                if (!releasesToApply.All(x => x.IsDelta)) {\n                    throw new Exception(\"Cannot apply combinations of delta and full packages\");\n                }\n\n                // Progress calculation is \"complex\" here. We need to known how many releases, and then give each release a similar amount of\n                // progress. For example, when applying 5 releases:\n                //\n                // release 1: 00 => 20\n                // release 2: 20 => 40\n                // release 3: 40 => 60\n                // release 4: 60 => 80\n                // release 5: 80 => 100\n                // \n\n                // Smash together our base full package and the nearest delta\n                var ret = await Task.Run(() => {\n                    var basePkg = new ReleasePackage(Path.Combine(rootAppDirectory, \"packages\", currentVersion.Filename));\n                    var deltaPkg = new ReleasePackage(Path.Combine(rootAppDirectory, \"packages\", releasesToApply.First().Filename));\n\n                    var deltaBuilder = new DeltaPackageBuilder(Directory.GetParent(this.rootAppDirectory).FullName);\n\n                    return deltaBuilder.ApplyDeltaPackage(basePkg, deltaPkg,\n                        Regex.Replace(deltaPkg.InputPackageFile, @\"-delta.nupkg$\", \".nupkg\", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant),\n                        x => progress.ReportReleaseProgress(x));\n                });\n\n                progress.FinishRelease();\n\n                if (releasesToApply.Count() == 1) {\n                    return ReleaseEntry.GenerateFromFile(ret.InputPackageFile);\n                }\n\n                var fi = new FileInfo(ret.InputPackageFile);\n                var entry = ReleaseEntry.GenerateFromFile(fi.OpenRead(), fi.Name);\n\n                // Recursively combine the rest of them\n                return await createFullPackagesFromDeltas(releasesToApply.Skip(1), entry, progress);\n            }\n\n            void executeSelfUpdate(SemanticVersion currentVersion)\n            {\n                var targetDir = getDirectoryForRelease(currentVersion);\n                var newSquirrel = Path.Combine(targetDir.FullName, \"Squirrel.exe\");\n                if (!File.Exists(newSquirrel)) {\n                    return;\n                }\n\n                // If we're running in the context of Update.exe, we can't \n                // update ourselves. Instead, ask the new Update.exe to do it\n                // once we exit\n                var us = Assembly.GetEntryAssembly();\n                if (us != null && Path.GetFileName(us.Location).Equals(\"update.exe\", StringComparison.OrdinalIgnoreCase)) {\n                    var appName = targetDir.Parent.Name;\n\n                    Process.Start(newSquirrel, \"--updateSelf=\" + us.Location);\n                    return;\n                }\n\n                // If we're *not* Update.exe, this is easy, it's just a file copy\n                Utility.Retry(() =>\n                    File.Copy(newSquirrel, Path.Combine(targetDir.Parent.FullName, \"Update.exe\"), true));\n            }\n\n            async Task invokePostInstall(SemanticVersion currentVersion, bool isInitialInstall, bool firstRunOnly, bool silentInstall)\n            {\n                var targetDir = getDirectoryForRelease(currentVersion);\n                var args = isInitialInstall ?\n                    String.Format(\"--squirrel-install {0}\", currentVersion) :\n                    String.Format(\"--squirrel-updated {0}\", currentVersion);\n\n                var squirrelApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(targetDir.FullName);\n\n                this.Log().Info(\"Squirrel Enabled Apps: [{0}]\", String.Join(\",\", squirrelApps));\n\n                // For each app, run the install command in-order and wait\n                if (!firstRunOnly) await squirrelApps.ForEachAsync(async exe => {\n                    using (var cts = new CancellationTokenSource()) { \n                        cts.CancelAfter(15 * 1000);\n\n                        try {\n                            await Utility.InvokeProcessAsync(exe, args, cts.Token);\n                        } catch (Exception ex) {\n                            this.Log().ErrorException(\"Couldn't run Squirrel hook, continuing: \" + exe, ex);\n                        }\n                    }\n                }, 1 /* at a time */);\n\n                // If this is the first run, we run the apps with first-run and \n                // *don't* wait for them, since they're probably the main EXE\n                if (squirrelApps.Count == 0) {\n                    this.Log().Warn(\"No apps are marked as Squirrel-aware! Going to run them all\");\n\n                    squirrelApps = targetDir.EnumerateFiles()\n                        .Where(x => x.Name.EndsWith(\".exe\", StringComparison.OrdinalIgnoreCase))\n                        .Where(x => !x.Name.StartsWith(\"squirrel.\", StringComparison.OrdinalIgnoreCase))\n                        .Select(x => x.FullName)\n                        .ToList();\n\n                    // Create shortcuts for apps automatically if they didn't\n                    // create any Squirrel-aware apps\n                    squirrelApps.ForEach(x => CreateShortcutsForExecutable(Path.GetFileName(x), ShortcutLocation.Desktop | ShortcutLocation.StartMenu, isInitialInstall == false, null, null));\n                }\n\n                if (!isInitialInstall || silentInstall) return;\n\n                var firstRunParam = isInitialInstall ? \"--squirrel-firstrun\" : \"\";\n                squirrelApps\n                    .Select(exe => new ProcessStartInfo(exe, firstRunParam) { WorkingDirectory = Path.GetDirectoryName(exe) })\n                    .ForEach(info => Process.Start(info));\n            }\n\n            void fixPinnedExecutables(SemanticVersion newCurrentVersion, bool removeAll = false)\n            {\n                if (Environment.OSVersion.Version < new Version(6, 1)) {\n                    this.Log().Warn(\"fixPinnedExecutables: Found OS Version '{0}', exiting...\", Environment.OSVersion.VersionString);\n                    return;\n                }\n\n                var newCurrentFolder = \"app-\" + newCurrentVersion;\n                var newAppPath = Path.Combine(rootAppDirectory, newCurrentFolder);\n\n                var taskbarPath = Path.Combine(\n                    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\n                    \"Microsoft\\\\Internet Explorer\\\\Quick Launch\\\\User Pinned\\\\TaskBar\");\n\n                if (!Directory.Exists(taskbarPath)) {\n                    this.Log().Info(\"fixPinnedExecutables: PinnedExecutables directory doesn't exitsts, skiping...\");\n                    return;\n                }\n\n                var resolveLink = new Func<FileInfo, ShellLink>(file => {\n                    try {\n                        this.Log().Debug(\"Examining Pin: \" + file);\n                        return new ShellLink(file.FullName);\n                    } catch (Exception ex) {\n                        var message = String.Format(\"File '{0}' could not be converted into a valid ShellLink\", file.FullName);\n                        this.Log().WarnException(message, ex);\n                        return null;\n                    }\n                });\n\n                var shellLinks = (new DirectoryInfo(taskbarPath)).GetFiles(\"*.lnk\").Select(resolveLink).ToArray();\n\n                foreach (var shortcut in shellLinks) {\n                    try {\n                        if (shortcut == null) continue;\n                        if (String.IsNullOrWhiteSpace(shortcut.Target)) continue;\n                        if (!shortcut.Target.StartsWith(rootAppDirectory, StringComparison.OrdinalIgnoreCase)) continue;\n\n                        if (removeAll) {\n                            Utility.DeleteFileHarder(shortcut.ShortCutFile);\n                        } else {\n                            updateLink(shortcut, newAppPath);\n                        }\n\n                    } catch (Exception ex) {\n                        var message = String.Format(\"fixPinnedExecutables: shortcut failed: {0}\", shortcut.Target);\n                        this.Log().ErrorException(message, ex);\n                    }\n                }\n            }\n\n            void updateLink(ShellLink shortcut, string newAppPath)\n            {\n                this.Log().Info(\"Processing shortcut '{0}'\", shortcut.ShortCutFile);\n\n                var target = Environment.ExpandEnvironmentVariables(shortcut.Target);\n                var targetIsUpdateDotExe = target.EndsWith(\"update.exe\", StringComparison.OrdinalIgnoreCase);\n\n                this.Log().Info(\"Old shortcut target: '{0}'\", target);\n\n                // NB: In 1.5.0 we accidentally fixed the target of pinned shortcuts but left the arguments,\n                // so if we find a shortcut with --processStart in the args, we're gonna stomp it even though\n                // what we _should_ do is stomp it only if the target is Update.exe\n                if (shortcut.Arguments.Contains(\"--processStart\")) {\n                    shortcut.Arguments = \"\";\n                }\n\n                if (!targetIsUpdateDotExe) {\n                    target = Path.Combine(rootAppDirectory, Path.GetFileName(shortcut.Target));\n                } else {\n                    target = Path.Combine(rootAppDirectory, Path.GetFileName(shortcut.IconPath));\n                }\n\n                this.Log().Info(\"New shortcut target: '{0}'\", target);\n\n                shortcut.WorkingDirectory = newAppPath;\n                shortcut.Target = target;\n\n                this.Log().Info(\"Old iconPath is: '{0}'\", shortcut.IconPath);\n                shortcut.IconPath = target;\n                shortcut.IconIndex = 0;\n\n                this.ErrorIfThrows(() => Utility.Retry(() => shortcut.Save(), 2), \"Couldn't write shortcut \" + shortcut.ShortCutFile);\n                this.Log().Info(\"Finished shortcut successfully\");\n            }\n\n            internal void unshimOurselves()\n            {\n                new[] { RegistryView.Registry32, RegistryView.Registry64 }.ForEach(view => {\n                    var baseKey = default(RegistryKey);\n                    var regKey = default(RegistryKey);\n\n                    try {\n                        baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, view);\n                        regKey = baseKey.OpenSubKey(@\"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers\");\n\n                        if (regKey == null) return;\n\n                        var toDelete = regKey.GetValueNames()\n                            .Where(x => x.StartsWith(rootAppDirectory, StringComparison.OrdinalIgnoreCase))\n                            .ToList();\n\n                        toDelete.ForEach(x =>\n                            this.Log().LogIfThrows(LogLevel.Warn, \"Failed to delete key: \" + x,\n                                () => regKey.DeleteValue(x)));\n                    } catch (Exception e) {\n                        this.Log().WarnException(\"Couldn't rewrite shim RegKey, most likely no apps are shimmed\", e);\n                    } finally {\n                        if (regKey != null) regKey.Dispose();\n                        if (baseKey != null) baseKey.Dispose();\n                    }\n                });\n            }\n\n            // NB: Once we uninstall the old version of the app, we try to schedule\n            // it to be deleted at next reboot. Unfortunately, depending on whether\n            // the user has admin permissions, this can fail. So as a failsafe,\n            // before we try to apply any update, we assume previous versions in the\n            // directory are \"dead\" (i.e. already uninstalled, but not deleted), and\n            // we blow them away. This is to make sure that we don't attempt to run\n            // an uninstaller on an already-uninstalled version.\n            async Task cleanDeadVersions(SemanticVersion currentVersion, SemanticVersion newVersion, bool forceUninstall = false)\n            {\n                if (newVersion == null) return;\n\n                var di = new DirectoryInfo(rootAppDirectory);\n                if (!di.Exists) return;\n\n                this.Log().Info(\"cleanDeadVersions: checking for version {0}\", newVersion);\n\n                string currentVersionFolder = null;\n                if (currentVersion != null) {\n                    currentVersionFolder = getDirectoryForRelease(currentVersion).Name;\n                    this.Log().Info(\"cleanDeadVersions: exclude current version folder {0}\", currentVersionFolder);\n                }\n\n                string newVersionFolder = null;\n                if (newVersion != null) {\n                    newVersionFolder = getDirectoryForRelease(newVersion).Name;\n                    this.Log().Info(\"cleanDeadVersions: exclude new version folder {0}\", newVersionFolder);\n                }\n\n                // NB: If we try to access a directory that has already been \n                // scheduled for deletion by MoveFileEx it throws what seems like\n                // NT's only error code, ERROR_ACCESS_DENIED. Squelch errors that\n                // come from here.\n                var toCleanup = di.GetDirectories()\n                    .Where(x => x.Name.ToLowerInvariant().Contains(\"app-\"))\n                    .Where(x => x.Name != newVersionFolder && x.Name != currentVersionFolder)\n                    .Where(x => !isAppFolderDead(x.FullName));\n\n                if (forceUninstall == false) {\n                    await toCleanup.ForEachAsync(async x => {\n                        var squirrelApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(x.FullName);\n                        var args = String.Format(\"--squirrel-obsolete {0}\", x.Name.Replace(\"app-\", \"\"));\n\n                        if (squirrelApps.Count > 0) {\n                            // For each app, run the install command in-order and wait\n                            await squirrelApps.ForEachAsync(async exe => {\n                                using (var cts = new CancellationTokenSource()) { \n                                    cts.CancelAfter(10 * 1000);\n\n                                    try {\n                                        await Utility.InvokeProcessAsync(exe, args, cts.Token);\n                                    } catch (Exception ex) {\n                                        this.Log().ErrorException(\"Coudln't run Squirrel hook, continuing: \" + exe, ex);\n                                    }\n                                }\n                            }, 1 /* at a time */);\n                        }\n                    });\n                }\n\n                // Include dead folders in folders to :fire:\n                toCleanup = di.GetDirectories()\n                    .Where(x => x.Name.ToLowerInvariant().Contains(\"app-\"))\n                    .Where(x => x.Name != newVersionFolder && x.Name != currentVersionFolder);\n\n                // Get the current process list in an attempt to not burn \n                // directories which have running processes\n                var runningProcesses = UnsafeUtility.EnumerateProcesses(); \n\n                // Finally, clean up the app-X.Y.Z directories\n                await toCleanup.ForEachAsync(async x => {\n                    try {\n                        if (runningProcesses.All(p => p.Item1 == null || !p.Item1.StartsWith(x.FullName, StringComparison.OrdinalIgnoreCase))) {\n                            await Utility.DeleteDirectoryOrJustGiveUp(x.FullName);\n                        }\n\n                        if (Directory.Exists(x.FullName)) {\n                            // NB: If we cannot clean up a directory, we need to make \n                            // sure that anyone finding it later won't attempt to run\n                            // Squirrel events on it. We'll mark it with a .dead file\n                            markAppFolderAsDead(x.FullName);\n                        }\n                    } catch (UnauthorizedAccessException ex) {\n                        this.Log().WarnException(\"Couldn't delete directory: \" + x.FullName, ex);\n\n                        // NB: Same deal as above\n                        markAppFolderAsDead(x.FullName);\n                    }\n                });\n\n                // Clean up the packages directory too\n                var releasesFile = Utility.LocalReleaseFileForAppDir(rootAppDirectory);\n                var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesFile, Encoding.UTF8));\n                var pkgDir = Utility.PackageDirectoryForAppDir(rootAppDirectory);\n                var releaseEntry = default(ReleaseEntry);\n\n                foreach (var entry in entries) {\n                    if (entry.Version == newVersion) {\n                        releaseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(pkgDir, entry.Filename));\n                        continue;\n                    }\n\n                    File.Delete(Path.Combine(pkgDir, entry.Filename));\n                }\n\n                ReleaseEntry.WriteReleaseFile(new[] { releaseEntry }, releasesFile);\n            }\n\n            static void markAppFolderAsDead(string appFolderPath)\n            {\n                File.WriteAllText(Path.Combine(appFolderPath, \".dead\"), \"\");\n            }\n\n            static bool isAppFolderDead(string appFolderPath)\n            {\n                return File.Exists(Path.Combine(appFolderPath, \".dead\"));\n            }\n\n            internal async Task<List<ReleaseEntry>> updateLocalReleasesFile()\n            {\n                return await Task.Run(() => ReleaseEntry.BuildReleasesFile(Utility.PackageDirectoryForAppDir(rootAppDirectory)));\n            }\n\n            IEnumerable<DirectoryInfo> getReleases()\n            {\n                var rootDirectory = new DirectoryInfo(rootAppDirectory);\n\n                if (!rootDirectory.Exists) return Enumerable.Empty<DirectoryInfo>();\n\n                return rootDirectory.GetDirectories()\n                    .Where(x => x.Name.StartsWith(\"app-\", StringComparison.InvariantCultureIgnoreCase));\n            }\n\n            DirectoryInfo getDirectoryForRelease(SemanticVersion releaseVersion)\n            {\n                return new DirectoryInfo(Path.Combine(rootAppDirectory, \"app-\" + releaseVersion));\n            }\n\n            string linkTargetForVersionInfo(ShortcutLocation location, IPackage package, FileVersionInfo versionInfo)\n            {\n                var possibleProductNames = new[] {\n                    versionInfo.ProductName,\n                    package.Title,\n                    versionInfo.FileDescription,\n                    Path.GetFileNameWithoutExtension(versionInfo.FileName)\n                };\n\n                var possibleCompanyNames = new[] {\n                    versionInfo.CompanyName,\n                    package.Authors.FirstOrDefault() ?? package.Id,\n                };\n\n                var prodName = possibleCompanyNames.First(x => !String.IsNullOrWhiteSpace(x));\n                var pkgName = possibleProductNames.First(x => !String.IsNullOrWhiteSpace(x));\n\n                return getLinkTarget(location, pkgName, prodName);\n            }\n\n            string getLinkTarget(ShortcutLocation location, string title, string applicationName, bool createDirectoryIfNecessary = true)\n            {\n                var dir = default(string);\n\n                switch (location) {\n                case ShortcutLocation.Desktop:\n                    dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);\n                    break;\n                case ShortcutLocation.StartMenu:\n                    dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), \"Programs\", applicationName);\n                    break;\n                case ShortcutLocation.Startup:\n                    dir = Environment.GetFolderPath (Environment.SpecialFolder.Startup);\n                    break;\n                case ShortcutLocation.AppRoot:\n                    dir = rootAppDirectory;\n                    break;\n                }\n\n                if (createDirectoryIfNecessary && !Directory.Exists(dir)) {\n                    Directory.CreateDirectory(dir);\n                }\n\n                return Path.Combine(dir, title + \".lnk\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateManager.CheckForUpdates.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager\n    {\n        internal class CheckForUpdateImpl : IEnableLogger\n        {\n            readonly string rootAppDirectory;\n\n            public CheckForUpdateImpl(string rootAppDirectory)\n            {\n                this.rootAppDirectory = rootAppDirectory;\n            }\n\n            public async Task<UpdateInfo> CheckForUpdate(\n                UpdaterIntention intention,\n                string localReleaseFile,\n                string updateUrlOrPath,\n                bool ignoreDeltaUpdates = false,\n                Action<int> progress = null,\n                IFileDownloader urlDownloader = null)\n            {\n                progress = progress ?? (_ => { });\n\n                var localReleases = Enumerable.Empty<ReleaseEntry>();\n                var stagingId = intention == UpdaterIntention.Install ? null : getOrCreateStagedUserId();\n\n                bool shouldInitialize = intention == UpdaterIntention.Install;\n\n                if (intention != UpdaterIntention.Install) {\n                    try {\n                        localReleases = Utility.LoadLocalReleases(localReleaseFile);\n                    }\n                    catch (Exception ex) {\n                        // Something has gone pear-shaped, let's start from scratch\n                        this.Log().WarnException(\"Failed to load local releases, starting from scratch\", ex);\n                        shouldInitialize = true;\n                    }\n                }\n\n                if (shouldInitialize) await initializeClientAppDirectory();\n\n                string releaseFile;\n\n                var latestLocalRelease = localReleases.Count() > 0 ?\n                    localReleases.MaxBy(x => x.Version).First() :\n                    default(ReleaseEntry);\n\n                // Fetch the remote RELEASES file, whether it's a local dir or an\n                // HTTP URL\n                if (Utility.IsHttpUrl(updateUrlOrPath)) {\n                    if (updateUrlOrPath.EndsWith(\"/\")) {\n                        updateUrlOrPath = updateUrlOrPath.Substring(0, updateUrlOrPath.Length - 1);\n                    }\n\n                    this.Log().Info(\"Downloading RELEASES file from {0}\", updateUrlOrPath);\n\n                    int retries = 3;\n\n                retry:\n\n                    try {\n                        var uri = Utility.AppendPathToUri(new Uri(updateUrlOrPath), \"RELEASES\");\n\n                        if (latestLocalRelease != null) {\n                            uri = Utility.AddQueryParamsToUri(uri, new Dictionary<string, string> {\n                                { \"id\", latestLocalRelease.PackageName },\n                                { \"localVersion\", latestLocalRelease.Version.ToString() },\n                                { \"arch\", Environment.Is64BitOperatingSystem ? \"amd64\" : \"x86\" }\n                            });\n                        }\n\n                        var data = await urlDownloader.DownloadUrl(uri.ToString());\n                        releaseFile = Encoding.UTF8.GetString(data);\n                    } catch (WebException ex) {\n                        this.Log().InfoException(\"Download resulted in WebException (returning blank release list)\", ex);\n\n                        if (retries <= 0) throw;\n                        retries--;\n                        goto retry;\n                    }\n\n                    progress(33);\n                } else {\n                    this.Log().Info(\"Reading RELEASES file from {0}\", updateUrlOrPath);\n\n                    if (!Directory.Exists(updateUrlOrPath)) {\n                        var message = String.Format(\n                            \"The directory {0} does not exist, something is probably broken with your application\",\n                            updateUrlOrPath);\n\n                        throw new Exception(message);\n                    }\n\n                    var fi = new FileInfo(Path.Combine(updateUrlOrPath, \"RELEASES\"));\n                    if (!fi.Exists) {\n                        var message = String.Format(\n                            \"The file {0} does not exist, something is probably broken with your application\",\n                            fi.FullName);\n\n                        this.Log().Warn(message);\n\n                        var packages = (new DirectoryInfo(updateUrlOrPath)).GetFiles(\"*.nupkg\");\n                        if (packages.Length == 0) {\n                            throw new Exception(message);\n                        }\n\n                        // NB: Create a new RELEASES file since we've got a directory of packages\n                        ReleaseEntry.WriteReleaseFile(\n                            packages.Select(x => ReleaseEntry.GenerateFromFile(x.FullName)), fi.FullName);\n                    }\n\n                    releaseFile = File.ReadAllText(fi.FullName, Encoding.UTF8);\n                    progress(33);\n                }\n\n                var ret = default(UpdateInfo);\n                var remoteReleases = ReleaseEntry.ParseReleaseFileAndApplyStaging(releaseFile, stagingId);\n                progress(66);\n\n                if (!remoteReleases.Any()) {\n                    throw new Exception(\"Remote release File is empty or corrupted\");\n                }\n\n                ret = determineUpdateInfo(intention, localReleases, remoteReleases, ignoreDeltaUpdates);\n\n                progress(100);\n                return ret;\n            }\n\n            async Task initializeClientAppDirectory()\n            {\n                // On bootstrap, we won't have any of our directories, create them\n                var pkgDir = Path.Combine(rootAppDirectory, \"packages\");\n                if (Directory.Exists(pkgDir)) {\n                    await Utility.DeleteDirectory(pkgDir);\n                }\n\n                Directory.CreateDirectory(pkgDir);\n            }\n\n            UpdateInfo determineUpdateInfo(UpdaterIntention intention, IEnumerable<ReleaseEntry> localReleases, IEnumerable<ReleaseEntry> remoteReleases, bool ignoreDeltaUpdates)\n            {\n                var packageDirectory = Utility.PackageDirectoryForAppDir(rootAppDirectory);\n                localReleases = localReleases ?? Enumerable.Empty<ReleaseEntry>();\n\n                if (remoteReleases == null) {\n                    this.Log().Warn(\"Release information couldn't be determined due to remote corrupt RELEASES file\");\n                    throw new Exception(\"Corrupt remote RELEASES file\");\n                }\n\n                var latestFullRelease = Utility.FindCurrentVersion(remoteReleases);\n                var currentRelease = Utility.FindCurrentVersion(localReleases);\n\n                if (latestFullRelease == currentRelease) {\n                    this.Log().Info(\"No updates, remote and local are the same\");\n\n                    var info = UpdateInfo.Create(currentRelease, new[] {latestFullRelease}, packageDirectory);\n                    return info;\n                }\n\n                if (ignoreDeltaUpdates) {\n                    remoteReleases = remoteReleases.Where(x => !x.IsDelta);\n                }\n\n                if (!localReleases.Any()) {\n                    if (intention == UpdaterIntention.Install) {\n                        this.Log().Info(\"First run, starting from scratch\");\n                    } else {\n                        this.Log().Warn(\"No local releases found, starting from scratch\");\n                    }\n\n                    return UpdateInfo.Create(null, new[] {latestFullRelease}, packageDirectory);\n                }\n\n                if (localReleases.Max(x => x.Version) > remoteReleases.Max(x => x.Version)) {\n                    this.Log().Warn(\"hwhat, local version is greater than remote version\");\n                    return UpdateInfo.Create(Utility.FindCurrentVersion(localReleases), new[] {latestFullRelease}, packageDirectory);\n                }\n\n                return UpdateInfo.Create(currentRelease, remoteReleases, packageDirectory);\n            }\n\n            internal Guid? getOrCreateStagedUserId()\n            {\n                var stagedUserIdFile = Path.Combine(rootAppDirectory, \"packages\", \".betaId\");\n                var ret = default(Guid);\n\n                try {\n                    if (!Guid.TryParse(File.ReadAllText(stagedUserIdFile, Encoding.UTF8), out ret)) {\n                        throw new Exception(\"File was read but contents were invalid\");\n                    }\n\n                    this.Log().Info(\"Using existing staging user ID: {0}\", ret.ToString());\n                    return ret;\n                } catch (Exception ex) {\n                    this.Log().DebugException(\"Couldn't read staging user ID, creating a blank one\", ex);\n                }\n\n                var prng = new Random();\n                var buf = new byte[4096];\n                prng.NextBytes(buf);\n\n                ret = Utility.CreateGuidFromHash(buf);\n                try {\n                    File.WriteAllText(stagedUserIdFile, ret.ToString(), Encoding.UTF8);\n                    this.Log().Info(\"Generated new staging user ID: {0}\", ret.ToString());\n                    return ret;\n                } catch (Exception ex) {\n                    this.Log().WarnException(\"Couldn't write out staging user ID, this user probably shouldn't get beta anything\", ex);\n                    return null;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateManager.DownloadReleases.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager\n    {\n        internal class DownloadReleasesImpl : IEnableLogger\n        {\n            readonly string rootAppDirectory;\n\n            public DownloadReleasesImpl(string rootAppDirectory)\n            {\n                this.rootAppDirectory = rootAppDirectory;\n            }\n\n            public async Task DownloadReleases(string updateUrlOrPath, IEnumerable<ReleaseEntry> releasesToDownload, Action<int> progress = null, IFileDownloader urlDownloader = null)\n            {\n                progress = progress ?? (_ => { });\n                urlDownloader = urlDownloader ?? new FileDownloader();\n                var packagesDirectory = Path.Combine(rootAppDirectory, \"packages\");\n\n                double current = 0;\n                double toIncrement = 100.0 / releasesToDownload.Count();\n\n                if (Utility.IsHttpUrl(updateUrlOrPath)) {\n                    // From Internet\n                    await releasesToDownload.ForEachAsync(async x => {\n                        var targetFile = Path.Combine(packagesDirectory, x.Filename);\n                        double component = 0;\n                        await downloadRelease(updateUrlOrPath, x, urlDownloader, targetFile, p => {\n                            lock (progress) {\n                                current -= component;\n                                component = toIncrement / 100.0 * p;\n                                progress((int)Math.Round(current += component));\n                            }\n                        });\n\n                        checksumPackage(x);\n                    });\n                } else {\n                    // From Disk\n                    await releasesToDownload.ForEachAsync(x => {\n                        var targetFile = Path.Combine(packagesDirectory, x.Filename);\n\n                        File.Copy(\n                            Path.Combine(updateUrlOrPath, x.Filename),\n                            targetFile,\n                            true);\n\n                        lock (progress) progress((int)Math.Round(current += toIncrement));\n                        checksumPackage(x);\n                    });\n                }\n            }\n\n            bool isReleaseExplicitlyHttp(ReleaseEntry x)\n            {\n                return x.BaseUrl != null && \n                    Uri.IsWellFormedUriString(x.BaseUrl, UriKind.Absolute);\n            }\n\n            Task downloadRelease(string updateBaseUrl, ReleaseEntry releaseEntry, IFileDownloader urlDownloader, string targetFile, Action<int> progress)\n            {\n                var baseUri = Utility.EnsureTrailingSlash(new Uri(updateBaseUrl));\n\n                var releaseEntryUrl = releaseEntry.BaseUrl + releaseEntry.Filename;\n                if (!String.IsNullOrEmpty(releaseEntry.Query)) {\n                    releaseEntryUrl += releaseEntry.Query;\n                }\n                var sourceFileUrl = new Uri(baseUri, releaseEntryUrl).AbsoluteUri;\n                File.Delete(targetFile);\n\n                return urlDownloader.DownloadFile(sourceFileUrl, targetFile, progress);\n            }\n\n            Task checksumAllPackages(IEnumerable<ReleaseEntry> releasesDownloaded)\n            {\n                return releasesDownloaded.ForEachAsync(x => checksumPackage(x));\n            }\n\n            void checksumPackage(ReleaseEntry downloadedRelease)\n            {\n                var targetPackage = new FileInfo(\n                    Path.Combine(rootAppDirectory, \"packages\", downloadedRelease.Filename));\n\n                if (!targetPackage.Exists) {\n                    this.Log().Error(\"File {0} should exist but doesn't\", targetPackage.FullName);\n\n                    throw new Exception(\"Checksummed file doesn't exist: \" + targetPackage.FullName);\n                }\n\n                if (targetPackage.Length != downloadedRelease.Filesize) {\n                    this.Log().Error(\"File Length should be {0}, is {1}\", downloadedRelease.Filesize, targetPackage.Length);\n                    targetPackage.Delete();\n\n                    throw new Exception(\"Checksummed file size doesn't match: \" + targetPackage.FullName);\n                }\n\n                using (var file = targetPackage.OpenRead()) {\n                    var hash = Utility.CalculateStreamSHA1(file);\n\n                    if (!hash.Equals(downloadedRelease.SHA1,StringComparison.OrdinalIgnoreCase)) {\n                        this.Log().Error(\"File SHA1 should be {0}, is {1}\", downloadedRelease.SHA1, hash);\n                        targetPackage.Delete();\n                        throw new Exception(\"Checksum doesn't match: \" + targetPackage.FullName);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateManager.Factory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Reflection;\nusing System.Runtime.Serialization;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.Json;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager\n    {\n        [DataContract]\n        public class Release\n        {\n            [DataMember(Name = \"prerelease\")]\n            public bool Prerelease { get; set; }\n\n            [DataMember(Name = \"published_at\")]\n            public DateTime PublishedAt { get; set; }\n\n            [DataMember(Name = \"html_url\")]\n            public string HtmlUrl { get; set; }\n        }\n\n        public static async Task<UpdateManager> GitHubUpdateManager(\n            string repoUrl,\n            string applicationName = null,\n            string rootDirectory = null,\n            IFileDownloader urlDownloader = null,\n            bool prerelease = false,\n            string accessToken = null)\n        {\n            var repoUri = new Uri(repoUrl);\n            var userAgent = new ProductInfoHeaderValue(\"Squirrel\", Assembly.GetExecutingAssembly().GetName().Version.ToString());\n\n            if (repoUri.Segments.Length != 3) {\n                throw new Exception(\"Repo URL must be to the root URL of the repo e.g. https://github.com/myuser/myrepo\");\n            }\n\n            var releasesApiBuilder = new StringBuilder(\"repos\")\n                .Append(repoUri.AbsolutePath)\n                .Append(\"/releases\");\n\n            if (!string.IsNullOrWhiteSpace(accessToken))\n                releasesApiBuilder.Append(\"?access_token=\").Append(accessToken);\n            \n            Uri baseAddress;\n\n            if (repoUri.Host.EndsWith(\"github.com\", StringComparison.OrdinalIgnoreCase)) {\n                baseAddress = new Uri(\"https://api.github.com/\");\n            } else {\n                // if it's not github.com, it's probably an Enterprise server\n                // now the problem with Enterprise is that the API doesn't come prefixed\n                // it comes suffixed\n                // so the API path of http://internal.github.server.local API location is\n                // http://interal.github.server.local/api/v3. \n                baseAddress = new Uri(string.Format(\"{0}{1}{2}/api/v3/\", repoUri.Scheme, Uri.SchemeDelimiter, repoUri.Host));\n            }\n\n            // above ^^ notice the end slashes for the baseAddress, explained here: http://stackoverflow.com/a/23438417/162694\n\n            using (var client = new HttpClient() { BaseAddress = baseAddress }) {\n                client.DefaultRequestHeaders.UserAgent.Add(userAgent);\n                var response = await client.GetAsync(releasesApiBuilder.ToString());\n                response.EnsureSuccessStatusCode();\n\n                var releases = SimpleJson.DeserializeObject<List<Release>>(await response.Content.ReadAsStringAsync());\n                var latestRelease = releases\n                    .Where(x => prerelease || !x.Prerelease)\n                    .OrderByDescending(x => x.PublishedAt)\n                    .First();\n\n                var latestReleaseUrl = latestRelease.HtmlUrl.Replace(\"/tag/\", \"/download/\");\n\n                return new UpdateManager(latestReleaseUrl, applicationName, rootDirectory, urlDownloader);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Squirrel/UpdateManager.InstallHelpers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Win32;\nusing NuGet;\nusing System.Reflection;\nusing Squirrel.SimpleSplat;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager\n    {\n        internal class InstallHelperImpl : IEnableLogger\n        {\n            readonly string applicationName;\n            readonly string rootAppDirectory;\n\n            public InstallHelperImpl(string applicationName, string rootAppDirectory)\n            {\n                this.applicationName = applicationName;\n                this.rootAppDirectory = rootAppDirectory;\n            }\n\n            const string currentVersionRegSubKey = @\"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\";\n            const string uninstallRegSubKey = @\"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\";\n            public async Task<RegistryKey> CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch)\n            {\n                var releaseContent = File.ReadAllText(Path.Combine(rootAppDirectory, \"packages\", \"RELEASES\"), Encoding.UTF8);\n                var releases = ReleaseEntry.ParseReleaseFile(releaseContent);\n                var latest = releases.Where(x => !x.IsDelta).OrderByDescending(x => x.Version).First();\n\n                // Download the icon and PNG => ICO it. If this doesn't work, who cares\n                var pkgPath = Path.Combine(rootAppDirectory, \"packages\", latest.Filename);\n                var zp = new ZipPackage(pkgPath);\n                    \n                var targetPng = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + \".png\");\n                var targetIco = Path.Combine(rootAppDirectory, \"app.ico\");\n\n                // NB: Sometimes the Uninstall key doesn't exist\n                using (var parentKey =\n                    RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)\n                        .CreateSubKey(\"Uninstall\", RegistryKeyPermissionCheck.ReadWriteSubTree)) { ; }\n\n                var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)\n                    .CreateSubKey(uninstallRegSubKey + \"\\\\\" + applicationName, RegistryKeyPermissionCheck.ReadWriteSubTree);\n\n                if (zp.IconUrl != null && !File.Exists(targetIco)) {\n                    try {\n                        using (var wc = Utility.CreateWebClient()) { \n                            await wc.DownloadFileTaskAsync(zp.IconUrl, targetPng);\n                            using (var fs = new FileStream(targetIco, FileMode.Create)) {\n                                if (zp.IconUrl.AbsolutePath.EndsWith(\"ico\")) {\n                                    var bytes = File.ReadAllBytes(targetPng);\n                                    fs.Write(bytes, 0, bytes.Length);\n                                } else {\n                                    using (var bmp = (Bitmap)Image.FromFile(targetPng))\n                                    using (var ico = Icon.FromHandle(bmp.GetHicon())) {\n                                        ico.Save(fs);\n                                    }\n                                }\n\n                                key.SetValue(\"DisplayIcon\", targetIco, RegistryValueKind.String);\n                            }\n                        }\n                    } catch(Exception ex) {\n                        this.Log().InfoException(\"Couldn't write uninstall icon, don't care\", ex);\n                    } finally {\n                        File.Delete(targetPng);\n                    }\n                }\n\n                var stringsToWrite = new[] {\n                    new { Key = \"DisplayName\", Value = zp.Title ?? zp.Description ?? zp.Summary },\n                    new { Key = \"DisplayVersion\", Value = zp.Version.ToString() },\n                    new { Key = \"InstallDate\", Value = DateTime.Now.ToString(\"yyyyMMdd\", CultureInfo.InvariantCulture) },\n                    new { Key = \"InstallLocation\", Value = rootAppDirectory },\n                    new { Key = \"Publisher\", Value = String.Join(\",\", zp.Authors) },\n                    new { Key = \"QuietUninstallString\", Value = String.Format(\"{0} {1}\", uninstallCmd, quietSwitch) },\n                    new { Key = \"UninstallString\", Value = uninstallCmd },\n                    new { Key = \"URLUpdateInfo\", Value = zp.ProjectUrl != null ? zp.ProjectUrl.ToString() : \"\", }\n                };\n\n                var dwordsToWrite = new[] {\n                    new { Key = \"EstimatedSize\", Value = (int)((new FileInfo(pkgPath)).Length / 1024) },\n                    new { Key = \"NoModify\", Value = 1 },\n                    new { Key = \"NoRepair\", Value = 1 },\n                    new { Key = \"Language\", Value = 0x0409 },\n                };\n\n                foreach (var kvp in stringsToWrite) {\n                    key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.String);\n                }\n                foreach (var kvp in dwordsToWrite) {\n                    key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.DWord);\n                }\n\n                return key;\n            }\n\n            public void KillAllProcessesBelongingToPackage()\n            {\n                var ourExe = Assembly.GetEntryAssembly();\n                var ourExePath = ourExe != null ? ourExe.Location : null;\n\n                UnsafeUtility.EnumerateProcesses()\n                    .Where(x => {\n                        // Processes we can't query will have an empty process name, we can't kill them\n                        // anyways\n                        if (String.IsNullOrWhiteSpace(x.Item1)) return false;\n\n                        // Files that aren't in our root app directory are untouched\n                        if (!x.Item1.StartsWith(rootAppDirectory, StringComparison.OrdinalIgnoreCase)) return false;\n\n                        // Never kill our own EXE\n                        if (ourExePath != null && x.Item1.Equals(ourExePath, StringComparison.OrdinalIgnoreCase)) return false;\n\n                        var name = Path.GetFileName(x.Item1).ToLowerInvariant();\n                        if (name == \"squirrel.exe\" || name == \"update.exe\") return false;\n\n                        return true;\n                    })\n                    .ForEach(x => {\n                        try {\n                            this.WarnIfThrows(() => Process.GetProcessById(x.Item2).Kill());\n                        } catch {}\n                    });\n            }\n\n            public Task<RegistryKey> CreateUninstallerRegistryEntry()\n            {\n                var updateDotExe = Path.Combine(rootAppDirectory, \"Update.exe\");\n                return CreateUninstallerRegistryEntry(String.Format(\"\\\"{0}\\\" --uninstall\", updateDotExe), \"-s\");\n            }\n\n            public void RemoveUninstallerRegistryEntry()\n            {\n                var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)\n                    .OpenSubKey(uninstallRegSubKey, true);\n                key.DeleteSubKeyTree(applicationName);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/UpdateManager.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Drawing;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Security.AccessControl;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Win32;\nusing NuGet;\nusing Squirrel.SimpleSplat;\nusing Squirrel.Shell;\n\nnamespace Squirrel\n{\n    public sealed partial class UpdateManager : IUpdateManager, IEnableLogger\n    {\n        readonly string rootAppDirectory;\n        readonly string applicationName;\n        readonly IFileDownloader urlDownloader;\n        readonly string updateUrlOrPath;\n\n        IDisposable updateLock;\n\n        public UpdateManager(string urlOrPath, \n            string applicationName = null,\n            string rootDirectory = null,\n            IFileDownloader urlDownloader = null)\n        {\n            Contract.Requires(!String.IsNullOrEmpty(urlOrPath));\n            Contract.Requires(!String.IsNullOrEmpty(applicationName));\n\n            updateUrlOrPath = urlOrPath;\n            this.applicationName = applicationName ?? UpdateManager.getApplicationName();\n            this.urlDownloader = urlDownloader ?? new FileDownloader();\n\n            if (rootDirectory != null) {\n                this.rootAppDirectory = Path.Combine(rootDirectory, this.applicationName);\n                return;\n            }\n\n            this.rootAppDirectory = Path.Combine(rootDirectory ?? GetLocalAppDataDirectory(), this.applicationName);\n        }\n\n        public async Task<UpdateInfo> CheckForUpdate(bool ignoreDeltaUpdates = false, Action<int> progress = null, UpdaterIntention intention = UpdaterIntention.Update)\n        {\n            var checkForUpdate = new CheckForUpdateImpl(rootAppDirectory);\n\n            await acquireUpdateLock();\n            return await checkForUpdate.CheckForUpdate(intention, Utility.LocalReleaseFileForAppDir(rootAppDirectory), updateUrlOrPath, ignoreDeltaUpdates, progress, urlDownloader);\n        }\n\n        public async Task DownloadReleases(IEnumerable<ReleaseEntry> releasesToDownload, Action<int> progress = null)\n        {\n            var downloadReleases = new DownloadReleasesImpl(rootAppDirectory);\n            await acquireUpdateLock();\n\n            await downloadReleases.DownloadReleases(updateUrlOrPath, releasesToDownload, progress, urlDownloader);\n        }\n\n        public async Task<string> ApplyReleases(UpdateInfo updateInfo, Action<int> progress = null)\n        {\n            var applyReleases = new ApplyReleasesImpl(rootAppDirectory);\n            await acquireUpdateLock();\n\n            return await applyReleases.ApplyReleases(updateInfo, false, false, progress);\n        }\n\n        public async Task FullInstall(bool silentInstall = false, Action<int> progress = null)\n        {\n            var updateInfo = await CheckForUpdate(intention: UpdaterIntention.Install);\n            await DownloadReleases(updateInfo.ReleasesToApply);\n\n            var applyReleases = new ApplyReleasesImpl(rootAppDirectory);\n            await acquireUpdateLock();\n\n            await applyReleases.ApplyReleases(updateInfo, silentInstall, true, progress);\n        }\n\n        public async Task FullUninstall()\n        {\n            var applyReleases = new ApplyReleasesImpl(rootAppDirectory);\n            await acquireUpdateLock();\n\n            this.KillAllExecutablesBelongingToPackage();\n            await applyReleases.FullUninstall();\n        }\n\n        public Task<RegistryKey> CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch)\n        {\n            var installHelpers = new InstallHelperImpl(applicationName, rootAppDirectory);\n            return installHelpers.CreateUninstallerRegistryEntry(uninstallCmd, quietSwitch);\n        }\n\n        public Task<RegistryKey> CreateUninstallerRegistryEntry()\n        {\n            var installHelpers = new InstallHelperImpl(applicationName, rootAppDirectory);\n            return installHelpers.CreateUninstallerRegistryEntry();\n        }\n\n        public void RemoveUninstallerRegistryEntry()\n        {\n            var installHelpers = new InstallHelperImpl(applicationName, rootAppDirectory);\n            installHelpers.RemoveUninstallerRegistryEntry();\n        }\n\n        public void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly, string programArguments = null, string icon = null)\n        {\n            var installHelpers = new ApplyReleasesImpl(rootAppDirectory);\n            installHelpers.CreateShortcutsForExecutable(exeName, locations, updateOnly, programArguments, icon);\n        }\n\n        public Dictionary<ShortcutLocation, ShellLink> GetShortcutsForExecutable(string exeName, ShortcutLocation locations, string programArguments = null)\n        {\n            var installHelpers = new ApplyReleasesImpl(rootAppDirectory);\n            return installHelpers.GetShortcutsForExecutable(exeName, locations, programArguments);\n        }\n\n\n        public void RemoveShortcutsForExecutable(string exeName, ShortcutLocation locations)\n        {\n            var installHelpers = new ApplyReleasesImpl(rootAppDirectory);\n            installHelpers.RemoveShortcutsForExecutable(exeName, locations);\n        }\n\n        public SemanticVersion CurrentlyInstalledVersion(string executable = null)\n        {\n            executable = executable ??\n                Path.GetDirectoryName(typeof(UpdateManager).Assembly.Location);\n\n            if (!executable.StartsWith(rootAppDirectory, StringComparison.OrdinalIgnoreCase)) {\n                return null;\n            }\n\n            var appDirName = executable.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)\n                .FirstOrDefault(x => x.StartsWith(\"app-\", StringComparison.OrdinalIgnoreCase));\n\n            if (appDirName == null) return null;\n            return appDirName.ToSemanticVersion();\n        }\n\n        public void KillAllExecutablesBelongingToPackage()\n        {\n            var installHelpers = new InstallHelperImpl(applicationName, rootAppDirectory);\n            installHelpers.KillAllProcessesBelongingToPackage();\n        }\n\n        public string ApplicationName {\n            get { return applicationName; }\n        }\n\n        public string RootAppDirectory {\n            get { return rootAppDirectory; }\n        }\n\n        public bool IsInstalledApp {\n            get { return Assembly.GetExecutingAssembly().Location.StartsWith(RootAppDirectory, StringComparison.OrdinalIgnoreCase); }\n        }\n\n        public void Dispose()\n        {\n            var disp = Interlocked.Exchange(ref updateLock, null);\n            if (disp != null) {\n                disp.Dispose();\n            }\n        }\n\n        static bool exiting = false;\n        public static void RestartApp(string exeToStart = null, string arguments = null)\n        { \n            // NB: Here's how this method works:\n            //\n            // 1. We're going to pass the *name* of our EXE and the params to \n            //    Update.exe\n            // 2. Update.exe is going to grab our PID (via getting its parent), \n            //    then wait for us to exit.\n            // 3. We exit cleanly, dropping any single-instance mutexes or \n            //    whatever.\n            // 4. Update.exe unblocks, then we launch the app again, possibly \n            //    launching a different version than we started with (this is why\n            //    we take the app's *name* rather than a full path)\n\n            exeToStart = exeToStart ?? Path.GetFileName(Assembly.GetEntryAssembly().Location);\n            var argsArg = arguments != null ?\n                String.Format(\"-a \\\"{0}\\\"\", arguments) : \"\";\n\n            exiting = true;\n\n            Process.Start(getUpdateExe(), String.Format(\"--processStartAndWait \\\"{0}\\\" {1}\", exeToStart, argsArg));\n\n            // NB: We have to give update.exe some time to grab our PID, but\n            // we can't use WaitForInputIdle because we probably don't have\n            // whatever WaitForInputIdle considers a message loop.\n            Thread.Sleep(500);\n            Environment.Exit(0);\n        }\n        \n        public static async Task<Process> RestartAppWhenExited(string exeToStart = null, string arguments = null)\n        { \n            // NB: Here's how this method works:\n            //\n            // 1. We're going to pass the *name* of our EXE and the params to \n            //    Update.exe\n            // 2. Update.exe is going to grab our PID (via getting its parent), \n            //    then wait for us to exit.\n            // 3. Return control and new Process back to caller and allow them to Exit as desired.\n            // 4. After our process exits, Update.exe unblocks, then we launch the app again, possibly \n            //    launching a different version than we started with (this is why\n            //    we take the app's *name* rather than a full path)\n\n            exeToStart = exeToStart ?? Path.GetFileName(Assembly.GetEntryAssembly().Location);\n            var argsArg = arguments != null ?\n                String.Format(\"-a \\\"{0}\\\"\", arguments) : \"\";\n\n            exiting = true;\n\n            var updateProcess = Process.Start(getUpdateExe(), String.Format(\"--processStartAndWait {0} {1}\", exeToStart, argsArg));\n\n            await Task.Delay(500);\n            \n            return updateProcess;\n        }\n\n        public static string GetLocalAppDataDirectory(string assemblyLocation = null)\n        {\n            // Try to divine our our own install location via reading tea leaves\n            //\n            // * We're Update.exe, running in the app's install folder\n            // * We're Update.exe, running on initial install from SquirrelTemp\n            // * We're a C# EXE with Squirrel linked in\n\n            var assembly = Assembly.GetEntryAssembly();\n            if (assemblyLocation == null && assembly == null) {\n                // dunno lol\n                return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);\n            }\n\n            assemblyLocation = assemblyLocation ?? assembly.Location;\n\n            if (Path.GetFileName(assemblyLocation).Equals(\"update.exe\", StringComparison.OrdinalIgnoreCase)) {\n                // NB: Both the \"SquirrelTemp\" case and the \"App's folder\" case \n                // mean that the root app dir is one up\n                var oneFolderUpFromAppFolder = Path.Combine(Path.GetDirectoryName(assemblyLocation), \"..\");\n                return Path.GetFullPath(oneFolderUpFromAppFolder);\n            }\n\n            var twoFoldersUpFromAppFolder = Path.Combine(Path.GetDirectoryName(assemblyLocation), \"..\\\\..\");\n            return Path.GetFullPath(twoFoldersUpFromAppFolder);\n        }\n\n        ~UpdateManager()\n        {\n            if (updateLock != null && !exiting) {\n                throw new Exception(\"You must dispose UpdateManager!\");\n            }\n        }\n\n        Task<IDisposable> acquireUpdateLock()\n        {\n            if (updateLock != null) return Task.FromResult(updateLock);\n\n            return Task.Run(() => {\n                var key = Utility.CalculateStreamSHA1(new MemoryStream(Encoding.UTF8.GetBytes(rootAppDirectory)));\n\n                IDisposable theLock;\n                try {\n                    theLock = ModeDetector.InUnitTestRunner() ?\n                        Disposable.Create(() => {}) : new SingleGlobalInstance(key, TimeSpan.FromMilliseconds(2000));\n                } catch (TimeoutException) {\n                    throw new TimeoutException(\"Couldn't acquire update lock, another instance may be running updates\");\n                }\n\n                var ret = Disposable.Create(() => {\n                    theLock.Dispose();\n                    updateLock = null;\n                });\n\n                updateLock = ret;\n                return ret;\n            });\n        }\n\n        /// <summary>\n        /// Calculates the total percentage of a specific step that should report within a specific range.\n        /// <para />\n        /// If a step needs to report between 50 -> 75 %, this method should be used as CalculateProgress(percentage, 50, 75). \n        /// </summary>\n        /// <param name=\"percentageOfCurrentStep\">The percentage of the current step, a value between 0 and 100.</param>\n        /// <param name=\"stepStartPercentage\">The start percentage of the range the current step represents.</param>\n        /// <param name=\"stepEndPercentage\">The end percentage of the range the current step represents.</param>\n        /// <returns>The calculated percentage that can be reported about the total progress.</returns>\n        internal static int CalculateProgress(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage)\n        {\n            // Ensure we are between 0 and 100\n            percentageOfCurrentStep = Math.Max(Math.Min(percentageOfCurrentStep, 100), 0);\n\n            var range = stepEndPercentage - stepStartPercentage;\n            var singleValue = range / 100d;\n            var totalPercentage = (singleValue * percentageOfCurrentStep) + stepStartPercentage;\n\n            return (int)totalPercentage;\n        }\n\n        static string getApplicationName()\n        {\n            var fi = new FileInfo(getUpdateExe());\n            return fi.Directory.Name;\n        }\n\n        static string getUpdateExe()\n        {\n            var assembly = Assembly.GetEntryAssembly();\n\n            // Are we update.exe?\n            if (assembly != null &&\n                Path.GetFileName(assembly.Location).Equals(\"update.exe\", StringComparison.OrdinalIgnoreCase) &&\n                assembly.Location.IndexOf(\"app-\", StringComparison.OrdinalIgnoreCase) == -1 &&\n                assembly.Location.IndexOf(\"SquirrelTemp\", StringComparison.OrdinalIgnoreCase) == -1) {\n                return Path.GetFullPath(assembly.Location);\n            }\n\n            assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();\n\n            var updateDotExe = Path.Combine(Path.GetDirectoryName(assembly.Location), \"..\\\\Update.exe\");\n            var target = new FileInfo(updateDotExe);\n\n            if (!target.Exists) throw new Exception(\"Update.exe not found, not a Squirrel-installed app?\");\n            return target.FullName;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel/Utility.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Diagnostics.Contracts;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Security.AccessControl;\nusing System.Security.Cryptography;\nusing System.Security.Principal;\nusing System.Threading;\nusing Squirrel.SimpleSplat;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Collections.Concurrent;\nusing System.Diagnostics;\nusing System.Net;\nusing NuGet;\n\nnamespace Squirrel\n{\n    static class Utility\n    {\n        public static string RemoveByteOrderMarkerIfPresent(string content)\n        {\n            return string.IsNullOrEmpty(content) ? \n                string.Empty : RemoveByteOrderMarkerIfPresent(Encoding.UTF8.GetBytes(content));\n        }\n\n        public static string RemoveByteOrderMarkerIfPresent(byte[] content)\n        {\n            byte[] output = { };\n\n            if (content == null) {\n                goto done;\n            }\n\n            Func<byte[], byte[], bool> matches = (bom, src) => {\n                if (src.Length < bom.Length) return false;\n\n                return !bom.Where((chr, index) => src[index] != chr).Any();\n            };\n\n            var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };\n            var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };\n            var utf16Be = new byte[] { 0xFE, 0xFF };\n            var utf16Le = new byte[] { 0xFF, 0xFE };\n            var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };\n\n            if (matches(utf32Be, content)) {\n                output = new byte[content.Length - utf32Be.Length];\n            } else if (matches(utf32Le, content)) {\n                output = new byte[content.Length - utf32Le.Length];\n            } else if (matches(utf16Be, content)) {\n                output = new byte[content.Length - utf16Be.Length];\n            } else if (matches(utf16Le, content)) {\n                output = new byte[content.Length - utf16Le.Length];\n            } else if (matches(utf8, content)) {\n                output = new byte[content.Length - utf8.Length];\n            } else {\n                output = content;\n            }\n\n        done:\n            if (output.Length > 0) {\n                Buffer.BlockCopy(content, content.Length - output.Length, output, 0, output.Length);\n            }\n\n            return Encoding.UTF8.GetString(output);\n        }\n\n        public static IEnumerable<FileInfo> GetAllFilesRecursively(this DirectoryInfo rootPath)\n        {\n            Contract.Requires(rootPath != null);\n\n            return rootPath.EnumerateFiles(\"*\", SearchOption.AllDirectories);\n        }\n\n        public static IEnumerable<string> GetAllFilePathsRecursively(string rootPath)\n        {\n            Contract.Requires(rootPath != null);\n\n            return Directory.EnumerateFiles(rootPath, \"*\", SearchOption.AllDirectories);\n        }\n\n        public static string CalculateFileSHA1(string filePath)\n        {\n            Contract.Requires(filePath != null);\n\n            using (var stream = File.OpenRead(filePath)) {\n                return CalculateStreamSHA1(stream);\n            }\n        }\n\n        public static string CalculateStreamSHA1(Stream file)\n        {\n            Contract.Requires(file != null && file.CanRead);\n\n            using (var sha1 = SHA1.Create()) {\n                return BitConverter.ToString(sha1.ComputeHash(file)).Replace(\"-\", String.Empty);\n            }\n        }\n\n        public static WebClient CreateWebClient()\n        {\n            // enable TLS support\n            // TLS 1.0 and 1.1 are enabled for backward compatibility and should be disabled in the future\n            // for security reasons\n            ServicePointManager.SecurityProtocol |=\n                SecurityProtocolType.Tls12 |\n                SecurityProtocolType.Tls11 |\n                SecurityProtocolType.Tls;\n            // disable SSLv3 support for security reasons\n            ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;\n\n            var ret = new WebClient();\n            var wp = WebRequest.DefaultWebProxy;\n            if (wp != null) {\n                wp.Credentials = CredentialCache.DefaultCredentials;\n                ret.Proxy = wp;\n            }\n\n            return ret;\n        }\n\n        public static async Task CopyToAsync(string from, string to)\n        {\n            Contract.Requires(!String.IsNullOrEmpty(from) && File.Exists(from));\n            Contract.Requires(!String.IsNullOrEmpty(to));\n\n            if (!File.Exists(from)) {\n                Log().Warn(\"The file {0} does not exist\", from);\n\n                // TODO: should we fail this operation?\n                return;\n            }\n\n            // XXX: SafeCopy\n            await Task.Run(() => File.Copy(from, to, true));\n        }\n\n        public static void Retry(this Action block, int retries = 2)\n        {\n            Contract.Requires(retries > 0);\n\n            Func<object> thunk = () => {\n                block();\n                return null;\n            };\n\n            thunk.Retry(retries);\n        }\n\n        public static T Retry<T>(this Func<T> block, int retries = 2)\n        {\n            Contract.Requires(retries > 0);\n\n            while (true) {\n                try {\n                    T ret = block();\n                    return ret;\n                } catch (Exception) {\n                    if (retries == 0) {\n                        throw;\n                    }\n\n                    retries--;\n                    Thread.Sleep(250);\n                }\n            }\n        }\n\n        public static Task<Tuple<int, string>> InvokeProcessAsync(string fileName, string arguments, CancellationToken ct, string workingDirectory = \"\")\n        {\n            var psi = new ProcessStartInfo(fileName, arguments);\n            if (Environment.OSVersion.Platform != PlatformID.Win32NT && fileName.EndsWith (\".exe\", StringComparison.OrdinalIgnoreCase)) {\n                psi = new ProcessStartInfo(\"wine\", fileName + \" \" + arguments);\n            }\n\n            psi.UseShellExecute = false;\n            psi.WindowStyle = ProcessWindowStyle.Hidden;\n            psi.ErrorDialog = false;\n            psi.CreateNoWindow = true;\n            psi.RedirectStandardOutput = true;\n            psi.RedirectStandardError = true;\n            psi.WorkingDirectory = workingDirectory;\n\n            return InvokeProcessAsync(psi, ct);\n        }\n\n        public static async Task<Tuple<int, string>> InvokeProcessAsync(ProcessStartInfo psi, CancellationToken ct)\n        {\n            var pi = Process.Start(psi);\n            await Task.Run(() => {\n                while (!ct.IsCancellationRequested) {\n                    if (pi.WaitForExit(2000)) return;\n                }\n\n                if (ct.IsCancellationRequested) {\n                    pi.Kill();\n                    ct.ThrowIfCancellationRequested();\n                }\n            });\n\n            string textResult = await pi.StandardOutput.ReadToEndAsync();\n            if (String.IsNullOrWhiteSpace(textResult) || pi.ExitCode != 0) {\n                textResult = (textResult ?? \"\") + \"\\n\" + await pi.StandardError.ReadToEndAsync();\n\n                if (String.IsNullOrWhiteSpace(textResult)) {\n                    textResult = String.Empty;\n                }\n            }\n\n            return Tuple.Create(pi.ExitCode, textResult.Trim());\n        }\n\n        public static Task ForEachAsync<T>(this IEnumerable<T> source, Action<T> body, int degreeOfParallelism = 4)\n        {\n            return ForEachAsync(source, x => Task.Run(() => body(x)), degreeOfParallelism);\n        }\n\n        public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> body, int degreeOfParallelism = 4)\n        {\n            return Task.WhenAll(\n                from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism)\n                select Task.Run(async () => {\n                    using (partition)\n                        while (partition.MoveNext())\n                            await body(partition.Current);\n                }));\n        }\n\n        static Lazy<string> directoryChars = new Lazy<string>(() => {\n            return \"abcdefghijklmnopqrstuvwxyz\" +\n                Enumerable.Range(0x03B0, 0x03FF - 0x03B0)   // Greek and Coptic\n                    .Concat(Enumerable.Range(0x0400, 0x04FF - 0x0400)) // Cyrillic\n                    .Aggregate(new StringBuilder(), (acc, x) => { acc.Append(Char.ConvertFromUtf32(x)); return acc; })\n                    .ToString();\n        });\n\n        internal static string tempNameForIndex(int index, string prefix)\n        {\n            if (index < directoryChars.Value.Length) {\n                return prefix + directoryChars.Value[index];\n            }\n\n            return prefix + directoryChars.Value[index % directoryChars.Value.Length] + tempNameForIndex(index / directoryChars.Value.Length, \"\");\n        }\n\n        public static DirectoryInfo GetTempDirectory(string localAppDirectory)\n        {\n            var tempDir = Environment.GetEnvironmentVariable(\"SQUIRREL_TEMP\");\n            tempDir = tempDir ?? Path.Combine(localAppDirectory ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), \"SquirrelTemp\");\n\n            var di = new DirectoryInfo(tempDir);\n            if (!di.Exists) di.Create();\n\n            return di;\n        }\n\n        public static IDisposable WithTempDirectory(out string path, string localAppDirectory = null)\n        {\n            var di = GetTempDirectory(localAppDirectory);\n            var tempDir = default(DirectoryInfo);\n\n            var names = Enumerable.Range(0, 1<<20).Select(x => tempNameForIndex(x, \"temp\"));\n\n            foreach (var name in names) {\n                var target = Path.Combine(di.FullName, name);\n\n                if (!File.Exists(target) && !Directory.Exists(target)) {\n                    Directory.CreateDirectory(target);\n                    tempDir = new DirectoryInfo(target);\n                    break;\n                }\n            }\n\n            path = tempDir.FullName;\n\n            return Disposable.Create(() => Task.Run(async () => await DeleteDirectory(tempDir.FullName)).Wait());\n        }\n\n        public static IDisposable WithTempFile(out string path, string localAppDirectory = null)\n        {\n            var di = GetTempDirectory(localAppDirectory);\n            var names = Enumerable.Range(0, 1<<20).Select(x => tempNameForIndex(x, \"temp\"));\n\n            path = \"\";\n            foreach (var name in names) {\n                path = Path.Combine(di.FullName, name);\n\n                if (!File.Exists(path) && !Directory.Exists(path)) {\n                    break;\n                }\n            }\n\n            var thePath = path;\n            return Disposable.Create(() => File.Delete(thePath));\n        }\n\n        public static async Task DeleteDirectory(string directoryPath)\n        {\n            Contract.Requires(!String.IsNullOrEmpty(directoryPath));\n\n            Log().Debug(\"Starting to delete folder: {0}\", directoryPath);\n\n            if (!Directory.Exists(directoryPath)) {\n                Log().Warn(\"DeleteDirectory: does not exist - {0}\", directoryPath);\n                return;\n            }\n\n            // From http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true/329502#329502\n            var files = new string[0];\n            try {\n                files = Directory.GetFiles(directoryPath);\n            } catch (UnauthorizedAccessException ex) {\n                var message = String.Format(\"The files inside {0} could not be read\", directoryPath);\n                Log().Warn(message, ex);\n            }\n\n            var dirs = new string[0];\n            try {\n                dirs = Directory.GetDirectories(directoryPath);\n            } catch (UnauthorizedAccessException ex) {\n                var message = String.Format(\"The directories inside {0} could not be read\", directoryPath);\n                Log().Warn(message, ex);\n            }\n\n            var fileOperations = files.ForEachAsync(file => {\n                File.SetAttributes(file, FileAttributes.Normal);\n                File.Delete(file);\n            });\n\n            var directoryOperations =\n                dirs.ForEachAsync(async dir => await DeleteDirectory(dir));\n\n            await Task.WhenAll(fileOperations, directoryOperations);\n\n            Log().Debug(\"Now deleting folder: {0}\", directoryPath);\n            File.SetAttributes(directoryPath, FileAttributes.Normal);\n\n            try {\n                Directory.Delete(directoryPath, false);\n            } catch (Exception ex) {\n                var message = String.Format(\"DeleteDirectory: could not delete - {0}\", directoryPath);\n                Log().ErrorException(message, ex);\n            }\n        }\n\n        public static string FindHelperExecutable(string toFind, IEnumerable<string> additionalDirs = null)\n        {\n            additionalDirs = additionalDirs ?? Enumerable.Empty<string>();\n            var dirs = (new[] { Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) })\n                .Concat(additionalDirs ?? Enumerable.Empty<string>());\n\n            var exe = @\".\\\" + toFind;\n            return dirs\n                .Select(x => Path.Combine(x, toFind))\n                .FirstOrDefault(x => File.Exists(x)) ?? exe;\n        }\n\n        static string find7Zip()\n        {\n            if (ModeDetector.InUnitTestRunner()) {\n                var vendorDir = Path.Combine(\n                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Replace(\"file:///\", \"\")),\n                    \"..\", \"..\", \"..\", \"..\",\n                    \"vendor\", \"7zip\"\n                );\n                return FindHelperExecutable(\"7z.exe\", new[] { vendorDir });\n            } else {\n                return FindHelperExecutable(\"7z.exe\");\n            }\n        }\n\n        public static async Task ExtractZipToDirectory(string zipFilePath, string outFolder)\n        {\n            var sevenZip = find7Zip();\n            var result = default(Tuple<int, string>);\n\n            try {\n                var cmd = sevenZip;\n                var args = String.Format(\"x \\\"{0}\\\" -tzip -mmt on -aoa -y -o\\\"{1}\\\" *\", zipFilePath, outFolder);\n                if (Environment.OSVersion.Platform != PlatformID.Win32NT) {\n                    cmd = \"wine\";\n                    args = sevenZip + \" \" + args;\n                }\n\n                result = await Utility.InvokeProcessAsync(cmd, args, CancellationToken.None);\n                if (result.Item1 != 0) throw new Exception(result.Item2);\n            } catch (Exception ex) {\n                Log().Error($\"Failed to extract file {zipFilePath} to {outFolder}\\n{ex.Message}\");\n                throw;\n            }\n        }\n\n        public static async Task CreateZipFromDirectory(string zipFilePath, string inFolder)\n        {\n            var sevenZip = find7Zip();\n            var result = default(Tuple<int, string>);\n\n            try {\n                var cmd = sevenZip;\n                var args = String.Format(\"a \\\"{0}\\\" -tzip -aoa -y -mmt on *\", zipFilePath);\n                if (Environment.OSVersion.Platform != PlatformID.Win32NT) {\n                    cmd = \"wine\";\n                    args = sevenZip + \" \" + args;\n                }\n\n                result = await Utility.InvokeProcessAsync(cmd, args, CancellationToken.None, inFolder);\n                if (result.Item1 != 0) throw new Exception(result.Item2);\n            } catch (Exception ex) {\n                Log().Error($\"Failed to extract file {zipFilePath} to {inFolder}\\n{ex.Message}\");\n                throw;\n            }\n        }\n\n        public static string AppDirForRelease(string rootAppDirectory, ReleaseEntry entry)\n        {\n            return Path.Combine(rootAppDirectory, \"app-\" + entry.Version.ToString());\n        }\n\n        public static string AppDirForVersion(string rootAppDirectory, SemanticVersion version)\n        {\n            return Path.Combine(rootAppDirectory, \"app-\" + version.ToString());\n        }\n\n        public static string PackageDirectoryForAppDir(string rootAppDirectory) \n        {\n            return Path.Combine(rootAppDirectory, \"packages\");\n        }\n\n        public static string LocalReleaseFileForAppDir(string rootAppDirectory)\n        {\n            return Path.Combine(PackageDirectoryForAppDir(rootAppDirectory), \"RELEASES\");\n        }\n\n        public static IEnumerable<ReleaseEntry> LoadLocalReleases(string localReleaseFile)\n        {\n            var file = File.OpenRead(localReleaseFile);\n\n            // NB: sr disposes file\n            using (var sr = new StreamReader(file, Encoding.UTF8)) {\n                return ReleaseEntry.ParseReleaseFile(sr.ReadToEnd());\n            }\n        }\n            \n        public static ReleaseEntry FindCurrentVersion(IEnumerable<ReleaseEntry> localReleases)\n        {\n            if (!localReleases.Any()) {\n                return null;\n            }\n\n            return localReleases.OrderByDescending(x => x.Version).FirstOrDefault(x => !x.IsDelta);\n        }\n\n        static TAcc scan<T, TAcc>(this IEnumerable<T> This, TAcc initialValue, Func<TAcc, T, TAcc> accFunc)\n        {\n            TAcc acc = initialValue;\n\n            foreach (var x in This)\n            {\n                acc = accFunc(acc, x);\n            }\n\n            return acc;\n        }\n\n        public static bool IsHttpUrl(string urlOrPath)\n        {\n            var uri = default(Uri);\n            if (!Uri.TryCreate(urlOrPath, UriKind.Absolute, out uri)) {\n                return false;\n            }\n\n            return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps;\n        }\n\n        public static Uri AppendPathToUri(Uri uri, string path)\n        {\n            var builder = new UriBuilder(uri);\n            if (!builder.Path.EndsWith(\"/\")) {\n                builder.Path += \"/\";\n            }\n\n            builder.Path += path;\n            return builder.Uri;\n        }\n\n        public static Uri EnsureTrailingSlash(Uri uri)\n        {\n            return AppendPathToUri(uri, \"\");\n        }\n\n        public static Uri AddQueryParamsToUri(Uri uri, IEnumerable<KeyValuePair<string, string>> newQuery)\n        {\n            var query = System.Web.HttpUtility.ParseQueryString(uri.Query);\n\n            foreach (var entry in newQuery) {\n                query[entry.Key] = entry.Value;\n            }\n\n            var builder = new UriBuilder(uri);\n            builder.Query = query.ToString();\n\n            return builder.Uri;\n        }\n\n        public static void DeleteFileHarder(string path, bool ignoreIfFails = false)\n        {\n            try {\n                Retry(() => File.Delete(path), 2);\n            } catch (Exception ex) {\n                if (ignoreIfFails) return;\n\n                LogHost.Default.ErrorException(\"Really couldn't delete file: \" + path, ex);\n                throw;\n            }\n        }\n\n        public static async Task DeleteDirectoryOrJustGiveUp(string dir)\n        {\n            try {\n                await Utility.DeleteDirectory(dir);\n            } catch {\n                var message = String.Format(\"Uninstall failed to delete dir '{0}'\", dir);\n            }\n        }\n\n        // http://stackoverflow.com/questions/3111669/how-can-i-determine-the-subsystem-used-by-a-given-net-assembly\n        public static bool ExecutableUsesWin32Subsystem(string peImage)\n        {\n            using (var s = new FileStream(peImage, FileMode.Open, FileAccess.Read)) {\n                var rawPeSignatureOffset = new byte[4];\n                s.Seek(0x3c, SeekOrigin.Begin);\n                s.Read(rawPeSignatureOffset, 0, 4);\n\n                int peSignatureOffset = rawPeSignatureOffset[0];\n                peSignatureOffset |= rawPeSignatureOffset[1] << 8;\n                peSignatureOffset |= rawPeSignatureOffset[2] << 16;\n                peSignatureOffset |= rawPeSignatureOffset[3] << 24;\n\n                var coffHeader = new byte[24];\n                s.Seek(peSignatureOffset, SeekOrigin.Begin);\n                s.Read(coffHeader, 0, 24);\n\n                byte[] signature = { (byte)'P', (byte)'E', (byte)'\\0', (byte)'\\0' };\n                for (int index = 0; index < 4; index++) {\n                    if (coffHeader[index] != signature[index]) throw new Exception(\"File is not a PE image\");\n                }\n\n                var subsystemBytes = new byte[2];\n                s.Seek(68, SeekOrigin.Current);\n                s.Read(subsystemBytes, 0, 2);\n\n                int subSystem = subsystemBytes[0] | subsystemBytes[1] << 8;\n                return subSystem == 2; /*IMAGE_SUBSYSTEM_WINDOWS_GUI*/\n            }\n        }\n\n        readonly static string[] peExtensions = new[] { \".exe\", \".dll\", \".node\" };\n        public static bool FileIsLikelyPEImage(string name)\n        {\n            var ext = Path.GetExtension(name);\n            return peExtensions.Any(x => ext.Equals(x, StringComparison.OrdinalIgnoreCase));\n        }\n\n        public static bool IsFileTopLevelInPackage(string fullName, string pkgPath)\n        {\n            var fn = fullName.ToLowerInvariant();\n            var pkg = pkgPath.ToLowerInvariant();\n            var relativePath = fn.Replace(pkg, \"\");\n\n            // NB: We want to match things like `/lib/net45/foo.exe` but not `/lib/net45/bar/foo.exe`\n            return relativePath.Split(Path.DirectorySeparatorChar).Length == 4;\n        }\n\n        public static void LogIfThrows(this IFullLogger This, LogLevel level, string message, Action block)\n        {\n            try {\n                block();\n            } catch (Exception ex) {\n                switch (level) {\n                case LogLevel.Debug:\n                    This.DebugException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Info:\n                    This.InfoException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Warn:\n                    This.WarnException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Error:\n                    This.ErrorException(message ?? \"\", ex);\n                    break;\n                }\n\n                throw;\n            }\n        }\n\n        public static async Task LogIfThrows(this IFullLogger This, LogLevel level, string message, Func<Task> block)\n        {\n            try {\n                await block();\n            } catch (Exception ex) {\n                switch (level) {\n                case LogLevel.Debug:\n                    This.DebugException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Info:\n                    This.InfoException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Warn:\n                    This.WarnException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Error:\n                    This.ErrorException(message ?? \"\", ex);\n                    break;\n                }\n                throw;\n            }\n        }\n\n        public static async Task<T> LogIfThrows<T>(this IFullLogger This, LogLevel level, string message, Func<Task<T>> block)\n        {\n            try {\n                return await block();\n            } catch (Exception ex) {\n                switch (level) {\n                case LogLevel.Debug:\n                    This.DebugException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Info:\n                    This.InfoException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Warn:\n                    This.WarnException(message ?? \"\", ex);\n                    break;\n                case LogLevel.Error:\n                    This.ErrorException(message ?? \"\", ex);\n                    break;\n                }\n                throw;\n            }\n        }\n\n        public static void WarnIfThrows(this IEnableLogger This, Action block, string message = null)\n        {\n            This.Log().LogIfThrows(LogLevel.Warn, message, block);\n        }\n\n        public static Task WarnIfThrows(this IEnableLogger This, Func<Task> block, string message = null)\n        {\n            return This.Log().LogIfThrows(LogLevel.Warn, message, block);\n        }\n\n        public static Task<T> WarnIfThrows<T>(this IEnableLogger This, Func<Task<T>> block, string message = null)\n        {\n            return This.Log().LogIfThrows(LogLevel.Warn, message, block);\n        }\n\n        public static void ErrorIfThrows(this IEnableLogger This, Action block, string message = null)\n        {\n            This.Log().LogIfThrows(LogLevel.Error, message, block);\n        }\n\n        public static Task ErrorIfThrows(this IEnableLogger This, Func<Task> block, string message = null)\n        {\n            return This.Log().LogIfThrows(LogLevel.Error, message, block);\n        }\n\n        public static Task<T> ErrorIfThrows<T>(this IEnableLogger This, Func<Task<T>> block, string message = null)\n        {\n            return This.Log().LogIfThrows(LogLevel.Error, message, block);\n        }\n\n        static IFullLogger logger;\n        static IFullLogger Log()\n        {\n            return logger ??\n                (logger = SquirrelLocator.CurrentMutable.GetService<ILogManager>().GetLogger(typeof(Utility)));\n        }\n\n        [DllImport(\"kernel32.dll\", SetLastError = true, CharSet = CharSet.Unicode)]\n        static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);\n\n        [Flags]\n        enum MoveFileFlags\n        {\n            MOVEFILE_REPLACE_EXISTING = 0x00000001,\n            MOVEFILE_COPY_ALLOWED = 0x00000002,\n            MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,\n            MOVEFILE_WRITE_THROUGH = 0x00000008,\n            MOVEFILE_CREATE_HARDLINK = 0x00000010,\n            MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020\n        }\n\n        public static Guid CreateGuidFromHash(string text)\n        {\n            return CreateGuidFromHash(text, Utility.IsoOidNamespace);\n        }\n        public static Guid CreateGuidFromHash(byte[] data)\n        {\n            return CreateGuidFromHash(data, Utility.IsoOidNamespace);\n        }\n\n        public static Guid CreateGuidFromHash(string text, Guid namespaceId)\n        {\n            return CreateGuidFromHash(Encoding.UTF8.GetBytes(text), namespaceId);\n        }\n\n        public static Guid CreateGuidFromHash(byte[] nameBytes, Guid namespaceId)\n        {\n            // convert the namespace UUID to network order (step 3)\n            byte[] namespaceBytes = namespaceId.ToByteArray();\n            SwapByteOrder(namespaceBytes);\n\n            // comput the hash of the name space ID concatenated with the \n            // name (step 4)\n            byte[] hash;\n            using (var algorithm = SHA1.Create()) {\n                algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0);\n                algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length);\n                hash = algorithm.Hash;\n            }\n\n            // most bytes from the hash are copied straight to the bytes of \n            // the new GUID (steps 5-7, 9, 11-12)\n            var newGuid = new byte[16];\n            Array.Copy(hash, 0, newGuid, 0, 16);\n\n            // set the four most significant bits (bits 12 through 15) of \n            // the time_hi_and_version field to the appropriate 4-bit \n            // version number from Section 4.1.3 (step 8)\n            newGuid[6] = (byte)((newGuid[6] & 0x0F) | (5 << 4));\n\n            // set the two most significant bits (bits 6 and 7) of the \n            // clock_seq_hi_and_reserved to zero and one, respectively \n            // (step 10)\n            newGuid[8] = (byte)((newGuid[8] & 0x3F) | 0x80);\n\n            // convert the resulting UUID to local byte order (step 13)\n            SwapByteOrder(newGuid);\n            return new Guid(newGuid);\n        }\n\n        /// <summary>\n        /// The namespace for fully-qualified domain names (from RFC 4122, Appendix C).\n        /// </summary>\n        public static readonly Guid DnsNamespace = new Guid(\"6ba7b810-9dad-11d1-80b4-00c04fd430c8\");\n\n        /// <summary>\n        /// The namespace for URLs (from RFC 4122, Appendix C).\n        /// </summary>\n        public static readonly Guid UrlNamespace = new Guid(\"6ba7b811-9dad-11d1-80b4-00c04fd430c8\");\n\n        /// <summary>\n        /// The namespace for ISO OIDs (from RFC 4122, Appendix C).\n        /// </summary>\n        public static readonly Guid IsoOidNamespace = new Guid(\"6ba7b812-9dad-11d1-80b4-00c04fd430c8\");\n\n        // Converts a GUID (expressed as a byte array) to/from network order (MSB-first).\n        static void SwapByteOrder(byte[] guid)\n        {\n            SwapBytes(guid, 0, 3);\n            SwapBytes(guid, 1, 2);\n            SwapBytes(guid, 4, 5);\n            SwapBytes(guid, 6, 7);\n        }\n\n        static void SwapBytes(byte[] guid, int left, int right)\n        {\n            byte temp = guid[left];\n            guid[left] = guid[right];\n            guid[right] = temp;\n        }\n    }\n\n    static unsafe class UnsafeUtility\n    {\n        public static List<Tuple<string, int>> EnumerateProcesses()\n        {\n            int bytesReturned = 0;\n            var pids = new int[16384];\n\n            fixed(int* p = pids) {\n                if (!NativeMethods.EnumProcesses((IntPtr)p, sizeof(int) * pids.Length, out bytesReturned)) {\n                    throw new Win32Exception(\"Failed to enumerate processes\");\n                }\n\n                if (bytesReturned < 1) throw new Exception(\"Failed to enumerate processes\");\n            }\n\n            return Enumerable.Range(0, bytesReturned / sizeof(int))\n                .Where(i => pids[i] > 0)\n                .Select(i => {\n                    try {\n                        var hProcess = NativeMethods.OpenProcess(ProcessAccess.QueryLimitedInformation, false, pids[i]);\n                        if (hProcess == IntPtr.Zero) throw new Win32Exception();\n\n                        var sb = new StringBuilder(256);\n                        var capacity = sb.Capacity;\n                        if (!NativeMethods.QueryFullProcessImageName(hProcess, 0, sb, ref capacity)) {\n                            throw new Win32Exception();\n                        }\n\n                        NativeMethods.CloseHandle(hProcess);\n                        return Tuple.Create(sb.ToString(), pids[i]);\n                    } catch (Exception) {\n                        return Tuple.Create(default(string), pids[i]);\n                    }\n                })\n                .ToList();\n        }\n    }\n\n    sealed class SingleGlobalInstance : IDisposable, IEnableLogger\n    {\n        IDisposable handle = null;\n\n        public SingleGlobalInstance(string key, TimeSpan timeOut)\n        {\n            if (ModeDetector.InUnitTestRunner()) {\n                return;\n            }\n\n            var path = Path.Combine(Path.GetTempPath(), \".squirrel-lock-\" + key);\n\n            var st = new Stopwatch();\n            st.Start();\n\n            var fh = default(FileStream);\n            while (st.Elapsed < timeOut) {\n                try {\n                    fh = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Delete);\n                    fh.Write(new byte[] { 0xba, 0xad, 0xf0, 0x0d, }, 0, 4);\n                    break;\n                } catch (Exception ex) {\n                    this.Log().WarnException(\"Failed to grab lockfile, will retry: \" + path, ex);\n                    Thread.Sleep(250);\n                }\n            }\n\n            st.Stop();\n\n            if (fh == null) {\n                throw new Exception(\"Couldn't acquire lock, is another instance running\");\n            }\n\n            handle = Disposable.Create(() => {\n                fh.Dispose();\n                File.Delete(path);\n            });\n        }\n\n        public void Dispose()\n        {\n            if (ModeDetector.InUnitTestRunner()) {\n                return;\n            }\n\n            var disp = Interlocked.Exchange(ref handle, null);\n            if (disp != null) disp.Dispose();\n        }\n\n        ~SingleGlobalInstance()\n        {\n            if (handle == null) return;\n            throw new AbandonedMutexException(\"Leaked a Mutex!\");\n        }\n    }\n\n    static class Disposable\n    {\n        public static IDisposable Create(Action action)\n        {\n            return new AnonDisposable(action);\n        }\n\n        class AnonDisposable : IDisposable\n        {\n            static readonly Action dummyBlock = (() => { });\n            Action block;\n\n            public AnonDisposable(Action b)\n            {\n                block = b;\n            }\n\n            public void Dispose()\n            {\n                Interlocked.Exchange(ref block, dummyBlock)();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Squirrel.nuspec",
    "content": "﻿<?xml version=\"1.0\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd\">\n  <metadata>\n    <version>2.0.1</version>\n    <authors>GitHub</authors>\n    <owners>Anaïs Betts</owners>\n    <licenseUrl>https://github.com/squirrel/Squirrel.Windows/blob/master/COPYING</licenseUrl>\n    <projectUrl>https://github.com/squirrel/Squirrel.Windows</projectUrl>\n    <iconUrl>https://raw.githubusercontent.com/Squirrel/Squirrel.Windows/master/docs/artwork/Squirrel-Logo-Square.png</iconUrl>\n\n    <dependencies>\n      <group targetFramework=\".NETFramework4.5\">\n        <dependency id=\"Mono.Cecil\" version=\"0.11.2\" />\n        <dependency id=\"SharpCompress\" version=\"[0.17.1]\" />\n      </group>\n      <group targetFramework=\".NETStandard2.0\">\n        <dependency id=\"Mono.Cecil\" version=\"0.11.2\" />\n        <dependency id=\"SharpCompress\" version=\"[0.17.1]\" />\n      </group>\n    </dependencies>\n\n    <id>squirrel.windows</id>\n    <title>Squirrel for Windows</title>\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <description>An installation and update framework for Windows applications</description>\n    <copyright>Copyright GitHub© 2017</copyright>\n  </metadata>\n  <files>\n    <file src=\"..\\Build\\Release\\net45\\Squirrel.*\" target=\"lib\\net45\" />\n    <file src=\"..\\Build\\Release\\net45\\NuGet.Squirrel.*\" target=\"lib\\net45\" />\n    <file src=\"..\\Build\\Release\\net45\\ICSharpCode.*\" target=\"lib\\net45\" />\n    <file src=\"..\\Build\\Release\\netstandard2.0\\Squirrel.*\" target=\"lib\\netstandard2.0\" />\n    <file src=\"..\\Build\\Release\\netstandard2.0\\NuGet.Squirrel.*\" target=\"lib\\netstandard2.0\" />\n    <file src=\"..\\Build\\Release\\netstandard2.0\\ICSharpCode.*\" target=\"lib\\netstandard2.0\" />\n    <file src=\"squirrel.windows.props\" target=\"build\" />\n    <file src=\"..\\Build\\Release\\Win32\\Setup.exe\" target=\"tools\" />\n    <file src=\"..\\Build\\Release\\Win32\\WriteZipToSetup.exe\" target=\"tools\" />\n    <file src=\"..\\Build\\Release\\Win32\\StubExecutable.exe\" target=\"tools\" />\n    <file src=\"..\\Build\\Release\\Net45\\Update.exe\" target=\"tools\\Squirrel.exe\" />\n    <file src=\"..\\Build\\Release\\Net45\\Update-Mono.exe\" target=\"tools\\Squirrel-Mono.exe\" />\n    <file src=\"..\\Build\\Release\\Net45\\Update.com\" target=\"tools\\Squirrel.com\" />\n    <file src=\"..\\Build\\Release\\Net45\\SyncReleases.exe\" target=\"tools\" />\n    <file src=\"Update\\signtool.exe\" target=\"tools\\signtool.exe\" />\n    <file src=\"Update\\rcedit.exe\" target=\"tools\\rcedit.exe\" />\n    <file src=\"..\\vendor\\wix\\*\" target=\"tools\" />\n    <file src=\"..\\vendor\\7zip\\*\" target=\"tools\" />\n  </files>\n</package>\n"
  },
  {
    "path": "src/StubExecutable/LICENSE.md",
    "content": "This executable uses the semver library from https://github.com/zmarko/semver, under the following license:\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Živanovc\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "src/StubExecutable/Resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by StubExecutable.rc\n//\n\n#define IDS_APP_TITLE\t\t\t103\n\n#define IDR_MAINFRAME\t\t\t128\n#define IDD_STUBEXECUTABLE_DIALOG\t102\n#define IDD_ABOUTBOX\t\t\t103\n#define IDM_ABOUT\t\t\t\t104\n#define IDM_EXIT\t\t\t\t105\n#define IDI_STUBEXECUTABLE\t\t\t107\n#define IDI_SMALL\t\t\t\t108\n#define IDC_STUBEXECUTABLE\t\t\t109\n#define IDC_MYICON\t\t\t\t2\n#ifndef IDC_STATIC\n#define IDC_STATIC\t\t\t\t-1\n#endif\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n\n#define _APS_NO_MFC\t\t\t\t\t130\n#define _APS_NEXT_RESOURCE_VALUE\t129\n#define _APS_NEXT_COMMAND_VALUE\t\t32771\n#define _APS_NEXT_CONTROL_VALUE\t\t1000\n#define _APS_NEXT_SYMED_VALUE\t\t110\n#endif\n#endif\n"
  },
  {
    "path": "src/StubExecutable/Semver200_comparator.cpp",
    "content": "/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Zivanovic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#include \"stdafx.h\"\n\n#include <algorithm>\n#include <functional>\n#include <map>\n#include \"semver200.h\"\n\nusing namespace std;\n\nnamespace version {\n\n\tnamespace {\n\n\t\t// Compare normal version identifiers.\n\t\tint compare_normal(const Version_data& l, const Version_data& r) {\n\t\t\tif (l.major > r.major) return 1;\n\t\t\tif (l.major < r.major) return -1;\n\t\t\tif (l.minor > r.minor) return 1;\n\t\t\tif (l.minor < r.minor) return -1;\n\t\t\tif (l.patch > r.patch) return 1;\n\t\t\tif (l.patch < r.patch) return -1;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Compare alphanumeric prerelease identifiers.\n\t\tinline int cmp_alnum_prerel_ids(const string& l, const string& r) {\n\t\t\t// If both versions have a prerelease section with the same prefix\n\t\t\t// and end with digits, compare based on the digits' numeric order\n\t\t\tauto index_l = l.find_last_not_of(\"0123456789\");\n\t\t\tauto index_r = r.find_last_not_of(\"0123456789\");\n\n\t\t\tif (index_l != string::npos && index_r != string::npos) {\n\t\t\t\tstring name_l = l.substr(0, index_l + 1);\n\t\t\t\tstring name_r = r.substr(0, index_r + 1);\n\n\t\t\t\tif (name_l == name_r) {\n\t\t\t\t\tint il = stoi(l.substr(index_l + 1));\n\t\t\t\t\tint ir = stoi(r.substr(index_r + 1));\n\n\t\t\t\t\treturn il > ir ? 1 : -1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tauto cmp = l.compare(r);\n\n\t\t\tif (cmp == 0) {\n\t\t\t\treturn cmp;\n\t\t\t} else {\n\t\t\t\treturn cmp > 0 ? 1 : -1;\n\t\t\t}\n\t\t}\n\n\t\t// Compare numeric prerelease identifiers.\n\t\tinline int cmp_num_prerel_ids(const string& l, const string& r) {\n\t\t\tlong long li = stoll(l);\n\t\t\tlong long ri = stoll(r);\n\t\t\tif (li == ri) return 0;\n\t\t\treturn li > ri ? 1 : -1;\n\t\t}\n\n\t\tusing Prerel_type_pair = pair<Id_type, Id_type>;\n\t\tusing Prerel_id_comparator = function<int(const string&, const string&)>;\n\t\tconst map<Prerel_type_pair, Prerel_id_comparator> comparators = {\n\t\t\t{ { Id_type::alnum, Id_type::alnum }, cmp_alnum_prerel_ids },\n\t\t\t{ { Id_type::alnum, Id_type::num }, [](const string&, const string&) {return 1;} },\n\t\t\t{ { Id_type::num, Id_type::alnum }, [](const string&, const string&) {return -1;} },\n\t\t\t{ { Id_type::num, Id_type::num }, cmp_num_prerel_ids }\n\t\t};\n\n\t\t// Compare prerelease identifiers based on their types.\n\t\tinline int compare_prerel_identifiers(const Prerelease_identifier& l, const Prerelease_identifier& r) {\n\t\t\tauto cmp = comparators.at({ l.second, r.second });\n\t\t\treturn cmp(l.first, r.first);\n\t\t}\n\n\t\tinline int cmp_rel_prerel(const Prerelease_identifiers& l, const Prerelease_identifiers& r) {\n\t\t\tif (l.empty() && !r.empty()) return 1;\n\t\t\tif (r.empty() && !l.empty()) return -1;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tint Semver200_comparator::compare(const Version_data& l, const Version_data& r) const {\n\t\t// Compare normal version components.\n\t\tint cmp = compare_normal(l, r);\n\t\tif (cmp != 0) return cmp;\n\n\t\t// Compare if one version is release and the other prerelease - release is always higher.\n\t\tcmp = cmp_rel_prerel(l.prerelease_ids, r.prerelease_ids);\n\t\tif (cmp != 0) return cmp;\n\n\t\t// Compare prerelease by looking at each identifier: numeric ones are compared as numbers,\n\t\t// alphanum as ASCII strings.\n\t\tauto shorter = min(l.prerelease_ids.size(), r.prerelease_ids.size());\n\t\tfor (size_t i = 0; i < shorter; i++) {\n\t\t\tcmp = compare_prerel_identifiers(l.prerelease_ids[i], r.prerelease_ids[i]);\n\t\t\tif (cmp != 0) return cmp;\n\t\t}\n\n\t\t// Prerelease identifiers are the same, to the length of the shorter version string;\n\t\t// if they are the same length, then versions are equal, otherwise, longer one wins.\n\t\tif (l.prerelease_ids.size() == r.prerelease_ids.size()) return 0;\n\t\treturn l.prerelease_ids.size() > r.prerelease_ids.size() ? 1 : -1;\n\t}\n\n}\n"
  },
  {
    "path": "src/StubExecutable/Semver200_parser.cpp",
    "content": "/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Zivanovic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#include \"stdafx.h\"\n\n#include <functional>\n#include <map>\n#include \"semver200.h\"\n\n#ifdef _MSC_VER\n// disable symbol name too long warning\n#pragma warning(disable:4503)\n#endif\n\nusing namespace std;\n\nnamespace version {\n\n\tnamespace {\n\t\tenum class Parser_state {\n\t\t\tmajor, minor, patch, prerelease, build\n\t\t};\n\n\t\tusing Validator = function<void(const string&, const char)>;\n\t\tusing State_transition_hook = function<void(string&)>;\n\t\t/// State transition is described by a character that triggers it, a state to transition to and\n\t\t/// optional hook to be invoked on transition.\n\t\tusing Transition = tuple<const char, Parser_state, State_transition_hook>;\n\t\tusing Transitions = vector<Transition>;\n\t\tusing State = tuple<Transitions, string&, Validator>;\n\t\tusing State_machine = map<Parser_state, State>;\n\n\t\t// Ranges of characters allowed in prerelease and build identifiers.\n\t\tconst vector<pair<char, char>> allowed_prerel_id_chars = {\n\t\t\t\t{ '0', '9' },{ 'A','Z' },{ 'a','z' },{ '-','-' }\n\t\t};\n\n\t\tinline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {\n\t\t\treturn make_tuple(c, p, pth);\n\t\t}\n\n\t\t/// Advance parser state machine by a single step.\n\t\t/**\n\t\tPerform single step of parser state machine: if character matches one from transition tables -\n\t\ttrigger transition to next state; otherwise, validate if current token is in legal state\n\t\t(throw Parse_error if not) and then add character to current token; State transition includes\n\t\tpreparing various vars for next state and invoking state transition hook (if specified) which is\n\t\twhere whole tokens are validated.\n\t\t*/\n\t\tinline void process_char(const char c, Parser_state& cstate, Parser_state& pstate,\n\t\t\tconst Transitions& transitions, string& target, Validator validate) {\n\t\t\tfor (const auto& transition : transitions) {\n\t\t\t\tif (c == get<0>(transition)) {\n\t\t\t\t\tif (get<2>(transition)) get<2>(transition)(target);\n\t\t\t\t\tpstate = cstate;\n\t\t\t\t\tcstate = get<1>(transition);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tvalidate(target, c);\n\t\t\ttarget.push_back(c);\n\t\t}\n\n\t\t/// Validate normal (major, minor, patch) version components.\n\t\tinline void normal_version_validator(const string& tgt, const char c) {\n\t\t\tif (c < '0' || c > '9') throw Parse_error(\"invalid character encountered: \" + string(1, c));\n\t\t\tif (tgt.compare(0, 1, \"0\") == 0) throw Parse_error(\"leading 0 not allowed\");\n\t\t}\n\n\t\t/// Validate that prerelease and build version identifiers are comprised of allowed chars only.\n\t\tinline void prerelease_version_validator(const string&, const char c) {\n\t\t\tbool res = false;\n\t\t\tfor (const auto& r : allowed_prerel_id_chars) {\n\t\t\t\tres |= (c >= r.first && c <= r.second);\n\t\t\t}\n\t\t\tif (!res)\n\t\t\t\tthrow Parse_error(\"invalid character encountered: \" + string(1, c));\n\t\t}\n\n\t\tinline bool is_identifier_numeric(const string& id) {\n\t\t\treturn id.find_first_not_of(\"0123456789\") == string::npos;\n\t\t}\n\n\t\tinline bool check_for_leading_0(const string& str) {\n\t\t\treturn str.length() > 1 && str[0] == '0';\n\t\t}\n\n\t\t/// Validate every individual prerelease identifier, determine it's type and add it to collection.\n\t\tvoid prerelease_hook_impl(string& id, Prerelease_identifiers& prerelease) {\n\t\t\tif (id.empty()) throw Parse_error(\"version identifier cannot be empty\");\n\t\t\tId_type t = Id_type::alnum;\n\t\t\tif (is_identifier_numeric(id)) {\n\t\t\t\tt = Id_type::num;\n\t\t\t\tif (check_for_leading_0(id)) {\n\t\t\t\t\tthrow Parse_error(\"numeric identifiers cannot have leading 0\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tprerelease.push_back(Prerelease_identifier(id, t));\n\t\t\tid.clear();\n\t\t}\n\n\t\t/// Validate every individual build identifier and add it to collection.\n\t\tvoid build_hook_impl(string& id, Parser_state& pstate, Build_identifiers& build,\n\t\t\tstd::string& prerelease_id, Prerelease_identifiers& prerelease) {\n\t\t\t// process last token left from parsing prerelease data\n\t\t\tif (pstate == Parser_state::prerelease) prerelease_hook_impl(prerelease_id, prerelease);\n\t\t\tif (id.empty()) throw Parse_error(\"version identifier cannot be empty\");\n\t\t\tbuild.push_back(id);\n\t\t\tid.clear();\n\t\t}\n\n\t}\n\n\t/// Parse semver 2.0.0-compatible string to Version_data structure.\n\t/**\n\tVersion text parser is implemented as a state machine. In each step one successive character from version\n\tstring is consumed and is either added to current token or triggers state transition. Hooks can be\n\tinjected into state transitions for validation/customization purposes.\n\t*/\n\tVersion_data Semver200_parser::parse(const string& s) const {\n\t\tstring major;\n\t\tstring minor;\n\t\tstring patch;\n\t\tstring prerelease_id;\n\t\tstring build_id;\n\t\tPrerelease_identifiers prerelease;\n\t\tBuild_identifiers build;\n\t\tParser_state cstate{ Parser_state::major };\n\t\tParser_state pstate;\n\n\t\tauto prerelease_hook = [&](string& id) {\n\t\t\tprerelease_hook_impl(id, prerelease);\n\t\t};\n\n\t\tauto build_hook = [&](string& id) {\n\t\t\tbuild_hook_impl(id, pstate, build, prerelease_id, prerelease);\n\t\t};\n\n\t\t// State transition tables\n\t\tauto major_trans = {\n\t\t\tmkx('.', Parser_state::minor, {})\n\t\t};\n\t\tauto minor_trans = {\n\t\t\tmkx('.', Parser_state::patch, {})\n\t\t};\n\t\tauto patch_trans = {\n\t\t\tmkx('-', Parser_state::prerelease, {}),\n\t\t\tmkx('+', Parser_state::build, {})\n\t\t};\n\t\tauto prerelease_trans = {\n\t\t\t// When identifier separator (.) is found, stay in the same state but invoke hook\n\t\t\t// in order to process each individual identifier separately.\n\t\t\tmkx('.', Parser_state::prerelease, prerelease_hook),\n\t\t\tmkx('+', Parser_state::build, {})\n\t\t};\n\t\tauto build_trans = {\n\t\t\t// Same stay-in-the-same-state-but-invoke-hook trick from above.\n\t\t\tmkx('.', Parser_state::build, build_hook)\n\t\t};\n\n\t\tState_machine state_machine = {\n\t\t\t{Parser_state::major, State{major_trans, major, normal_version_validator}},\n\t\t\t{Parser_state::minor, State{minor_trans, minor, normal_version_validator}},\n\t\t\t{Parser_state::patch, State{patch_trans, patch, normal_version_validator}},\n\t\t\t{Parser_state::prerelease, State{prerelease_trans, prerelease_id, prerelease_version_validator}},\n\t\t\t{Parser_state::build, State{build_trans, build_id, prerelease_version_validator}}\n\t\t};\n\n\t\t// Main loop.\n\t\tfor (const auto& c : s) {\n\t\t\tauto state = state_machine.at(cstate);\n\t\t\tprocess_char(c, cstate, pstate, get<0>(state), get<1>(state), get<2>(state));\n\t\t}\n\n\t\t// Trigger appropriate hooks in order to process last token, because no state transition was\n\t\t// triggered for it.\n\t\tif (cstate == Parser_state::prerelease) {\n\t\t\tprerelease_hook(prerelease_id);\n\t\t} else if (cstate == Parser_state::build) {\n\t\t\tbuild_hook(build_id);\n\t\t}\n\n\t\ttry {\n\t\t\treturn Version_data{ stoi(major), stoi(minor), stoi(patch), prerelease, build };\n\t\t} catch (invalid_argument& ex) {\n\t\t\tthrow Parse_error(ex.what());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/StubExecutable/StubExecutable.cpp",
    "content": "// StubExecutable.cpp : Defines the entry point for the application.\n//\n\n#include \"stdafx.h\"\n#include \"StubExecutable.h\"\n\n#include \"semver200.h\"\n\nusing namespace std;\n\nbool FileExists(const std::wstring& filePath) {\n    DWORD fileAttributes = GetFileAttributes(filePath.c_str());\n    return (fileAttributes != INVALID_FILE_ATTRIBUTES) && !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY);\n}\n\nwchar_t* FindRootAppDir() \n{\n\twchar_t* ourDirectory = new wchar_t[MAX_PATH];\n\n\tGetModuleFileName(GetModuleHandle(NULL), ourDirectory, MAX_PATH);\n\twchar_t* lastSlash = wcsrchr(ourDirectory, L'\\\\');\n\tif (!lastSlash) {\n\t\tdelete[] ourDirectory;\n\t\treturn NULL;\n\t}\n\n\t// Null-terminate the string at the slash so now it's a directory\n\t*lastSlash = 0x0;\n\treturn ourDirectory;\n}\n\nwchar_t* FindOwnExecutableName() \n{\n\twchar_t* ourDirectory = new wchar_t[MAX_PATH];\n\n\tGetModuleFileName(GetModuleHandle(NULL), ourDirectory, MAX_PATH);\n\twchar_t* lastSlash = wcsrchr(ourDirectory, L'\\\\');\n\tif (!lastSlash) {\n\t\tdelete[] ourDirectory;\n\t\treturn NULL;\n\t}\n\n\twchar_t* ret = _wcsdup(lastSlash + 1);\n\tdelete[] ourDirectory;\n\treturn ret;\n}\n\nstd::wstring FindLatestAppDir() \n{\n\tstd::wstring ourDir;\n\tourDir.assign(FindRootAppDir());\n\n\tourDir += L\"\\\\app-*\";\n\n\tWIN32_FIND_DATA fileInfo = { 0 };\n\tHANDLE hFile = FindFirstFile(ourDir.c_str(), &fileInfo);\n\tif (hFile == INVALID_HANDLE_VALUE) {\n\t\treturn NULL;\n\t}\n\n\tversion::Semver200_version acc(\"0.0.0\");\n\tstd::wstring acc_s;\n\n\tdo {\n\t\tstd::wstring appVer = fileInfo.cFileName;\n\t\tappVer = appVer.substr(4);   // Skip 'app-'\n\t\tif (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tstd::string s(appVer.begin(), appVer.end());\n\n\t\tversion::Semver200_version thisVer(s);\n\n\t\t// Skip the directory which contains a .not-finished file\n\t\tstd::wstring appFolder = fileInfo.cFileName;\n\t\tstd::wstring dirPath = ourDir.substr(0, ourDir.size() - 5) + appFolder;\n\t\tif (FileExists(dirPath + L\"\\\\.not-finished\")) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (thisVer > acc) {\n\t\t\tacc = thisVer;\n\t\t\tacc_s = appVer;\n\t\t}\n\t} while (FindNextFile(hFile, &fileInfo));\n\n\tif (acc == version::Semver200_version(\"0.0.0\")) {\n\t\treturn NULL;\n\t}\n\n\tourDir.assign(FindRootAppDir());\n\tstd::wstringstream ret;\n\tret << ourDir << L\"\\\\app-\" << acc_s;\n\n\tFindClose(hFile);\n\treturn ret.str();\n}\n\nint APIENTRY wWinMain(_In_ HINSTANCE hInstance,\n                     _In_opt_ HINSTANCE hPrevInstance,\n                     _In_ LPWSTR    lpCmdLine,\n                     _In_ int       nCmdShow)\n{\n\tstd::wstring appName;\n\tappName.assign(FindOwnExecutableName());\n\n\tstd::wstring workingDir(FindLatestAppDir());\n\tstd::wstring fullPath(workingDir + L\"\\\\\" + appName);\n\n\tSTARTUPINFO si = { 0 };\n\tPROCESS_INFORMATION pi = { 0 };\n\n\tsi.cb = sizeof(si);\n\tsi.dwFlags = STARTF_USESHOWWINDOW;\n\tsi.wShowWindow = nCmdShow;\n\n\tstd::wstring cmdLine(L\"\\\"\");\n\tcmdLine += fullPath;\n\tcmdLine += L\"\\\" \";\n\tcmdLine += lpCmdLine;\n\n\twchar_t* lpCommandLine = _wcsdup(cmdLine.c_str());\n\twchar_t* lpCurrentDirectory = _wcsdup(workingDir.c_str());\n\tif (!CreateProcess(NULL, lpCommandLine, NULL, NULL, true, 0, NULL, lpCurrentDirectory, &si, &pi)) {\n\t\treturn -1;\n\t}\n\n\tAllowSetForegroundWindow(pi.dwProcessId);\n\tWaitForInputIdle(pi.hProcess, 5 * 1000);\n\treturn 0;\n}\n"
  },
  {
    "path": "src/StubExecutable/StubExecutable.h",
    "content": "#pragma once\n\n#include \"resource.h\"\n"
  },
  {
    "path": "src/StubExecutable/StubExecutable.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C028DB2A-E7C5-4232-8C22-D5FBA2176136}</ProjectGuid>\n    <ConfigurationType>Application</ConfigurationType>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>StubExecutable</RootNamespace>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)'=='Debug'\" Label=\"Configuration\">\n    <UseDebugLibraries>true</UseDebugLibraries>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)'=='Release'\" Label=\"Configuration\">\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MinSpace</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Resource.h\" />\n    <ClInclude Include=\"semver200.h\" />\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"StubExecutable.h\" />\n    <ClInclude Include=\"targetver.h\" />\n    <ClInclude Include=\"version.h\" />\n    <ClInclude Include=\"version.inl\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Semver200_comparator.cpp\" />\n    <ClCompile Include=\"Semver200_parser.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"StubExecutable.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"StubExecutable.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"small.ico\" />\n    <Image Include=\"StubExecutable.ico\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "src/StubExecutable/StubExecutable.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"targetver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StubExecutable.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"semver200.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"version.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"version.inl\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StubExecutable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Semver200_comparator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Semver200_parser.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"StubExecutable.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"small.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"StubExecutable.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/StubExecutable/semver200.h",
    "content": "/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Zivanovic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#pragma once\n\n#include \"version.h\"\n\nnamespace version {\n\n\t/// Parse string into Version_data structure according to semantic versioning 2.0.0 rules.\n\tstruct Semver200_parser {\n\t\tVersion_data parse(const std::string&) const;\n\t};\n\n\t/// Compare Version_data to another using semantic versioning 2.0.0 rules.\n\tstruct Semver200_comparator {\n\t\tint compare(const Version_data&, const Version_data&) const;\n\t};\n\n\t/// Concrete version class that binds all semver 2.0.0 functionality together.\n\tclass Semver200_version : public Basic_version<Semver200_parser, Semver200_comparator> {\n\tpublic:\n\t\tSemver200_version()\n\t\t\t: Basic_version{ Semver200_parser(), Semver200_comparator() } {}\n\n\t\tSemver200_version(const std::string& v)\n\t\t\t: Basic_version{ v, Semver200_parser(), Semver200_comparator() } {}\n\t};\n\n}"
  },
  {
    "path": "src/StubExecutable/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\n// StubExecutable.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n// TODO: reference any additional headers you need in STDAFX.H\n// and not in this file\n"
  },
  {
    "path": "src/StubExecutable/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently, but\n// are changed infrequently\n//\n\n#pragma once\n\n#include \"targetver.h\"\n\n#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers\n// Windows Header Files:\n#include <windows.h>\n\n// C RunTime Header Files\n#include <stdlib.h>\n#include <malloc.h>\n#include <memory.h>\n#include <tchar.h>\n#include <string>\n#include <iostream>\n\n\n// TODO: reference additional headers your program requires here\n"
  },
  {
    "path": "src/StubExecutable/targetver.h",
    "content": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n\n#include <SDKDDKVer.h>\n"
  },
  {
    "path": "src/StubExecutable/version.h",
    "content": "﻿/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Zivanovic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#pragma once\n\n#include <ostream>\n#include <string>\n#include <vector>\n\nnamespace version {\n\n\t/// Any error in parsing or validation of version string will result in Parse_error exception being thrown.\n\tclass Parse_error : public std::runtime_error {\n\t\tusing std::runtime_error::runtime_error;\n\t};\n\n\t/// Type of prerelease identifier: alphanumeric or numeric.\n\t/**\n\tType of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while\n\tnumeric identifiers are compared as numbers.\n\t*/\n\tenum class Id_type {\n\t\talnum, ///< Identifier is alphanumerical\n\t\tnum ///< Identifier is numeric\n\t};\n\n\t/// Container for prerelease identifier value and it's type.\n\t/**\n\tPrerelease version string consist of an optional series of dot-separated identifiers.\n\tThese identifiers can be either numerical or alphanumerical.\n\tThis structure describes one such identifier.\n\t*/\n\tusing Prerelease_identifier = std::pair<std::string, Id_type>;\n\n\t/// Container for all prerelease identifiers for a given version string.\n\tusing Prerelease_identifiers = std::vector<Prerelease_identifier>;\n\n\t/// Build identifier is arbitrary string with no special meaning with regards to version precedence.\n\tusing Build_identifier = std::string;\n\n\t/// Container for all build identifiers of a given version string.\n\tusing Build_identifiers = std::vector<Build_identifier>;\n\n\t/// Description of version broken into parts, as per semantic versioning specification.\n\tstruct Version_data {\n\t\tint major; ///< Major version, change only on incompatible API modifications.\n\t\tint minor; ///< Minor version, change on backwards-compatible API modifications.\n\t\tint patch; ///< Patch version, change only on bugfixes.\n\n\t\t/// Optional series of prerelease identifiers.\n\t\tPrerelease_identifiers prerelease_ids;\n\n\t\t/// Optional series of build identifiers.\n\t\tBuild_identifiers build_ids;\n\t};\n\n\t// Forward declaration required for operators' template declarations.\n\ttemplate<typename Parser, typename Comparator>\n\tclass Basic_version;\n\n\t/// Test if left-hand version operand is of lower precedence than the right-hand version.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator<(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Test if left-hand version operand if of equal precedence as the right-hand version.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator==(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Output version object to stream using standard semver format (X.Y.Z-PR+B).\n\ttemplate<typename Parser, typename Comparator>\n\tstd::ostream& operator<<(std::ostream&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Test if left-hand version and right-hand version are of different precedence.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator!=(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Test if left-hand version operand is of higher precedence than the right-hand version.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator>(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Test if left-hand version operand is of higher or equal precedence as the right-hand version.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator>=(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\t/// Test if left-hand version operand is of lower or equal precedence as the right-hand version.\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator<=(const Basic_version<Parser, Comparator>&,\n\t\tconst Basic_version<Parser, Comparator>&);\n\n\n\t/// Base class for various version parsing and precedence ordering schemes.\n\t/**\n\tBasic_version class describes general version object without prescribing parsing,\n\tvalidation and comparison rules. These rules are implemented by supplied Parser and\n\tComparator objects.\n\t*/\n\ttemplate<typename Parser, typename Comparator>\n\tclass Basic_version {\n\tpublic:\n\t\t/// Construct Basic_version object using Parser object to parse default (\"0.0.0\") version string and Comparator for comparison.\n\t\tBasic_version(Parser, Comparator);\n\n\t\t/// Construct Basic_version object using Parser to parse supplied version string and Comparator for comparison.\n\t\tBasic_version(const std::string&, Parser, Comparator);\n\n\t\t/// Construct Basic_version by copying data from another one.\n\t\tBasic_version(const Basic_version&);\n\n\t\t/// Copy version data from another Basic_version to this one.\n\t\tBasic_version& operator=(const Basic_version&);\n\n\t\tint major() const; ///< Get major version.\n\t\tint minor() const; ///< Get minor version.\n\t\tint patch() const; ///< Get patch version.\n\t\tconst std::string prerelease() const; ///< Get prerelease version string.\n\t\tconst std::string build() const; ///< Get build version string.\n\n\t\tfriend bool operator< <>(const Basic_version&, const Basic_version&);\n\t\tfriend bool operator== <>(const Basic_version&, const Basic_version&);\n\t\tfriend std::ostream& operator<< <>(std::ostream&s, const Basic_version&);\n\n\tprivate:\n\t\tParser parser_;\n\t\tComparator comparator_;\n\t\tVersion_data ver_;\n\t};\n}\n\n#include \"version.inl\"\n"
  },
  {
    "path": "src/StubExecutable/version.inl",
    "content": "/*\nThe MIT License (MIT)\n\nCopyright (c) 2015 Marko Zivanovic\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#pragma once\n\n#include <sstream>\n#include \"version.h\"\n\nnamespace version {\n\n\tnamespace {\n\n\t\t/// Utility function to splice all vector elements to output stream, using designated separator \n\t\t/// between elements and function object for getting values from vector elements.\n\t\ttemplate<typename T, typename F>\n\t\tstd::ostream& splice(std::ostream& os, const std::vector<T>& vec, const std::string& sep, F read) {\n\t\t\tif (!vec.empty()) {\n\t\t\t\tfor (auto it = vec.cbegin(); it < vec.cend() - 1; ++it) {\n\t\t\t\t\tos << read(*it) << sep;\n\t\t\t\t}\n\t\t\t\tos << read(*vec.crbegin());\n\t\t\t}\n\t\t\treturn os;\n\t\t}\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tBasic_version<Parser, Comparator>::Basic_version(Parser p, Comparator c)\n\t\t: parser_(p), comparator_(c), ver_(parser_.parse(\"0.0.0\")) {}\n\n\ttemplate<typename Parser, typename Comparator>\n\tBasic_version<Parser, Comparator>::Basic_version(const std::string& v, Parser p, Comparator c)\n\t\t: parser_(p), comparator_(c), ver_(parser_.parse(v)) {}\n\n\ttemplate<typename Parser, typename Comparator>\n\tBasic_version<Parser, Comparator>::Basic_version(const Basic_version<Parser, Comparator>&) = default;\n\n\ttemplate<typename Parser, typename Comparator>\n\tBasic_version<Parser, Comparator>& Basic_version<Parser, Comparator>::operator=(\n\t\tconst Basic_version<Parser, Comparator>&) = default;\n\n\ttemplate<typename Parser, typename Comparator>\n\tint Basic_version<Parser, Comparator>::major() const {\n\t\treturn ver_.major;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tint Basic_version<Parser, Comparator>::minor() const {\n\t\treturn ver_.minor;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tint Basic_version<Parser, Comparator>::patch() const {\n\t\treturn ver_.patch;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tconst std::string Basic_version<Parser, Comparator>::prerelease() const {\n\t\tstd::stringstream ss;\n\t\tsplice(ss, ver_.prerelease_ids, \".\", [](const auto& id) { return id.first;});\n\t\treturn ss.str();\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tconst std::string Basic_version<Parser, Comparator>::build() const {\n\t\tstd::stringstream ss;\n\t\tsplice(ss, ver_.build_ids, \".\", [](const auto& id) { return id;});\n\t\treturn ss.str();\n\t}\n\n\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator<(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn l.comparator_.compare(l.ver_, r.ver_) == -1;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tbool operator==(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn l.comparator_.compare(l.ver_, r.ver_) == 0;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tstd::ostream& operator<<(std::ostream& os,\n\t\tconst Basic_version<Parser, Comparator>& v) {\n\t\tos << v.ver_.major << \".\" << v.ver_.minor << \".\" << v.ver_.patch;\n\t\tstd::string prl = v.prerelease();\n\t\tif (!prl.empty()) {\n\t\t\tos << \"-\" << prl;\n\t\t}\n\t\tstd::string bld = v.build();\n\t\tif (!bld.empty()) {\n\t\t\tos << \"+\" << bld;\n\t\t}\n\t\treturn os;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tinline bool operator!=(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn !(l == r);\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tinline bool operator>(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn r < l;\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tinline bool operator>=(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn !(l < r);\n\t}\n\n\ttemplate<typename Parser, typename Comparator>\n\tinline bool operator<=(const Basic_version<Parser, Comparator>& l,\n\t\tconst Basic_version<Parser, Comparator>& r) {\n\t\treturn !(l > r);\n\t}\n}\n"
  },
  {
    "path": "src/SyncReleases/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.5\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "src/SyncReleases/Mono.Options/Options.cs",
    "content": "//\n// Options.cs\n//\n// Authors:\n//  Jonathan Pryor <jpryor@novell.com>\n//  Federico Di Gregorio <fog@initd.org>\n//  Rolf Bjarne Kvinge <rolf@xamarin.com>\n//\n// Copyright (C) 2008 Novell (http://www.novell.com)\n// Copyright (C) 2009 Federico Di Gregorio.\n// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n// \n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n// \n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n\n// Compile With:\n//   gmcs -debug+ -r:System.Core Options.cs -o:NDesk.Options.dll\n//   gmcs -debug+ -d:LINQ -r:System.Core Options.cs -o:NDesk.Options.dll\n//\n// The LINQ version just changes the implementation of\n// OptionSet.Parse(IEnumerable<string>), and confers no semantic changes.\n\n//\n// A Getopt::Long-inspired option parsing library for C#.\n//\n// NDesk.Options.OptionSet is built upon a key/value table, where the\n// key is a option format string and the value is a delegate that is \n// invoked when the format string is matched.\n//\n// Option format strings:\n//  Regex-like BNF Grammar: \n//    name: .+\n//    type: [=:]\n//    sep: ( [^{}]+ | '{' .+ '}' )?\n//    aliases: ( name type sep ) ( '|' name type sep )*\n// \n// Each '|'-delimited name is an alias for the associated action.  If the\n// format string ends in a '=', it has a required value.  If the format\n// string ends in a ':', it has an optional value.  If neither '=' or ':'\n// is present, no value is supported.  `=' or `:' need only be defined on one\n// alias, but if they are provided on more than one they must be consistent.\n//\n// Each alias portion may also end with a \"key/value separator\", which is used\n// to split option values if the option accepts > 1 value.  If not specified,\n// it defaults to '=' and ':'.  If specified, it can be any character except\n// '{' and '}' OR the *string* between '{' and '}'.  If no separator should be\n// used (i.e. the separate values should be distinct arguments), then \"{}\"\n// should be used as the separator.\n//\n// Options are extracted either from the current option by looking for\n// the option name followed by an '=' or ':', or is taken from the\n// following option IFF:\n//  - The current option does not contain a '=' or a ':'\n//  - The current option requires a value (i.e. not a Option type of ':')\n//\n// The `name' used in the option format string does NOT include any leading\n// option indicator, such as '-', '--', or '/'.  All three of these are\n// permitted/required on any named option.\n//\n// Option bundling is permitted so long as:\n//   - '-' is used to start the option group\n//   - all of the bundled options are a single character\n//   - at most one of the bundled options accepts a value, and the value\n//     provided starts from the next character to the end of the string.\n//\n// This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value'\n// as '-Dname=value'.\n//\n// Option processing is disabled by specifying \"--\".  All options after \"--\"\n// are returned by OptionSet.Parse() unchanged and unprocessed.\n//\n// Unprocessed options are returned from OptionSet.Parse().\n//\n// Examples:\n//  int verbose = 0;\n//  OptionSet p = new OptionSet ()\n//    .Add (\"v\", v => ++verbose)\n//    .Add (\"name=|value=\", v => Console.WriteLine (v));\n//  p.Parse (new string[]{\"-v\", \"--v\", \"/v\", \"-name=A\", \"/name\", \"B\", \"extra\"});\n//\n// The above would parse the argument string array, and would invoke the\n// lambda expression three times, setting `verbose' to 3 when complete.  \n// It would also print out \"A\" and \"B\" to standard output.\n// The returned array would contain the string \"extra\".\n//\n// C# 3.0 collection initializers are supported and encouraged:\n//  var p = new OptionSet () {\n//    { \"h|?|help\", v => ShowHelp () },\n//  };\n//\n// System.ComponentModel.TypeConverter is also supported, allowing the use of\n// custom data types in the callback type; TypeConverter.ConvertFromString()\n// is used to convert the value option to an instance of the specified\n// type:\n//\n//  var p = new OptionSet () {\n//    { \"foo=\", (Foo f) => Console.WriteLine (f.ToString ()) },\n//  };\n//\n// Random other tidbits:\n//  - Boolean options (those w/o '=' or ':' in the option format string)\n//    are explicitly enabled if they are followed with '+', and explicitly\n//    disabled if they are followed with '-':\n//      string a = null;\n//      var p = new OptionSet () {\n//        { \"a\", s => a = s },\n//      };\n//      p.Parse (new string[]{\"-a\"});   // sets v != null\n//      p.Parse (new string[]{\"-a+\"});  // sets v != null\n//      p.Parse (new string[]{\"-a-\"});  // sets v == null\n//\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.ComponentModel;\nusing System.Globalization;\nusing System.IO;\nusing System.Runtime.Serialization;\nusing System.Security.Permissions;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\n#if LINQ\nusing System.Linq;\n#endif\n\n#if TEST\nusing NDesk.Options;\n#endif\n\n#if NDESK_OPTIONS\nnamespace NDesk.Options\n#else\nnamespace Mono.Options\n#endif\n{\n\tstatic class StringCoda {\n\n\t\tpublic static IEnumerable<string> WrappedLines (string self, params int[] widths)\n\t\t{\n\t\t\tIEnumerable<int> w = widths;\n\t\t\treturn WrappedLines (self, w);\n\t\t}\n\n\t\tpublic static IEnumerable<string> WrappedLines (string self, IEnumerable<int> widths)\n\t\t{\n\t\t\tif (widths == null)\n\t\t\t\tthrow new ArgumentNullException (\"widths\");\n\t\t\treturn CreateWrappedLinesIterator (self, widths);\n\t\t}\n\n\t\tprivate static IEnumerable<string> CreateWrappedLinesIterator (string self, IEnumerable<int> widths)\n\t\t{\n\t\t\tif (string.IsNullOrEmpty (self)) {\n\t\t\t\tyield return string.Empty;\n\t\t\t\tyield break;\n\t\t\t}\n\t\t\tusing (IEnumerator<int> ewidths = widths.GetEnumerator ()) {\n\t\t\t\tbool? hw = null;\n\t\t\t\tint width = GetNextWidth (ewidths, int.MaxValue, ref hw);\n\t\t\t\tint start = 0, end;\n\t\t\t\tdo {\n\t\t\t\t\tend = GetLineEnd (start, width, self);\n\t\t\t\t\tchar c = self [end-1];\n\t\t\t\t\tif (char.IsWhiteSpace (c))\n\t\t\t\t\t\t--end;\n\t\t\t\t\tbool needContinuation = end != self.Length && !IsEolChar (c);\n\t\t\t\t\tstring continuation = \"\";\n\t\t\t\t\tif (needContinuation) {\n\t\t\t\t\t\t--end;\n\t\t\t\t\t\tcontinuation = \"-\";\n\t\t\t\t\t}\n\t\t\t\t\tstring line = self.Substring (start, end - start) + continuation;\n\t\t\t\t\tyield return line;\n\t\t\t\t\tstart = end;\n\t\t\t\t\tif (char.IsWhiteSpace (c))\n\t\t\t\t\t\t++start;\n\t\t\t\t\twidth = GetNextWidth (ewidths, width, ref hw);\n\t\t\t\t} while (start < self.Length);\n\t\t\t}\n\t\t}\n\n\t\tprivate static int GetNextWidth (IEnumerator<int> ewidths, int curWidth, ref bool? eValid)\n\t\t{\n\t\t\tif (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {\n\t\t\t\tcurWidth = (eValid = ewidths.MoveNext ()).Value ? ewidths.Current : curWidth;\n\t\t\t\t// '.' is any character, - is for a continuation\n\t\t\t\tconst string minWidth = \".-\";\n\t\t\t\tif (curWidth < minWidth.Length)\n\t\t\t\t\tthrow new ArgumentOutOfRangeException (\"widths\",\n\t\t\t\t\t\t\tstring.Format (\"Element must be >= {0}, was {1}.\", minWidth.Length, curWidth));\n\t\t\t\treturn curWidth;\n\t\t\t}\n\t\t\t// no more elements, use the last element.\n\t\t\treturn curWidth;\n\t\t}\n\n\t\tprivate static bool IsEolChar (char c)\n\t\t{\n\t\t\treturn !char.IsLetterOrDigit (c);\n\t\t}\n\n\t\tprivate static int GetLineEnd (int start, int length, string description)\n\t\t{\n\t\t\tint end = System.Math.Min (start + length, description.Length);\n\t\t\tint sep = -1;\n\t\t\tfor (int i = start; i < end; ++i) {\n\t\t\t\tif (description [i] == '\\n')\n\t\t\t\t\treturn i+1;\n\t\t\t\tif (IsEolChar (description [i]))\n\t\t\t\t\tsep = i+1;\n\t\t\t}\n\t\t\tif (sep == -1 || end == description.Length)\n\t\t\t\treturn end;\n\t\t\treturn sep;\n\t\t}\n\t}\n\n\tpublic class OptionValueCollection : IList, IList<string> {\n\n\t\tList<string> values = new List<string> ();\n\t\tOptionContext c;\n\n\t\tinternal OptionValueCollection (OptionContext c)\n\t\t{\n\t\t\tthis.c = c;\n\t\t}\n\n\t\t#region ICollection\n\t\tvoid ICollection.CopyTo (Array array, int index)  {(values as ICollection).CopyTo (array, index);}\n\t\tbool ICollection.IsSynchronized                   {get {return (values as ICollection).IsSynchronized;}}\n\t\tobject ICollection.SyncRoot                       {get {return (values as ICollection).SyncRoot;}}\n\t\t#endregion\n\n\t\t#region ICollection<T>\n\t\tpublic void Add (string item)                       {values.Add (item);}\n\t\tpublic void Clear ()                                {values.Clear ();}\n\t\tpublic bool Contains (string item)                  {return values.Contains (item);}\n\t\tpublic void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);}\n\t\tpublic bool Remove (string item)                    {return values.Remove (item);}\n\t\tpublic int Count                                    {get {return values.Count;}}\n\t\tpublic bool IsReadOnly                              {get {return false;}}\n\t\t#endregion\n\n\t\t#region IEnumerable\n\t\tIEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();}\n\t\t#endregion\n\n\t\t#region IEnumerable<T>\n\t\tpublic IEnumerator<string> GetEnumerator () {return values.GetEnumerator ();}\n\t\t#endregion\n\n\t\t#region IList\n\t\tint IList.Add (object value)                {return (values as IList).Add (value);}\n\t\tbool IList.Contains (object value)          {return (values as IList).Contains (value);}\n\t\tint IList.IndexOf (object value)            {return (values as IList).IndexOf (value);}\n\t\tvoid IList.Insert (int index, object value) {(values as IList).Insert (index, value);}\n\t\tvoid IList.Remove (object value)            {(values as IList).Remove (value);}\n\t\tvoid IList.RemoveAt (int index)             {(values as IList).RemoveAt (index);}\n\t\tbool IList.IsFixedSize                      {get {return false;}}\n\t\tobject IList.this [int index]               {get {return this [index];} set {(values as IList)[index] = value;}}\n\t\t#endregion\n\n\t\t#region IList<T>\n\t\tpublic int IndexOf (string item)            {return values.IndexOf (item);}\n\t\tpublic void Insert (int index, string item) {values.Insert (index, item);}\n\t\tpublic void RemoveAt (int index)            {values.RemoveAt (index);}\n\n\t\tprivate void AssertValid (int index)\n\t\t{\n\t\t\tif (c.Option == null)\n\t\t\t\tthrow new InvalidOperationException (\"OptionContext.Option is null.\");\n\t\t\tif (index >= c.Option.MaxValueCount)\n\t\t\t\tthrow new ArgumentOutOfRangeException (\"index\");\n\t\t\tif (c.Option.OptionValueType == OptionValueType.Required &&\n\t\t\t\t\tindex >= values.Count)\n\t\t\t\tthrow new OptionException (string.Format (\n\t\t\t\t\t\t\tc.OptionSet.MessageLocalizer (\"Missing required value for option '{0}'.\"), c.OptionName), \n\t\t\t\t\t\tc.OptionName);\n\t\t}\n\n\t\tpublic string this [int index] {\n\t\t\tget {\n\t\t\t\tAssertValid (index);\n\t\t\t\treturn index >= values.Count ? null : values [index];\n\t\t\t}\n\t\t\tset {\n\t\t\t\tvalues [index] = value;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic List<string> ToList ()\n\t\t{\n\t\t\treturn new List<string> (values);\n\t\t}\n\n\t\tpublic string[] ToArray ()\n\t\t{\n\t\t\treturn values.ToArray ();\n\t\t}\n\n\t\tpublic override string ToString ()\n\t\t{\n\t\t\treturn string.Join (\", \", values.ToArray ());\n\t\t}\n\t}\n\n\tpublic class OptionContext {\n\t\tprivate Option                option;\n\t\tprivate string                name;\n\t\tprivate int                   index;\n\t\tprivate OptionSet             set;\n\t\tprivate OptionValueCollection c;\n\n\t\tpublic OptionContext (OptionSet set)\n\t\t{\n\t\t\tthis.set = set;\n\t\t\tthis.c   = new OptionValueCollection (this);\n\t\t}\n\n\t\tpublic Option Option {\n\t\t\tget {return option;}\n\t\t\tset {option = value;}\n\t\t}\n\n\t\tpublic string OptionName { \n\t\t\tget {return name;}\n\t\t\tset {name = value;}\n\t\t}\n\n\t\tpublic int OptionIndex {\n\t\t\tget {return index;}\n\t\t\tset {index = value;}\n\t\t}\n\n\t\tpublic OptionSet OptionSet {\n\t\t\tget {return set;}\n\t\t}\n\n\t\tpublic OptionValueCollection OptionValues {\n\t\t\tget {return c;}\n\t\t}\n\t}\n\n\tpublic enum OptionValueType {\n\t\tNone, \n\t\tOptional,\n\t\tRequired,\n\t}\n\n\tpublic abstract class Option {\n\t\tstring prototype, description;\n\t\tstring[] names;\n\t\tOptionValueType type;\n\t\tint count;\n\t\tstring[] separators;\n\t\tbool hidden;\n\n\t\tprotected Option (string prototype, string description)\n\t\t\t: this (prototype, description, 1, false)\n\t\t{\n\t\t}\n\n\t\tprotected Option (string prototype, string description, int maxValueCount)\n\t\t\t: this (prototype, description, maxValueCount, false)\n\t\t{\n\t\t}\n\n\t\tprotected Option (string prototype, string description, int maxValueCount, bool hidden)\n\t\t{\n\t\t\tif (prototype == null)\n\t\t\t\tthrow new ArgumentNullException (\"prototype\");\n\t\t\tif (prototype.Length == 0)\n\t\t\t\tthrow new ArgumentException (\"Cannot be the empty string.\", \"prototype\");\n\t\t\tif (maxValueCount < 0)\n\t\t\t\tthrow new ArgumentOutOfRangeException (\"maxValueCount\");\n\n\t\t\tthis.prototype   = prototype;\n\t\t\tthis.description = description;\n\t\t\tthis.count       = maxValueCount;\n\t\t\tthis.names       = (this is OptionSet.Category)\n\t\t\t\t// append GetHashCode() so that \"duplicate\" categories have distinct\n\t\t\t\t// names, e.g. adding multiple \"\" categories should be valid.\n\t\t\t\t? new[]{prototype + this.GetHashCode ()}\n\t\t\t\t: prototype.Split ('|');\n\n\t\t\tif (this is OptionSet.Category)\n\t\t\t\treturn;\n\n\t\t\tthis.type        = ParsePrototype ();\n\t\t\tthis.hidden      = hidden;\n\n\t\t\tif (this.count == 0 && type != OptionValueType.None)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\"Cannot provide maxValueCount of 0 for OptionValueType.Required or \" +\n\t\t\t\t\t\t\t\"OptionValueType.Optional.\",\n\t\t\t\t\t\t\"maxValueCount\");\n\t\t\tif (this.type == OptionValueType.None && maxValueCount > 1)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Cannot provide maxValueCount of {0} for OptionValueType.None.\", maxValueCount),\n\t\t\t\t\t\t\"maxValueCount\");\n\t\t\tif (Array.IndexOf (names, \"<>\") >= 0 && \n\t\t\t\t\t((names.Length == 1 && this.type != OptionValueType.None) ||\n\t\t\t\t\t (names.Length > 1 && this.MaxValueCount > 1)))\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\"The default option handler '<>' cannot require values.\",\n\t\t\t\t\t\t\"prototype\");\n\t\t}\n\n\t\tpublic string           Prototype       {get {return prototype;}}\n\t\tpublic string           Description     {get {return description;}}\n\t\tpublic OptionValueType  OptionValueType {get {return type;}}\n\t\tpublic int              MaxValueCount   {get {return count;}}\n\t\tpublic bool             Hidden          {get {return hidden;}}\n\n\t\tpublic string[] GetNames ()\n\t\t{\n\t\t\treturn (string[]) names.Clone ();\n\t\t}\n\n\t\tpublic string[] GetValueSeparators ()\n\t\t{\n\t\t\tif (separators == null)\n\t\t\t\treturn new string [0];\n\t\t\treturn (string[]) separators.Clone ();\n\t\t}\n\n\t\tprotected static T Parse<T> (string value, OptionContext c)\n\t\t{\n\t\t\tType tt = typeof (T);\n\t\t\tbool nullable = tt.IsValueType && tt.IsGenericType && \n\t\t\t\t!tt.IsGenericTypeDefinition && \n\t\t\t\ttt.GetGenericTypeDefinition () == typeof (Nullable<>);\n\t\t\tType targetType = nullable ? tt.GetGenericArguments () [0] : typeof (T);\n\t\t\tTypeConverter conv = TypeDescriptor.GetConverter (targetType);\n\t\t\tT t = default (T);\n\t\t\ttry {\n\t\t\t\tif (value != null)\n\t\t\t\t\tt = (T) conv.ConvertFromString (value);\n\t\t\t}\n\t\t\tcatch (Exception e) {\n\t\t\t\tthrow new OptionException (\n\t\t\t\t\t\tstring.Format (\n\t\t\t\t\t\t\tc.OptionSet.MessageLocalizer (\"Could not convert string `{0}' to type {1} for option `{2}'.\"),\n\t\t\t\t\t\t\tvalue, targetType.Name, c.OptionName),\n\t\t\t\t\t\tc.OptionName, e);\n\t\t\t}\n\t\t\treturn t;\n\t\t}\n\n\t\tinternal string[] Names           {get {return names;}}\n\t\tinternal string[] ValueSeparators {get {return separators;}}\n\n\t\tstatic readonly char[] NameTerminator = new char[]{'=', ':'};\n\n\t\tprivate OptionValueType ParsePrototype ()\n\t\t{\n\t\t\tchar type = '\\0';\n\t\t\tList<string> seps = new List<string> ();\n\t\t\tfor (int i = 0; i < names.Length; ++i) {\n\t\t\t\tstring name = names [i];\n\t\t\t\tif (name.Length == 0)\n\t\t\t\t\tthrow new ArgumentException (\"Empty option names are not supported.\", \"prototype\");\n\n\t\t\t\tint end = name.IndexOfAny (NameTerminator);\n\t\t\t\tif (end == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\tnames [i] = name.Substring (0, end);\n\t\t\t\tif (type == '\\0' || type == name [end])\n\t\t\t\t\ttype = name [end];\n\t\t\t\telse \n\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\tstring.Format (\"Conflicting option types: '{0}' vs. '{1}'.\", type, name [end]),\n\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\tAddSeparators (name, end, seps);\n\t\t\t}\n\n\t\t\tif (type == '\\0')\n\t\t\t\treturn OptionValueType.None;\n\n\t\t\tif (count <= 1 && seps.Count != 0)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Cannot provide key/value separators for Options taking {0} value(s).\", count),\n\t\t\t\t\t\t\"prototype\");\n\t\t\tif (count > 1) {\n\t\t\t\tif (seps.Count == 0)\n\t\t\t\t\tthis.separators = new string[]{\":\", \"=\"};\n\t\t\t\telse if (seps.Count == 1 && seps [0].Length == 0)\n\t\t\t\t\tthis.separators = null;\n\t\t\t\telse\n\t\t\t\t\tthis.separators = seps.ToArray ();\n\t\t\t}\n\n\t\t\treturn type == '=' ? OptionValueType.Required : OptionValueType.Optional;\n\t\t}\n\n\t\tprivate static void AddSeparators (string name, int end, ICollection<string> seps)\n\t\t{\n\t\t\tint start = -1;\n\t\t\tfor (int i = end+1; i < name.Length; ++i) {\n\t\t\t\tswitch (name [i]) {\n\t\t\t\t\tcase '{':\n\t\t\t\t\t\tif (start != -1)\n\t\t\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\t\t\tstart = i+1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '}':\n\t\t\t\t\t\tif (start == -1)\n\t\t\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\t\t\tseps.Add (name.Substring (start, i-start));\n\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (start == -1)\n\t\t\t\t\t\t\tseps.Add (name [i].ToString ());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (start != -1)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\"prototype\");\n\t\t}\n\n\t\tpublic void Invoke (OptionContext c)\n\t\t{\n\t\t\tOnParseComplete (c);\n\t\t\tc.OptionName  = null;\n\t\t\tc.Option      = null;\n\t\t\tc.OptionValues.Clear ();\n\t\t}\n\n\t\tprotected abstract void OnParseComplete (OptionContext c);\n\n\t\tpublic override string ToString ()\n\t\t{\n\t\t\treturn Prototype;\n\t\t}\n\t}\n\n\tpublic abstract class ArgumentSource {\n\n\t\tprotected ArgumentSource ()\n\t\t{\n\t\t}\n\n\t\tpublic abstract string[] GetNames ();\n\t\tpublic abstract string Description { get; }\n\t\tpublic abstract bool GetArguments (string value, out IEnumerable<string> replacement);\n\n\t\tpublic static IEnumerable<string> GetArgumentsFromFile (string file)\n\t\t{\n\t\t\treturn GetArguments (File.OpenText (file), true);\n\t\t}\n\n\t\tpublic static IEnumerable<string> GetArguments (TextReader reader)\n\t\t{\n\t\t\treturn GetArguments (reader, false);\n\t\t}\n\n\t\t// Cribbed from mcs/driver.cs:LoadArgs(string)\n\t\tstatic IEnumerable<string> GetArguments (TextReader reader, bool close)\n\t\t{\n\t\t\ttry {\n\t\t\t\tStringBuilder arg = new StringBuilder ();\n\n\t\t\t\tstring line;\n\t\t\t\twhile ((line = reader.ReadLine ()) != null) {\n\t\t\t\t\tint t = line.Length;\n\n\t\t\t\t\tfor (int i = 0; i < t; i++) {\n\t\t\t\t\t\tchar c = line [i];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif (c == '\"' || c == '\\'') {\n\t\t\t\t\t\t\tchar end = c;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (i++; i < t; i++){\n\t\t\t\t\t\t\t\tc = line [i];\n\n\t\t\t\t\t\t\t\tif (c == end)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\targ.Append (c);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (c == ' ') {\n\t\t\t\t\t\t\tif (arg.Length > 0) {\n\t\t\t\t\t\t\t\tyield return arg.ToString ();\n\t\t\t\t\t\t\t\targ.Length = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\targ.Append (c);\n\t\t\t\t\t}\n\t\t\t\t\tif (arg.Length > 0) {\n\t\t\t\t\t\tyield return arg.ToString ();\n\t\t\t\t\t\targ.Length = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (close)\n\t\t\t\t\treader.Close ();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic class ResponseFileSource : ArgumentSource {\n\n\t\tpublic override string[] GetNames ()\n\t\t{\n\t\t\treturn new string[]{\"@file\"};\n\t\t}\n\n\t\tpublic override string Description {\n\t\t\tget {return \"Read response file for more options.\";}\n\t\t}\n\n\t\tpublic override bool GetArguments (string value, out IEnumerable<string> replacement)\n\t\t{\n\t\t\tif (string.IsNullOrEmpty (value) || !value.StartsWith (\"@\")) {\n\t\t\t\treplacement = null;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treplacement = ArgumentSource.GetArgumentsFromFile (value.Substring (1));\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t[Serializable]\n\tpublic class OptionException : Exception {\n\t\tprivate string option;\n\n\t\tpublic OptionException ()\n\t\t{\n\t\t}\n\n\t\tpublic OptionException (string message, string optionName)\n\t\t\t: base (message)\n\t\t{\n\t\t\tthis.option = optionName;\n\t\t}\n\n\t\tpublic OptionException (string message, string optionName, Exception innerException)\n\t\t\t: base (message, innerException)\n\t\t{\n\t\t\tthis.option = optionName;\n\t\t}\n\n\t\tprotected OptionException (SerializationInfo info, StreamingContext context)\n\t\t\t: base (info, context)\n\t\t{\n\t\t\tthis.option = info.GetString (\"OptionName\");\n\t\t}\n\n\t\tpublic string OptionName {\n\t\t\tget {return this.option;}\n\t\t}\n\n\t\t[SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]\n\t\tpublic override void GetObjectData (SerializationInfo info, StreamingContext context)\n\t\t{\n\t\t\tbase.GetObjectData (info, context);\n\t\t\tinfo.AddValue (\"OptionName\", option);\n\t\t}\n\t}\n\n\tpublic delegate void OptionAction<TKey, TValue> (TKey key, TValue value);\n\n\tpublic class OptionSet : KeyedCollection<string, Option>\n\t{\n\t\tpublic OptionSet ()\n\t\t\t: this (delegate (string f) {return f;})\n\t\t{\n\t\t}\n\n\t\tpublic OptionSet (Converter<string, string> localizer)\n\t\t{\n\t\t\tthis.localizer = localizer;\n\t\t\tthis.roSources = new ReadOnlyCollection<ArgumentSource>(sources);\n\t\t}\n\n\t\tConverter<string, string> localizer;\n\n\t\tpublic Converter<string, string> MessageLocalizer {\n\t\t\tget {return localizer;}\n\t\t}\n\n\t\tList<ArgumentSource> sources = new List<ArgumentSource> ();\n\t\tReadOnlyCollection<ArgumentSource> roSources;\n\n\t\tpublic ReadOnlyCollection<ArgumentSource> ArgumentSources {\n\t\t\tget {return roSources;}\n\t\t}\n\n\n\t\tprotected override string GetKeyForItem (Option item)\n\t\t{\n\t\t\tif (item == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\tif (item.Names != null && item.Names.Length > 0)\n\t\t\t\treturn item.Names [0];\n\t\t\t// This should never happen, as it's invalid for Option to be\n\t\t\t// constructed w/o any names.\n\t\t\tthrow new InvalidOperationException (\"Option has no names!\");\n\t\t}\n\n\t\t[Obsolete (\"Use KeyedCollection.this[string]\")]\n\t\tprotected Option GetOptionForName (string option)\n\t\t{\n\t\t\tif (option == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\ttry {\n\t\t\t\treturn base [option];\n\t\t\t}\n\t\t\tcatch (KeyNotFoundException) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprotected override void InsertItem (int index, Option item)\n\t\t{\n\t\t\tbase.InsertItem (index, item);\n\t\t\tAddImpl (item);\n\t\t}\n\n\t\tprotected override void RemoveItem (int index)\n\t\t{\n\t\t\tOption p = Items [index];\n\t\t\tbase.RemoveItem (index);\n\t\t\t// KeyedCollection.RemoveItem() handles the 0th item\n\t\t\tfor (int i = 1; i < p.Names.Length; ++i) {\n\t\t\t\tDictionary.Remove (p.Names [i]);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void SetItem (int index, Option item)\n\t\t{\n\t\t\tbase.SetItem (index, item);\n\t\t\tAddImpl (item);\n\t\t}\n\n\t\tprivate void AddImpl (Option option)\n\t\t{\n\t\t\tif (option == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\tList<string> added = new List<string> (option.Names.Length);\n\t\t\ttry {\n\t\t\t\t// KeyedCollection.InsertItem/SetItem handle the 0th name.\n\t\t\t\tfor (int i = 1; i < option.Names.Length; ++i) {\n\t\t\t\t\tDictionary.Add (option.Names [i], option);\n\t\t\t\t\tadded.Add (option.Names [i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception) {\n\t\t\t\tforeach (string name in added)\n\t\t\t\t\tDictionary.Remove (name);\n\t\t\t\tthrow;\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add (string header)\n\t\t{\n\t\t\tif (header == null)\n\t\t\t\tthrow new ArgumentNullException (\"header\");\n\t\t\tAdd (new Category (header));\n\t\t\treturn this;\n\t\t}\n\n\t\tinternal sealed class Category : Option {\n\n\t\t\t// Prototype starts with '=' because this is an invalid prototype\n\t\t\t// (see Option.ParsePrototype(), and thus it'll prevent Category\n\t\t\t// instances from being accidentally used as normal options.\n\t\t\tpublic Category (string description)\n\t\t\t\t: base (\"=:Category:= \" + description, description)\n\t\t\t{\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\tthrow new NotSupportedException (\"Category.OnParseComplete should not be invoked.\");\n\t\t\t}\n\t\t}\n\n\n\t\tpublic new OptionSet Add (Option option)\n\t\t{\n\t\t\tbase.Add (option);\n\t\t\treturn this;\n\t\t}\n\n\t\tsealed class ActionOption : Option {\n\t\t\tAction<OptionValueCollection> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, int count, Action<OptionValueCollection> action)\n\t\t\t\t: this (prototype, description, count, action, false)\n\t\t\t{\n\t\t\t}\n\n\t\t\tpublic ActionOption (string prototype, string description, int count, Action<OptionValueCollection> action, bool hidden)\n\t\t\t\t: base (prototype, description, count, hidden)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (c.OptionValues);\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, Action<string> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, Action<string> action)\n\t\t{\n\t\t\treturn Add (prototype, description, action, false);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, Action<string> action, bool hidden)\n\t\t{\n\t\t\tif (action == null)\n\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\tOption p = new ActionOption (prototype, description, 1, \n\t\t\t\t\tdelegate (OptionValueCollection v) { action (v [0]); }, hidden);\n\t\t\tbase.Add (p);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, OptionAction<string, string> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, OptionAction<string, string> action)\n\t\t{\n\t\t\treturn Add (prototype, description, action, false);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, OptionAction<string, string> action, bool hidden)\t{\n\t\t\tif (action == null)\n\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\tOption p = new ActionOption (prototype, description, 2, \n\t\t\t\t\tdelegate (OptionValueCollection v) {action (v [0], v [1]);}, hidden);\n\t\t\tbase.Add (p);\n\t\t\treturn this;\n\t\t}\n\n\t\tsealed class ActionOption<T> : Option {\n\t\t\tAction<T> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, Action<T> action)\n\t\t\t\t: base (prototype, description, 1)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (Parse<T> (c.OptionValues [0], c));\n\t\t\t}\n\t\t}\n\n\t\tsealed class ActionOption<TKey, TValue> : Option {\n\t\t\tOptionAction<TKey, TValue> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, OptionAction<TKey, TValue> action)\n\t\t\t\t: base (prototype, description, 2)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (\n\t\t\t\t\t\tParse<TKey> (c.OptionValues [0], c),\n\t\t\t\t\t\tParse<TValue> (c.OptionValues [1], c));\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add<T> (string prototype, Action<T> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add<T> (string prototype, string description, Action<T> action)\n\t\t{\n\t\t\treturn Add (new ActionOption<T> (prototype, description, action));\n\t\t}\n\n\t\tpublic OptionSet Add<TKey, TValue> (string prototype, OptionAction<TKey, TValue> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add<TKey, TValue> (string prototype, string description, OptionAction<TKey, TValue> action)\n\t\t{\n\t\t\treturn Add (new ActionOption<TKey, TValue> (prototype, description, action));\n\t\t}\n\n\t\tpublic OptionSet Add (ArgumentSource source)\n\t\t{\n\t\t\tif (source == null)\n\t\t\t\tthrow new ArgumentNullException (\"source\");\n\t\t\tsources.Add (source);\n\t\t\treturn this;\n\t\t}\n\n\t\tprotected virtual OptionContext CreateOptionContext ()\n\t\t{\n\t\t\treturn new OptionContext (this);\n\t\t}\n\n\t\tpublic List<string> Parse (IEnumerable<string> arguments)\n\t\t{\n\t\t\tif (arguments == null)\n\t\t\t\tthrow new ArgumentNullException (\"arguments\");\n\t\t\tOptionContext c = CreateOptionContext ();\n\t\t\tc.OptionIndex = -1;\n\t\t\tbool process = true;\n\t\t\tList<string> unprocessed = new List<string> ();\n\t\t\tOption def = Contains (\"<>\") ? this [\"<>\"] : null;\n\t\t\tArgumentEnumerator ae = new ArgumentEnumerator (arguments);\n\t\t\tforeach (string argument in ae) {\n\t\t\t\t++c.OptionIndex;\n\t\t\t\tif (argument == \"--\") {\n\t\t\t\t\tprocess = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!process) {\n\t\t\t\t\tUnprocessed (unprocessed, def, c, argument);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (AddSource (ae, argument))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (!Parse (argument, c))\n\t\t\t\t\tUnprocessed (unprocessed, def, c, argument);\n\t\t\t}\n\t\t\tif (c.Option != null)\n\t\t\t\tc.Option.Invoke (c);\n\t\t\treturn unprocessed;\n\t\t}\n\n\t\tclass ArgumentEnumerator : IEnumerable<string> {\n\t\t\tList<IEnumerator<string>> sources = new List<IEnumerator<string>> ();\n\n\t\t\tpublic ArgumentEnumerator (IEnumerable<string> arguments)\n\t\t\t{\n\t\t\t\tsources.Add (arguments.GetEnumerator ());\n\t\t\t}\n\n\t\t\tpublic void Add (IEnumerable<string> arguments)\n\t\t\t{\n\t\t\t\tsources.Add (arguments.GetEnumerator ());\n\t\t\t}\n\n\t\t\tpublic IEnumerator<string> GetEnumerator ()\n\t\t\t{\n\t\t\t\tdo {\n\t\t\t\t\tIEnumerator<string> c = sources [sources.Count-1];\n\t\t\t\t\tif (c.MoveNext ())\n\t\t\t\t\t\tyield return c.Current;\n\t\t\t\t\telse {\n\t\t\t\t\t\tc.Dispose ();\n\t\t\t\t\t\tsources.RemoveAt (sources.Count-1);\n\t\t\t\t\t}\n\t\t\t\t} while (sources.Count > 0);\n\t\t\t}\n\n\t\t\tIEnumerator IEnumerable.GetEnumerator ()\n\t\t\t{\n\t\t\t\treturn GetEnumerator ();\n\t\t\t}\n\t\t}\n\n\t\tbool AddSource (ArgumentEnumerator ae, string argument)\n\t\t{\n\t\t\tforeach (ArgumentSource source in sources) {\n\t\t\t\tIEnumerable<string> replacement;\n\t\t\t\tif (!source.GetArguments (argument, out replacement))\n\t\t\t\t\tcontinue;\n\t\t\t\tae.Add (replacement);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate static bool Unprocessed (ICollection<string> extra, Option def, OptionContext c, string argument)\n\t\t{\n\t\t\tif (def == null) {\n\t\t\t\textra.Add (argument);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tc.OptionValues.Add (argument);\n\t\t\tc.Option = def;\n\t\t\tc.Option.Invoke (c);\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate readonly Regex ValueOption = new Regex (\n\t\t\t@\"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$\");\n\n\t\tprotected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)\n\t\t{\n\t\t\tif (argument == null)\n\t\t\t\tthrow new ArgumentNullException (\"argument\");\n\n\t\t\tflag = name = sep = value = null;\n\t\t\tMatch m = ValueOption.Match (argument);\n\t\t\tif (!m.Success) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tflag  = m.Groups [\"flag\"].Value;\n\t\t\tname  = m.Groups [\"name\"].Value;\n\t\t\tif (m.Groups [\"sep\"].Success && m.Groups [\"value\"].Success) {\n\t\t\t\tsep   = m.Groups [\"sep\"].Value;\n\t\t\t\tvalue = m.Groups [\"value\"].Value;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual bool Parse (string argument, OptionContext c)\n\t\t{\n\t\t\tif (c.Option != null) {\n\t\t\t\tParseValue (argument, c);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tstring f, n, s, v;\n\t\t\tif (!GetOptionParts (argument, out f, out n, out s, out v))\n\t\t\t\treturn false;\n\n\t\t\tOption p;\n\t\t\tif (Contains (n)) {\n\t\t\t\tp = this [n];\n\t\t\t\tc.OptionName = f + n;\n\t\t\t\tc.Option     = p;\n\t\t\t\tswitch (p.OptionValueType) {\n\t\t\t\t\tcase OptionValueType.None:\n\t\t\t\t\t\tc.OptionValues.Add (n);\n\t\t\t\t\t\tc.Option.Invoke (c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase OptionValueType.Optional:\n\t\t\t\t\tcase OptionValueType.Required: \n\t\t\t\t\t\tParseValue (v, c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// no match; is it a bool option?\n\t\t\tif (ParseBool (argument, n, c))\n\t\t\t\treturn true;\n\t\t\t// is it a bundled option?\n\t\t\tif (ParseBundledValue (f, string.Concat (n + s + v), c))\n\t\t\t\treturn true;\n\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void ParseValue (string option, OptionContext c)\n\t\t{\n\t\t\tif (option != null)\n\t\t\t\tforeach (string o in c.Option.ValueSeparators != null \n\t\t\t\t\t\t? option.Split (c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)\n\t\t\t\t\t\t: new string[]{option}) {\n\t\t\t\t\tc.OptionValues.Add (o);\n\t\t\t\t}\n\t\t\tif (c.OptionValues.Count == c.Option.MaxValueCount || \n\t\t\t\t\tc.Option.OptionValueType == OptionValueType.Optional)\n\t\t\t\tc.Option.Invoke (c);\n\t\t\telse if (c.OptionValues.Count > c.Option.MaxValueCount) {\n\t\t\t\tthrow new OptionException (localizer (string.Format (\n\t\t\t\t\t\t\t\t\"Error: Found {0} option values when expecting {1}.\", \n\t\t\t\t\t\t\t\tc.OptionValues.Count, c.Option.MaxValueCount)),\n\t\t\t\t\t\tc.OptionName);\n\t\t\t}\n\t\t}\n\n\t\tprivate bool ParseBool (string option, string n, OptionContext c)\n\t\t{\n\t\t\tOption p;\n\t\t\tstring rn;\n\t\t\tif (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') &&\n\t\t\t\t\tContains ((rn = n.Substring (0, n.Length-1)))) {\n\t\t\t\tp = this [rn];\n\t\t\t\tstring v = n [n.Length-1] == '+' ? option : null;\n\t\t\t\tc.OptionName  = option;\n\t\t\t\tc.Option      = p;\n\t\t\t\tc.OptionValues.Add (v);\n\t\t\t\tp.Invoke (c);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool ParseBundledValue (string f, string n, OptionContext c)\n\t\t{\n\t\t\tif (f != \"-\")\n\t\t\t\treturn false;\n\t\t\tfor (int i = 0; i < n.Length; ++i) {\n\t\t\t\tOption p;\n\t\t\t\tstring opt = f + n [i].ToString ();\n\t\t\t\tstring rn = n [i].ToString ();\n\t\t\t\tif (!Contains (rn)) {\n\t\t\t\t\tif (i == 0)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tthrow new OptionException (string.Format (localizer (\n\t\t\t\t\t\t\t\t\t\"Cannot bundle unregistered option '{0}'.\"), opt), opt);\n\t\t\t\t}\n\t\t\t\tp = this [rn];\n\t\t\t\tswitch (p.OptionValueType) {\n\t\t\t\t\tcase OptionValueType.None:\n\t\t\t\t\t\tInvoke (c, opt, n, p);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase OptionValueType.Optional:\n\t\t\t\t\tcase OptionValueType.Required: {\n\t\t\t\t\t\tstring v     = n.Substring (i+1);\n\t\t\t\t\t\tc.Option     = p;\n\t\t\t\t\t\tc.OptionName = opt;\n\t\t\t\t\t\tParseValue (v.Length != 0 ? v : null, c);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new InvalidOperationException (\"Unknown OptionValueType: \" + p.OptionValueType);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate static void Invoke (OptionContext c, string name, string value, Option option)\n\t\t{\n\t\t\tc.OptionName  = name;\n\t\t\tc.Option      = option;\n\t\t\tc.OptionValues.Add (value);\n\t\t\toption.Invoke (c);\n\t\t}\n\n\t\tprivate const int OptionWidth = 29;\n\t\tprivate const int Description_FirstWidth  = 80 - OptionWidth;\n\t\tprivate const int Description_RemWidth    = 80 - OptionWidth - 2;\n\n\t\tpublic void WriteOptionDescriptions (TextWriter o)\n\t\t{\n\t\t\tforeach (Option p in this) {\n\t\t\t\tint written = 0;\n\n\t\t\t\tif (p.Hidden)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tCategory c = p as Category;\n\t\t\t\tif (c != null) {\n\t\t\t\t\tWriteDescription (o, p.Description, \"\", 80, 80);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!WriteOptionPrototype (o, p, ref written))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (written < OptionWidth)\n\t\t\t\t\to.Write (new string (' ', OptionWidth - written));\n\t\t\t\telse {\n\t\t\t\t\to.WriteLine ();\n\t\t\t\t\to.Write (new string (' ', OptionWidth));\n\t\t\t\t}\n\n\t\t\t\tWriteDescription (o, p.Description, new string (' ', OptionWidth+2),\n\t\t\t\t\t\tDescription_FirstWidth, Description_RemWidth);\n\t\t\t}\n\n\t\t\tforeach (ArgumentSource s in sources) {\n\t\t\t\tstring[] names = s.GetNames ();\n\t\t\t\tif (names == null || names.Length == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tint written = 0;\n\n\t\t\t\tWrite (o, ref written, \"  \");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t\tfor (int i = 1; i < names.Length; ++i) {\n\t\t\t\t\tWrite (o, ref written, \", \");\n\t\t\t\t\tWrite (o, ref written, names [i]);\n\t\t\t\t}\n\n\t\t\t\tif (written < OptionWidth)\n\t\t\t\t\to.Write (new string (' ', OptionWidth - written));\n\t\t\t\telse {\n\t\t\t\t\to.WriteLine ();\n\t\t\t\t\to.Write (new string (' ', OptionWidth));\n\t\t\t\t}\n\n\t\t\t\tWriteDescription (o, s.Description, new string (' ', OptionWidth+2),\n\t\t\t\t\t\tDescription_FirstWidth, Description_RemWidth);\n\t\t\t}\n\t\t}\n\n\t\tvoid WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth)\n\t\t{\n\t\t\tbool indent = false;\n\t\t\tforeach (string line in GetLines (localizer (GetDescription (value)), firstWidth, remWidth)) {\n\t\t\t\tif (indent)\n\t\t\t\t\to.Write (prefix);\n\t\t\t\to.WriteLine (line);\n\t\t\t\tindent = true;\n\t\t\t}\n\t\t}\n\n\t\tbool WriteOptionPrototype (TextWriter o, Option p, ref int written)\n\t\t{\n\t\t\tstring[] names = p.Names;\n\n\t\t\tint i = GetNextOptionIndex (names, 0);\n\t\t\tif (i == names.Length)\n\t\t\t\treturn false;\n\n\t\t\tif (names [i].Length == 1) {\n\t\t\t\tWrite (o, ref written, \"  -\");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWrite (o, ref written, \"      --\");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t}\n\n\t\t\tfor ( i = GetNextOptionIndex (names, i+1); \n\t\t\t\t\ti < names.Length; i = GetNextOptionIndex (names, i+1)) {\n\t\t\t\tWrite (o, ref written, \", \");\n\t\t\t\tWrite (o, ref written, names [i].Length == 1 ? \"-\" : \"--\");\n\t\t\t\tWrite (o, ref written, names [i]);\n\t\t\t}\n\n\t\t\tif (p.OptionValueType == OptionValueType.Optional ||\n\t\t\t\t\tp.OptionValueType == OptionValueType.Required) {\n\t\t\t\tif (p.OptionValueType == OptionValueType.Optional) {\n\t\t\t\t\tWrite (o, ref written, localizer (\"[\"));\n\t\t\t\t}\n\t\t\t\tWrite (o, ref written, localizer (\"=\" + GetArgumentName (0, p.MaxValueCount, p.Description)));\n\t\t\t\tstring sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0 \n\t\t\t\t\t? p.ValueSeparators [0]\n\t\t\t\t\t: \" \";\n\t\t\t\tfor (int c = 1; c < p.MaxValueCount; ++c) {\n\t\t\t\t\tWrite (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description)));\n\t\t\t\t}\n\t\t\t\tif (p.OptionValueType == OptionValueType.Optional) {\n\t\t\t\t\tWrite (o, ref written, localizer (\"]\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic int GetNextOptionIndex (string[] names, int i)\n\t\t{\n\t\t\twhile (i < names.Length && names [i] == \"<>\") {\n\t\t\t\t++i;\n\t\t\t}\n\t\t\treturn i;\n\t\t}\n\n\t\tstatic void Write (TextWriter o, ref int n, string s)\n\t\t{\n\t\t\tn += s.Length;\n\t\t\to.Write (s);\n\t\t}\n\n\t\tprivate static string GetArgumentName (int index, int maxIndex, string description)\n\t\t{\n\t\t\tif (description == null)\n\t\t\t\treturn maxIndex == 1 ? \"VALUE\" : \"VALUE\" + (index + 1);\n\t\t\tstring[] nameStart;\n\t\t\tif (maxIndex == 1)\n\t\t\t\tnameStart = new string[]{\"{0:\", \"{\"};\n\t\t\telse\n\t\t\t\tnameStart = new string[]{\"{\" + index + \":\"};\n\t\t\tfor (int i = 0; i < nameStart.Length; ++i) {\n\t\t\t\tint start, j = 0;\n\t\t\t\tdo {\n\t\t\t\t\tstart = description.IndexOf (nameStart [i], j);\n\t\t\t\t} while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);\n\t\t\t\tif (start == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\tint end = description.IndexOf (\"}\", start);\n\t\t\t\tif (end == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\treturn description.Substring (start + nameStart [i].Length, end - start - nameStart [i].Length);\n\t\t\t}\n\t\t\treturn maxIndex == 1 ? \"VALUE\" : \"VALUE\" + (index + 1);\n\t\t}\n\n\t\tprivate static string GetDescription (string description)\n\t\t{\n\t\t\tif (description == null)\n\t\t\t\treturn string.Empty;\n\t\t\tStringBuilder sb = new StringBuilder (description.Length);\n\t\t\tint start = -1;\n\t\t\tfor (int i = 0; i < description.Length; ++i) {\n\t\t\t\tswitch (description [i]) {\n\t\t\t\t\tcase '{':\n\t\t\t\t\t\tif (i == start) {\n\t\t\t\t\t\t\tsb.Append ('{');\n\t\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (start < 0)\n\t\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '}':\n\t\t\t\t\t\tif (start < 0) {\n\t\t\t\t\t\t\tif ((i+1) == description.Length || description [i+1] != '}')\n\t\t\t\t\t\t\t\tthrow new InvalidOperationException (\"Invalid option description: \" + description);\n\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\tsb.Append (\"}\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsb.Append (description.Substring (start, i - start));\n\t\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ':':\n\t\t\t\t\t\tif (start < 0)\n\t\t\t\t\t\t\tgoto default;\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (start < 0)\n\t\t\t\t\t\t\tsb.Append (description [i]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.ToString ();\n\t\t}\n\n\t\tprivate static IEnumerable<string> GetLines (string description, int firstWidth, int remWidth)\n\t\t{\n\t\t\treturn StringCoda.WrappedLines (description, firstWidth, remWidth);\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "src/SyncReleases/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Net.Http;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Mono.Options;\nusing Octokit;\nusing Squirrel.SimpleSplat;\nusing Squirrel;\nusing Squirrel.Json;\n\nnamespace SyncReleases\n{\n    class Program : IEnableLogger \n    {\n        static OptionSet opts;\n\n        public static int Main(string[] args)\n        {\n            var pg = new Program();\n            try {\n                return pg.main(args).Result;\n            } catch (Exception ex) {\n                // NB: Normally this is a terrible idea but we want to make\n                // sure Setup.exe above us gets the nonzero error code\n                Console.Error.WriteLine(ex);\n                return -1;\n            }\n        }\n\n        async Task<int> main(string[] args)\n        {\n            using (var logger = new SetupLogLogger(false) { Level = Squirrel.SimpleSplat.LogLevel.Info }) {\n                Squirrel.SimpleSplat.SquirrelLocator.CurrentMutable.Register(() => logger, typeof(Squirrel.SimpleSplat.ILogger));\n\n                var releaseDir = default(string);\n                var repoUrl = default(string);\n                var token = default(string);\n\n                opts = new OptionSet() {\n                    \"Usage: SyncReleases.exe command [OPTS]\",\n                    \"Builds a Releases directory from releases on GitHub\",\n                    \"\",\n                    \"Options:\",\n                    { \"h|?|help\", \"Display Help and exit\", _ => {} },\n                    { \"r=|releaseDir=\", \"Path to a release directory to download to\", v => releaseDir = v},\n                    { \"u=|url=\", \"When pointing to GitHub, use the URL to the repository root page, else point to an existing remote Releases folder\", v => repoUrl = v},\n                    { \"t=|token=\", \"The OAuth token to use as login credentials\", v => token = v},\n                };\n\n                opts.Parse(args);\n\n                if (repoUrl == null || repoUrl.StartsWith(\"http\", true, CultureInfo.InvariantCulture) == false) {\n                    ShowHelp();\n                    return -1;\n                }\n\n                var releaseDirectoryInfo = new DirectoryInfo(releaseDir ?? Path.Combine(\".\", \"Releases\"));\n                if (!releaseDirectoryInfo.Exists) releaseDirectoryInfo.Create();\n\n                var githubException = default(Exception);\n                try {\n                    await SyncImplementations.SyncFromGitHub(repoUrl, token, releaseDirectoryInfo);\n                    return 0;\n                } catch (Exception ex) {\n                    githubException = ex;\n                    Console.Error.WriteLine(\"Attempting to sync URL as remote RELEASES folder\");\n                }\n\n                try {\n                    await SyncImplementations.SyncRemoteReleases(new Uri(repoUrl), releaseDirectoryInfo);\n                } catch (Exception) {\n                    Console.Error.WriteLine(\"Failed to sync URL as GitHub repo: \" + githubException.Message);\n                    throw;\n                }\n            }\n\n            return 0;\n        }\n        \n        public void ShowHelp()\n        {\n            opts.WriteOptionDescriptions(Console.Out);\n        }\n    }\n\n    class SetupLogLogger : Squirrel.SimpleSplat.ILogger, IDisposable\n    {\n        StreamWriter inner;\n        readonly object gate = 42;\n        public Squirrel.SimpleSplat.LogLevel Level { get; set; }\n\n        public SetupLogLogger(bool saveInTemp)\n        {\n            var dir = saveInTemp ?\n                Path.GetTempPath() : \n                Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);\n\n            var file = Path.Combine(dir, \"SquirrelSetup.log\");\n            if (File.Exists(file)) File.Delete(file);\n\n            inner = new StreamWriter(file, false, Encoding.UTF8);\n        }\n\n        public void Write(string message, LogLevel logLevel)\n        {\n            if (logLevel < Level) {\n                return;\n            }\n\n            lock (gate) inner.WriteLine(message);\n        }\n\n        public void Dispose()\n        {\n            lock(gate) inner.Dispose();\n        }\n    }\n}\n"
  },
  {
    "path": "src/SyncReleases/SyncImplementations.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Net.Http;\nusing System.Threading.Tasks;\nusing Squirrel;\nusing Octokit;\nusing System.Reflection;\nusing System.Net;\n\nnamespace SyncReleases\n{\n    internal class SyncImplementations\n    {\n        static SyncImplementations()\n        {\n            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;\n        }\n\n        public static async Task SyncRemoteReleases(Uri targetUri, DirectoryInfo releasesDir)\n        {\n            var releasesUri = Utility.AppendPathToUri(targetUri, \"RELEASES\");\n            var releasesIndex = await retryAsync(3, () => downloadReleasesIndex(releasesUri));\n\n            File.WriteAllText(Path.Combine(releasesDir.FullName, \"RELEASES\"), releasesIndex);\n\n            var releasesToDownload = ReleaseEntry.ParseReleaseFile(releasesIndex)\n                .Where(x => !x.IsDelta)\n                .OrderByDescending(x => x.Version)\n                .Take(1)\n                .Select(x => new {\n                    LocalPath = Path.Combine(releasesDir.FullName, x.Filename),\n                    RemoteUrl = new Uri(Utility.EnsureTrailingSlash(targetUri), x.BaseUrl + x.Filename + x.Query)\n                 });\n\n            foreach (var releaseToDownload in releasesToDownload) {\n                await retryAsync(3, () => downloadRelease(releaseToDownload.LocalPath, releaseToDownload.RemoteUrl));\n            }\n        }\n\n        public static async Task SyncFromGitHub(string repoUrl, string token, DirectoryInfo releaseDirectoryInfo)\n        {\n            var repoUri = new Uri(repoUrl);\n            var userAgent = new ProductHeaderValue(\"SyncReleases\", Assembly.GetExecutingAssembly().GetName().Version.ToString());\n\n            var client = new GitHubClient(userAgent, repoUri);\n\n            if (token != null) {\n                client.Credentials = new Credentials(token);\n            }\n\n            var nwo = nwoFromRepoUrl(repoUrl);\n            var releases = (await client.Release.GetAll(nwo.Item1, nwo.Item2))\n                .OrderByDescending(x => x.PublishedAt)\n                .Take(5);\n\n            await releases.ForEachAsync(async release => {\n                // NB: Why do I have to double-fetch the release assets? It's already in GetAll\n                var assets = await client.Release.GetAllAssets(nwo.Item1, nwo.Item2, release.Id);\n\n                await assets\n                    .Where(x => x.Name.EndsWith(\".nupkg\", StringComparison.OrdinalIgnoreCase))\n                    .Where(x => {\n                        var fi = new FileInfo(Path.Combine(releaseDirectoryInfo.FullName, x.Name));\n                        return !(fi.Exists && fi.Length == x.Size);\n                    })\n                    .ForEachAsync(async x => {\n                        var target = new FileInfo(Path.Combine(releaseDirectoryInfo.FullName, x.Name));\n                        if (target.Exists) target.Delete();\n\n                        await retryAsync(3, async () => {\n                            var hc = new HttpClient();\n                            var rq = new HttpRequestMessage(HttpMethod.Get, x.Url);\n                            rq.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(\"application/octet-stream\"));\n                            rq.Headers.UserAgent.Add(new System.Net.Http.Headers.ProductInfoHeaderValue(userAgent.Name, userAgent.Version));\n                            if (token != null) {\n                                rq.Headers.Add(\"Authorization\", \"Bearer \" + token);\n                            }\n\n                            var resp = await hc.SendAsync(rq);\n                            resp.EnsureSuccessStatusCode();\n\n                            using (var from = await resp.Content.ReadAsStreamAsync())\n                            using (var to = File.OpenWrite(target.FullName)) {\n                                await from.CopyToAsync(to);\n                            }\n                        });\n                    });\n            });\n\n            var entries = releaseDirectoryInfo.GetFiles(\"*.nupkg\")\n                .AsParallel()\n                .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));\n\n            ReleaseEntry.WriteReleaseFile(entries, Path.Combine(releaseDirectoryInfo.FullName, \"RELEASES\"));\n        }\n\n        static async Task<string> downloadReleasesIndex(Uri uri)\n        {\n            Console.WriteLine(\"Trying to download RELEASES index from {0}\", uri);\n\n            var userAgent = new System.Net.Http.Headers.ProductInfoHeaderValue(\"Squirrel\", Assembly.GetExecutingAssembly().GetName().Version.ToString());\n\n            using (HttpClient client = new HttpClient()) {\n                client.DefaultRequestHeaders.UserAgent.Add(userAgent);\n                return await client.GetStringAsync(uri);\n            }\n        }\n\n        static async Task downloadRelease(string localPath, Uri remoteUrl)\n        {\n            if (File.Exists(localPath)) {\n                File.Delete(localPath);\n            }\n\n            Console.WriteLine(\"Downloading release from {0}\", remoteUrl);\n            var wc = new NotBrokenWebClient();\n            await wc.DownloadFileTaskAsync(remoteUrl, localPath);\n        }\n\n        static Tuple<string, string> nwoFromRepoUrl(string repoUrl)\n        {\n            var uri = new Uri(repoUrl);\n\n            var segments = uri.AbsolutePath.Split('/');\n            if (segments.Count() != 3) {\n                throw new Exception(\"Repo URL must be to the root URL of the repo e.g. https://github.com/myuser/myrepo\");\n            }\n\n            return Tuple.Create(segments[1], segments[2]);\n        }\n\n        static async Task<T> retryAsync<T>(int count, Func<Task<T>> block)\n        {\n            int retryCount = count;\n\n        retry:\n            try {\n                return await block();\n            } catch (Exception) {\n                retryCount--;\n                if (retryCount >= 0) goto retry;\n\n                throw;\n            }\n        }\n\n        static async Task retryAsync(int count, Func<Task> block)\n        {\n            await retryAsync(count, async () => { await block(); return false; });\n        }\n    }\n\n    class NotBrokenWebClient : WebClient\n    {\n        protected override WebRequest GetWebRequest(Uri address)\n        {\n            var wr = base.GetWebRequest(address);\n            var hwr = wr as HttpWebRequest;\n            if (hwr == null) return wr;\n\n            hwr.AllowAutoRedirect = true;\n            hwr.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;\n            return hwr;\n        }\n    }\n}\n"
  },
  {
    "path": "src/SyncReleases/SyncReleases.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.NET.Sdk\" />\n\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <OutputType>Exe</OutputType>\n    <Description>SyncReleases</Description>\n    <Title>SyncReleases</Title>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\vendor\\nuget\\src\\Core\\Core.csproj\" />\n    <ProjectReference Include=\"..\\Squirrel\\Squirrel.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Octokit\" Version=\"0.10.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"ILRepack\" Version=\"1.26.0\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n  <Import Project=\"Sdk.targets\" Sdk=\"Microsoft.NET.Sdk\" />\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\n    <PostBuildEvent>\n      cd \"$(TargetDir)\"\n      \"$(NuGetPackageRoot)ilrepack\\1.26.0\\tools\\ILRepack.exe\" /internalize /out:$(TargetFileName).tmp $(TargetFileName) SharpCompress.dll Microsoft.Web.XmlTransform.dll Squirrel.dll Octokit.dll NuGet.Squirrel.dll\n      del \"$(TargetFileName)\"\n      ren \"$(TargetFileName).tmp\" \"$(TargetFileName)\"\n    </PostBuildEvent>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "src/Update/AnimatedGifWindow.cs",
    "content": "﻿#if !MONO\nusing System;\nusing System.IO;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows;\nusing System.Windows.Controls;\nusing System.Windows.Input;\nusing System.Windows.Media;\nusing System.Windows.Media.Imaging;\nusing System.Windows.Shell;\nusing WpfAnimatedGif;\n\nnamespace Squirrel.Update\n{\n    public class AnimatedGifWindow : Window\n    {\n        public AnimatedGifWindow()\n        {\n            var img = new Image();\n            var src = default(BitmapImage);\n\n            var executionLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            var source = Path.Combine(\n                executionLocation,\n                \"background.gif\");\n\n            if (File.Exists(source)) {\n                src = new BitmapImage();\n                src.BeginInit();\n                src.StreamSource = File.OpenRead(source);\n                src.EndInit();\n\n                ImageBehavior.SetAnimatedSource(img, src);\n                this.Content = img;\n                this.Width = src.Width;\n                this.Height = src.Height;\n            }\n\n            var setupIcon = Path.Combine(executionLocation, \"setupIcon.ico\");\n            if (File.Exists(setupIcon)) {\n                Icon = BitmapFrame.Create(new Uri(setupIcon, UriKind.Relative));\n            }\n\n            this.AllowsTransparency = true;\n            this.WindowStyle = WindowStyle.None;\n            this.WindowStartupLocation = WindowStartupLocation.CenterScreen;\n            this.ShowInTaskbar = true;\n            this.Topmost = true;\n            this.TaskbarItemInfo = new TaskbarItemInfo {\n                ProgressState = TaskbarItemProgressState.Normal\n            };\n            this.Title = \"Installing...\";\n            this.Background = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));\n        }\n\n        public static void ShowWindow(TimeSpan initialDelay, CancellationToken token, ProgressSource progressSource)\n        {\n            var wnd = default(AnimatedGifWindow);\n\n            var thread = new Thread(() => {\n                if (token.IsCancellationRequested) return;\n\n                try {\n                    Task.Delay(initialDelay, token).ContinueWith(t => { return true; }).Wait();\n                } catch (Exception) {\n                    return;\n                }\n\n                wnd = new AnimatedGifWindow();\n                wnd.Show();\n\n                Task.Delay(TimeSpan.FromSeconds(5.0), token).ContinueWith(t => {\n                    if (t.IsCanceled) return;\n                    wnd.Dispatcher.BeginInvoke(new Action(() => wnd.Topmost = false));\n                });\n\n                token.Register(() => wnd.Dispatcher.BeginInvoke(new Action(wnd.Close)));\n                EventHandler<int> progressSourceOnProgress = ((sender, p) =>\n                    wnd.Dispatcher.BeginInvoke(\n                        new Action(() => wnd.TaskbarItemInfo.ProgressValue = p/100.0)));\n                progressSource.Progress += progressSourceOnProgress;\n                try {\n                    (new Application()).Run(wnd);\n                } finally {\n                    progressSource.Progress -= progressSourceOnProgress;\n                }\n            });\n\n            thread.SetApartmentState(ApartmentState.STA);\n            thread.Start();\n        }\n\n        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)\n        {\n            base.OnMouseLeftButtonDown(e);\n            this.DragMove();\n        }\n    }\n}\n\n#endif"
  },
  {
    "path": "src/Update/App.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.5\" />\n    </startup>\n</configuration>"
  },
  {
    "path": "src/Update/AuthenticodeTools.cs",
    "content": "﻿using System;\nusing System.Runtime.InteropServices;\n\nnamespace Squirrel.Update\n{\n    internal static class AuthenticodeTools\n    {\n        [DllImport(\"Wintrust.dll\", PreserveSig = true, SetLastError = false)]\n        static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData);\n\n        static uint winVerifyTrust(string fileName)\n        {\n            Guid wintrust_action_generic_verify_v2 = new Guid(\"{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}\");\n\n            uint result = 0;\n            using (WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO(fileName, Guid.Empty))\n            using (UnmanagedPointer guidPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))), AllocMethod.HGlobal))\n            using (UnmanagedPointer wvtDataPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))), AllocMethod.HGlobal))\n            {\n                WINTRUST_DATA data = new WINTRUST_DATA(fileInfo);\n                IntPtr pGuid = guidPtr;\n                IntPtr pData = wvtDataPtr;\n\n                Marshal.StructureToPtr(wintrust_action_generic_verify_v2, pGuid, true);\n                Marshal.StructureToPtr(data, pData, true);\n\n                result = WinVerifyTrust(IntPtr.Zero, pGuid, pData);\n            }\n            return result;\n\n        }\n        public static bool IsTrusted(string fileName)\n        {\n            return winVerifyTrust(fileName) == 0;\n        }\n    }\n\n    internal struct WINTRUST_FILE_INFO : IDisposable\n    {\n        public WINTRUST_FILE_INFO(string fileName, Guid subject)\n        {\n\n            cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));\n            pcwszFilePath = fileName;\n\n            if (subject != Guid.Empty) {\n                pgKnownSubject = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));\n                Marshal.StructureToPtr(subject, pgKnownSubject, true);\n            } else {\n                pgKnownSubject = IntPtr.Zero;\n            }\n\n            hFile = IntPtr.Zero;\n\n        }\n\n        public uint cbStruct;\n\n        [MarshalAs(UnmanagedType.LPTStr)]\n        public string pcwszFilePath;\n\n        public IntPtr hFile;\n        public IntPtr pgKnownSubject;\n\n        public void Dispose()\n        {\n            Dispose(true);\n        }\n\n        void Dispose(bool disposing)\n        {\n            if (pgKnownSubject != IntPtr.Zero) {\n                Marshal.DestroyStructure(this.pgKnownSubject, typeof(Guid));\n                Marshal.FreeHGlobal(this.pgKnownSubject);\n            }\n        }\n    }\n\n    enum AllocMethod {\n        HGlobal, CoTaskMem\n    };\n\n    enum UnionChoice {\n        File = 1,\n        Catalog,\n        Blob,\n        Signer,\n        Cert\n    };\n\n    enum UiChoice {\n        All = 1,\n        NoUI,\n        NoBad,\n        NoGood\n    };\n    enum RevocationCheckFlags {\n        None = 0,\n        WholeChain\n    };\n    enum StateAction {\n        Ignore = 0,\n        Verify,\n        Close,\n        AutoCache,\n        AutoCacheFlush\n    };\n    enum TrustProviderFlags {\n        UseIE4Trust = 1,\n        NoIE4Chain = 2,\n        NoPolicyUsage = 4,\n        RevocationCheckNone = 16,\n        RevocationCheckEndCert = 32,\n        RevocationCheckChain = 64,\n        RecovationCheckChainExcludeRoot = 128,\n        Safer = 256,\n        HashOnly = 512,\n        UseDefaultOSVerCheck = 1024,\n        LifetimeSigning = 2048\n    };\n    enum UIContext {\n        Execute = 0,\n        Install\n    };\n\n    [StructLayout(LayoutKind.Sequential)]\n\n    internal struct WINTRUST_DATA : IDisposable\n    {\n        public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo)\n        {\n            this.cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA));\n            pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)));\n\n            Marshal.StructureToPtr(fileInfo, pInfoStruct, false);\n\n            this.dwUnionChoice = UnionChoice.File;\n\n            pPolicyCallbackData = IntPtr.Zero;\n            pSIPCallbackData = IntPtr.Zero;\n            dwUIChoice = UiChoice.NoUI;\n            fdwRevocationChecks = RevocationCheckFlags.None;\n            dwStateAction = StateAction.Ignore;\n            hWVTStateData = IntPtr.Zero;\n            pwszURLReference = IntPtr.Zero;\n            dwProvFlags = TrustProviderFlags.Safer;\n            dwUIContext = UIContext.Execute;\n        }\n\n        public uint cbStruct;\n        public IntPtr pPolicyCallbackData;\n        public IntPtr pSIPCallbackData;\n        public UiChoice dwUIChoice;\n        public RevocationCheckFlags fdwRevocationChecks;\n        public UnionChoice dwUnionChoice;\n        public IntPtr pInfoStruct;\n        public StateAction dwStateAction;\n        public IntPtr hWVTStateData;\n        public TrustProviderFlags dwProvFlags;\n        public UIContext dwUIContext;\n\n        IntPtr pwszURLReference;\n        \n        public void Dispose()\n        {\n            Dispose(true);\n        }\n\n\n\n        void Dispose(bool disposing)\n        {\n            if (dwUnionChoice == UnionChoice.File) {\n                WINTRUST_FILE_INFO info = new WINTRUST_FILE_INFO();\n                Marshal.PtrToStructure(pInfoStruct, info);\n\n                info.Dispose();\n\n                Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO));\n            }\n\n            Marshal.FreeHGlobal(pInfoStruct);\n        }\n    }\n\n    internal sealed class UnmanagedPointer : IDisposable\n    {\n        IntPtr m_ptr;\n        AllocMethod m_meth;\n\n        internal UnmanagedPointer(IntPtr ptr, AllocMethod method)\n        {\n            m_meth = method;\n            m_ptr = ptr;\n        }\n\n        ~UnmanagedPointer()\n        {\n            Dispose(false);\n        }\n\n        void Dispose(bool disposing)\n        {\n            if (m_ptr != IntPtr.Zero) {\n                if (m_meth == AllocMethod.HGlobal) {\n                    Marshal.FreeHGlobal(m_ptr);\n                } else if (m_meth == AllocMethod.CoTaskMem) {\n                    Marshal.FreeCoTaskMem(m_ptr);\n                }\n\n                m_ptr = IntPtr.Zero;\n            }\n\n            if (disposing) {\n                GC.SuppressFinalize(this);\n            }\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n        }\n\n        public static implicit operator IntPtr(UnmanagedPointer ptr)\n        {\n            return ptr.m_ptr;\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Update/CopStache.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Squirrel.Update\n{\n    public static class CopStache\n    {\n        public static string Render(string template, Dictionary<string, string> identifiers)\n        {\n            var buf = new StringBuilder();\n\n            foreach (var line in template.Split('\\n')) {\n                identifiers[\"RandomGuid\"] = (Guid.NewGuid()).ToString();\n\n                foreach (var key in identifiers.Keys) {\n                    buf.Replace(\"{{\" + key + \"}}\", SecurityElement.Escape(identifiers[key]));\n                }\n\n                buf.AppendLine(line);\n            }\n\n            return buf.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Update/Mono.Options/Options.cs",
    "content": "//\n// Options.cs\n//\n// Authors:\n//  Jonathan Pryor <jpryor@novell.com>\n//  Federico Di Gregorio <fog@initd.org>\n//  Rolf Bjarne Kvinge <rolf@xamarin.com>\n//\n// Copyright (C) 2008 Novell (http://www.novell.com)\n// Copyright (C) 2009 Federico Di Gregorio.\n// Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to\n// the following conditions:\n//\n// The above copyright notice and this permission notice shall be\n// included in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n//\n\n// Compile With:\n//   gmcs -debug+ -r:System.Core Options.cs -o:NDesk.Options.dll\n//   gmcs -debug+ -d:LINQ -r:System.Core Options.cs -o:NDesk.Options.dll\n//\n// The LINQ version just changes the implementation of\n// OptionSet.Parse(IEnumerable<string>), and confers no semantic changes.\n\n//\n// A Getopt::Long-inspired option parsing library for C#.\n//\n// NDesk.Options.OptionSet is built upon a key/value table, where the\n// key is a option format string and the value is a delegate that is\n// invoked when the format string is matched.\n//\n// Option format strings:\n//  Regex-like BNF Grammar:\n//    name: .+\n//    type: [=:]\n//    sep: ( [^{}]+ | '{' .+ '}' )?\n//    aliases: ( name type sep ) ( '|' name type sep )*\n//\n// Each '|'-delimited name is an alias for the associated action.  If the\n// format string ends in a '=', it has a required value.  If the format\n// string ends in a ':', it has an optional value.  If neither '=' or ':'\n// is present, no value is supported.  `=' or `:' need only be defined on one\n// alias, but if they are provided on more than one they must be consistent.\n//\n// Each alias portion may also end with a \"key/value separator\", which is used\n// to split option values if the option accepts > 1 value.  If not specified,\n// it defaults to '=' and ':'.  If specified, it can be any character except\n// '{' and '}' OR the *string* between '{' and '}'.  If no separator should be\n// used (i.e. the separate values should be distinct arguments), then \"{}\"\n// should be used as the separator.\n//\n// Options are extracted either from the current option by looking for\n// the option name followed by an '=' or ':', or is taken from the\n// following option IFF:\n//  - The current option does not contain a '=' or a ':'\n//  - The current option requires a value (i.e. not a Option type of ':')\n//\n// The `name' used in the option format string does NOT include any leading\n// option indicator, such as '-', '--', or '/'.  All three of these are\n// permitted/required on any named option.\n//\n// Option bundling is permitted so long as:\n//   - '-' is used to start the option group\n//   - all of the bundled options are a single character\n//   - at most one of the bundled options accepts a value, and the value\n//     provided starts from the next character to the end of the string.\n//\n// This allows specifying '-a -b -c' as '-abc', and specifying '-D name=value'\n// as '-Dname=value'.\n//\n// Option processing is disabled by specifying \"--\".  All options after \"--\"\n// are returned by OptionSet.Parse() unchanged and unprocessed.\n//\n// Unprocessed options are returned from OptionSet.Parse().\n//\n// Examples:\n//  int verbose = 0;\n//  OptionSet p = new OptionSet ()\n//    .Add (\"v\", v => ++verbose)\n//    .Add (\"name=|value=\", v => Console.WriteLine (v));\n//  p.Parse (new string[]{\"-v\", \"--v\", \"/v\", \"-name=A\", \"/name\", \"B\", \"extra\"});\n//\n// The above would parse the argument string array, and would invoke the\n// lambda expression three times, setting `verbose' to 3 when complete.\n// It would also print out \"A\" and \"B\" to standard output.\n// The returned array would contain the string \"extra\".\n//\n// C# 3.0 collection initializers are supported and encouraged:\n//  var p = new OptionSet () {\n//    { \"h|?|help\", v => ShowHelp () },\n//  };\n//\n// System.ComponentModel.TypeConverter is also supported, allowing the use of\n// custom data types in the callback type; TypeConverter.ConvertFromString()\n// is used to convert the value option to an instance of the specified\n// type:\n//\n//  var p = new OptionSet () {\n//    { \"foo=\", (Foo f) => Console.WriteLine (f.ToString ()) },\n//  };\n//\n// Random other tidbits:\n//  - Boolean options (those w/o '=' or ':' in the option format string)\n//    are explicitly enabled if they are followed with '+', and explicitly\n//    disabled if they are followed with '-':\n//      string a = null;\n//      var p = new OptionSet () {\n//        { \"a\", s => a = s },\n//      };\n//      p.Parse (new string[]{\"-a\"});   // sets v != null\n//      p.Parse (new string[]{\"-a+\"});  // sets v != null\n//      p.Parse (new string[]{\"-a-\"});  // sets v == null\n//\n\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.ComponentModel;\nusing System.Globalization;\nusing System.IO;\nusing System.Runtime.Serialization;\nusing System.Security.Permissions;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\n#if LINQ\nusing System.Linq;\n#endif\n\n#if TEST\nusing NDesk.Options;\n#endif\n\n#if NDESK_OPTIONS\nnamespace NDesk.Options\n#else\nnamespace Mono.Options\n#endif\n{\n\tstatic class StringCoda {\n\n\t\tpublic static IEnumerable<string> WrappedLines (string self, params int[] widths)\n\t\t{\n\t\t\tIEnumerable<int> w = widths;\n\t\t\treturn WrappedLines (self, w);\n\t\t}\n\n\t\tpublic static IEnumerable<string> WrappedLines (string self, IEnumerable<int> widths)\n\t\t{\n\t\t\tif (widths == null)\n\t\t\t\tthrow new ArgumentNullException (\"widths\");\n\t\t\treturn CreateWrappedLinesIterator (self, widths);\n\t\t}\n\n\t\tprivate static IEnumerable<string> CreateWrappedLinesIterator (string self, IEnumerable<int> widths)\n\t\t{\n\t\t\tif (string.IsNullOrEmpty (self)) {\n\t\t\t\tyield return string.Empty;\n\t\t\t\tyield break;\n\t\t\t}\n\t\t\tusing (IEnumerator<int> ewidths = widths.GetEnumerator ()) {\n\t\t\t\tbool? hw = null;\n\t\t\t\tint width = GetNextWidth (ewidths, int.MaxValue, ref hw);\n\t\t\t\tint start = 0, end;\n\t\t\t\tdo {\n\t\t\t\t\tend = GetLineEnd (start, width, self);\n\t\t\t\t\tchar c = self [end-1];\n\t\t\t\t\tif (char.IsWhiteSpace (c))\n\t\t\t\t\t\t--end;\n\t\t\t\t\tbool needContinuation = end != self.Length && !IsEolChar (c);\n\t\t\t\t\tstring continuation = \"\";\n\t\t\t\t\tif (needContinuation) {\n\t\t\t\t\t\t--end;\n\t\t\t\t\t\tcontinuation = \"-\";\n\t\t\t\t\t}\n\t\t\t\t\tstring line = self.Substring (start, end - start) + continuation;\n\t\t\t\t\tyield return line;\n\t\t\t\t\tstart = end;\n\t\t\t\t\tif (char.IsWhiteSpace (c))\n\t\t\t\t\t\t++start;\n\t\t\t\t\twidth = GetNextWidth (ewidths, width, ref hw);\n\t\t\t\t} while (start < self.Length);\n\t\t\t}\n\t\t}\n\n\t\tprivate static int GetNextWidth (IEnumerator<int> ewidths, int curWidth, ref bool? eValid)\n\t\t{\n\t\t\tif (!eValid.HasValue || (eValid.HasValue && eValid.Value)) {\n\t\t\t\tcurWidth = (eValid = ewidths.MoveNext ()).Value ? ewidths.Current : curWidth;\n\t\t\t\t// '.' is any character, - is for a continuation\n\t\t\t\tconst string minWidth = \".-\";\n\t\t\t\tif (curWidth < minWidth.Length)\n\t\t\t\t\tthrow new ArgumentOutOfRangeException (\"widths\",\n\t\t\t\t\t\t\tstring.Format (\"Element must be >= {0}, was {1}.\", minWidth.Length, curWidth));\n\t\t\t\treturn curWidth;\n\t\t\t}\n\t\t\t// no more elements, use the last element.\n\t\t\treturn curWidth;\n\t\t}\n\n\t\tprivate static bool IsEolChar (char c)\n\t\t{\n\t\t\treturn !char.IsLetterOrDigit (c);\n\t\t}\n\n\t\tprivate static int GetLineEnd (int start, int length, string description)\n\t\t{\n\t\t\tint end = System.Math.Min (start + length, description.Length);\n\t\t\tint sep = -1;\n\t\t\tfor (int i = start; i < end; ++i) {\n\t\t\t\tif (description [i] == '\\n')\n\t\t\t\t\treturn i+1;\n\t\t\t\tif (IsEolChar (description [i]))\n\t\t\t\t\tsep = i+1;\n\t\t\t}\n\t\t\tif (sep == -1 || end == description.Length)\n\t\t\t\treturn end;\n\t\t\treturn sep;\n\t\t}\n\t}\n\n\tpublic class OptionValueCollection : IList, IList<string> {\n\n\t\tList<string> values = new List<string> ();\n\t\tOptionContext c;\n\n\t\tinternal OptionValueCollection (OptionContext c)\n\t\t{\n\t\t\tthis.c = c;\n\t\t}\n\n\t\t#region ICollection\n\t\tvoid ICollection.CopyTo (Array array, int index)  {(values as ICollection).CopyTo (array, index);}\n\t\tbool ICollection.IsSynchronized                   {get {return (values as ICollection).IsSynchronized;}}\n\t\tobject ICollection.SyncRoot                       {get {return (values as ICollection).SyncRoot;}}\n\t\t#endregion\n\n\t\t#region ICollection<T>\n\t\tpublic void Add (string item)                       {values.Add (item);}\n\t\tpublic void Clear ()                                {values.Clear ();}\n\t\tpublic bool Contains (string item)                  {return values.Contains (item);}\n\t\tpublic void CopyTo (string[] array, int arrayIndex) {values.CopyTo (array, arrayIndex);}\n\t\tpublic bool Remove (string item)                    {return values.Remove (item);}\n\t\tpublic int Count                                    {get {return values.Count;}}\n\t\tpublic bool IsReadOnly                              {get {return false;}}\n\t\t#endregion\n\n\t\t#region IEnumerable\n\t\tIEnumerator IEnumerable.GetEnumerator () {return values.GetEnumerator ();}\n\t\t#endregion\n\n\t\t#region IEnumerable<T>\n\t\tpublic IEnumerator<string> GetEnumerator () {return values.GetEnumerator ();}\n\t\t#endregion\n\n\t\t#region IList\n\t\tint IList.Add (object value)                {return (values as IList).Add (value);}\n\t\tbool IList.Contains (object value)          {return (values as IList).Contains (value);}\n\t\tint IList.IndexOf (object value)            {return (values as IList).IndexOf (value);}\n\t\tvoid IList.Insert (int index, object value) {(values as IList).Insert (index, value);}\n\t\tvoid IList.Remove (object value)            {(values as IList).Remove (value);}\n\t\tvoid IList.RemoveAt (int index)             {(values as IList).RemoveAt (index);}\n\t\tbool IList.IsFixedSize                      {get {return false;}}\n\t\tobject IList.this [int index]               {get {return this [index];} set {(values as IList)[index] = value;}}\n\t\t#endregion\n\n\t\t#region IList<T>\n\t\tpublic int IndexOf (string item)            {return values.IndexOf (item);}\n\t\tpublic void Insert (int index, string item) {values.Insert (index, item);}\n\t\tpublic void RemoveAt (int index)            {values.RemoveAt (index);}\n\n\t\tprivate void AssertValid (int index)\n\t\t{\n\t\t\tif (c.Option == null)\n\t\t\t\tthrow new InvalidOperationException (\"OptionContext.Option is null.\");\n\t\t\tif (index >= c.Option.MaxValueCount)\n\t\t\t\tthrow new ArgumentOutOfRangeException (\"index\");\n\t\t\tif (c.Option.OptionValueType == OptionValueType.Required &&\n\t\t\t\t\tindex >= values.Count)\n\t\t\t\tthrow new OptionException (string.Format (\n\t\t\t\t\t\t\tc.OptionSet.MessageLocalizer (\"Missing required value for option '{0}'.\"), c.OptionName),\n\t\t\t\t\t\tc.OptionName);\n\t\t}\n\n\t\tpublic string this [int index] {\n\t\t\tget {\n\t\t\t\tAssertValid (index);\n\t\t\t\treturn index >= values.Count ? null : values [index];\n\t\t\t}\n\t\t\tset {\n\t\t\t\tvalues [index] = value;\n\t\t\t}\n\t\t}\n\t\t#endregion\n\n\t\tpublic List<string> ToList ()\n\t\t{\n\t\t\treturn new List<string> (values);\n\t\t}\n\n\t\tpublic string[] ToArray ()\n\t\t{\n\t\t\treturn values.ToArray ();\n\t\t}\n\n\t\tpublic override string ToString ()\n\t\t{\n\t\t\treturn string.Join (\", \", values.ToArray ());\n\t\t}\n\t}\n\n\tpublic class OptionContext {\n\t\tprivate Option                option;\n\t\tprivate string                name;\n\t\tprivate int                   index;\n\t\tprivate OptionSet             set;\n\t\tprivate OptionValueCollection c;\n\n\t\tpublic OptionContext (OptionSet set)\n\t\t{\n\t\t\tthis.set = set;\n\t\t\tthis.c   = new OptionValueCollection (this);\n\t\t}\n\n\t\tpublic Option Option {\n\t\t\tget {return option;}\n\t\t\tset {option = value;}\n\t\t}\n\n\t\tpublic string OptionName {\n\t\t\tget {return name;}\n\t\t\tset {name = value;}\n\t\t}\n\n\t\tpublic int OptionIndex {\n\t\t\tget {return index;}\n\t\t\tset {index = value;}\n\t\t}\n\n\t\tpublic OptionSet OptionSet {\n\t\t\tget {return set;}\n\t\t}\n\n\t\tpublic OptionValueCollection OptionValues {\n\t\t\tget {return c;}\n\t\t}\n\t}\n\n\tpublic enum OptionValueType {\n\t\tNone,\n\t\tOptional,\n\t\tRequired,\n\t}\n\n\tpublic abstract class Option {\n\t\tstring prototype, description;\n\t\tstring[] names;\n\t\tOptionValueType type;\n\t\tint count;\n\t\tstring[] separators;\n\t\tbool hidden;\n\n\t\tprotected Option (string prototype, string description)\n\t\t\t: this (prototype, description, 1, false)\n\t\t{\n\t\t}\n\n\t\tprotected Option (string prototype, string description, int maxValueCount)\n\t\t\t: this (prototype, description, maxValueCount, false)\n\t\t{\n\t\t}\n\n\t\tprotected Option (string prototype, string description, int maxValueCount, bool hidden)\n\t\t{\n\t\t\tif (prototype == null)\n\t\t\t\tthrow new ArgumentNullException (\"prototype\");\n\t\t\tif (prototype.Length == 0)\n\t\t\t\tthrow new ArgumentException (\"Cannot be the empty string.\", \"prototype\");\n\t\t\tif (maxValueCount < 0)\n\t\t\t\tthrow new ArgumentOutOfRangeException (\"maxValueCount\");\n\n\t\t\tthis.prototype   = prototype;\n\t\t\tthis.description = description;\n\t\t\tthis.count       = maxValueCount;\n\t\t\tthis.names       = (this is OptionSet.Category)\n\t\t\t\t// append GetHashCode() so that \"duplicate\" categories have distinct\n\t\t\t\t// names, e.g. adding multiple \"\" categories should be valid.\n\t\t\t\t? new[]{prototype + this.GetHashCode ()}\n\t\t\t\t: prototype.Split ('|');\n\n\t\t\tif (this is OptionSet.Category)\n\t\t\t\treturn;\n\n\t\t\tthis.type        = ParsePrototype ();\n\t\t\tthis.hidden      = hidden;\n\n\t\t\tif (this.count == 0 && type != OptionValueType.None)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\"Cannot provide maxValueCount of 0 for OptionValueType.Required or \" +\n\t\t\t\t\t\t\t\"OptionValueType.Optional.\",\n\t\t\t\t\t\t\"maxValueCount\");\n\t\t\tif (this.type == OptionValueType.None && maxValueCount > 1)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Cannot provide maxValueCount of {0} for OptionValueType.None.\", maxValueCount),\n\t\t\t\t\t\t\"maxValueCount\");\n\t\t\tif (Array.IndexOf (names, \"<>\") >= 0 &&\n\t\t\t\t\t((names.Length == 1 && this.type != OptionValueType.None) ||\n\t\t\t\t\t (names.Length > 1 && this.MaxValueCount > 1)))\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\"The default option handler '<>' cannot require values.\",\n\t\t\t\t\t\t\"prototype\");\n\t\t}\n\n\t\tpublic string           Prototype       {get {return prototype;}}\n\t\tpublic string           Description     {get {return description;}}\n\t\tpublic OptionValueType  OptionValueType {get {return type;}}\n\t\tpublic int              MaxValueCount   {get {return count;}}\n\t\tpublic bool             Hidden          {get {return hidden;}}\n\n\t\tpublic string[] GetNames ()\n\t\t{\n\t\t\treturn (string[]) names.Clone ();\n\t\t}\n\n\t\tpublic string[] GetValueSeparators ()\n\t\t{\n\t\t\tif (separators == null)\n\t\t\t\treturn new string [0];\n\t\t\treturn (string[]) separators.Clone ();\n\t\t}\n\n\t\tprotected static T Parse<T> (string value, OptionContext c)\n\t\t{\n\t\t\tType tt = typeof (T);\n\t\t\tbool nullable = tt.IsValueType && tt.IsGenericType &&\n\t\t\t\t!tt.IsGenericTypeDefinition &&\n\t\t\t\ttt.GetGenericTypeDefinition () == typeof (Nullable<>);\n\t\t\tType targetType = nullable ? tt.GetGenericArguments () [0] : typeof (T);\n\t\t\tTypeConverter conv = TypeDescriptor.GetConverter (targetType);\n\t\t\tT t = default (T);\n\t\t\ttry {\n\t\t\t\tif (value != null)\n\t\t\t\t\tt = (T) conv.ConvertFromString (value);\n\t\t\t}\n\t\t\tcatch (Exception e) {\n\t\t\t\tthrow new OptionException (\n\t\t\t\t\t\tstring.Format (\n\t\t\t\t\t\t\tc.OptionSet.MessageLocalizer (\"Could not convert string `{0}' to type {1} for option `{2}'.\"),\n\t\t\t\t\t\t\tvalue, targetType.Name, c.OptionName),\n\t\t\t\t\t\tc.OptionName, e);\n\t\t\t}\n\t\t\treturn t;\n\t\t}\n\n\t\tinternal string[] Names           {get {return names;}}\n\t\tinternal string[] ValueSeparators {get {return separators;}}\n\n\t\tstatic readonly char[] NameTerminator = new char[]{'=', ':'};\n\n\t\tprivate OptionValueType ParsePrototype ()\n\t\t{\n\t\t\tchar type = '\\0';\n\t\t\tList<string> seps = new List<string> ();\n\t\t\tfor (int i = 0; i < names.Length; ++i) {\n\t\t\t\tstring name = names [i];\n\t\t\t\tif (name.Length == 0)\n\t\t\t\t\tthrow new ArgumentException (\"Empty option names are not supported.\", \"prototype\");\n\n\t\t\t\tint end = name.IndexOfAny (NameTerminator);\n\t\t\t\tif (end == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\tnames [i] = name.Substring (0, end);\n\t\t\t\tif (type == '\\0' || type == name [end])\n\t\t\t\t\ttype = name [end];\n\t\t\t\telse\n\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\tstring.Format (\"Conflicting option types: '{0}' vs. '{1}'.\", type, name [end]),\n\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\tAddSeparators (name, end, seps);\n\t\t\t}\n\n\t\t\tif (type == '\\0')\n\t\t\t\treturn OptionValueType.None;\n\n\t\t\tif (count <= 1 && seps.Count != 0)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Cannot provide key/value separators for Options taking {0} value(s).\", count),\n\t\t\t\t\t\t\"prototype\");\n\t\t\tif (count > 1) {\n\t\t\t\tif (seps.Count == 0)\n\t\t\t\t\tthis.separators = new string[]{\":\", \"=\"};\n\t\t\t\telse if (seps.Count == 1 && seps [0].Length == 0)\n\t\t\t\t\tthis.separators = null;\n\t\t\t\telse\n\t\t\t\t\tthis.separators = seps.ToArray ();\n\t\t\t}\n\n\t\t\treturn type == '=' ? OptionValueType.Required : OptionValueType.Optional;\n\t\t}\n\n\t\tprivate static void AddSeparators (string name, int end, ICollection<string> seps)\n\t\t{\n\t\t\tint start = -1;\n\t\t\tfor (int i = end+1; i < name.Length; ++i) {\n\t\t\t\tswitch (name [i]) {\n\t\t\t\t\tcase '{':\n\t\t\t\t\t\tif (start != -1)\n\t\t\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\t\t\tstart = i+1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '}':\n\t\t\t\t\t\tif (start == -1)\n\t\t\t\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\t\t\t\"prototype\");\n\t\t\t\t\t\tseps.Add (name.Substring (start, i-start));\n\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (start == -1)\n\t\t\t\t\t\t\tseps.Add (name [i].ToString ());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (start != -1)\n\t\t\t\tthrow new ArgumentException (\n\t\t\t\t\t\tstring.Format (\"Ill-formed name/value separator found in \\\"{0}\\\".\", name),\n\t\t\t\t\t\t\"prototype\");\n\t\t}\n\n\t\tpublic void Invoke (OptionContext c)\n\t\t{\n\t\t\tOnParseComplete (c);\n\t\t\tc.OptionName  = null;\n\t\t\tc.Option      = null;\n\t\t\tc.OptionValues.Clear ();\n\t\t}\n\n\t\tprotected abstract void OnParseComplete (OptionContext c);\n\n\t\tpublic override string ToString ()\n\t\t{\n\t\t\treturn Prototype;\n\t\t}\n\t}\n\n\tpublic abstract class ArgumentSource {\n\n\t\tprotected ArgumentSource ()\n\t\t{\n\t\t}\n\n\t\tpublic abstract string[] GetNames ();\n\t\tpublic abstract string Description { get; }\n\t\tpublic abstract bool GetArguments (string value, out IEnumerable<string> replacement);\n\n\t\tpublic static IEnumerable<string> GetArgumentsFromFile (string file)\n\t\t{\n\t\t\treturn GetArguments (File.OpenText (file), true);\n\t\t}\n\n\t\tpublic static IEnumerable<string> GetArguments (TextReader reader)\n\t\t{\n\t\t\treturn GetArguments (reader, false);\n\t\t}\n\n\t\t// Cribbed from mcs/driver.cs:LoadArgs(string)\n\t\tstatic IEnumerable<string> GetArguments (TextReader reader, bool close)\n\t\t{\n\t\t\ttry {\n\t\t\t\tStringBuilder arg = new StringBuilder ();\n\n\t\t\t\tstring line;\n\t\t\t\twhile ((line = reader.ReadLine ()) != null) {\n\t\t\t\t\tint t = line.Length;\n\n\t\t\t\t\tfor (int i = 0; i < t; i++) {\n\t\t\t\t\t\tchar c = line [i];\n\n\t\t\t\t\t\tif (c == '\"' || c == '\\'') {\n\t\t\t\t\t\t\tchar end = c;\n\n\t\t\t\t\t\t\tfor (i++; i < t; i++){\n\t\t\t\t\t\t\t\tc = line [i];\n\n\t\t\t\t\t\t\t\tif (c == end)\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\targ.Append (c);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (c == ' ') {\n\t\t\t\t\t\t\tif (arg.Length > 0) {\n\t\t\t\t\t\t\t\tyield return arg.ToString ();\n\t\t\t\t\t\t\t\targ.Length = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\targ.Append (c);\n\t\t\t\t\t}\n\t\t\t\t\tif (arg.Length > 0) {\n\t\t\t\t\t\tyield return arg.ToString ();\n\t\t\t\t\t\targ.Length = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (close)\n\t\t\t\t\treader.Close ();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic class ResponseFileSource : ArgumentSource {\n\n\t\tpublic override string[] GetNames ()\n\t\t{\n\t\t\treturn new string[]{\"@file\"};\n\t\t}\n\n\t\tpublic override string Description {\n\t\t\tget {return \"Read response file for more options.\";}\n\t\t}\n\n\t\tpublic override bool GetArguments (string value, out IEnumerable<string> replacement)\n\t\t{\n\t\t\tif (string.IsNullOrEmpty (value) || !value.StartsWith (\"@\")) {\n\t\t\t\treplacement = null;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treplacement = ArgumentSource.GetArgumentsFromFile (value.Substring (1));\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t[Serializable]\n\tpublic class OptionException : Exception {\n\t\tprivate string option;\n\n\t\tpublic OptionException ()\n\t\t{\n\t\t}\n\n\t\tpublic OptionException (string message, string optionName)\n\t\t\t: base (message)\n\t\t{\n\t\t\tthis.option = optionName;\n\t\t}\n\n\t\tpublic OptionException (string message, string optionName, Exception innerException)\n\t\t\t: base (message, innerException)\n\t\t{\n\t\t\tthis.option = optionName;\n\t\t}\n\n\t\tprotected OptionException (SerializationInfo info, StreamingContext context)\n\t\t\t: base (info, context)\n\t\t{\n\t\t\tthis.option = info.GetString (\"OptionName\");\n\t\t}\n\n\t\tpublic string OptionName {\n\t\t\tget {return this.option;}\n\t\t}\n\n\t\t[SecurityPermission (SecurityAction.LinkDemand, SerializationFormatter = true)]\n\t\tpublic override void GetObjectData (SerializationInfo info, StreamingContext context)\n\t\t{\n\t\t\tbase.GetObjectData (info, context);\n\t\t\tinfo.AddValue (\"OptionName\", option);\n\t\t}\n\t}\n\n\tpublic delegate void OptionAction<TKey, TValue> (TKey key, TValue value);\n\n\tpublic class OptionSet : KeyedCollection<string, Option>\n\t{\n\t\tpublic OptionSet ()\n\t\t\t: this (delegate (string f) {return f;})\n\t\t{\n\t\t}\n\n\t\tpublic OptionSet (Converter<string, string> localizer)\n\t\t{\n\t\t\tthis.localizer = localizer;\n\t\t\tthis.roSources = new ReadOnlyCollection<ArgumentSource>(sources);\n\t\t}\n\n\t\tConverter<string, string> localizer;\n\n\t\tpublic Converter<string, string> MessageLocalizer {\n\t\t\tget {return localizer;}\n\t\t}\n\n\t\tList<ArgumentSource> sources = new List<ArgumentSource> ();\n\t\tReadOnlyCollection<ArgumentSource> roSources;\n\n\t\tpublic ReadOnlyCollection<ArgumentSource> ArgumentSources {\n\t\t\tget {return roSources;}\n\t\t}\n\n\n\t\tprotected override string GetKeyForItem (Option item)\n\t\t{\n\t\t\tif (item == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\tif (item.Names != null && item.Names.Length > 0)\n\t\t\t\treturn item.Names [0];\n\t\t\t// This should never happen, as it's invalid for Option to be\n\t\t\t// constructed w/o any names.\n\t\t\tthrow new InvalidOperationException (\"Option has no names!\");\n\t\t}\n\n\t\t[Obsolete (\"Use KeyedCollection.this[string]\")]\n\t\tprotected Option GetOptionForName (string option)\n\t\t{\n\t\t\tif (option == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\ttry {\n\t\t\t\treturn base [option];\n\t\t\t}\n\t\t\tcatch (KeyNotFoundException) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprotected override void InsertItem (int index, Option item)\n\t\t{\n\t\t\tbase.InsertItem (index, item);\n\t\t\tAddImpl (item);\n\t\t}\n\n\t\tprotected override void RemoveItem (int index)\n\t\t{\n\t\t\tOption p = Items [index];\n\t\t\tbase.RemoveItem (index);\n\t\t\t// KeyedCollection.RemoveItem() handles the 0th item\n\t\t\tfor (int i = 1; i < p.Names.Length; ++i) {\n\t\t\t\tDictionary.Remove (p.Names [i]);\n\t\t\t}\n\t\t}\n\n\t\tprotected override void SetItem (int index, Option item)\n\t\t{\n\t\t\tbase.SetItem (index, item);\n\t\t\tAddImpl (item);\n\t\t}\n\n\t\tprivate void AddImpl (Option option)\n\t\t{\n\t\t\tif (option == null)\n\t\t\t\tthrow new ArgumentNullException (\"option\");\n\t\t\tList<string> added = new List<string> (option.Names.Length);\n\t\t\ttry {\n\t\t\t\t// KeyedCollection.InsertItem/SetItem handle the 0th name.\n\t\t\t\tfor (int i = 1; i < option.Names.Length; ++i) {\n\t\t\t\t\tDictionary.Add (option.Names [i], option);\n\t\t\t\t\tadded.Add (option.Names [i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception) {\n\t\t\t\tforeach (string name in added)\n\t\t\t\t\tDictionary.Remove (name);\n\t\t\t\tthrow;\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add (string header)\n\t\t{\n\t\t\tif (header == null)\n\t\t\t\tthrow new ArgumentNullException (\"header\");\n\t\t\tAdd (new Category (header));\n\t\t\treturn this;\n\t\t}\n\n\t\tinternal sealed class Category : Option {\n\n\t\t\t// Prototype starts with '=' because this is an invalid prototype\n\t\t\t// (see Option.ParsePrototype(), and thus it'll prevent Category\n\t\t\t// instances from being accidentally used as normal options.\n\t\t\tpublic Category (string description)\n\t\t\t\t: base (\"=:Category:= \" + description, description)\n\t\t\t{\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\tthrow new NotSupportedException (\"Category.OnParseComplete should not be invoked.\");\n\t\t\t}\n\t\t}\n\n\n\t\tpublic new OptionSet Add (Option option)\n\t\t{\n\t\t\tbase.Add (option);\n\t\t\treturn this;\n\t\t}\n\n\t\tsealed class ActionOption : Option {\n\t\t\tAction<OptionValueCollection> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, int count, Action<OptionValueCollection> action)\n\t\t\t\t: this (prototype, description, count, action, false)\n\t\t\t{\n\t\t\t}\n\n\t\t\tpublic ActionOption (string prototype, string description, int count, Action<OptionValueCollection> action, bool hidden)\n\t\t\t\t: base (prototype, description, count, hidden)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (c.OptionValues);\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, Action<string> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, Action<string> action)\n\t\t{\n\t\t\treturn Add (prototype, description, action, false);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, Action<string> action, bool hidden)\n\t\t{\n\t\t\tif (action == null)\n\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\tOption p = new ActionOption (prototype, description, 1,\n\t\t\t\t\tdelegate (OptionValueCollection v) { action (v [0]); }, hidden);\n\t\t\tbase.Add (p);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, OptionAction<string, string> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, OptionAction<string, string> action)\n\t\t{\n\t\t\treturn Add (prototype, description, action, false);\n\t\t}\n\n\t\tpublic OptionSet Add (string prototype, string description, OptionAction<string, string> action, bool hidden)\t{\n\t\t\tif (action == null)\n\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\tOption p = new ActionOption (prototype, description, 2,\n\t\t\t\t\tdelegate (OptionValueCollection v) {action (v [0], v [1]);}, hidden);\n\t\t\tbase.Add (p);\n\t\t\treturn this;\n\t\t}\n\n\t\tsealed class ActionOption<T> : Option {\n\t\t\tAction<T> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, Action<T> action)\n\t\t\t\t: base (prototype, description, 1)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (Parse<T> (c.OptionValues [0], c));\n\t\t\t}\n\t\t}\n\n\t\tsealed class ActionOption<TKey, TValue> : Option {\n\t\t\tOptionAction<TKey, TValue> action;\n\n\t\t\tpublic ActionOption (string prototype, string description, OptionAction<TKey, TValue> action)\n\t\t\t\t: base (prototype, description, 2)\n\t\t\t{\n\t\t\t\tif (action == null)\n\t\t\t\t\tthrow new ArgumentNullException (\"action\");\n\t\t\t\tthis.action = action;\n\t\t\t}\n\n\t\t\tprotected override void OnParseComplete (OptionContext c)\n\t\t\t{\n\t\t\t\taction (\n\t\t\t\t\t\tParse<TKey> (c.OptionValues [0], c),\n\t\t\t\t\t\tParse<TValue> (c.OptionValues [1], c));\n\t\t\t}\n\t\t}\n\n\t\tpublic OptionSet Add<T> (string prototype, Action<T> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add<T> (string prototype, string description, Action<T> action)\n\t\t{\n\t\t\treturn Add (new ActionOption<T> (prototype, description, action));\n\t\t}\n\n\t\tpublic OptionSet Add<TKey, TValue> (string prototype, OptionAction<TKey, TValue> action)\n\t\t{\n\t\t\treturn Add (prototype, null, action);\n\t\t}\n\n\t\tpublic OptionSet Add<TKey, TValue> (string prototype, string description, OptionAction<TKey, TValue> action)\n\t\t{\n\t\t\treturn Add (new ActionOption<TKey, TValue> (prototype, description, action));\n\t\t}\n\n\t\tpublic OptionSet Add (ArgumentSource source)\n\t\t{\n\t\t\tif (source == null)\n\t\t\t\tthrow new ArgumentNullException (\"source\");\n\t\t\tsources.Add (source);\n\t\t\treturn this;\n\t\t}\n\n\t\tprotected virtual OptionContext CreateOptionContext ()\n\t\t{\n\t\t\treturn new OptionContext (this);\n\t\t}\n\n\t\tpublic List<string> Parse (IEnumerable<string> arguments)\n\t\t{\n\t\t\tif (arguments == null)\n\t\t\t\tthrow new ArgumentNullException (\"arguments\");\n\t\t\tOptionContext c = CreateOptionContext ();\n\t\t\tc.OptionIndex = -1;\n\t\t\tbool process = true;\n\t\t\tList<string> unprocessed = new List<string> ();\n\t\t\tOption def = Contains (\"<>\") ? this [\"<>\"] : null;\n\t\t\tArgumentEnumerator ae = new ArgumentEnumerator (arguments);\n\t\t\tforeach (string argument in ae) {\n\t\t\t\t++c.OptionIndex;\n\t\t\t\tif (argument == \"--\") {\n\t\t\t\t\tprocess = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!process) {\n\t\t\t\t\tUnprocessed (unprocessed, def, c, argument);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (AddSource (ae, argument))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (!Parse (argument, c))\n\t\t\t\t\tUnprocessed (unprocessed, def, c, argument);\n\t\t\t}\n\t\t\tif (c.Option != null)\n\t\t\t\tc.Option.Invoke (c);\n\t\t\treturn unprocessed;\n\t\t}\n\n\t\tclass ArgumentEnumerator : IEnumerable<string> {\n\t\t\tList<IEnumerator<string>> sources = new List<IEnumerator<string>> ();\n\n\t\t\tpublic ArgumentEnumerator (IEnumerable<string> arguments)\n\t\t\t{\n\t\t\t\tsources.Add (arguments.GetEnumerator ());\n\t\t\t}\n\n\t\t\tpublic void Add (IEnumerable<string> arguments)\n\t\t\t{\n\t\t\t\tsources.Add (arguments.GetEnumerator ());\n\t\t\t}\n\n\t\t\tpublic IEnumerator<string> GetEnumerator ()\n\t\t\t{\n\t\t\t\tdo {\n\t\t\t\t\tIEnumerator<string> c = sources [sources.Count-1];\n\t\t\t\t\tif (c.MoveNext ())\n\t\t\t\t\t\tyield return c.Current;\n\t\t\t\t\telse {\n\t\t\t\t\t\tc.Dispose ();\n\t\t\t\t\t\tsources.RemoveAt (sources.Count-1);\n\t\t\t\t\t}\n\t\t\t\t} while (sources.Count > 0);\n\t\t\t}\n\n\t\t\tIEnumerator IEnumerable.GetEnumerator ()\n\t\t\t{\n\t\t\t\treturn GetEnumerator ();\n\t\t\t}\n\t\t}\n\n\t\tbool AddSource (ArgumentEnumerator ae, string argument)\n\t\t{\n\t\t\tforeach (ArgumentSource source in sources) {\n\t\t\t\tIEnumerable<string> replacement;\n\t\t\t\tif (!source.GetArguments (argument, out replacement))\n\t\t\t\t\tcontinue;\n\t\t\t\tae.Add (replacement);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate static bool Unprocessed (ICollection<string> extra, Option def, OptionContext c, string argument)\n\t\t{\n\t\t\tif (def == null) {\n\t\t\t\textra.Add (argument);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tc.OptionValues.Add (argument);\n\t\t\tc.Option = def;\n\t\t\tc.Option.Invoke (c);\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate readonly Regex ValueOption = new Regex (\n\t\t\t@\"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$\");\n\n\t\tprotected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)\n\t\t{\n\t\t\tif (argument == null)\n\t\t\t\tthrow new ArgumentNullException (\"argument\");\n\n\t\t\tflag = name = sep = value = null;\n\t\t\tMatch m = ValueOption.Match (argument);\n\t\t\tif (!m.Success) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tflag  = m.Groups [\"flag\"].Value;\n\t\t\tname  = m.Groups [\"name\"].Value;\n\t\t\tif (m.Groups [\"sep\"].Success && m.Groups [\"value\"].Success) {\n\t\t\t\tsep   = m.Groups [\"sep\"].Value;\n\t\t\t\tvalue = m.Groups [\"value\"].Value;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprotected virtual bool Parse (string argument, OptionContext c)\n\t\t{\n\t\t\tif (c.Option != null) {\n\t\t\t\tParseValue (argument, c);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tstring f, n, s, v;\n\t\t\tif (!GetOptionParts (argument, out f, out n, out s, out v))\n\t\t\t\treturn false;\n\n\t\t\tOption p;\n\t\t\tif (Contains (n)) {\n\t\t\t\tp = this [n];\n\t\t\t\tc.OptionName = f + n;\n\t\t\t\tc.Option     = p;\n\t\t\t\tswitch (p.OptionValueType) {\n\t\t\t\t\tcase OptionValueType.None:\n\t\t\t\t\t\tc.OptionValues.Add (n);\n\t\t\t\t\t\tc.Option.Invoke (c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase OptionValueType.Optional:\n\t\t\t\t\tcase OptionValueType.Required:\n\t\t\t\t\t\tParseValue (v, c);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// no match; is it a bool option?\n\t\t\tif (ParseBool (argument, n, c))\n\t\t\t\treturn true;\n\t\t\t// is it a bundled option?\n\t\t\tif (ParseBundledValue (f, string.Concat (n + s + v), c))\n\t\t\t\treturn true;\n\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void ParseValue (string option, OptionContext c)\n\t\t{\n\t\t\tif (option != null)\n\t\t\t\tforeach (string o in c.Option.ValueSeparators != null\n\t\t\t\t\t\t? option.Split (c.Option.ValueSeparators, c.Option.MaxValueCount - c.OptionValues.Count, StringSplitOptions.None)\n\t\t\t\t\t\t: new string[]{option}) {\n\t\t\t\t\tc.OptionValues.Add (o);\n\t\t\t\t}\n\t\t\tif (c.OptionValues.Count == c.Option.MaxValueCount ||\n\t\t\t\t\tc.Option.OptionValueType == OptionValueType.Optional)\n\t\t\t\tc.Option.Invoke (c);\n\t\t\telse if (c.OptionValues.Count > c.Option.MaxValueCount) {\n\t\t\t\tthrow new OptionException (localizer (string.Format (\n\t\t\t\t\t\t\t\t\"Error: Found {0} option values when expecting {1}.\",\n\t\t\t\t\t\t\t\tc.OptionValues.Count, c.Option.MaxValueCount)),\n\t\t\t\t\t\tc.OptionName);\n\t\t\t}\n\t\t}\n\n\t\tprivate bool ParseBool (string option, string n, OptionContext c)\n\t\t{\n\t\t\tOption p;\n\t\t\tstring rn;\n\t\t\tif (n.Length >= 1 && (n [n.Length-1] == '+' || n [n.Length-1] == '-') &&\n\t\t\t\t\tContains ((rn = n.Substring (0, n.Length-1)))) {\n\t\t\t\tp = this [rn];\n\t\t\t\tstring v = n [n.Length-1] == '+' ? option : null;\n\t\t\t\tc.OptionName  = option;\n\t\t\t\tc.Option      = p;\n\t\t\t\tc.OptionValues.Add (v);\n\t\t\t\tp.Invoke (c);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate bool ParseBundledValue (string f, string n, OptionContext c)\n\t\t{\n\t\t\tif (f != \"-\")\n\t\t\t\treturn false;\n\t\t\tfor (int i = 0; i < n.Length; ++i) {\n\t\t\t\tOption p;\n\t\t\t\tstring opt = f + n [i].ToString ();\n\t\t\t\tstring rn = n [i].ToString ();\n\t\t\t\tif (!Contains (rn)) {\n\t\t\t\t\tif (i == 0)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tthrow new OptionException (string.Format (localizer (\n\t\t\t\t\t\t\t\t\t\"Cannot bundle unregistered option '{0}'.\"), opt), opt);\n\t\t\t\t}\n\t\t\t\tp = this [rn];\n\t\t\t\tswitch (p.OptionValueType) {\n\t\t\t\t\tcase OptionValueType.None:\n\t\t\t\t\t\tInvoke (c, opt, n, p);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase OptionValueType.Optional:\n\t\t\t\t\tcase OptionValueType.Required: {\n\t\t\t\t\t\tstring v     = n.Substring (i+1);\n\t\t\t\t\t\tc.Option     = p;\n\t\t\t\t\t\tc.OptionName = opt;\n\t\t\t\t\t\tParseValue (v.Length != 0 ? v : null, c);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new InvalidOperationException (\"Unknown OptionValueType: \" + p.OptionValueType);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate static void Invoke (OptionContext c, string name, string value, Option option)\n\t\t{\n\t\t\tc.OptionName  = name;\n\t\t\tc.Option      = option;\n\t\t\tc.OptionValues.Add (value);\n\t\t\toption.Invoke (c);\n\t\t}\n\n\t\tprivate const int OptionWidth = 29;\n\t\tprivate const int Description_FirstWidth  = 80 - OptionWidth;\n\t\tprivate const int Description_RemWidth    = 80 - OptionWidth - 2;\n\n\t\tpublic void WriteOptionDescriptions (TextWriter o)\n\t\t{\n\t\t\tforeach (Option p in this) {\n\t\t\t\tint written = 0;\n\n\t\t\t\tif (p.Hidden)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tCategory c = p as Category;\n\t\t\t\tif (c != null) {\n\t\t\t\t\tWriteDescription (o, p.Description, \"\", 80, 80);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!WriteOptionPrototype (o, p, ref written))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (written < OptionWidth)\n\t\t\t\t\to.Write (new string (' ', OptionWidth - written));\n\t\t\t\telse {\n\t\t\t\t\to.WriteLine ();\n\t\t\t\t\to.Write (new string (' ', OptionWidth));\n\t\t\t\t}\n\n\t\t\t\tWriteDescription (o, p.Description, new string (' ', OptionWidth+2),\n\t\t\t\t\t\tDescription_FirstWidth, Description_RemWidth);\n\t\t\t}\n\n\t\t\tforeach (ArgumentSource s in sources) {\n\t\t\t\tstring[] names = s.GetNames ();\n\t\t\t\tif (names == null || names.Length == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tint written = 0;\n\n\t\t\t\tWrite (o, ref written, \"  \");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t\tfor (int i = 1; i < names.Length; ++i) {\n\t\t\t\t\tWrite (o, ref written, \", \");\n\t\t\t\t\tWrite (o, ref written, names [i]);\n\t\t\t\t}\n\n\t\t\t\tif (written < OptionWidth)\n\t\t\t\t\to.Write (new string (' ', OptionWidth - written));\n\t\t\t\telse {\n\t\t\t\t\to.WriteLine ();\n\t\t\t\t\to.Write (new string (' ', OptionWidth));\n\t\t\t\t}\n\n\t\t\t\tWriteDescription (o, s.Description, new string (' ', OptionWidth+2),\n\t\t\t\t\t\tDescription_FirstWidth, Description_RemWidth);\n\t\t\t}\n\t\t}\n\n\t\tvoid WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth)\n\t\t{\n\t\t\tbool indent = false;\n\t\t\tforeach (string line in GetLines (localizer (GetDescription (value)), firstWidth, remWidth)) {\n\t\t\t\tif (indent)\n\t\t\t\t\to.Write (prefix);\n\t\t\t\to.WriteLine (line);\n\t\t\t\tindent = true;\n\t\t\t}\n\t\t}\n\n\t\tbool WriteOptionPrototype (TextWriter o, Option p, ref int written)\n\t\t{\n\t\t\tstring[] names = p.Names;\n\n\t\t\tint i = GetNextOptionIndex (names, 0);\n\t\t\tif (i == names.Length)\n\t\t\t\treturn false;\n\n\t\t\tif (names [i].Length == 1) {\n\t\t\t\tWrite (o, ref written, \"  -\");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tWrite (o, ref written, \"      --\");\n\t\t\t\tWrite (o, ref written, names [0]);\n\t\t\t}\n\n\t\t\tfor ( i = GetNextOptionIndex (names, i+1);\n\t\t\t\t\ti < names.Length; i = GetNextOptionIndex (names, i+1)) {\n\t\t\t\tWrite (o, ref written, \", \");\n\t\t\t\tWrite (o, ref written, names [i].Length == 1 ? \"-\" : \"--\");\n\t\t\t\tWrite (o, ref written, names [i]);\n\t\t\t}\n\n\t\t\tif (p.OptionValueType == OptionValueType.Optional ||\n\t\t\t\t\tp.OptionValueType == OptionValueType.Required) {\n\t\t\t\tif (p.OptionValueType == OptionValueType.Optional) {\n\t\t\t\t\tWrite (o, ref written, localizer (\"[\"));\n\t\t\t\t}\n\t\t\t\tWrite (o, ref written, localizer (\"=\" + GetArgumentName (0, p.MaxValueCount, p.Description)));\n\t\t\t\tstring sep = p.ValueSeparators != null && p.ValueSeparators.Length > 0\n\t\t\t\t\t? p.ValueSeparators [0]\n\t\t\t\t\t: \" \";\n\t\t\t\tfor (int c = 1; c < p.MaxValueCount; ++c) {\n\t\t\t\t\tWrite (o, ref written, localizer (sep + GetArgumentName (c, p.MaxValueCount, p.Description)));\n\t\t\t\t}\n\t\t\t\tif (p.OptionValueType == OptionValueType.Optional) {\n\t\t\t\t\tWrite (o, ref written, localizer (\"]\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tstatic int GetNextOptionIndex (string[] names, int i)\n\t\t{\n\t\t\twhile (i < names.Length && names [i] == \"<>\") {\n\t\t\t\t++i;\n\t\t\t}\n\t\t\treturn i;\n\t\t}\n\n\t\tstatic void Write (TextWriter o, ref int n, string s)\n\t\t{\n\t\t\tn += s.Length;\n\t\t\to.Write (s);\n\t\t}\n\n\t\tprivate static string GetArgumentName (int index, int maxIndex, string description)\n\t\t{\n\t\t\tif (description == null)\n\t\t\t\treturn maxIndex == 1 ? \"VALUE\" : \"VALUE\" + (index + 1);\n\t\t\tstring[] nameStart;\n\t\t\tif (maxIndex == 1)\n\t\t\t\tnameStart = new string[]{\"{0:\", \"{\"};\n\t\t\telse\n\t\t\t\tnameStart = new string[]{\"{\" + index + \":\"};\n\t\t\tfor (int i = 0; i < nameStart.Length; ++i) {\n\t\t\t\tint start, j = 0;\n\t\t\t\tdo {\n\t\t\t\t\tstart = description.IndexOf (nameStart [i], j);\n\t\t\t\t} while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);\n\t\t\t\tif (start == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\tint end = description.IndexOf (\"}\", start);\n\t\t\t\tif (end == -1)\n\t\t\t\t\tcontinue;\n\t\t\t\treturn description.Substring (start + nameStart [i].Length, end - start - nameStart [i].Length);\n\t\t\t}\n\t\t\treturn maxIndex == 1 ? \"VALUE\" : \"VALUE\" + (index + 1);\n\t\t}\n\n\t\tprivate static string GetDescription (string description)\n\t\t{\n\t\t\tif (description == null)\n\t\t\t\treturn string.Empty;\n\t\t\tStringBuilder sb = new StringBuilder (description.Length);\n\t\t\tint start = -1;\n\t\t\tfor (int i = 0; i < description.Length; ++i) {\n\t\t\t\tswitch (description [i]) {\n\t\t\t\t\tcase '{':\n\t\t\t\t\t\tif (i == start) {\n\t\t\t\t\t\t\tsb.Append ('{');\n\t\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (start < 0)\n\t\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '}':\n\t\t\t\t\t\tif (start < 0) {\n\t\t\t\t\t\t\tif ((i+1) == description.Length || description [i+1] != '}')\n\t\t\t\t\t\t\t\tthrow new InvalidOperationException (\"Invalid option description: \" + description);\n\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\tsb.Append (\"}\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tsb.Append (description.Substring (start, i - start));\n\t\t\t\t\t\t\tstart = -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ':':\n\t\t\t\t\t\tif (start < 0)\n\t\t\t\t\t\t\tgoto default;\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (start < 0)\n\t\t\t\t\t\t\tsb.Append (description [i]);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.ToString ();\n\t\t}\n\n\t\tprivate static IEnumerable<string> GetLines (string description, int firstWidth, int remWidth)\n\t\t{\n\t\t\treturn StringCoda.WrappedLines (description, firstWidth, remWidth);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Update/Program.cs",
    "content": "﻿using NuGet;\nusing Squirrel.SimpleSplat;\nusing Squirrel.Json;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Globalization;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Squirrel.Update\n{\n    enum UpdateAction {\n        Unset = 0, Install, Uninstall, Download, Update, Releasify, Shortcut,\n        Deshortcut, ProcessStart, UpdateSelf, CheckForUpdate\n    }\n\n    class Program : IEnableLogger\n    {\n        static StartupOption opt;\n\n        public static int Main(string[] args)\n        {\n            var pg = new Program();\n            try {\n                return pg.main(args);\n            } catch (Exception ex) {\n                // NB: Normally this is a terrible idea but we want to make\n                // sure Setup.exe above us gets the nonzero error code\n                Console.Error.WriteLine(ex);\n                return -1;\n            }\n        }\n\n        int main(string[] args)\n        {\n            try {\n                opt = new StartupOption(args);\n            } catch (Exception ex) {\n                using (var logger = new SetupLogLogger(true, \"OptionParsing\") { Level = LogLevel.Info }) {\n                    SquirrelLocator.CurrentMutable.Register(() => logger, typeof(Squirrel.SimpleSplat.ILogger));\n                    logger.Write($\"Failed to parse command line options. {ex.Message}\", LogLevel.Error);\n                }\n                throw;\n            }\n\n            // NB: Trying to delete the app directory while we have Setup.log\n            // open will actually crash the uninstaller\n            bool isUninstalling = opt.updateAction == UpdateAction.Uninstall;\n\n            using (var logger = new SetupLogLogger(isUninstalling, opt.updateAction.ToString()) {Level = LogLevel.Info}) {\n                SquirrelLocator.CurrentMutable.Register(() => logger, typeof (SimpleSplat.ILogger));\n\n                try {\n                    return executeCommandLine(args);\n                } catch (Exception ex) {\n                    logger.Write(\"Finished with unhandled exception: \" + ex, LogLevel.Fatal);\n                    throw;\n                }\n            }\n        }\n\n        int executeCommandLine(string[] args)\n        {\n            var animatedGifWindowToken = new CancellationTokenSource();\n\n#if !MONO\n            // Uncomment to test Gifs\n            /*\n            var ps = new ProgressSource();\n            int i = 0; var t = new Timer(_ => ps.Raise(i += 10), null, 0, 1000);\n            AnimatedGifWindow.ShowWindow(TimeSpan.FromMilliseconds(0), animatedGifWindowToken.Token, ps);\n            Thread.Sleep(10 * 60 * 1000);\n            */\n#endif\n\n            using (Disposable.Create(() => animatedGifWindowToken.Cancel())) {\n\n                this.Log().Info(\"Starting Squirrel Updater: \" + String.Join(\" \", args));\n\n                if (args.Any(x => x.StartsWith(\"/squirrel\", StringComparison.OrdinalIgnoreCase))) {\n                    // NB: We're marked as Squirrel-aware, but we don't want to do\n                    // anything in response to these events\n                    return 0;\n                }\n\n                if (opt.updateAction == UpdateAction.Unset) {\n                    ShowHelp();\n                    return -1;\n                }\n\n                switch (opt.updateAction) {\n#if !MONO\n                case UpdateAction.Install:\n                    var progressSource = new ProgressSource();\n                    if (!opt.silentInstall) {\n                        AnimatedGifWindow.ShowWindow(TimeSpan.FromSeconds(4), animatedGifWindowToken.Token, progressSource);\n                    }\n\n                    Install(opt.silentInstall, progressSource, Path.GetFullPath(opt.target)).Wait();\n                    animatedGifWindowToken.Cancel();\n                    break;\n                case UpdateAction.Uninstall:\n                    Uninstall().Wait();\n                    break;\n                case UpdateAction.Download:\n                    Console.WriteLine(Download(opt.target).Result);\n                    break;\n                case UpdateAction.Update:\n                    Update(opt.target).Wait();\n                    break;\n                case UpdateAction.CheckForUpdate:\n                    Console.WriteLine(CheckForUpdate(opt.target).Result);\n                    break;\n                case UpdateAction.UpdateSelf:\n                    UpdateSelf().Wait();\n                    break;\n                case UpdateAction.Shortcut:\n                    Shortcut(opt.target, opt.shortcutArgs, opt.processStartArgs, opt.setupIcon, opt.onlyUpdateShortcuts);\n                    break;\n                case UpdateAction.Deshortcut:\n                    Deshortcut(opt.target, opt.shortcutArgs);\n                    break;\n                case UpdateAction.ProcessStart:\n                    ProcessStart(opt.processStart, opt.processStartArgs, opt.shouldWait);\n                    break;\n#endif\n                case UpdateAction.Releasify:\n                    Releasify(opt.target, opt.releaseDir, opt.packagesDir, opt.bootstrapperExe, opt.backgroundGif, opt.signingParameters, opt.baseUrl, opt.setupIcon, !opt.noMsi, opt.packageAs64Bit, opt.frameworkVersion, !opt.noDelta);\n                    break;\n                }\n            }\n            this.Log().Info(\"Finished Squirrel Updater\");\n            return 0;\n        }\n\n        public async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)\n        {\n            sourceDirectory = sourceDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            var releasesPath = Path.Combine(sourceDirectory, \"RELEASES\");\n\n            this.Log().Info(\"Starting install, writing to {0}\", sourceDirectory);\n\n            if (!File.Exists(releasesPath)) {\n                this.Log().Info(\"RELEASES doesn't exist, creating it at \" + releasesPath);\n                var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()\n                    .Where(x => x.Name.EndsWith(\".nupkg\", StringComparison.OrdinalIgnoreCase))\n                    .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));\n\n                ReleaseEntry.WriteReleaseFile(nupkgs, releasesPath);\n            }\n\n            var ourAppName = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesPath, Encoding.UTF8))\n                .First().PackageName;\n\n            using (var mgr = new UpdateManager(sourceDirectory, ourAppName)) {\n                this.Log().Info(\"About to install to: \" + mgr.RootAppDirectory);\n                if (Directory.Exists(mgr.RootAppDirectory)) {\n                    this.Log().Warn(\"Install path {0} already exists, burning it to the ground\", mgr.RootAppDirectory);\n\n                    mgr.KillAllExecutablesBelongingToPackage();\n                    await Task.Delay(500);\n\n                    await this.ErrorIfThrows(() => Utility.DeleteDirectory(mgr.RootAppDirectory),\n                        \"Failed to remove existing directory on full install, is the app still running???\");\n\n                    this.ErrorIfThrows(() => Utility.Retry(() => Directory.CreateDirectory(mgr.RootAppDirectory), 3),\n                        \"Couldn't recreate app directory, perhaps Antivirus is blocking it\");\n                }\n\n                Directory.CreateDirectory(mgr.RootAppDirectory);\n\n                var updateTarget = Path.Combine(mgr.RootAppDirectory, \"Update.exe\");\n                this.ErrorIfThrows(() => File.Copy(Assembly.GetExecutingAssembly().Location, updateTarget, true),\n                    \"Failed to copy Update.exe to \" + updateTarget);\n\n                await mgr.FullInstall(silentInstall, progressSource.Raise);\n\n                await this.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),\n                    \"Failed to create uninstaller registry entry\");\n            }\n        }\n\n        public async Task Update(string updateUrl, string appName = null)\n        {\n            appName = appName ?? getAppNameFromDirectory();\n\n            this.Log().Info(\"Starting update, downloading from \" + updateUrl);\n\n            using (var mgr = new UpdateManager(updateUrl, appName)) {\n                bool ignoreDeltaUpdates = false;\n                this.Log().Info(\"About to update to: \" + mgr.RootAppDirectory);\n\n            retry:\n                try {\n                    // 3 % (3 stages)\n                    var updateInfo = await mgr.CheckForUpdate(intention: UpdaterIntention.Update, ignoreDeltaUpdates: ignoreDeltaUpdates, progress: x => Console.WriteLine(UpdateManager.CalculateProgress(x, 0, 3)));\n\n                    // 3 - 30 %\n                    await mgr.DownloadReleases(updateInfo.ReleasesToApply, x => Console.WriteLine(UpdateManager.CalculateProgress(x, 3, 30)));\n\n                    // 30 - 100 %\n                    await mgr.ApplyReleases(updateInfo, x => Console.WriteLine(UpdateManager.CalculateProgress(x, 30, 100)));\n                } catch (Exception ex) {\n                    if (ignoreDeltaUpdates) {\n                        this.Log().ErrorException(\"Really couldn't apply updates!\", ex);\n                        throw;\n                    }\n\n                    this.Log().WarnException(\"Failed to apply updates, falling back to full updates\", ex);\n                    ignoreDeltaUpdates = true;\n                    goto retry;\n                }\n\n                var updateTarget = Path.Combine(mgr.RootAppDirectory, \"Update.exe\");\n\n                await this.ErrorIfThrows(() =>\n                    mgr.CreateUninstallerRegistryEntry(),\n                    \"Failed to create uninstaller registry entry\");\n            }\n        }\n\n        public async Task UpdateSelf()\n        {\n            waitForParentToExit();\n            var src = Assembly.GetExecutingAssembly().Location;\n            var updateDotExeForOurPackage = Path.Combine(\n                Path.GetDirectoryName(src),\n                \"..\", \"Update.exe\");\n\n            await Task.Run(() => {\n                File.Copy(src, updateDotExeForOurPackage, true);\n            });\n        }\n\n        public async Task<string> Download(string updateUrl, string appName = null)\n        {\n            appName = appName ?? getAppNameFromDirectory();\n\n            this.Log().Info(\"Fetching update information, downloading from \" + updateUrl);\n            using (var mgr = new UpdateManager(updateUrl, appName)) {\n                var updateInfo = await mgr.CheckForUpdate(intention: UpdaterIntention.Update, progress: x => Console.WriteLine(x / 3));\n                await mgr.DownloadReleases(updateInfo.ReleasesToApply, x => Console.WriteLine(33 + x / 3));\n\n                var releaseNotes = updateInfo.FetchReleaseNotes();\n\n                var sanitizedUpdateInfo = new {\n                    currentVersion = updateInfo.CurrentlyInstalledVersion.Version.ToString(),\n                    futureVersion = updateInfo.FutureReleaseEntry.Version.ToString(),\n                    releasesToApply = updateInfo.ReleasesToApply.Select(x => new {\n                        version = x.Version.ToString(),\n                        releaseNotes = releaseNotes.ContainsKey(x) ? releaseNotes[x] : \"\",\n                    }).ToArray(),\n                };\n\n                return SimpleJson.SerializeObject(sanitizedUpdateInfo);\n            }\n        }\n\n        public async Task<string> CheckForUpdate(string updateUrl, string appName = null)\n        {\n            appName = appName ?? getAppNameFromDirectory();\n\n            this.Log().Info(\"Fetching update information, downloading from \" + updateUrl);\n            using (var mgr = new UpdateManager(updateUrl, appName)) {\n                var updateInfo = await mgr.CheckForUpdate(intention: UpdaterIntention.Update, progress: x => Console.WriteLine(x));\n                var releaseNotes = updateInfo.FetchReleaseNotes();\n\n                var sanitizedUpdateInfo = new {\n                    currentVersion = updateInfo.CurrentlyInstalledVersion.Version.ToString(),\n                    futureVersion = updateInfo.FutureReleaseEntry.Version.ToString(),\n                    releasesToApply = updateInfo.ReleasesToApply.Select(x => new {\n                        version = x.Version.ToString(),\n                        releaseNotes = releaseNotes.ContainsKey(x) ? releaseNotes[x] : \"\",\n                    }).ToArray(),\n                };\n\n                return SimpleJson.SerializeObject(sanitizedUpdateInfo);\n            }\n        }\n\n        public async Task Uninstall(string appName = null)\n        {\n            this.Log().Info(\"Starting uninstall for app: \" + appName);\n\n            appName = appName ?? getAppNameFromDirectory();\n            using (var mgr = new UpdateManager(\"\", appName)) {\n                await mgr.FullUninstall();\n                mgr.RemoveUninstallerRegistryEntry();\n            }\n        }\n\n        public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null, string backgroundGif = null, string signingOpts = null, string baseUrl = null, string setupIcon = null, bool generateMsi = true, bool packageAs64Bit = false, string frameworkVersion = null, bool generateDeltas = true)\n        {\n            ensureConsole();\n\n            if (baseUrl != null) {\n                if (!Utility.IsHttpUrl(baseUrl)) {\n                    throw new Exception(string.Format(\"Invalid --baseUrl '{0}'. A base URL must start with http or https and be a valid URI.\", baseUrl));\n                }\n\n                if (!baseUrl.EndsWith(\"/\")) {\n                    baseUrl += \"/\";\n                }\n            }\n\n            targetDir = targetDir ?? Path.Combine(\".\", \"Releases\");\n            packagesDir = packagesDir ?? \".\";\n            bootstrapperExe = bootstrapperExe ?? Path.Combine(\".\", \"Setup.exe\");\n\n            if (!Directory.Exists(targetDir)) {\n                Directory.CreateDirectory(targetDir);\n            }\n\n            if (!File.Exists(bootstrapperExe)) {\n                bootstrapperExe = Path.Combine(\n                    Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),\n                    \"Setup.exe\");\n            }\n\n            this.Log().Info(\"Bootstrapper EXE found at:\" + bootstrapperExe);\n\n            var di = new DirectoryInfo(targetDir);\n            File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);\n\n            var allNuGetFiles = di.EnumerateFiles()\n                .Where(x => x.Name.EndsWith(\".nupkg\", StringComparison.OrdinalIgnoreCase));\n\n            var toProcess = allNuGetFiles.Where(x => !x.Name.Contains(\"-delta\") && !x.Name.Contains(\"-full\"));\n            var processed = new List<string>();\n\n            var releaseFilePath = Path.Combine(di.FullName, \"RELEASES\");\n            var previousReleases = new List<ReleaseEntry>();\n            if (File.Exists(releaseFilePath)) {\n                previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)));\n            }\n\n            foreach (var file in toProcess) {\n                this.Log().Info(\"Creating release package: \" + file.FullName);\n\n                var rp = new ReleasePackage(file.FullName);\n                rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir, contentsPostProcessHook: pkgPath => {\n                    new DirectoryInfo(pkgPath).GetAllFilesRecursively()\n                        .Where(x => x.Name.ToLowerInvariant().EndsWith(\".exe\"))\n                        .Where(x => !x.Name.ToLowerInvariant().Contains(\"squirrel.exe\"))\n                        .Where(x => Utility.IsFileTopLevelInPackage(x.FullName, pkgPath))\n                        .Where(x => Utility.ExecutableUsesWin32Subsystem(x.FullName))\n                        .ForEachAsync(x => createExecutableStubForExe(x.FullName))\n                        .Wait();\n\n                    if (signingOpts == null) return;\n\n                    new DirectoryInfo(pkgPath).GetAllFilesRecursively()\n                        .Where(x => Utility.FileIsLikelyPEImage(x.Name))\n                        .ForEachAsync(async x => {\n                            if (isPEFileSigned(x.FullName)) {\n                                this.Log().Info(\"{0} is already signed, skipping\", x.FullName);\n                                return;\n                            }\n\n                            this.Log().Info(\"About to sign {0}\", x.FullName);\n                            await signPEFile(x.FullName, signingOpts);\n                        }, 1)\n                        .Wait();\n                });\n\n                processed.Add(rp.ReleasePackageFile);\n\n                var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);\n                if (prev != null && generateDeltas) {\n                    var deltaBuilder = new DeltaPackageBuilder(null);\n\n                    var dp = deltaBuilder.CreateDeltaPackage(prev, rp,\n                        Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace(\"full\", \"delta\")));\n                    processed.Insert(0, dp.InputPackageFile);\n                }\n            }\n\n            foreach (var file in toProcess) { File.Delete(file.FullName); }\n\n            var newReleaseEntries = processed\n                .Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))\n                .ToList();\n            var distinctPreviousReleases = previousReleases\n                .Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));\n            var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList();\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);\n\n            var targetSetupExe = Path.Combine(di.FullName, \"Setup.exe\");\n            var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();\n\n            File.Copy(bootstrapperExe, targetSetupExe, true);\n            var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, backgroundGif, signingOpts, setupIcon).Result;\n\n            var writeZipToSetup = Utility.FindHelperExecutable(\"WriteZipToSetup.exe\");\n\n            try {\n                var arguments = String.Format(\"\\\"{0}\\\" \\\"{1}\\\" \\\"--set-required-framework\\\" \\\"{2}\\\"\", targetSetupExe, zipPath, frameworkVersion);\n                var result = Utility.InvokeProcessAsync(writeZipToSetup, arguments, CancellationToken.None).Result;\n                if (result.Item1 != 0) throw new Exception(\"Failed to write Zip to Setup.exe!\\n\\n\" + result.Item2);\n            } catch (Exception ex) {\n                this.Log().ErrorException(\"Failed to update Setup.exe with new Zip file\", ex);\n            } finally {\n                File.Delete(zipPath);\n            }\n\n            Utility.Retry(() =>\n                setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait());\n\n            if (signingOpts != null) {\n                signPEFile(targetSetupExe, signingOpts).Wait();\n            }\n\n            if (generateMsi) {\n                createMsiPackage(targetSetupExe, new ZipPackage(package), packageAs64Bit).Wait();\n\n                if (signingOpts != null) {\n                    signPEFile(targetSetupExe.Replace(\".exe\", \".msi\"), signingOpts).Wait();\n                }\n            }\n        }\n\n        public void Shortcut(string exeName, string shortcutArgs, string processStartArgs, string icon, bool onlyUpdate)\n        {\n            if (String.IsNullOrWhiteSpace(exeName)) {\n                ShowHelp();\n                return;\n            }\n\n            var appName = getAppNameFromDirectory();\n            var defaultLocations = ShortcutLocation.StartMenu | ShortcutLocation.Desktop;\n            var locations = parseShortcutLocations(shortcutArgs);\n\n            using (var mgr = new UpdateManager(\"\", appName)) {\n                mgr.CreateShortcutsForExecutable(exeName, locations ?? defaultLocations, onlyUpdate, processStartArgs, icon);\n            }\n        }\n\n        public void Deshortcut(string exeName, string shortcutArgs)\n        {\n            if (String.IsNullOrWhiteSpace(exeName)) {\n                ShowHelp();\n                return;\n            }\n\n            var appName = getAppNameFromDirectory();\n            var defaultLocations = ShortcutLocation.StartMenu | ShortcutLocation.Desktop;\n            var locations = parseShortcutLocations(shortcutArgs);\n\n            using (var mgr = new UpdateManager(\"\", appName)) {\n                mgr.RemoveShortcutsForExecutable(exeName, locations ?? defaultLocations);\n            }\n        }\n\n        public void ProcessStart(string exeName, string arguments, bool shouldWait)\n        {\n            if (String.IsNullOrWhiteSpace(exeName)) {\n                ShowHelp();\n                return;\n            }\n\n            // Find the latest installed version's app dir\n            var appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            var releases = ReleaseEntry.ParseReleaseFile(\n                File.ReadAllText(Utility.LocalReleaseFileForAppDir(appDir), Encoding.UTF8));\n\n            // NB: We add the hacked up version in here to handle a migration\n            // issue, where versions of Squirrel pre PR #450 will not understand\n            // prerelease tags, so it will end up writing the release name sans\n            // tags. However, the RELEASES file _will_ have them, so we need to look\n            // for directories that match both the real version, and the sanitized\n            // version, giving priority to the former.\n            var latestAppDir = releases\n                .OrderByDescending(x => x.Version)\n                .SelectMany(x => new[] {\n                    Utility.AppDirForRelease(appDir, x),\n                    Utility.AppDirForVersion(appDir, new SemanticVersion(x.Version.Version.Major, x.Version.Version.Minor, x.Version.Version.Build, \"\"))\n                })\n                .FirstOrDefault(x => Directory.Exists(x));\n\n            // Check for the EXE name they want\n            var targetExe = new FileInfo(Path.Combine(latestAppDir, exeName.Replace(\"%20\", \" \")));\n            this.Log().Info(\"Want to launch '{0}'\", targetExe);\n\n            // Check for path canonicalization attacks\n            if (!targetExe.FullName.StartsWith(latestAppDir, StringComparison.Ordinal)) {\n                throw new ArgumentException();\n            }\n\n            if (!targetExe.Exists) {\n                this.Log().Error(\"File {0} doesn't exist in current release\", targetExe);\n                throw new ArgumentException();\n            }\n\n            if (shouldWait) waitForParentToExit();\n\n            try {\n                this.Log().Info(\"About to launch: '{0}': {1}\", targetExe.FullName, arguments ?? \"\");\n                Process.Start(new ProcessStartInfo(targetExe.FullName, arguments ?? \"\") { WorkingDirectory = Path.GetDirectoryName(targetExe.FullName) });\n            } catch (Exception ex) {\n                this.Log().ErrorException(\"Failed to start process\", ex);\n            }\n        }\n\n        public void ShowHelp()\n        {\n            ensureConsole();\n            opt.WriteOptionDescriptions();\n        }\n\n        void waitForParentToExit()\n        {\n            // Grab a handle the parent process\n            var parentPid = NativeMethods.GetParentProcessId();\n            var handle = default(IntPtr);\n\n            // Wait for our parent to exit\n            try {\n                handle = NativeMethods.OpenProcess(ProcessAccess.Synchronize, false, parentPid);\n                if (handle != IntPtr.Zero) {\n                    this.Log().Info(\"About to wait for parent PID {0}\", parentPid);\n                    NativeMethods.WaitForSingleObject(handle, 0xFFFFFFFF /*INFINITE*/);\n                } else {\n                    this.Log().Info(\"Parent PID {0} no longer valid - ignoring\", parentPid);\n                }\n            } finally {\n                if (handle != IntPtr.Zero) NativeMethods.CloseHandle(handle);\n            }\n        }\n\n        async Task<string> createSetupEmbeddedZip(string fullPackage, string releasesDir, string backgroundGif, string signingOpts, string setupIcon)\n        {\n            string tempPath;\n\n            this.Log().Info(\"Building embedded zip file for Setup.exe\");\n            using (Utility.WithTempDirectory(out tempPath, null)) {\n                this.ErrorIfThrows(() => {\n                    File.Copy(Assembly.GetEntryAssembly().Location.Replace(\"-Mono.exe\", \".exe\"), Path.Combine(tempPath, \"Update.exe\"));\n                    File.Copy(fullPackage, Path.Combine(tempPath, Path.GetFileName(fullPackage)));\n                }, \"Failed to write package files to temp dir: \" + tempPath);\n\n                if (!String.IsNullOrWhiteSpace(backgroundGif)) {\n                    this.ErrorIfThrows(() => {\n                        File.Copy(backgroundGif, Path.Combine(tempPath, \"background.gif\"));\n                    }, \"Failed to write animated GIF to temp dir: \" + tempPath);\n                }\n\n                if (!String.IsNullOrWhiteSpace(setupIcon)) {\n                    this.ErrorIfThrows(() => {\n                        File.Copy(setupIcon, Path.Combine(tempPath, \"setupIcon.ico\"));\n                    }, \"Failed to write icon to temp dir: \" + tempPath);\n                }\n\n                var releases = new[] { ReleaseEntry.GenerateFromFile(fullPackage) };\n                ReleaseEntry.WriteReleaseFile(releases, Path.Combine(tempPath, \"RELEASES\"));\n\n                var target = Path.GetTempFileName();\n                File.Delete(target);\n\n                // Sign Update.exe so that virus scanners don't think we're\n                // pulling one over on them\n                if (signingOpts != null) {\n                    var di = new DirectoryInfo(tempPath);\n\n                    var files = di.EnumerateFiles()\n                        .Where(x => x.Name.ToLowerInvariant().EndsWith(\".exe\"))\n                        .Select(x => x.FullName);\n\n                    await files.ForEachAsync(x => signPEFile(x, signingOpts));\n                }\n\n                this.ErrorIfThrows(() =>\n                    ZipFile.CreateFromDirectory(tempPath, target, CompressionLevel.Optimal, false),\n                    \"Failed to create Zip file from directory: \" + tempPath);\n\n                return target;\n            }\n        }\n\n        static async Task signPEFile(string exePath, string signingOpts)\n        {\n            // Try to find SignTool.exe\n            var exe = @\".\\signtool.exe\";\n            if (!File.Exists(exe)) {\n                exe = Path.Combine(\n                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),\n                    \"signtool.exe\");\n\n                // Run down PATH and hope for the best\n                if (!File.Exists(exe)) exe = \"signtool.exe\";\n            }\n\n            var processResult = await Utility.InvokeProcessAsync(exe,\n                String.Format(\"sign {0} \\\"{1}\\\"\", signingOpts, exePath), CancellationToken.None);\n\n            if (processResult.Item1 != 0) {\n                var optsWithPasswordHidden = new Regex(@\"(?x)                    #ignore pattern white space so we can leave comments\n                    (?i)                #ignore case\n                    (?<=/p\\s+)          #positive look behind for /p that is followed by white space(s)\n                    .*?                 #get everything lazy way \n                    (?=\\s+)             #positive look ahead for white space(s) \n                \"\n                ).Replace(signingOpts, \"/p ********\");\n                var msg = String.Format(\"Failed to sign, command invoked was: '{0} sign {1} {2}'\",\n                    exe, optsWithPasswordHidden, exePath);\n\n                throw new Exception(msg);\n            } else {\n                Console.WriteLine(processResult.Item2);\n            }\n        }\n        bool isPEFileSigned(string path)\n        {\n#if MONO\n            return Path.GetExtension(path).Equals(\".exe\", StringComparison.OrdinalIgnoreCase);\n#else\n            try {\n                return AuthenticodeTools.IsTrusted(path);\n            } catch (Exception ex) {\n                this.Log().ErrorException(\"Failed to determine signing status for \" + path, ex);\n                return false;\n            }\n#endif\n        }\n\n        async Task createExecutableStubForExe(string fullName)\n        {\n            var exe = Utility.FindHelperExecutable(@\"StubExecutable.exe\");\n\n            var target = Path.Combine(\n                Path.GetDirectoryName(fullName),\n                Path.GetFileNameWithoutExtension(fullName) + \"_ExecutionStub.exe\");\n\n            await Utility.CopyToAsync(exe, target);\n\n            await Utility.InvokeProcessAsync(\n                Utility.FindHelperExecutable(\"WriteZipToSetup.exe\"),\n                String.Format(\"--copy-stub-resources \\\"{0}\\\" \\\"{1}\\\"\", fullName, target),\n                CancellationToken.None);\n        }\n\n        static async Task setPEVersionInfoAndIcon(string exePath, IPackage package, string iconPath = null)\n        {\n            var realExePath = Path.GetFullPath(exePath);\n            var company = String.Join(\",\", package.Authors);\n            var verStrings = new Dictionary<string, string>() {\n                { \"CompanyName\", company },\n                { \"LegalCopyright\", package.Copyright ?? \"Copyright © \" + DateTime.Now.Year.ToString() + \" \" + company },\n                { \"FileDescription\", package.Summary ?? package.Description ?? \"Installer for \" + package.Id },\n                { \"ProductName\", package.Description ?? package.Summary ?? package.Id },\n            };\n\n            var args = verStrings.Aggregate(new StringBuilder(\"\\\"\" + realExePath + \"\\\"\"), (acc, x) => { acc.AppendFormat(\" --set-version-string \\\"{0}\\\" \\\"{1}\\\"\", x.Key, x.Value); return acc; });\n            args.AppendFormat(\" --set-file-version {0} --set-product-version {0}\", package.Version.ToString());\n            if (iconPath != null) {\n                args.AppendFormat(\" --set-icon \\\"{0}\\\"\", Path.GetFullPath(iconPath));\n            }\n\n            // Try to find rcedit.exe\n            string exe = Utility.FindHelperExecutable(\"rcedit.exe\");\n\n            var processResult = await Utility.InvokeProcessAsync(exe, args.ToString(), CancellationToken.None);\n\n            if (processResult.Item1 != 0) {\n                var msg = String.Format(\n                    \"Failed to modify resources, command invoked was: '{0} {1}'\\n\\nOutput was:\\n{2}\",\n                    exe, args, processResult.Item2);\n\n                throw new Exception(msg);\n            } else {\n                Console.WriteLine(processResult.Item2);\n            }\n        }\n\n        static async Task createMsiPackage(string setupExe, IPackage package, bool packageAs64Bit)\n        {\n            var pathToWix = pathToWixTools();\n            var setupExeDir = Path.GetDirectoryName(setupExe);\n            var company = String.Join(\",\", package.Authors);\n\n            var culture = CultureInfo.GetCultureInfo(package.Language ?? \"\").TextInfo.ANSICodePage;\n\n\n            var templateText = File.ReadAllText(Path.Combine(pathToWix, \"template.wxs\"));\n            var templateData = new Dictionary<string, string> {\n                { \"Id\", package.Id },\n                { \"Title\", package.Title },\n                { \"Author\", company },\n                { \"Version\", Regex.Replace(package.Version.ToString(), @\"-.*$\", \"\") },\n                { \"Summary\", package.Summary ?? package.Description ?? package.Id },\n                { \"Codepage\", $\"{culture}\" },\n                { \"Platform\", packageAs64Bit ? \"x64\" : \"x86\" },\n                { \"ProgramFilesFolder\", packageAs64Bit ? \"ProgramFiles64Folder\" : \"ProgramFilesFolder\" },\n                { \"Win64YesNo\", packageAs64Bit ? \"yes\" : \"no\" }\n            };\n\n            // NB: We need some GUIDs that are based on the package ID, but unique (i.e.\n            // \"Unique but consistent\").\n            for (int i=1; i <= 10; i++) {\n                templateData[String.Format(\"IdAsGuid{0}\", i)] = Utility.CreateGuidFromHash(String.Format(\"{0}:{1}\", package.Id, i)).ToString();\n            }\n\n            var templateResult = CopStache.Render(templateText, templateData);\n\n            var wxsTarget = Path.Combine(setupExeDir, \"Setup.wxs\");\n            File.WriteAllText(wxsTarget, templateResult, Encoding.UTF8);\n\n            var candleParams = String.Format(\"-nologo -ext WixNetFxExtension -out \\\"{0}\\\" \\\"{1}\\\"\", wxsTarget.Replace(\".wxs\", \".wixobj\"), wxsTarget);\n            var processResult = await Utility.InvokeProcessAsync(\n                Path.Combine(pathToWix, \"candle.exe\"), candleParams, CancellationToken.None, setupExeDir);\n\n            if (processResult.Item1 != 0) {\n                var msg = String.Format(\n                    \"Failed to compile WiX template, command invoked was: '{0} {1}'\\n\\nOutput was:\\n{2}\",\n                    \"candle.exe\", candleParams, processResult.Item2);\n\n                throw new Exception(msg);\n            }\n\n            var lightParams = String.Format(\"-ext WixNetFxExtension -sval -out \\\"{0}\\\" \\\"{1}\\\"\", wxsTarget.Replace(\".wxs\", \".msi\"), wxsTarget.Replace(\".wxs\", \".wixobj\"));\n            processResult = await Utility.InvokeProcessAsync(\n                Path.Combine(pathToWix, \"light.exe\"), lightParams, CancellationToken.None, setupExeDir);\n\n            if (processResult.Item1 != 0) {\n                var msg = String.Format(\n                    \"Failed to link WiX template, command invoked was: '{0} {1}'\\n\\nOutput was:\\n{2}\",\n                    \"light.exe\", lightParams, processResult.Item2);\n\n                throw new Exception(msg);\n            }\n\n            var toDelete = new[] {\n                wxsTarget,\n                wxsTarget.Replace(\".wxs\", \".wixobj\"),\n                wxsTarget.Replace(\".wxs\", \".wixpdb\"),\n            };\n\n            await Utility.ForEachAsync(toDelete, x => Utility.DeleteFileHarder(x));\n        }\n\n        static string pathToWixTools()\n        {\n            var ourPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n\n            // Same Directory? (i.e. released)\n            if (File.Exists(Path.Combine(ourPath, \"candle.exe\"))) {\n                return ourPath;\n            }\n\n            // Debug Mode (i.e. in vendor)\n            var debugPath = Path.Combine(ourPath, \"..\", \"..\", \"..\", \"vendor\", \"wix\");\n            if (File.Exists(Path.Combine(debugPath, \"candle.exe\"))) {\n                return Path.GetFullPath(debugPath);\n            }\n\n            throw new Exception(\"WiX tools can't be found\");\n        }\n\n        static string getAppNameFromDirectory(string path = null)\n        {\n            path = path ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);\n            return (new DirectoryInfo(path)).Name;\n        }\n\n        static ShortcutLocation? parseShortcutLocations(string shortcutArgs)\n        {\n            var ret = default(ShortcutLocation?);\n\n            if (!String.IsNullOrWhiteSpace(shortcutArgs)) {\n                var args = shortcutArgs.Split(new[] { ',' });\n\n                foreach (var arg in args) {\n                    var location = (ShortcutLocation)(Enum.Parse(typeof(ShortcutLocation), arg, false));\n                    if (ret.HasValue) {\n                        ret |= location;\n                    } else {\n                        ret = location;\n                    }\n                }\n            }\n\n            return ret;\n        }\n\n        static int consoleCreated = 0;\n        static void ensureConsole()\n        {\n            if (Environment.OSVersion.Platform != PlatformID.Win32NT) return;\n\n            if (Interlocked.CompareExchange(ref consoleCreated, 1, 0) == 1) return;\n\n            if (!NativeMethods.AttachConsole(-1)) {\n                NativeMethods.AllocConsole();\n            }\n\n            NativeMethods.GetStdHandle(StandardHandles.STD_ERROR_HANDLE);\n            NativeMethods.GetStdHandle(StandardHandles.STD_OUTPUT_HANDLE);\n        }\n    }\n\n    public class ProgressSource\n    {\n        public event EventHandler<int> Progress;\n\n        public void Raise(int i)\n        {\n            if (Progress != null)\n                Progress.Invoke(this, i);\n        }\n    }\n\n    class SetupLogLogger : SimpleSplat.ILogger, IDisposable\n    {\n        TextWriter inner;\n        readonly object gate = 42;\n        public SimpleSplat.LogLevel Level { get; set; }\n\n        public SetupLogLogger(bool saveInTemp, string commandSuffix = null)\n        {\n            for (int i=0; i < 10; i++) {\n                try {\n                    var dir = saveInTemp ?\n                        Path.GetTempPath() :\n                        Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);\n                    var fileName = commandSuffix == null ? String.Format($\"Squirrel.{i}.log\", i) : String.Format($\"Squirrel-{commandSuffix}.{i}.log\", i);\n                    var file = Path.Combine(dir, fileName.Replace(\".0.log\", \".log\"));\n                    var str = File.Open(file, FileMode.Append, FileAccess.Write, FileShare.Read);\n                    inner = new StreamWriter(str, Encoding.UTF8, 4096, false) { AutoFlush = true };\n                    return;\n                } catch (Exception ex) {\n                    // Didn't work? Keep going\n                    Console.Error.WriteLine(\"Couldn't open log file, trying new file: \" + ex.ToString());\n                }\n            }\n\n            inner = Console.Error;\n        }\n\n        public void Write(string message, LogLevel logLevel)\n        {\n            if (logLevel < Level) {\n                return;\n            }\n\n            lock (gate) inner.WriteLine($\"[{DateTime.Now.ToString(\"dd/MM/yy HH:mm:ss\")}] {logLevel.ToString().ToLower()}: {message}\");\n        }\n\n        public void Dispose()\n        {\n            lock (gate) {\n                inner.Flush();\n                inner.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Update/StartupOption.cs",
    "content": "﻿using Mono.Options;\nusing System;\n\nnamespace Squirrel.Update\n{\n    internal class StartupOption\n    {\n        private readonly OptionSet optionSet;\n\n        internal bool silentInstall { get; private set; } = false;\n        internal UpdateAction updateAction { get; private set; } = default(UpdateAction);\n        internal string target { get; private set; } = default(string);\n        internal string releaseDir { get; private set; } = default(string);\n        internal string packagesDir { get; private set; } = default(string);\n        internal string bootstrapperExe { get; private set; } = default(string);\n        internal string backgroundGif { get; private set; } = default(string);\n        internal string signingParameters { get; private set; } = default(string);\n        internal string baseUrl { get; private set; } = default(string);\n        internal string processStart { get; private set; } = default(string);\n        internal string processStartArgs { get; private set; } = default(string);\n        internal string setupIcon { get; private set; } = default(string);\n        internal string icon { get; private set; } = default(string);\n        internal string shortcutArgs { get; private set; } = default(string);\n        internal string frameworkVersion { get; private set; } = \"net45\";\n        internal bool shouldWait { get; private set; } = false;\n        internal bool noMsi { get; private set; } = (Environment.OSVersion.Platform != PlatformID.Win32NT);        // NB: WiX doesn't work under Mono / Wine\n        internal bool packageAs64Bit { get; private set; } = false;\n        internal bool noDelta { get; private set; } = false;\n        internal bool onlyUpdateShortcuts { get; private set; } = false;\n               \n        public StartupOption(string[] args) {\n           optionSet = Parse(args);\n        }\n\n        private OptionSet Parse(string[] args) {\n            var opts = new OptionSet() {\n                \"Usage: Squirrel.exe command [OPTS]\",\n                \"Manages Squirrel packages\",\n                \"\",\n                \"Commands\",\n                { \"install=\", \"Install the app whose package is in the specified directory\", v => { updateAction = UpdateAction.Install; target = v; } },\n                { \"uninstall\", \"Uninstall the app the same dir as Update.exe\", v => updateAction = UpdateAction.Uninstall},\n                { \"download=\", \"Download the releases specified by the URL and write new results to stdout as JSON\", v => { updateAction = UpdateAction.Download; target = v; } },\n                { \"checkForUpdate=\", \"Check for one available update and writes new results to stdout as JSON\", v => { updateAction = UpdateAction.CheckForUpdate; target = v; } },\n                { \"update=\", \"Update the application to the latest remote version specified by URL\", v => { updateAction = UpdateAction.Update; target = v; } },\n                { \"releasify=\", \"Update or generate a releases directory with a given NuGet package\", v => { updateAction = UpdateAction.Releasify; target = v; } },\n                { \"createShortcut=\", \"Create a shortcut for the given executable name\", v => { updateAction = UpdateAction.Shortcut; target = v; } },\n                { \"removeShortcut=\", \"Remove a shortcut for the given executable name\", v => { updateAction = UpdateAction.Deshortcut; target = v; } },\n                { \"updateSelf=\", \"Copy the currently executing Update.exe into the default location\", v => { updateAction =  UpdateAction.UpdateSelf; target = v; } },\n                { \"processStart=\", \"Start an executable in the latest version of the app package\", v => { updateAction =  UpdateAction.ProcessStart; processStart = v; }, true},\n                { \"processStartAndWait=\", \"Start an executable in the latest version of the app package\", v => { updateAction =  UpdateAction.ProcessStart; processStart = v; shouldWait = true; }, true},\n                \"\",\n                \"Options:\",\n                { \"h|?|help\", \"Display Help and exit\", _ => {} },\n                { \"r=|releaseDir=\", \"Path to a release directory to use with releasify\", v => releaseDir = v},\n                { \"p=|packagesDir=\", \"Path to the NuGet Packages directory for C# apps\", v => packagesDir = v},\n                { \"bootstrapperExe=\", \"Path to the Setup.exe to use as a template\", v => bootstrapperExe = v},\n                { \"g=|loadingGif=\", \"Path to an animated GIF to be displayed during installation\", v => backgroundGif = v},\n                { \"i=|icon\", \"Path to an ICO file that will be used for icon shortcuts\", v => icon = v},\n                { \"setupIcon=\", \"Path to an ICO file that will be used for the Setup executable's icon\", v => setupIcon = v},\n                { \"n=|signWithParams=\", \"Sign the installer via SignTool.exe with the parameters given\", v => signingParameters = v},\n                { \"s|silent\", \"Silent install\", _ => silentInstall = true},\n                { \"b=|baseUrl=\", \"Provides a base URL to prefix the RELEASES file packages with\", v => baseUrl = v, true},\n                { \"a=|process-start-args=\", \"Arguments that will be used when starting executable\", v => processStartArgs = v, true},\n                { \"l=|shortcut-locations=\", \"Comma-separated string of shortcut locations, e.g. 'Desktop,StartMenu'\", v => shortcutArgs = v},\n                { \"no-msi\", \"Don't generate an MSI package\", v => noMsi = true},\n                { \"no-delta\", \"Don't generate delta packages to save time\", v => noDelta = true},\n                { \"framework-version=\", \"Set the required .NET framework version, e.g. net461\", v => frameworkVersion = v },\n                { \"msi-win64\", \"Mark the MSI as 64-bit, which is useful in Enterprise deployment scenarios\", _ => packageAs64Bit = true},\n                { \"updateOnly\", \"Update shortcuts that already exist, rather than creating new ones\", _ => onlyUpdateShortcuts = true},\n            };\n\n            opts.Parse(args);\n\n            // NB: setupIcon and icon are just aliases for compatibility\n            // reasons, because of a dumb breaking rename I made in 1.0.1\n            setupIcon = setupIcon ?? icon;\n\n            return opts;\n        }\n\n        internal void WriteOptionDescriptions() {\n            optionSet.WriteOptionDescriptions(Console.Out);\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Update/Update-Mono.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.NET.Sdk\" />\n\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <OutputType>Exe</OutputType>\n    <Description>Update</Description>\n    <Title>Update</Title>\n    <ApplicationManifest>app.manifest</ApplicationManifest>\n    <DefineConstants>$(DefineConstants);MONO</DefineConstants>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"rcedit.exe\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"signtool.exe\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"update.com\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\vendor\\nuget\\src\\Core\\Core.csproj\" />\n    <ProjectReference Include=\"..\\Squirrel\\Squirrel.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"WpfAnimatedGif\" Version=\"1.4.15.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"ILRepack\" Version=\"1.26.0\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n  <Import Project=\"Sdk.targets\" Sdk=\"Microsoft.NET.Sdk\" />\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\n    <PostBuildEvent>\n      cd \"$(TargetDir)\"\n      \"$(NuGetPackageRoot)ilrepack\\1.26.0\\tools\\ILRepack.exe\" /internalize /out:$(TargetFileName).tmp $(TargetFileName) Microsoft.Web.XmlTransform.dll Squirrel.dll NuGet.Squirrel.dll Mono.Cecil.dll SharpCompress.dll\n      del \"$(TargetFileName)\"\n      ren \"$(TargetFileName).tmp\" \"$(TargetFileName)\"\n    </PostBuildEvent>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Update/Update.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"Sdk.props\" Sdk=\"Microsoft.NET.Sdk\" />\n\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <OutputType>WinExe</OutputType>\n    <Description>Update</Description>\n    <Title>Update</Title>\n    <ApplicationManifest>app.manifest</ApplicationManifest>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"rcedit.exe\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"signtool.exe\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"update.com\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\vendor\\nuget\\src\\Core\\Core.csproj\" />\n    <ProjectReference Include=\"..\\Squirrel\\Squirrel.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"WpfAnimatedGif\" Version=\"1.4.15.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"ILRepack\" Version=\"1.26.0\" PrivateAssets=\"All\" />\n  </ItemGroup>\n\n  <Import Project=\"Sdk.targets\" Sdk=\"Microsoft.NET.Sdk\" />\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\n    <PostBuildEvent>\n      cd \"$(TargetDir)\"\n      \"$(NuGetPackageRoot)ilrepack\\1.26.0\\tools\\ILRepack.exe\" /internalize /out:$(TargetFileName).tmp $(TargetFileName) WpfAnimatedGif.dll SharpCompress.dll Microsoft.Web.XmlTransform.dll Squirrel.dll NuGet.Squirrel.dll Mono.Cecil.dll\n      del \"$(TargetFileName)\"\n      ren \"$(TargetFileName).tmp\" \"$(TargetFileName)\"\n    </PostBuildEvent>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Update/app.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n  <assemblyIdentity version=\"1.2.0.0\" name=\"Squirrel.app\"/>\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">\n    <security>\n      <requestedPrivileges xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" />\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <!-- Windows Vista -->\n      <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" />\n\n      <!-- Windows 7 -->\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" />\n\n      <!-- Windows 8 -->\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" />\n\n      <!-- Windows 8.1 -->\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" />\n\n      <!-- Windows 10 -->\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" />\n    </application>\n  </compatibility>\n\n  <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->\n  <dependency>\n    <dependentAssembly>\n      <assemblyIdentity\n          type=\"win32\"\n          name=\"Microsoft.Windows.Common-Controls\"\n          version=\"6.0.0.0\"\n          processorArchitecture=\"*\"\n          publicKeyToken=\"6595b64144ccf1df\"\n          language=\"*\"\n        />\n    </dependentAssembly>\n  </dependency>\n\n</assembly>\n"
  },
  {
    "path": "src/Update/packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"DeltaCompressionDotNet\" version=\"1.1.0\" targetFramework=\"net45\" />\n  <package id=\"Microsoft.Web.Xdt\" version=\"2.1.1\" targetFramework=\"net45\" />\n  <package id=\"Mono.Cecil\" version=\"0.9.6.1\" targetFramework=\"net45\" />\n  <package id=\"Mono.Options\" version=\"1.1\" targetFramework=\"net45\" />\n  <package id=\"SharpCompress\" version=\"0.17.1\" targetFramework=\"net45\" />\n  <package id=\"SimpleJson\" version=\"0.38.0\" targetFramework=\"net45\" />\n  <package id=\"Splat\" version=\"1.6.2\" targetFramework=\"net45\" />\n  <package id=\"WpfAnimatedGif\" version=\"1.4.15\" targetFramework=\"net45\" />\n</packages>"
  },
  {
    "path": "src/WriteZipToSetup/WriteZipToSetup.cpp",
    "content": "// WriteZipToSetup.cpp : Defines the entry point for the console application.\n//\n\n#include \"stdafx.h\"\n\nusing namespace std;\n\nBOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam)\n{\n\tHANDLE hUpdate = (HANDLE)lParam;\n\tHRSRC hFindItAgain = FindResourceEx(hModule, lpszType, lpszName, wIDLanguage);\n\n\tHGLOBAL hGlobal = LoadResource(hModule, hFindItAgain);\n\tif (!hGlobal) return true;\n\n\tUpdateResource(hUpdate, lpszType, lpszName, wIDLanguage, LockResource(hGlobal), SizeofResource(hModule, hFindItAgain));\n\treturn true;\n}\n\nBOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)\n{\n\tHANDLE hUpdate = (HANDLE)lParam;\n\n\tEnumResourceLanguages(hModule, lpszType, lpszName, EnumResLangProc, (LONG_PTR)hUpdate);\n\treturn true;\n}\n\nBOOL CALLBACK EnumResTypeProc(HMODULE hMod, LPTSTR lpszType, LONG_PTR lParam)\n{\n\tstd::vector<wchar_t*>* typeList = (std::vector<wchar_t*>*)lParam;\n\tif (IS_INTRESOURCE(lpszType)) {\n\t\ttypeList->push_back(lpszType);\n\t} else {\n\t\ttypeList->push_back(_wcsdup(lpszType));\n\t}\n\n\treturn true;\n}\n\nint CopyResourcesToStubExecutable(wchar_t* src, wchar_t* dest)\n{\n\tHMODULE hSrc = LoadLibraryEx(src, NULL, LOAD_LIBRARY_AS_DATAFILE);\n\tif (!hSrc) return GetLastError();\n\n\tHANDLE hUpdate = BeginUpdateResource(dest, true);\n\tif (!hUpdate) return GetLastError();\n\n\tstd::vector<wchar_t*> typeList;\n\tEnumResourceTypes(hSrc, EnumResTypeProc, (LONG_PTR)&typeList);\n\n\tfor (auto& type : typeList) {\n\t\tEnumResourceNames(hSrc, type, EnumResNameProc, (LONG_PTR)hUpdate);\n\t}\n\n\tEndUpdateResource(hUpdate, false);\n\treturn 0;\n}\n\nint wmain(int argc, wchar_t* argv[])\n{\n\tif (argc > 1 && wcscmp(argv[1], L\"--copy-stub-resources\") == 0) {\n\t\tif (argc != 4) goto fail;\n\t\treturn CopyResourcesToStubExecutable(argv[2], argv[3]);\n\t}\n\tbool setFramework = false;\n\tif (argc == 5 && wcscmp(argv[3], L\"--set-required-framework\") == 0) {\n\t\tsetFramework = true;\n\t} else if (argc != 3) {\n\t\tgoto fail;\n\t}\n\n\twprintf(L\"Setup: %s, Zip: %s\\n\", argv[1], argv[2]);\n\n\t// Read the entire zip file into memory, yolo\n\tHANDLE hFile = CreateFile(argv[2], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\n\tif (hFile == INVALID_HANDLE_VALUE) {\n\t\tprintf(\"Can't open Zip file\\n\");\n\t\treturn -1;\n\t}\n\n\tBY_HANDLE_FILE_INFORMATION fileInfo;\n\tif (!GetFileInformationByHandle(hFile, &fileInfo)) {\n\t\tgoto fail;\n\t}\n\n\tBYTE* pBuf = new BYTE[fileInfo.nFileSizeLow + 0x1000];\n\tBYTE* pCurrent = pBuf;\n\tDWORD dwBytesRead;\n\n\tprintf(\"Starting to read in Zip file!\\n\");\n\tdo {\n\t\tif (!ReadFile(hFile, pCurrent, 0x1000, &dwBytesRead, NULL)) {\n\t\t\tprintf(\"Failed to read file! 0x%u\\n\", GetLastError());\n\t\t\tgoto fail;\n\t\t}\n\n\t\tpCurrent += dwBytesRead;\n\t} while (dwBytesRead > 0);\n\n\tprintf(\"Updating Resource!\\n\");\n\tHANDLE hRes = BeginUpdateResource(argv[1], false);\n\tif (!hRes) {\n\t\tprintf(\"Couldn't open setup.exe for writing\\n\");\n\t\tgoto fail;\n\t}\n\n\tif (!UpdateResource(hRes, L\"DATA\", (LPCWSTR)131, 0x0409, pBuf, fileInfo.nFileSizeLow)) {\n\t\tprintf(\"Failed to update resource\\n\");\n\t\tgoto fail;\n\t}\n\n\tif (setFramework) {\n\t\tif (!UpdateResource(hRes, L\"FLAGS\", (LPCWSTR)132, 0x0409, argv[4], (wcslen(argv[4])+1) * sizeof(wchar_t))) {\n\t\t\tprintf(\"Failed to update resource\\n\");\n\t\t\tgoto fail;\n\t\t}\n\t}\n\n\tprintf(\"Finished!\\n\");\n\tif (!EndUpdateResource(hRes, false)) {\n\t\tprintf(\"Failed to update resource\\n\");\n\t\tgoto fail;\n\t}\n\n\tprintf(\"It worked!\\n\");\n\treturn 0;\n\nfail:\n\tprintf(\"Usage: WriteZipToSetup [Setup.exe template] [Zip File]\\n\");\n\treturn -1;\n}\n"
  },
  {
    "path": "src/WriteZipToSetup/WriteZipToSetup.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{4D3C8B70-075D-48A5-9FF3-EDB87347B136}</ProjectGuid>\n    <ConfigurationType>Application</ConfigurationType>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>WriteZipToSetup</RootNamespace>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <UseDebugLibraries>true</UseDebugLibraries>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MinSpace</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader>Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"WriteZipToSetup.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "src/WriteZipToSetup/WriteZipToSetup.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"WriteZipToSetup.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/WriteZipToSetup/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\n// WriteZipToSetup.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n// TODO: reference any additional headers you need in STDAFX.H\n// and not in this file\n"
  },
  {
    "path": "src/WriteZipToSetup/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently, but\n// are changed infrequently\n//\n\n#pragma once\n\n#include <stdio.h>\n#include <tchar.h>\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\n// C RunTime Header Files\n#include <stdlib.h>\n#include <malloc.h>\n#include <memory.h>\n#include <tchar.h>\n#include <string>\n#include <iostream>\n#include <vector>\n\n// TODO: reference additional headers your program requires here\n"
  },
  {
    "path": "src/build_official.cmd",
    "content": "@echo off\n\nsetlocal\npushd %~dp0\n\n:parse_args\nif not \"%1\"==\"\" shift & goto parse_args\n\n:: Init\n\nif \"%VCToolsVersion%\"==\"\" call :StartDeveloperCommandPrompt || exit /b\n\n\n:: Clean\n\nrd /s /q ..\\build ..\\packages 2> nul\n\n\n:: Build\n\nnuget restore ..\\Squirrel.sln || exit /b\n\nmsbuild -Restore ..\\Squirrel.sln -p:Configuration=Release -v:m -m -nr:false -bl:..\\build\\logs\\build.binlog || exit /b\n\n\n:: Pack .nupkg\n\nnuget pack Squirrel.nuspec -OutputDirectory ..\\build\\artifacts || exit /b\n\n\n:: Layout electron-winstaller\n::\n:: The NPM package electron-winstaller allows developers to\n:: build Windows installers for Electron apps using Squirrel\n:: (https://github.com/electron/windows-installer)\n::\n:: The following copies the required files into a single folder\n:: which can then be copied to the electron-winstaller/vendor folder\n:: (either manually or in an automated way).\n\nmd ..\\build\\artifacts\\electron-winstaller\\vendor\n\ncopy ..\\build\\Release\\net45\\Update.exe ..\\build\\artifacts\\electron-winstaller\\vendor\\Squirrel.exe || exit /b\ncopy ..\\build\\Release\\net45\\update.com ..\\build\\artifacts\\electron-winstaller\\vendor\\Squirrel.com || exit /b\ncopy ..\\build\\Release\\net45\\Update.pdb ..\\build\\artifacts\\electron-winstaller\\vendor\\Squirrel.pdb || exit /b\ncopy ..\\build\\Release\\Win32\\Setup.exe ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\Win32\\Setup.pdb ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\net45\\Update-Mono.exe ..\\build\\artifacts\\electron-winstaller\\vendor\\Squirrel-Mono.exe || exit /b\ncopy ..\\build\\Release\\net45\\Update-Mono.pdb ..\\build\\artifacts\\electron-winstaller\\vendor\\Squirrel-Mono.pdb || exit /b\ncopy ..\\build\\Release\\Win32\\StubExecutable.exe ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\net45\\SyncReleases.exe ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\net45\\SyncReleases.pdb ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\Win32\\WriteZipToSetup.exe ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\ncopy ..\\build\\Release\\Win32\\WriteZipToSetup.pdb ..\\build\\artifacts\\electron-winstaller\\vendor || exit /b\n\n\ngoto LExit\n\n:StartDeveloperCommandPrompt\nif not \"%SquirrelSkipVsDevCmd%\"==\"\" (\n  echo Skipping initializing developer command prompt\n  exit /b\n)\n\necho Initializing developer command prompt\n\nif not exist \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" (\n  \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\"\n  exit /b 2\n)\n\nfor /f \"usebackq delims=\" %%i in (`\"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -version [16.0^,18.0^) -property installationPath`) do (\n  if exist \"%%i\\Common7\\Tools\\vsdevcmd.bat\" (\n    call \"%%i\\Common7\\Tools\\vsdevcmd.bat\" -no_logo\n    exit /b\n  )\n  echo developer command prompt not found in %%i\n)\n\necho No versions of developer command prompt found\nexit /b 2\n\n:LExit\n\npopd\nendlocal\n"
  },
  {
    "path": "src/squirrel.windows.props",
    "content": "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <SquirrelToolsPath>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\\tools'))</SquirrelToolsPath>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "test/Directory.Build.props",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <Import Project=\"..\\src\\Directory.Build.props\" />\n\n  <PropertyGroup>\n    <OutputPath>$(BaseOutputPath)$(Configuration)\\test\\</OutputPath>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "test/Squirrel.Tests/ApplyReleasesProgressTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Squirrel.Tests\n{\n    public class ApplyReleasesProgressTests\n    {\n\n        [Fact(Skip = \"Test does not pass consistently due to dependency on Task.Delay()\")]\n        public async Task CalculatesPercentageCorrectly()\n        {\n            // Just 1 complex situation should be enough to cover this\n\n            var percentage = 0;\n            var progress = new ApplyReleasesProgress(5, x => percentage = x);\n\n            // 2 releases already finished\n            progress.FinishRelease();\n            progress.FinishRelease();\n\n            // Report 40 % in current release\n            progress.ReportReleaseProgress(50);\n\n            // Required for callback to be invoked\n            await Task.Delay(50);\n\n            // 20 per release\n            // 10 because we are half-way the 3rd release\n            var expectedProgress = 20 + 20 + 10;\n\n            Assert.Equal(expectedProgress, percentage);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/ApplyReleasesTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing NuGet;\nusing Squirrel.SimpleSplat;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests\n{\n    public class FakeUrlDownloader : IFileDownloader\n    {\n        public Task<byte[]> DownloadUrl(string url)\n        {\n            return Task.FromResult(new byte[0]);\n        }\n\n        public async Task DownloadFile(string url, string targetFile, Action<int> progress)\n        {\n        }\n    }\n\n    public class ApplyReleasesTests : IEnableLogger\n    {\n        [Fact]\n        public async Task CleanInstallRunsSquirrelAwareAppsWithInstallFlag()\n        {\n            string tempDir;\n            string remotePkgDir;\n\n            using (Utility.WithTempDirectory(out tempDir))\n            using (Utility.WithTempDirectory(out remotePkgDir)) {\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.1.0\", remotePkgDir);\n                var pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.FullInstall();\n\n                    // NB: We execute the Squirrel-aware apps, so we need to give\n                    // them a minute to settle or else the using statement will\n                    // try to blow away a running process\n                    await Task.Delay(1000);\n\n                    Assert.False(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.1.0\", \"args2.txt\")));\n                    Assert.True(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.1.0\", \"args.txt\")));\n\n                    var text = File.ReadAllText(Path.Combine(tempDir, \"theApp\", \"app-0.1.0\", \"args.txt\"), Encoding.UTF8);\n                    Assert.Contains(\"firstrun\", text);\n                }\n            }\n        }\n\n        [Fact]\n        public async Task UpgradeRunsSquirrelAwareAppsWithUpgradeFlag()\n        {\n            string tempDir;\n            string remotePkgDir;\n\n            using (Utility.WithTempDirectory(out tempDir))\n            using (Utility.WithTempDirectory(out remotePkgDir)) {\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.1.0\", remotePkgDir);\n                var pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.FullInstall();\n                }\n\n                await Task.Delay(1000);\n\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.2.0\", remotePkgDir);\n                pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.UpdateApp();\n                }\n\n                await Task.Delay(1000);\n\n                Assert.False(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.2.0\", \"args2.txt\")));\n                Assert.True(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.2.0\", \"args.txt\")));\n\n                var text = File.ReadAllText(Path.Combine(tempDir, \"theApp\", \"app-0.2.0\", \"args.txt\"), Encoding.UTF8);\n                Assert.Contains(\"updated|0.2.0\", text);\n            }\n        }\n\n        [Fact]\n        public async Task RunningUpgradeAppTwiceDoesntCrash()\n        {\n            string tempDir;\n            string remotePkgDir;\n\n            using (Utility.WithTempDirectory(out tempDir))\n            using (Utility.WithTempDirectory(out remotePkgDir)) {\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.1.0\", remotePkgDir);\n                var pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.FullInstall();\n                }\n\n                await Task.Delay(1000);\n\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.2.0\", remotePkgDir);\n                pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.UpdateApp();\n                }\n\n                await Task.Delay(1000);\n\n                // NB: The 2nd time we won't have any updates to apply. We should just do nothing!\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.UpdateApp();\n                }\n\n                await Task.Delay(1000);\n            }\n        }\n\n        [Fact]\n        public async Task FullUninstallRemovesAllVersions()\n        {\n            string tempDir;\n            string remotePkgDir;\n\n            using (Utility.WithTempDirectory(out tempDir))\n            using (Utility.WithTempDirectory(out remotePkgDir)) {\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.1.0\", remotePkgDir);\n                var pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.FullInstall();\n                }\n\n                await Task.Delay(1000);\n\n                IntegrationTestHelper.CreateFakeInstalledApp(\"0.2.0\", remotePkgDir);\n                pkgs = ReleaseEntry.BuildReleasesFile(remotePkgDir);\n                ReleaseEntry.WriteReleaseFile(pkgs, Path.Combine(remotePkgDir, \"RELEASES\"));\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.UpdateApp();\n                }\n\n                await Task.Delay(1000);\n\n                using (var fixture = new UpdateManager(remotePkgDir, \"theApp\", tempDir)) {\n                    await fixture.FullUninstall();\n                }\n\n                Assert.False(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.1.0\", \"args.txt\")));\n                Assert.False(File.Exists(Path.Combine(tempDir, \"theApp\", \"app-0.2.0\", \"args.txt\")));\n                Assert.True(File.Exists(Path.Combine(tempDir, \"theApp\", \".dead\")));\n            }\n        }\n\n        [Fact]\n        public void WhenNoNewReleasesAreAvailableTheListIsEmpty()\n        {\n            string tempDir;\n            using (Utility.WithTempDirectory(out tempDir)) {\n                var appDir = Directory.CreateDirectory(Path.Combine(tempDir, \"theApp\"));\n                var packages = Path.Combine(appDir.FullName, \"packages\");\n                Directory.CreateDirectory(packages);\n\n                var package = \"Squirrel.Core.1.0.0.0-full.nupkg\";\n                File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", package), Path.Combine(packages, package));\n\n                var aGivenPackage = Path.Combine(packages, package);\n                var baseEntry = ReleaseEntry.GenerateFromFile(aGivenPackage);\n\n                var updateInfo = UpdateInfo.Create(baseEntry, new[] { baseEntry }, \"dontcare\");\n\n                Assert.Empty(updateInfo.ReleasesToApply);\n            }\n        }\n\n        [Fact]\n        public void ThrowsWhenOnlyDeltaReleasesAreAvailable()\n        {\n            string tempDir;\n            using (Utility.WithTempDirectory(out tempDir))\n            {\n                var appDir = Directory.CreateDirectory(Path.Combine(tempDir, \"theApp\"));\n                var packages = Path.Combine(appDir.FullName, \"packages\");\n                Directory.CreateDirectory(packages);\n\n                var baseFile = \"Squirrel.Core.1.0.0.0-full.nupkg\";\n                File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", baseFile),\n                          Path.Combine(packages, baseFile));\n                var basePackage = Path.Combine(packages, baseFile);\n                var baseEntry = ReleaseEntry.GenerateFromFile(basePackage);\n\n                var deltaFile = \"Squirrel.Core.1.1.0.0-delta.nupkg\";\n                File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", deltaFile),\n                          Path.Combine(packages, deltaFile));\n                var deltaPackage = Path.Combine(packages, deltaFile);\n                var deltaEntry = ReleaseEntry.GenerateFromFile(deltaPackage);\n\n                Assert.Throws<Exception>(\n                    () => UpdateInfo.Create(baseEntry, new[] { deltaEntry }, \"dontcare\"));\n            }\n        }\n\n        [Fact]\n        public async Task ApplyReleasesWithOneReleaseFile()\n        {\n            string tempDir;\n\n            using (Utility.WithTempDirectory(out tempDir)) {\n                string appDir = Path.Combine(tempDir, \"theApp\");\n                string packagesDir = Path.Combine(appDir, \"packages\");\n                Directory.CreateDirectory(packagesDir);\n\n                new[] {\n                    \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                    \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(packagesDir, x)));\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.0.0.0-full.nupkg\"));\n                var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.1.0.0-full.nupkg\"));\n\n                var updateInfo = UpdateInfo.Create(baseEntry, new[] { latestFullEntry }, packagesDir);\n                updateInfo.ReleasesToApply.Contains(latestFullEntry).ShouldBeTrue();\n\n                var progress = new List<int>();\n\n                await fixture.ApplyReleases(updateInfo, false, false, progress.Add);\n                this.Log().Info(\"Progress: [{0}]\", String.Join(\",\", progress));\n\n                progress\n                    .Aggregate(0, (acc, x) => { (x >= acc).ShouldBeTrue(); return x; })\n                    .ShouldEqual(100);\n\n                var filesToFind = new[] {\n                    new {Name = \"NLog.dll\", Version = new Version(\"2.0.0.0\")},\n                    new {Name = \"NSync.Core.dll\", Version = new Version(\"1.1.0.0\")},\n                };\n\n                filesToFind.ForEach(x => {\n                    var path = Path.Combine(tempDir, \"theApp\", \"app-1.1.0.0\", x.Name);\n                    this.Log().Info(\"Looking for {0}\", path);\n                    File.Exists(path).ShouldBeTrue();\n\n                    var vi = FileVersionInfo.GetVersionInfo(path);\n                    var verInfo = new Version(vi.FileVersion ?? \"1.0.0.0\");\n                    x.Version.ShouldEqual(verInfo);\n                });\n            }\n        }\n\n        [Fact]\n        public async Task ApplyReleaseWhichRemovesAFile()\n        {\n            string tempDir;\n\n            using (Utility.WithTempDirectory(out tempDir)) {\n                string appDir = Path.Combine(tempDir, \"theApp\");\n                string packagesDir = Path.Combine(appDir, \"packages\");\n                Directory.CreateDirectory(packagesDir);\n\n                new[] {\n                    \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    \"Squirrel.Core.1.2.0.0-full.nupkg\",\n                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(packagesDir, x)));\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.1.0.0-full.nupkg\"));\n                var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.2.0.0-full.nupkg\"));\n\n                var updateInfo = UpdateInfo.Create(baseEntry, new[] { latestFullEntry }, packagesDir);\n                updateInfo.ReleasesToApply.Contains(latestFullEntry).ShouldBeTrue();\n\n                var progress = new List<int>();\n                await fixture.ApplyReleases(updateInfo, false, false, progress.Add);\n                this.Log().Info(\"Progress: [{0}]\", String.Join(\",\", progress));\n\n                progress\n                    .Aggregate(0, (acc, x) => { (x >= acc).ShouldBeTrue(); return x; })\n                    .ShouldEqual(100);\n\n                var rootDirectory = Path.Combine(tempDir, \"theApp\", \"app-1.2.0.0\");\n\n                new[] {\n                    new {Name = \"NLog.dll\", Version = new Version(\"2.0.0.0\")},\n                    new {Name = \"NSync.Core.dll\", Version = new Version(\"1.1.0.0\")},\n                }.ForEach(x => {\n                    var path = Path.Combine(rootDirectory, x.Name);\n                    this.Log().Info(\"Looking for {0}\", path);\n                    File.Exists(path).ShouldBeTrue();\n                });\n\n                var removedFile = Path.Combine(\"sub\", \"Ionic.Zip.dll\");\n                var deployedPath = Path.Combine(rootDirectory, removedFile);\n                File.Exists(deployedPath).ShouldBeFalse();\n            }\n        }\n\n        [Fact]\n        public async Task ApplyReleaseWhichMovesAFileToADifferentDirectory()\n        {\n            string tempDir;\n\n            using (Utility.WithTempDirectory(out tempDir))\n            {\n                string appDir = Path.Combine(tempDir, \"theApp\");\n                string packagesDir = Path.Combine(appDir, \"packages\");\n                Directory.CreateDirectory(packagesDir);\n\n                new[] {\n                    \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    \"Squirrel.Core.1.3.0.0-full.nupkg\",\n                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(packagesDir, x)));\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.1.0.0-full.nupkg\"));\n                var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.3.0.0-full.nupkg\"));\n\n                var updateInfo = UpdateInfo.Create(baseEntry, new[] { latestFullEntry }, packagesDir);\n                updateInfo.ReleasesToApply.Contains(latestFullEntry).ShouldBeTrue();\n\n                var progress = new List<int>();\n                await fixture.ApplyReleases(updateInfo, false, false, progress.Add);\n                this.Log().Info(\"Progress: [{0}]\", String.Join(\",\", progress));\n\n                progress\n                    .Aggregate(0, (acc, x) => { (x >= acc).ShouldBeTrue(); return x; })\n                    .ShouldEqual(100);\n\n                var rootDirectory = Path.Combine(tempDir, \"theApp\", \"app-1.3.0.0\");\n\n                new[] {\n                    new {Name = \"NLog.dll\", Version = new Version(\"2.0.0.0\")},\n                    new {Name = \"NSync.Core.dll\", Version = new Version(\"1.1.0.0\")},\n                }.ForEach(x => {\n                    var path = Path.Combine(rootDirectory, x.Name);\n                    this.Log().Info(\"Looking for {0}\", path);\n                    File.Exists(path).ShouldBeTrue();\n                });\n\n                var oldFile = Path.Combine(rootDirectory, \"sub\", \"Ionic.Zip.dll\");\n                File.Exists(oldFile).ShouldBeFalse();\n\n                var newFile = Path.Combine(rootDirectory, \"other\", \"Ionic.Zip.dll\");\n                File.Exists(newFile).ShouldBeTrue();\n            }\n        }\n\n        [Fact]\n        public async Task ApplyReleasesWithDeltaReleases()\n        {\n            string tempDir;\n\n            using (Utility.WithTempDirectory(out tempDir)) {\n                string appDir = Path.Combine(tempDir, \"theApp\");\n                string packagesDir = Path.Combine(appDir, \"packages\");\n                Directory.CreateDirectory(packagesDir);\n\n                new[] {\n                    \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                    \"Squirrel.Core.1.1.0.0-delta.nupkg\",\n                    \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(packagesDir, x)));\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.0.0.0-full.nupkg\"));\n                var deltaEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.1.0.0-delta.nupkg\"));\n                var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(packagesDir, \"Squirrel.Core.1.1.0.0-full.nupkg\"));\n\n                var updateInfo = UpdateInfo.Create(baseEntry, new[] { deltaEntry, latestFullEntry }, packagesDir);\n                updateInfo.ReleasesToApply.Contains(deltaEntry).ShouldBeTrue();\n\n                var progress = new List<int>();\n\n                await fixture.ApplyReleases(updateInfo, false, false, progress.Add);\n                this.Log().Info(\"Progress: [{0}]\", String.Join(\",\", progress));\n\n                progress\n                    .Aggregate(0, (acc, x) => { (x >= acc).ShouldBeTrue(); return x; })\n                    .ShouldEqual(100);\n\n                var filesToFind = new[] {\n                    new {Name = \"NLog.dll\", Version = new Version(\"2.0.0.0\")},\n                    new {Name = \"NSync.Core.dll\", Version = new Version(\"1.1.0.0\")},\n                };\n\n                filesToFind.ForEach(x => {\n                    var path = Path.Combine(tempDir, \"theApp\", \"app-1.1.0.0\", x.Name);\n                    this.Log().Info(\"Looking for {0}\", path);\n                    File.Exists(path).ShouldBeTrue();\n\n                    var vi = FileVersionInfo.GetVersionInfo(path);\n                    var verInfo = new Version(vi.FileVersion ?? \"1.0.0.0\");\n                    x.Version.ShouldEqual(verInfo);\n                });\n            }\n        }\n\n        [Fact]\n        public async Task CreateFullPackagesFromDeltaSmokeTest()\n        {\n            string tempDir;\n            using (Utility.WithTempDirectory(out tempDir)) {\n                string appDir = Path.Combine(tempDir, \"theApp\");\n                string packagesDir = Path.Combine(appDir, \"packages\");\n                Directory.CreateDirectory(packagesDir);\n\n                new[] {\n                    \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                    \"Squirrel.Core.1.1.0.0-delta.nupkg\"\n                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(tempDir, \"theApp\", \"packages\", x)));\n\n                var urlDownloader = new FakeUrlDownloader();\n                var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, \"theApp\", \"packages\", \"Squirrel.Core.1.0.0.0-full.nupkg\"));\n                var deltaEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, \"theApp\", \"packages\", \"Squirrel.Core.1.1.0.0-delta.nupkg\"));\n\n                var resultObs = (Task<ReleaseEntry>)fixture.GetType().GetMethod(\"createFullPackagesFromDeltas\", BindingFlags.NonPublic | BindingFlags.Instance)\n                    .Invoke(fixture, new object[] { new[] {deltaEntry}, baseEntry, null });\n\n                var result = await resultObs;\n                var zp = new ZipPackage(Path.Combine(tempDir, \"theApp\", \"packages\", result.Filename));\n                zp.Version.ToString().ShouldEqual(\"1.1.0.0\");\n            }\n        }\n\n        [Fact]\n        public async Task CreateShortcutsRoundTrip()\n        {\n            string remotePkgPath;\n            string path;\n\n            using (Utility.WithTempDirectory(out path)) {\n                using (Utility.WithTempDirectory(out remotePkgPath))\n                using (var mgr = new UpdateManager(remotePkgPath, \"theApp\", path)) {\n                    IntegrationTestHelper.CreateFakeInstalledApp(\"1.0.0.1\", remotePkgPath);\n                    await mgr.FullInstall();\n                }\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(Path.Combine(path, \"theApp\"));\n                fixture.CreateShortcutsForExecutable(\"SquirrelAwareApp.exe\", ShortcutLocation.Desktop | ShortcutLocation.StartMenu | ShortcutLocation.Startup | ShortcutLocation.AppRoot, false, null, null);\n\n                // NB: COM is Weird.\n                Thread.Sleep(1000);\n                fixture.RemoveShortcutsForExecutable(\"SquirrelAwareApp.exe\", ShortcutLocation.Desktop | ShortcutLocation.StartMenu | ShortcutLocation.Startup | ShortcutLocation.AppRoot);\n\n                // NB: Squirrel-Aware first-run might still be running, slow\n                // our roll before blowing away the temp path\n                Thread.Sleep(1000);\n            }\n        }\n        \n        [Fact]\n        public void UnshimOurselvesSmokeTest()\n        {\n            // NB: This smoke test is really more of a manual test - try it\n            // by shimming Slack, then verifying the shim goes away\n            var appDir = Environment.ExpandEnvironmentVariables(@\"%LocalAppData%\\Slack\");\n            var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n            fixture.unshimOurselves();\n        }\n\n        [Fact(Skip = \"This test is currently failing in CI\")]\n        public async Task GetShortcutsSmokeTest()\n        {\n            string remotePkgPath;\n            string path;\n\n            using (Utility.WithTempDirectory(out path)) {\n                using (Utility.WithTempDirectory(out remotePkgPath))\n                using (var mgr = new UpdateManager(remotePkgPath, \"theApp\", path)) {\n                    IntegrationTestHelper.CreateFakeInstalledApp(\"1.0.0.1\", remotePkgPath);\n                    await mgr.FullInstall();\n                }\n\n                var fixture = new UpdateManager.ApplyReleasesImpl(Path.Combine(path, \"theApp\"));\n                var result = fixture.GetShortcutsForExecutable(\"SquirrelAwareApp.exe\", ShortcutLocation.Desktop | ShortcutLocation.StartMenu | ShortcutLocation.Startup, null);\n\n                Assert.Equal(3, result.Keys.Count);\n\n                // NB: Squirrel-Aware first-run might still be running, slow\n                // our roll before blowing away the temp path\n                Thread.Sleep(1000);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Squirrel.Tests/CheckForUpdateTests.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests\n{\n    public class CheckForUpdateTests\n    {\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public void NewReleasesShouldBeDetected()\n        {\n            Assert.False(true, \"Rewrite this to be an integration test\");\n            /*\n            string localReleasesFile = Path.Combine(\".\", \"theApp\", \"packages\", \"RELEASES\");\n\n            var fileInfo = new Mock<FileInfoBase>();\n            fileInfo.Setup(x => x.OpenRead())\n                .Returns(File.OpenRead(IntegrationTestHelper.GetPath(\"fixtures\", \"RELEASES-OnePointOh\")));\n\n            var fs = new Mock<IFileSystemFactory>();\n            fs.Setup(x => x.GetFileInfo(localReleasesFile)).Returns(fileInfo.Object);\n\n            var urlDownloader = new Mock<IUrlDownloader>();\n            var dlPath = IntegrationTestHelper.GetPath(\"fixtures\", \"RELEASES-OnePointOne\");\n            urlDownloader.Setup(x => x.DownloadUrl(It.IsAny<string>(), It.IsAny<IObserver<int>>()))\n                .Returns(Observable.Return(File.ReadAllText(dlPath, Encoding.UTF8)));\n\n            var fixture = new UpdateManager(\"http://lol\", \"theApp\", \".\", fs.Object, urlDownloader.Object);\n            var result = default(UpdateInfo);\n\n            using (fixture) {\n                result = fixture.CheckForUpdate().First();\n            }\n\n            Assert.NotNull(result);\n            Assert.Equal(1, result.ReleasesToApply.Single().Version.Major);\n            Assert.Equal(1, result.ReleasesToApply.Single().Version.Minor);\n            */\n        }\n\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public void CorruptedReleaseFileMeansWeStartFromScratch()\n        {\n            Assert.False(true, \"Rewrite this to be an integration test\");\n\n            /*\n            string localPackagesDir = Path.Combine(\".\", \"theApp\", \"packages\");\n            string localReleasesFile = Path.Combine(localPackagesDir, \"RELEASES\");\n\n            var fileInfo = new Mock<FileInfoBase>();\n            fileInfo.Setup(x => x.Exists).Returns(true);\n            fileInfo.Setup(x => x.OpenRead())\n                .Returns(new MemoryStream(Encoding.UTF8.GetBytes(\"lol this isn't right\")));\n\n            var dirInfo = new Mock<DirectoryInfoBase>();\n            dirInfo.Setup(x => x.Exists).Returns(true);\n\n            var fs = new Mock<IFileSystemFactory>();\n            fs.Setup(x => x.GetFileInfo(localReleasesFile)).Returns(fileInfo.Object);\n            fs.Setup(x => x.CreateDirectoryRecursive(localPackagesDir)).Verifiable();\n            fs.Setup(x => x.DeleteDirectoryRecursive(localPackagesDir)).Verifiable();\n            fs.Setup(x => x.GetDirectoryInfo(localPackagesDir)).Returns(dirInfo.Object);\n\n            var urlDownloader = new Mock<IUrlDownloader>();\n            var dlPath = IntegrationTestHelper.GetPath(\"fixtures\", \"RELEASES-OnePointOne\");\n            urlDownloader.Setup(x => x.DownloadUrl(It.IsAny<string>(), It.IsAny<IObserver<int>>()))\n                .Returns(Observable.Return(File.ReadAllText(dlPath, Encoding.UTF8)));\n\n            var fixture = new UpdateManager(\"http://lol\", \"theApp\", \".\", fs.Object, urlDownloader.Object);\n            using (fixture) {\n                fixture.CheckForUpdate().First();\n            }\n\n            fs.Verify(x => x.CreateDirectoryRecursive(localPackagesDir), Times.Once());\n            fs.Verify(x => x.DeleteDirectoryRecursive(localPackagesDir), Times.Once());\n            */\n        }\n\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public void CorruptRemoteFileShouldThrowOnCheck()\n        {\n            Assert.False(true, \"Rewrite this to be an integration test\");\n\n            /*\n            string localPackagesDir = Path.Combine(\".\", \"theApp\", \"packages\");\n            string localReleasesFile = Path.Combine(localPackagesDir, \"RELEASES\");\n\n            var fileInfo = new Mock<FileInfoBase>();\n            fileInfo.Setup(x => x.Exists).Returns(false);\n\n            var dirInfo = new Mock<DirectoryInfoBase>();\n            dirInfo.Setup(x => x.Exists).Returns(true);\n\n            var fs = new Mock<IFileSystemFactory>();\n            fs.Setup(x => x.GetFileInfo(localReleasesFile)).Returns(fileInfo.Object);\n            fs.Setup(x => x.CreateDirectoryRecursive(localPackagesDir)).Verifiable();\n            fs.Setup(x => x.DeleteDirectoryRecursive(localPackagesDir)).Verifiable();\n            fs.Setup(x => x.GetDirectoryInfo(localPackagesDir)).Returns(dirInfo.Object);\n\n            var urlDownloader = new Mock<IUrlDownloader>();\n            urlDownloader.Setup(x => x.DownloadUrl(It.IsAny<string>(), It.IsAny<IObserver<int>>()))\n                .Returns(Observable.Return(\"lol this isn't right\"));\n\n            var fixture = new UpdateManager(\"http://lol\", \"theApp\", \".\", fs.Object, urlDownloader.Object);\n\n            using (fixture) {\n                Assert.Throws<Exception>(() => fixture.CheckForUpdate().First());   \n            }\n            */\n        }\n\n        [Fact(Skip = \"TODO\")]\n        public void IfLocalVersionGreaterThanRemoteWeRollback()\n        {\n            throw new NotImplementedException();\n        }\n\n        [Fact(Skip = \"TODO\")]\n        public void IfLocalAndRemoteAreEqualThenDoNothing()\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/ContentTypeTests.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Xml;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests.Core\n{\n    public class ContentTypeTests\n    {\n        [Theory(Skip = \"This test is currently failing in CI\")]\n        [InlineData(\"basic.xml\", \"basic-merged.xml\")]\n        [InlineData(\"complex.xml\", \"complex-merged.xml\")]\n        public void MergeContentTypes(string inputFileName, string expectedFileName)\n        {\n            var inputFile = IntegrationTestHelper.GetPath(\"fixtures\", \"content-types\", inputFileName);\n            var expectedFile = IntegrationTestHelper.GetPath(\"fixtures\", \"content-types\", expectedFileName);\n            var tempFile = Path.GetTempFileName() + \".xml\";\n\n            var expected = new XmlDocument();\n            expected.Load(expectedFile);\n\n            var existingTypes = GetContentTypes(expected);\n\n            try {\n                File.Copy(inputFile, tempFile);\n\n                var actual = new XmlDocument();\n                actual.Load(tempFile);\n\n                ContentType.Merge(actual);\n\n                var actualTypes = GetContentTypes(actual);\n\n                Assert.Equal(existingTypes, actualTypes);\n            } finally {\n                File.Delete(tempFile);\n            }\n        }\n\n        static IEnumerable<XmlElement> GetContentTypes(XmlNode doc)\n        {\n            var expectedTypesElement = doc.FirstChild.NextSibling;\n            return expectedTypesElement.ChildNodes.OfType<XmlElement>();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/DeltaPackageTests.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing NuGet;\nusing Squirrel;\nusing Squirrel.SimpleSplat;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests.Core\n{\n    public class ApplyDeltaPackageTests : IEnableLogger\n    {\n        [Fact]\n        public void ApplyDeltaPackageSmokeTest()\n        {\n            var basePackage = new ReleasePackage(IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.0.0.0-full.nupkg\"));\n            var deltaPackage = new ReleasePackage(IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0-delta.nupkg\"));\n            var expectedPackageFile = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0-full.nupkg\");\n            var outFile = Path.GetTempFileName() + \".nupkg\";\n\n            try {\n                var deltaBuilder = new DeltaPackageBuilder();\n                deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile);\n\n                var result = new ZipPackage(outFile);\n                var expected = new ZipPackage(expectedPackageFile);\n\n                result.Id.ShouldEqual(expected.Id);\n                result.Version.ShouldEqual(expected.Version);\n\n                this.Log().Info(\"Expected file list:\");\n                var expectedList = expected.GetFiles().Select(x => x.Path).OrderBy(x => x).ToList();\n                expectedList.ForEach(x => this.Log().Info(x));\n\n                this.Log().Info(\"Actual file list:\");\n                var actualList = result.GetFiles().Select(x => x.Path).OrderBy(x => x).ToList();\n                actualList.ForEach(x => this.Log().Info(x));\n\n                Enumerable.Zip(expectedList, actualList, (e, a) => e == a)\n                    .All(x => x != false)\n                    .ShouldBeTrue();\n            } finally {\n                if (File.Exists(outFile)) {\n                    File.Delete(outFile);\n                }\n            }\n        }\n\n        [Fact]\n        public void ApplyDeltaWithBothBsdiffAndNormalDiffDoesntFail()\n        {\n            var basePackage = new ReleasePackage(IntegrationTestHelper.GetPath(\"fixtures\", \"slack-1.1.8-full.nupkg\"));\n            var deltaPackage = new ReleasePackage(IntegrationTestHelper.GetPath(\"fixtures\", \"slack-1.2.0-delta.nupkg\"));\n            var outFile = Path.GetTempFileName() + \".nupkg\";\n\n            try {\n                var deltaBuilder = new DeltaPackageBuilder();\n                deltaBuilder.ApplyDeltaPackage(basePackage, deltaPackage, outFile);\n\n                var result = new ZipPackage(outFile);\n\n                result.Id.ShouldEqual(\"slack\");\n                result.Version.ShouldEqual(new SemanticVersion(\"1.2.0\"));\n            } finally {\n                if (File.Exists(outFile)) {\n                    File.Delete(outFile);\n                }\n            }\n        }\n\n        [Fact(Skip = \"Rewrite this test, the original uses too many heavyweight fixtures\")]\n        public void ApplyMultipleDeltaPackagesGeneratesCorrectHash()\n        {\n            Assert.True(false, \"Rewrite this test, the original uses too many heavyweight fixtures\");\n        }\n    }\n\n    public class CreateDeltaPackageTests : IEnableLogger\n    {\n        [Fact]\n        public void CreateDeltaPackageIntegrationTest()\n        {\n            var basePackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var newPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.2.0-pre.nupkg\");\n\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var baseFixture = new ReleasePackage(basePackage);\n            var fixture = new ReleasePackage(newPackage);\n\n            var tempFiles = Enumerable.Range(0, 3)\n                .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + \".nupkg\")\n                .ToArray();\n\n            try {\n                baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);\n                fixture.CreateReleasePackage(tempFiles[1], sourceDir);\n\n                (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n                (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n\n                var deltaBuilder = new DeltaPackageBuilder();\n                deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);\n\n                var fullPkg = new ZipPackage(tempFiles[1]);\n                var deltaPkg = new ZipPackage(tempFiles[2]);\n\n                //\n                // Package Checks\n                //\n\n                fullPkg.Id.ShouldEqual(deltaPkg.Id);\n                fullPkg.Version.CompareTo(deltaPkg.Version).ShouldEqual(0);\n\n                // Delta packages should be smaller than the original!\n                var fileInfos = tempFiles.Select(x => new FileInfo(x)).ToArray();\n                this.Log().Info(\"Base Size: {0}, Current Size: {1}, Delta Size: {2}\",\n                    fileInfos[0].Length, fileInfos[1].Length, fileInfos[2].Length);\n\n                (fileInfos[2].Length - fileInfos[1].Length).ShouldBeLessThan(0);\n\n                //\n                // File Checks\n                ///\n\n                var deltaPkgFiles = deltaPkg.GetFiles().ToList();\n                deltaPkgFiles.Count.ShouldBeGreaterThan(0);\n\n                this.Log().Info(\"Files in delta package:\");\n                deltaPkgFiles.ForEach(x => this.Log().Info(x.Path));\n\n                var newFilesAdded = new[] {\n                    \"Newtonsoft.Json.dll\",\n                    \"Refit.dll\",\n                    \"Refit-Portable.dll\",\n                    \"Castle.Core.dll\",\n                }.Select(x => x.ToLowerInvariant());\n\n                // vNext adds a dependency on Refit\n                newFilesAdded\n                    .All(x => deltaPkgFiles.Any(y => y.Path.ToLowerInvariant().Contains(x)))\n                    .ShouldBeTrue();\n\n                // All the other files should be diffs and shasums\n                deltaPkgFiles\n                    .Where(x => !newFilesAdded.Any(y => x.Path.ToLowerInvariant().Contains(y)))\n                    .All(x => x.Path.ToLowerInvariant().EndsWith(\"diff\") || x.Path.ToLowerInvariant().EndsWith(\"shasum\"))\n                    .ShouldBeTrue();\n\n                // Every .diff file should have a shasum file\n                deltaPkg.GetFiles().Any(x => x.Path.ToLowerInvariant().EndsWith(\".diff\")).ShouldBeTrue();\n                deltaPkg.GetFiles()\n                    .Where(x => x.Path.ToLowerInvariant().EndsWith(\".diff\"))\n                    .ForEach(x => {\n                        var lookingFor = x.Path.Replace(\".diff\", \".shasum\");\n                        this.Log().Info(\"Looking for corresponding shasum file: {0}\", lookingFor);\n                        deltaPkg.GetFiles().Any(y => y.Path == lookingFor).ShouldBeTrue();\n                    });\n            } finally {\n                tempFiles.ForEach(File.Delete);\n            }\n        }\n\n        [Fact]\n        public void WhenBasePackageIsNewerThanNewPackageThrowException()\n        {\n            var basePackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.2.0-pre.nupkg\");\n            var newPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var baseFixture = new ReleasePackage(basePackage);\n            var fixture = new ReleasePackage(newPackage);\n\n            var tempFiles = Enumerable.Range(0, 3)\n                .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + \".nupkg\")\n                .ToArray();\n\n            try {\n                baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);\n                fixture.CreateReleasePackage(tempFiles[1], sourceDir);\n\n                (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n                (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n\n                Assert.Throws<InvalidOperationException>(() =>\n                {\n                    var deltaBuilder = new DeltaPackageBuilder();\n                    deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);\n                });\n            } finally {\n                tempFiles.ForEach(File.Delete);\n            }\n        }\n\n        [Fact]\n        public void WhenBasePackageReleaseIsNullThrowsException()\n        {\n            var basePackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.0.0.0.nupkg\");\n            var newPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0.nupkg\");\n\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var baseFixture = new ReleasePackage(basePackage);\n            var fixture = new ReleasePackage(newPackage);\n\n            var tempFile = Path.GetTempPath() + Guid.NewGuid() + \".nupkg\";\n\n            try {\n                Assert.Throws<ArgumentException>(() => {\n                    var deltaBuilder = new DeltaPackageBuilder();\n                    deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFile);\n                });\n            } finally {\n                File.Delete(tempFile);\n            }\n        }\n\n        [Fact]\n        public void WhenBasePackageDoesNotExistThrowException()\n        {\n            var basePackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var newPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.2.0-pre.nupkg\");\n\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var baseFixture = new ReleasePackage(basePackage);\n            var fixture = new ReleasePackage(newPackage);\n\n            var tempFiles = Enumerable.Range(0, 3)\n                .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + \".nupkg\")\n                .ToArray();\n\n            try {\n                baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);\n                fixture.CreateReleasePackage(tempFiles[1], sourceDir);\n\n                (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n                (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n\n                // NOW WATCH AS THE FILE DISAPPEARS\n                File.Delete(baseFixture.ReleasePackageFile);\n\n                Assert.Throws<FileNotFoundException>(() => {\n                    var deltaBuilder = new DeltaPackageBuilder();\n                    deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);\n                });\n            } finally {\n                tempFiles.ForEach(File.Delete);\n            }\n        }\n\n        [Fact]\n        public void WhenNewPackageDoesNotExistThrowException()\n        {\n            var basePackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var newPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.2.0-pre.nupkg\");\n\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var baseFixture = new ReleasePackage(basePackage);\n            var fixture = new ReleasePackage(newPackage);\n\n            var tempFiles = Enumerable.Range(0, 3)\n                .Select(_ => Path.GetTempPath() + Guid.NewGuid().ToString() + \".nupkg\")\n                .ToArray();\n\n            try {\n                baseFixture.CreateReleasePackage(tempFiles[0], sourceDir);\n                fixture.CreateReleasePackage(tempFiles[1], sourceDir);\n\n                (new FileInfo(baseFixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n                (new FileInfo(fixture.ReleasePackageFile)).Exists.ShouldBeTrue();\n\n                // NOW WATCH AS THE FILE DISAPPEARS\n                File.Delete(fixture.ReleasePackageFile);\n\n                Assert.Throws<FileNotFoundException>(() => {\n                    var deltaBuilder = new DeltaPackageBuilder();\n                    deltaBuilder.CreateDeltaPackage(baseFixture, fixture, tempFiles[2]);\n                });\n            } finally {\n                tempFiles.ForEach(File.Delete);\n            }\n        }\n\n        [Fact]\n        public void HandleBsDiffWithoutExtraData()\n        {\n            var baseFileData = new byte[] { 1, 1, 1, 1 };\n            var newFileData = new byte[] { 2, 1, 1, 1 };\n\n            byte[] patchData;\n\n            using (var patchOut = new MemoryStream())\n            {\n                Bsdiff.BinaryPatchUtility.Create(baseFileData, newFileData, patchOut);\n                patchData = patchOut.ToArray();\n            }\n\n            using (var toPatch = new MemoryStream(baseFileData))\n            using (var patched = new MemoryStream())\n            {\n                Bsdiff.BinaryPatchUtility.Apply(toPatch, () => new MemoryStream(patchData), patched);\n\n                Assert.Equal(newFileData, patched.ToArray());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/DownloadReleasesTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.SimpleSplat;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests\n{\n    public class DownloadReleasesTests : IEnableLogger\n    {\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public void ChecksumShouldFailIfFilesAreMissing()\n        {\n            Assert.False(true, \"Rewrite this to be an integration test\");\n\n            /*\n            var filename = \"Squirrel.Core.1.0.0.0.nupkg\";\n            var nuGetPkg = IntegrationTestHelper.GetPath(\"fixtures\", filename);\n            var fs = new Mock<IFileSystemFactory>();\n            var urlDownloader = new Mock<IUrlDownloader>();\n\n            ReleaseEntry entry;\n            using (var f = File.OpenRead(nuGetPkg)) {\n                entry = ReleaseEntry.GenerateFromFile(f, filename);\n            }\n\n            var fileInfo = new Mock<FileInfoBase>();\n            fileInfo.Setup(x => x.OpenRead()).Returns(File.OpenRead(nuGetPkg));\n            fileInfo.Setup(x => x.Exists).Returns(false);\n\n            fs.Setup(x => x.GetFileInfo(Path.Combine(\".\", \"theApp\", \"packages\", filename))).Returns(fileInfo.Object);\n\n            var fixture = ExposedObject.From(\n                new UpdateManager(\"http://lol\", \"theApp\", \".\", fs.Object, urlDownloader.Object));\n\n            bool shouldDie = true;\n            try {\n                // NB: We can't use Assert.Throws here because the binder\n                // will try to pick the wrong method\n                fixture.checksumPackage(entry);\n            } catch (Exception) {\n                shouldDie = false;\n            }\n\n            shouldDie.ShouldBeFalse();\n            */\n        }\n\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public void ChecksumShouldFailIfFilesAreBogus()\n        {\n            Assert.False(true, \"Rewrite this to be an integration test\");\n\n            /*\n            var filename = \"Squirrel.Core.1.0.0.0.nupkg\";\n            var nuGetPkg = IntegrationTestHelper.GetPath(\"fixtures\", filename);\n            var fs = new Mock<IFileSystemFactory>();\n            var urlDownloader = new Mock<IUrlDownloader>();\n\n            ReleaseEntry entry;\n            using (var f = File.OpenRead(nuGetPkg)) {\n                entry = ReleaseEntry.GenerateFromFile(f, filename);\n            }\n\n            var fileInfo = new Mock<FileInfoBase>();\n            fileInfo.Setup(x => x.OpenRead()).Returns(new MemoryStream(Encoding.UTF8.GetBytes(\"Lol broken\")));\n            fileInfo.Setup(x => x.Exists).Returns(true);\n            fileInfo.Setup(x => x.Length).Returns(new FileInfo(nuGetPkg).Length);\n            fileInfo.Setup(x => x.Delete()).Verifiable();\n\n            fs.Setup(x => x.GetFileInfo(Path.Combine(\".\", \"theApp\", \"packages\", filename))).Returns(fileInfo.Object);\n\n            var fixture = ExposedObject.From(\n                new UpdateManager(\"http://lol\", \"theApp\", \".\", fs.Object, urlDownloader.Object));\n\n            bool shouldDie = true;\n            try {\n                fixture.checksumPackage(entry);\n            } catch (Exception ex) {\n                this.Log().InfoException(\"Checksum failure\", ex);\n                shouldDie = false;\n            }\n\n            shouldDie.ShouldBeFalse();\n            fileInfo.Verify(x => x.Delete(), Times.Once());\n            */\n        }\n\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public async Task DownloadReleasesFromHttpServerIntegrationTest()\n        {\n            Assert.False(true, \"Rewrite this to not use the SampleUpdatingApp\");\n\n            /*\n            string tempDir = null;\n\n            var updateDir = new DirectoryInfo(IntegrationTestHelper.GetPath(\"..\", \"SampleUpdatingApp\", \"SampleReleasesFolder\"));\n\n            IDisposable disp;\n            try {\n                var httpServer = new StaticHttpServer(30405, updateDir.FullName);\n                disp = httpServer.Start();\n            } catch (HttpListenerException) {\n                Assert.False(true, @\"Windows sucks, go run 'netsh http add urlacl url=http://+:30405/ user=MYMACHINE\\MyUser\");\n                return;\n            }\n\n            var entriesToDownload = updateDir.GetFiles(\"*.nupkg\")\n                .Select(x => ReleaseEntry.GenerateFromFile(x.FullName))\n                .ToArray();\n\n            entriesToDownload.Count().ShouldBeGreaterThan(0);\n\n            using (disp)\n            using (Utility.WithTempDirectory(out tempDir)) {\n                // NB: This is normally done by CheckForUpdates, but since \n                // we're skipping that in the test we have to do it ourselves\n                Directory.CreateDirectory(Path.Combine(tempDir, \"SampleUpdatingApp\", \"packages\"));\n\n                var fixture = new UpdateManager(\"http://localhost:30405\", \"SampleUpdatingApp\", tempDir);\n                using (fixture) {\n                    var progress = new List<int>();\n                    await fixture.DownloadReleases(entriesToDownload, progress.Add);\n\n                    progress\n                        .Aggregate(0, (acc, x) => { x.ShouldBeGreaterThan(acc); return x; })\n                        .ShouldEqual(100);\n                }\n\n                entriesToDownload.ForEach(x => {\n                    this.Log().Info(\"Looking for {0}\", x.Filename);\n                    var actualFile = Path.Combine(tempDir, \"SampleUpdatingApp\", \"packages\", x.Filename);\n                    File.Exists(actualFile).ShouldBeTrue();\n\n                    var actualEntry = ReleaseEntry.GenerateFromFile(actualFile);\n                    actualEntry.SHA1.ShouldEqual(x.SHA1);\n                    actualEntry.Version.ShouldEqual(x.Version);\n                });\n            }\n            */\n        }\n\n        [Fact(Skip = \"Rewrite this to be an integration test\")]\n        public async Task DownloadReleasesFromFileDirectoryIntegrationTest()\n        {\n            Assert.False(true, \"Rewrite this to not use the SampleUpdatingApp\");\n\n            /*\n            string tempDir = null;\n\n            var updateDir = new DirectoryInfo(IntegrationTestHelper.GetPath(\"..\", \"SampleUpdatingApp\", \"SampleReleasesFolder\"));\n\n            var entriesToDownload = updateDir.GetFiles(\"*.nupkg\")\n                .Select(x => ReleaseEntry.GenerateFromFile(x.FullName))\n                .ToArray();\n\n            entriesToDownload.Count().ShouldBeGreaterThan(0);\n\n            using (Utility.WithTempDirectory(out tempDir)) {\n                // NB: This is normally done by CheckForUpdates, but since \n                // we're skipping that in the test we have to do it ourselves\n                Directory.CreateDirectory(Path.Combine(tempDir, \"SampleUpdatingApp\", \"packages\"));\n\n                var fixture = new UpdateManager(updateDir.FullName, \"SampleUpdatingApp\", tempDir);\n                using (fixture) {\n                    var progress = new List<int>();\n\n                    await fixture.DownloadReleases(entriesToDownload, progress.Add);\n                    this.Log().Info(\"Progress: [{0}]\", String.Join(\",\", progress));\n\n                    progress\n                        .Aggregate(0, (acc, x) => { x.ShouldBeGreaterThan(acc); return x; })\n                        .ShouldEqual(100);\n                }\n\n                entriesToDownload.ForEach(x => {\n                    this.Log().Info(\"Looking for {0}\", x.Filename);\n                    var actualFile = Path.Combine(tempDir, \"SampleUpdatingApp\", \"packages\", x.Filename);\n                    File.Exists(actualFile).ShouldBeTrue();\n\n                    var actualEntry = ReleaseEntry.GenerateFromFile(actualFile);\n                    actualEntry.SHA1.ShouldEqual(x.SHA1);\n                    actualEntry.Version.ShouldEqual(x.Version);\n                });\n            }\n            */\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.InteropServices;\nusing Xunit;\n\n[assembly: ComVisible(false)]\n[assembly: CollectionBehavior(MaxParallelThreads=1, DisableTestParallelization=true)]\n[assembly: AssemblyMetadata(\"SquirrelAwareVersion\", \"1\")]"
  },
  {
    "path": "test/Squirrel.Tests/ReleaseEntryTests.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\nusing NuGet;\n\nnamespace Squirrel.Tests.Core\n{\n    public class ReleaseEntryTests\n    {\n        [Theory]\n        [InlineData(@\"94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502\", \"MyCoolApp-1.0.nupkg\", 1004502, null, null)]\n        [InlineData(@\"3a2eadd15dd984e4559f2b4d790ec8badaeb6a39   MyCoolApp-1.1.nupkg   1040561\", \"MyCoolApp-1.1.nupkg\", 1040561, null, null)]\n        [InlineData(@\"14db31d2647c6d2284882a2e101924a9c409ee67  MyCoolApp-1.1.nupkg.delta  80396\", \"MyCoolApp-1.1.nupkg.delta\", 80396, null, null)]\n        [InlineData(@\"0000000000000000000000000000000000000000  http://test.org/Folder/MyCoolApp-1.2.nupkg  2569\", \"MyCoolApp-1.2.nupkg\", 2569, \"http://test.org/Folder/\", null)]\n        [InlineData(@\"0000000000000000000000000000000000000000  http://test.org/Folder/MyCoolApp-1.2.nupkg?query=param  2569\", \"MyCoolApp-1.2.nupkg\", 2569, \"http://test.org/Folder/\", \"?query=param\")]\n        [InlineData(@\"0000000000000000000000000000000000000000  https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg  1231953\", \"MyCoolApp-1.2-delta.nupkg\", 1231953, \"https://www.test.org/Folder/\", null)]\n        [InlineData(@\"0000000000000000000000000000000000000000  https://www.test.org/Folder/MyCoolApp-1.2-delta.nupkg?query=param  1231953\", \"MyCoolApp-1.2-delta.nupkg\", 1231953, \"https://www.test.org/Folder/\", \"?query=param\")]\n        public void ParseValidReleaseEntryLines(string releaseEntry, string fileName, long fileSize, string baseUrl, string query)\n        {\n            var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);\n            Assert.Equal(fileName, fixture.Filename);\n            Assert.Equal(fileSize, fixture.Filesize);\n            Assert.Equal(baseUrl, fixture.BaseUrl);\n            Assert.Equal(query, fixture.Query);\n        }\n\n        [Theory]\n        [InlineData(@\"0000000000000000000000000000000000000000  file:/C/Folder/MyCoolApp-0.0.nupkg  0\")]\n        [InlineData(@\"0000000000000000000000000000000000000000  C:\\Folder\\MyCoolApp-0.0.nupkg  0\")]\n        [InlineData(@\"0000000000000000000000000000000000000000  ..\\OtherFolder\\MyCoolApp-0.0.nupkg  0\")]\n        [InlineData(@\"0000000000000000000000000000000000000000  ../OtherFolder/MyCoolApp-0.0.nupkg  0\")]\n        [InlineData(@\"0000000000000000000000000000000000000000  \\\\Somewhere\\NetworkShare\\MyCoolApp-0.0.nupkg.delta  0\")]\n        public void ParseThrowsWhenInvalidReleaseEntryLines(string releaseEntry)\n        {\n            Assert.Throws<Exception>(() => ReleaseEntry.ParseReleaseEntry(releaseEntry));\n        }\n\n        [Theory]\n        [InlineData(@\"0000000000000000000000000000000000000000 file.nupkg 0\")]\n        [InlineData(@\"0000000000000000000000000000000000000000 http://path/file.nupkg 0\")]\n        public void EntryAsStringMatchesParsedInput(string releaseEntry)\n        {\n            var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);\n            Assert.Equal(releaseEntry, fixture.EntryAsString);\n        }\n\n        [Theory]\n        [InlineData(\"Squirrel.Core.1.0.0.0.nupkg\", 4457, \"75255cfd229a1ed1447abe1104f5635e69975d30\")]\n        [InlineData(\"Squirrel.Core.1.1.0.0.nupkg\", 15830, \"9baf1dbacb09940086c8c62d9a9dbe69fe1f7593\")]\n        public void GenerateFromFileTest(string name, long size, string sha1)\n        {\n            var path = IntegrationTestHelper.GetPath(\"fixtures\", name);\n\n            using (var f = File.OpenRead(path)) {\n                var fixture = ReleaseEntry.GenerateFromFile(f, \"dontcare\");\n                Assert.Equal(size, fixture.Filesize);\n                Assert.Equal(sha1, fixture.SHA1.ToLowerInvariant());\n            }\n        }\n\n        [Theory]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.nupkg                  123\", 1, 2, 0, 0, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-full.nupkg             123\", 1, 2, 0, 0, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-delta.nupkg            123\", 1, 2, 0, 0, \"\", true)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1.nupkg            123\", 1, 2, 0, 0, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1-full.nupkg       123\", 1, 2, 0, 0, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1-delta.nupkg      123\", 1, 2, 0, 0, \"beta1\", true)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.nupkg                123\", 1, 2, 3, 0, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-full.nupkg           123\", 1, 2, 3, 0, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-delta.nupkg          123\", 1, 2, 3, 0, \"\", true)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1.nupkg          123\", 1, 2, 3, 0, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1-full.nupkg     123\", 1, 2, 3, 0, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1-delta.nupkg    123\", 1, 2, 3, 0, \"beta1\", true)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4.nupkg              123\", 1, 2, 3, 4, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-full.nupkg         123\", 1, 2, 3, 4, \"\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-delta.nupkg        123\", 1, 2, 3, 4, \"\", true)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-beta1.nupkg        123\", 1, 2, 3, 4, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-beta1-full.nupkg   123\", 1, 2, 3, 4, \"beta1\", false)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-beta1-delta.nupkg  123\", 1, 2, 3, 4, \"beta1\", true)]\n        public void ParseVersionTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, bool isDelta)\n        {\n            var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);\n\n            Assert.Equal(new SemanticVersion(new Version(major, minor, patch, revision), prerelease), fixture.Version);\n            Assert.Equal(isDelta, fixture.IsDelta);\n        }\n\n        [Theory]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool-App-1.2.nupkg                  123\", \"MyCool-App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool_App-1.2-full.nupkg             123\", \"MyCool_App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-delta.nupkg            123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1.nupkg            123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1-full.nupkg       123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-beta1-delta.nupkg      123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool-App-1.2.3.nupkg                123\", \"MyCool-App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool_App-1.2.3-full.nupkg           123\", \"MyCool_App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-delta.nupkg          123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1.nupkg          123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1-full.nupkg     123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3-beta1-delta.nupkg    123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool-App-1.2.3.4.nupkg              123\", \"MyCool-App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool_App-1.2.3.4-full.nupkg         123\", \"MyCool_App\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-delta.nupkg        123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-beta1.nupkg        123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.3.4-beta1-full.nupkg   123\", \"MyCoolApp\")]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCool-App-1.2.3.4-beta1-delta.nupkg  123\", \"MyCool-App\")]\n        public void CheckPackageName(string releaseEntry, string expected)\n        {\n            var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);\n            Assert.Equal(expected, fixture.PackageName);\n        }\n\n        [Theory]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2.nupkg                  123 # 10%\", 1, 2, 0, 0, \"\", false, 0.1f)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-full.nupkg             123 # 90%\", 1, 2, 0, 0, \"\", false, 0.9f)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-delta.nupkg            123\", 1, 2, 0, 0, \"\", true, null)]\n        [InlineData(\"0000000000000000000000000000000000000000  MyCoolApp-1.2-delta.nupkg            123 # 5%\", 1, 2, 0, 0, \"\", true, 0.05f)]\n        public void ParseStagingPercentageTest(string releaseEntry, int major, int minor, int patch, int revision, string prerelease, bool isDelta, float? stagingPercentage)\n        {\n            var fixture = ReleaseEntry.ParseReleaseEntry(releaseEntry);\n\n            Assert.Equal(new SemanticVersion(new Version(major, minor, patch, revision), prerelease), fixture.Version);\n            Assert.Equal(isDelta, fixture.IsDelta);\n\n            if (stagingPercentage.HasValue) {\n                Assert.True(Math.Abs(fixture.StagingPercentage.Value - stagingPercentage.Value) < 0.001);\n            } else {\n                Assert.Null(fixture.StagingPercentage);\n            }\n        }\n\n\n        [Fact]\n        public void CanParseGeneratedReleaseEntryAsString()\n        {\n            var path = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0.nupkg\");\n            var entryAsString = ReleaseEntry.GenerateFromFile(path).EntryAsString;\n            ReleaseEntry.ParseReleaseEntry(entryAsString);\n        }\n\n        [Fact]\n        public void InvalidReleaseNotesThrowsException()\n        {\n            var path = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.0.0.0.nupkg\");\n            var fixture = ReleaseEntry.GenerateFromFile(path);\n            Assert.Throws<Exception>(() => fixture.GetReleaseNotes(IntegrationTestHelper.GetPath(\"fixtures\")));\n        }\n\n        [Fact]\n        public void GetLatestReleaseWithNullCollectionReturnsNull()\n        {\n            Assert.Null(ReleaseEntry.GetPreviousRelease(\n                null, null, null));\n        }\n\n        [Fact]\n        public void GetLatestReleaseWithEmptyCollectionReturnsNull()\n        {\n            Assert.Null(ReleaseEntry.GetPreviousRelease(\n                Enumerable.Empty<ReleaseEntry>(), null, null));\n        }\n\n        [Fact]\n        public void WhenCurrentReleaseMatchesLastReleaseReturnNull()\n        {\n            var package = new ReleasePackage(\"Espera-1.7.6-beta.nupkg\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.6-beta.nupkg\"))\n            };\n            Assert.Null(ReleaseEntry.GetPreviousRelease(\n                releaseEntries, package, @\"C:\\temp\\somefolder\"));\n        }\n\n        [Fact]\n        public void WhenMultipleReleaseMatchesReturnEarlierResult()\n        {\n            var expected = new SemanticVersion(\"1.7.5-beta\");\n            var package = new ReleasePackage(\"Espera-1.7.6-beta.nupkg\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.6-beta.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.5-beta.nupkg\"))\n            };\n\n            var actual = ReleaseEntry.GetPreviousRelease(\n                releaseEntries,\n                package,\n                @\"C:\\temp\\\");\n\n            Assert.Equal(expected, actual.Version);\n        }\n\n        [Fact]\n        public void WhenMultipleReleasesFoundReturnPreviousVersion()\n        {\n            var expected = new SemanticVersion(\"1.7.6-beta\");\n            var input = new ReleasePackage(\"Espera-1.7.7-beta.nupkg\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.6-beta.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.5-beta.nupkg\"))\n            };\n\n            var actual = ReleaseEntry.GetPreviousRelease(\n                releaseEntries,\n                input,\n                @\"C:\\temp\\\");\n\n            Assert.Equal(expected, actual.Version);\n        }\n\n        [Fact]\n        public void WhenMultipleReleasesFoundInOtherOrderReturnPreviousVersion()\n        {\n            var expected = new SemanticVersion(\"1.7.6-beta\");\n            var input = new ReleasePackage(\"Espera-1.7.7-beta.nupkg\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.5-beta.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.7.6-beta.nupkg\"))\n            };\n\n            var actual = ReleaseEntry.GetPreviousRelease(\n                releaseEntries,\n                input,\n                @\"C:\\temp\\\");\n\n            Assert.Equal(expected, actual.Version);\n        }\n\n        [Fact]\n        public void WhenReleasesAreOutOfOrderSortByVersion()\n        {\n            var path = Path.GetTempFileName();\n            var firstVersion = new SemanticVersion(\"1.0.0\");\n            var secondVersion = new SemanticVersion(\"1.1.0\");\n            var thirdVersion = new SemanticVersion(\"1.2.0\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-delta.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-delta.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.0.0-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();\n\n            Assert.Equal(firstVersion, releases[0].Version);\n            Assert.Equal(secondVersion, releases[1].Version);\n            Assert.Equal(true, releases[1].IsDelta);\n            Assert.Equal(secondVersion, releases[2].Version);\n            Assert.Equal(false, releases[2].IsDelta);\n            Assert.Equal(thirdVersion, releases[3].Version);\n            Assert.Equal(true, releases[3].IsDelta);\n            Assert.Equal(thirdVersion, releases[4].Version);\n            Assert.Equal(false, releases[4].IsDelta);\n        }\n\n        [Fact]\n        public void WhenPreReleasesAreOutOfOrderSortByNumericSuffix()\n        {\n            var path = Path.GetTempFileName();\n            var firstVersion = new SemanticVersion(\"1.1.9-beta105\");\n            var secondVersion = new SemanticVersion(\"1.2.0-beta9\");\n            var thirdVersion = new SemanticVersion(\"1.2.0-beta10\");\n            var fourthVersion = new SemanticVersion(\"1.2.0-beta100\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-beta1-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-beta9-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-beta100-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.9-beta105-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-beta10-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();\n\n            Assert.Equal(firstVersion, releases[0].Version);\n            Assert.Equal(secondVersion, releases[2].Version);\n            Assert.Equal(thirdVersion, releases[3].Version);\n            Assert.Equal(fourthVersion, releases[4].Version);\n        }\n\n        [Fact]\n        public void StagingUsersGetBetaSoftware()\n        {\n            // NB: We're kind of using a hack here, in that we know that the \n            // last 4 bytes are used as the percentage, and the percentage \n            // effectively measures, \"How close are you to zero\". Guid.Empty\n            // is v close to zero, because it is zero.\n            var path = Path.GetTempFileName();\n            var ourGuid = Guid.Empty;\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-full.nupkg\", 0.1f)),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.0.0-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();\n            Assert.Equal(3, releases.Length);\n        }\n\n        [Fact]\n        public void BorkedUsersGetProductionSoftware()\n        {\n            var path = Path.GetTempFileName();\n            var ourGuid = default(Guid?);\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-full.nupkg\", 0.1f)),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.0.0-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();\n            Assert.Equal(2, releases.Length);\n        }\n\n        [Theory]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-ffffffffffff}\")]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-888888888888}\")]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-444444444444}\")]\n        public void UnluckyUsersGetProductionSoftware(string inputGuid)\n        {\n            var path = Path.GetTempFileName();\n            var ourGuid = Guid.ParseExact(inputGuid, \"B\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-full.nupkg\", 0.1f)),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.0.0-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();\n            Assert.Equal(2, releases.Length);\n        }\n\n        [Theory]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-333333333333}\")]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-111111111111}\")]\n        [InlineData(\"{22b29e6f-bd2e-43d2-85ca-000000000000}\")]\n        public void LuckyUsersGetBetaSoftware(string inputGuid)\n        {\n            var path = Path.GetTempFileName();\n            var ourGuid = Guid.ParseExact(inputGuid, \"B\");\n\n            var releaseEntries = new[] {\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.2.0-full.nupkg\", 0.25f)),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.1.0-full.nupkg\")),\n                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry(\"Espera-1.0.0-full.nupkg\"))\n            };\n\n            ReleaseEntry.WriteReleaseFile(releaseEntries, path);\n\n            var releases = ReleaseEntry.ParseReleaseFileAndApplyStaging(File.ReadAllText(path), ourGuid).ToArray();\n            Assert.Equal(3, releases.Length);\n        }\n\n        [Fact]\n        public void ParseReleaseFileShouldReturnNothingForBlankFiles()\n        {\n            Assert.True(ReleaseEntry.ParseReleaseFile(\"\").Count() == 0);\n            Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 0);\n        }\n\n        static string MockReleaseEntry(string name, float? percentage = null)\n        {\n            if (percentage.HasValue) {\n                var ret = String.Format(\"94689fede03fed7ab59c24337673a27837f0c3ec  {0}  1004502 # {1:F0}%\", name, percentage * 100.0f);\n                return ret;\n            } else {\n                return String.Format(\"94689fede03fed7ab59c24337673a27837f0c3ec  {0}  1004502\", name);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/ReleasePackageTests.cs",
    "content": "﻿using System.Runtime.Versioning;\nusing MarkdownSharp;\nusing NuGet;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Xml.Linq;\nusing Squirrel.SimpleSplat;\nusing Xunit;\n\nnamespace Squirrel.Tests.Core\n{\n    public class CreateReleasePackageTests : IEnableLogger\n    {\n        [Fact]\n        public void SemanticVersionDoesWhatIWant()\n        {\n            var sv = new SemanticVersion(\"1.2.3.4\");\n            var dontcare = default(SemanticVersion);\n\n            Assert.False(SemanticVersion.TryParseStrict(sv.ToString(), out dontcare));\n        }\n\n        [Fact]\n        public void ReleasePackageIntegrationTest()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var outputPackage = Path.GetTempFileName() + \".nupkg\";\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n\n            var fixture = new ReleasePackage(inputPackage);\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            try {\n                fixture.CreateReleasePackage(outputPackage, sourceDir);\n\n                this.Log().Info(\"Resulting package is at {0}\", outputPackage);\n                var pkg = new ZipPackage(outputPackage);\n\n                int refs = pkg.FrameworkAssemblies.Count();\n                this.Log().Info(\"Found {0} refs\", refs);\n                refs.ShouldEqual(0);\n\n                this.Log().Info(\"Files in release package:\");\n\n                List<IPackageFile> files = pkg.GetFiles().ToList();\n                files.ForEach(x => this.Log().Info(x.Path));\n\n                List<string> nonDesktopPaths = new[] {\"sl\", \"winrt\", \"netcore\", \"win8\", \"windows8\", \"MonoAndroid\", \"MonoTouch\", \"MonoMac\", \"wp\", }\n                    .Select(x => @\"lib\\\" + x)\n                    .ToList();\n\n                files.Any(x => nonDesktopPaths.Any(y => x.Path.ToLowerInvariant().Contains(y.ToLowerInvariant()))).ShouldBeFalse();\n                files.Any(x => x.Path.ToLowerInvariant().EndsWith(@\".xml\")).ShouldBeFalse();\n            } finally {\n                File.Delete(outputPackage);\n            }\n        }\n\n        [Fact]\n        public void FindPackageInOurLocalPackageList()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.0.0.0.nupkg\");\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            var fixture = ExposedObject.From(new ReleasePackage(inputPackage));\n            IPackage result = fixture.matchPackage(new LocalPackageRepository(sourceDir), \"xunit\", VersionUtility.ParseVersionSpec(\"[1.0,2.0]\"));\n\n            result.Id.ShouldEqual(\"xunit\");\n            result.Version.Version.Major.ShouldEqual(2);\n            result.Version.Version.Minor.ShouldEqual(0);\n        }\n\n        [Fact]\n        public void FindDependentPackagesForDummyPackage()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var fixture = new ReleasePackage(inputPackage);\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            IEnumerable<IPackage> results = fixture.findAllDependentPackages(default(IPackage), (IPackageRepository)new LocalPackageRepository(sourceDir), default(HashSet<string>), default(FrameworkName));\n            results.Count().ShouldBeGreaterThan(0);\n        }\n\n        [Fact]\n        public void CanLoadPackageWhichHasNoDependencies()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.NoDependencies.1.0.0.0.nupkg\");\n            var outputPackage = Path.GetTempFileName() + \".nupkg\";\n            var fixture = new ReleasePackage(inputPackage);\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n            try {\n                fixture.CreateReleasePackage(outputPackage, sourceDir);\n            }\n            finally {\n                File.Delete(outputPackage);\n            }\n        }\n\n        [Fact]\n        public void CanResolveMultipleLevelsOfDependencies()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Tests.0.1.0-pre.nupkg\");\n            var outputPackage = Path.GetTempFileName() + \".nupkg\";\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n\n            var fixture = new ReleasePackage(inputPackage);\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            try {\n                fixture.CreateReleasePackage(outputPackage, sourceDir);\n\n                this.Log().Info(\"Resulting package is at {0}\", outputPackage);\n                var pkg = new ZipPackage(outputPackage);\n\n                int refs = pkg.FrameworkAssemblies.Count();\n                this.Log().Info(\"Found {0} refs\", refs);\n                refs.ShouldEqual(0);\n\n                this.Log().Info(\"Files in release package:\");\n                pkg.GetFiles().ForEach(x => this.Log().Info(x.Path));\n\n                var filesToLookFor = new[] {\n                    \"xunit.assert.dll\",         // Tests => Xunit => Xunit.Assert\n                    \"NuGet.Core.dll\",           // Tests => NuGet\n                    \"Squirrel.Tests.dll\",\n                };\n\n                filesToLookFor.ForEach(name => {\n                    this.Log().Info(\"Looking for {0}\", name);\n                    pkg.GetFiles().Any(y => y.Path.ToLowerInvariant().Contains(name.ToLowerInvariant())).ShouldBeTrue();\n                });\n            } finally {\n                File.Delete(outputPackage);\n            }\n        }\n\n        [Fact]\n        public void SpecFileMarkdownRenderingTest()\n        {\n            var dontcare = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0.nupkg\");\n            var inputSpec = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.1.0.0.nuspec\");\n            var fixture = new ReleasePackage(dontcare);\n\n            var targetFile = Path.GetTempFileName();\n            File.Copy(inputSpec, targetFile, true);\n\n            try {\n                var processor = new Func<string, string>(input =>\n                    (new Markdown()).Transform(input));\n\n                // NB: For No Reason At All, renderReleaseNotesMarkdown is\n                // invulnerable to ExposedObject. Whyyyyyyyyy\n                var renderMinfo = fixture.GetType().GetMethod(\"renderReleaseNotesMarkdown\",\n                    BindingFlags.NonPublic | BindingFlags.Instance);\n                renderMinfo.Invoke(fixture, new object[] {targetFile, processor});\n\n                var doc = XDocument.Load(targetFile);\n                XNamespace ns = \"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\";\n                var relNotesElement = doc.Descendants(ns + \"releaseNotes\").First();\n                var htmlText = relNotesElement.Value;\n\n                this.Log().Info(\"HTML Text:\\n{0}\", htmlText);\n\n                htmlText.Contains(\"## Release Notes\").ShouldBeFalse();\n            } finally {\n                File.Delete(targetFile);\n            }\n        }\n\n        [Fact]\n        public void UsesTheRightVersionOfADependencyWhenMultipleAreInPackages()\n        {\n            var outputPackage = Path.GetTempFileName() + \".nupkg\";\n            string outputFile = null;\n\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"CaliburnMicroDemo.1.0.0.nupkg\");\n\n            var wrongPackage = \"Caliburn.Micro.1.4.1.nupkg\";\n            var wrongPackagePath = IntegrationTestHelper.GetPath(\"fixtures\", wrongPackage);\n            var rightPackage = \"Caliburn.Micro.1.5.2.nupkg\";\n            var rightPackagePath = IntegrationTestHelper.GetPath(\"fixtures\", rightPackage);\n\n            try {\n                var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n                (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n                File.Copy(wrongPackagePath, Path.Combine(sourceDir, wrongPackage), true);\n                File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true);\n\n                var package = new ReleasePackage(inputPackage);\n                var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir);\n\n                var zipPackage = new ZipPackage(outputFileName);\n\n                var fileName = \"Caliburn.Micro.dll\";\n                var dependency = zipPackage.GetLibFiles()\n                    .Where(f => f.Path.EndsWith(fileName))\n                    .Single(f => f.TargetFramework == FrameworkTargetVersion.Net40);\n\n                outputFile = new FileInfo(Path.Combine(sourceDir, fileName)).FullName;\n\n                using (var of = File.Create(outputFile))\n                {\n                    dependency.GetStream().CopyTo(of);\n                }\n\n                var assemblyName = AssemblyName.GetAssemblyName(outputFile);\n                Assert.Equal(1, assemblyName.Version.Major);\n                Assert.Equal(5, assemblyName.Version.Minor);\n            } finally {\n                File.Delete(outputPackage);\n                File.Delete(outputFile);\n            }\n        }\n\n        [Fact]\n        public void DependentPackageNotFoundAndThrowsError()\n        {\n            string packagesDir;\n            // use empty packages folder\n            using (Utility.WithTempDirectory(out packagesDir)) {\n                var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"ProjectDependsOnJsonDotNet.1.0.nupkg\");\n\n                var outputPackage = Path.GetTempFileName() + \".nupkg\";\n\n                try {\n                    var package = new ReleasePackage(inputPackage);\n                    Assert.Throws<Exception>(() =>\n                        package.CreateReleasePackage(outputPackage, packagesDir));\n                } finally {\n                    File.Delete(outputPackage);\n                }\n            }\n        }\n\n        [Fact]\n        public void ContentFilesAreIncludedInCreatedPackage()\n        {\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"ProjectWithContent.1.0.0.0-beta.nupkg\");\n            var outputPackage = Path.GetTempFileName() + \".zip\";\n            var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n\n            var fixture = new ReleasePackage(inputPackage);\n            (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n            try {\n                fixture.CreateReleasePackage(outputPackage, sourceDir);\n\n                this.Log().Info(\"Resulting package is at {0}\", outputPackage);\n                var pkg = new ZipPackage(outputPackage);\n\n                int refs = pkg.FrameworkAssemblies.Count();\n                this.Log().Info(\"Found {0} refs\", refs);\n                refs.ShouldEqual(0);\n\n                this.Log().Info(\"Files in release package:\");\n\n                var contentFiles = pkg.GetContentFiles();\n                Assert.Equal(2, contentFiles.Count());\n\n                var contentFilePaths = contentFiles.Select(f => f.EffectivePath);\n\n                Assert.Contains(\"some-words.txt\", contentFilePaths);\n                Assert.Contains(\"dir\\\\item-in-subdirectory.txt\", contentFilePaths);\n\n                Assert.Equal(1, pkg.GetLibFiles().Count());\n            } finally {\n                File.Delete(outputPackage);\n            }\n        }\n\n        [Fact]\n        public void WhenAProjectContainsNet45BinariesItContainsTheNecessaryDependency()\n        {\n            var outputPackage = Path.GetTempFileName() + \".nupkg\";\n\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"ThisShouldBeANet45Project.1.0.nupkg\");\n\n            var rightPackage = \"Caliburn.Micro.1.5.2.nupkg\";\n            var rightPackagePath = IntegrationTestHelper.GetPath(\"fixtures\", rightPackage);\n\n            try {\n                var sourceDir = IntegrationTestHelper.GetPath(\"fixtures\", \"packages\");\n                (new DirectoryInfo(sourceDir)).Exists.ShouldBeTrue();\n\n                File.Copy(rightPackagePath, Path.Combine(sourceDir, rightPackage), true);\n\n                var package = new ReleasePackage(inputPackage);\n                var outputFileName = package.CreateReleasePackage(outputPackage, sourceDir);\n\n                var zipPackage = new ZipPackage(outputFileName);\n\n                var dependency = zipPackage.GetLibFiles()\n                    .Where(f => f.Path.EndsWith(\"Caliburn.Micro.dll\"))\n                    .FirstOrDefault(f => f.TargetFramework == FrameworkTargetVersion.Net45);\n\n                Assert.NotNull(dependency);\n            } finally {\n                File.Delete(outputPackage);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/Squirrel.Tests.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net45</TargetFramework>\n    <Description>Squirrel.Tests</Description>\n    <Title>Squirrel.Tests</Title>\n    <IsPackable>false</IsPackable>\n    <IsTest>true</IsTest>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"fixtures\\**\" CopyToOutputDirectory=\"PreserveNewest\" />\n    <None Include=\"..\\..\\.nuget\\nuget.exe\" CopyToOutputDirectory=\"PreserveNewest\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Squirrel\\Squirrel.csproj\" />\n    <ProjectReference Include=\"..\\..\\vendor\\nuget\\src\\Core\\Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Reference Include=\"Microsoft.CSharp\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"15.8.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.0.0\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.0.0\" PrivateAssets=\"All\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "test/Squirrel.Tests/SquirrelAwareExecutableDetectorTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\n\nnamespace Squirrel.Tests\n{\n    public class SquirrelAwareExecutableDetectorTests\n    {\n#if DEBUG\n        private const string NativeBuildRootRelativePath = @\"..\\..\\Win32\\\";\n        private const string ManagedBuildRootRelativePath = @\"..\\..\\net45\\\";\n#else\n        private const string NativeBuildRootRelativePath = @\"..\\..\\Win32\\\";\n        private const string ManagedBuildRootRelativePath = @\"..\\..\\net45\\\";\n#endif\n\n        [Fact]\n        public void AtomShellShouldBeSquirrelAware()\n        {\n            var target = IntegrationTestHelper.GetPath(\"fixtures\", \"atom.exe\");\n\n            Assert.True(File.Exists(target));\n            Assert.True(SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target) == 1);\n        }\n\n        [Fact]\n        public void SquirrelAwareViaVersionBlock()\n        {\n            var target = IntegrationTestHelper.GetPath(NativeBuildRootRelativePath, \"Setup.exe\");\n            Assert.True(File.Exists(target));\n\n            var ret = SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target);\n            Assert.Equal(1, ret.Value);\n        }\n\n        [Fact]\n        public void SquirrelAwareViaLanguageNeutralVersionBlock()\n        {\n            var target = IntegrationTestHelper.GetPath(\"fixtures\", \"SquirrelAwareTweakedNetCoreApp.exe\");\n            Assert.True(File.Exists(target));\n\n            var ret = SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target);\n            \n            Assert.NotNull(ret);\n            Assert.Equal(1, ret.Value);\n        }\n\n\n        [Fact]\n        public void SquirrelAwareViaAssemblyAttribute()\n        {\n            var target = Assembly.GetExecutingAssembly().Location;\n\n            Assert.True(File.Exists(target));\n\n            var ret = SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target);\n            Assert.Equal(1, ret.Value);\n        }\n\n        [Fact]\n        public void NotSquirrelAware()\n        {\n            var target = IntegrationTestHelper.GetPath(ManagedBuildRootRelativePath, \"Update.exe\");\n            Assert.True(File.Exists(target));\n\n            var ret = SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target);\n            Assert.Null(ret);\n        }\n\n        [Fact]\n        public void SquirrelAwareTestAppShouldBeSquirrelAware()\n        {\n            var target = IntegrationTestHelper.GetPath(\"fixtures\", \"SquirrelAwareApp.exe\");\n            Assert.True(File.Exists(target));\n\n            Assert.NotNull(SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target));\n        }\n\n        [Fact]\n        public void NotSquirrelAwareTestAppShouldNotBeSquirrelAware()\n        {\n            var target = IntegrationTestHelper.GetPath(\"fixtures\", \"NotSquirrelAwareApp.exe\");\n            Assert.True(File.Exists(target));\n\n            Assert.Null(SquirrelAwareExecutableDetector.GetPESquirrelAwareVersion(target));\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/AssertExtensions.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Globalization;\nusing System.IO;\nusing Xunit;\n\nnamespace Squirrel.Tests.TestHelpers\n{\n    public static class AssertExtensions\n    {\n        public static void ShouldBeAboutEqualTo(this DateTimeOffset expected, DateTimeOffset current)\n        {\n            Assert.Equal(expected.Date, current.Date);\n            Assert.Equal(expected.Offset, current.Offset);\n            Assert.Equal(expected.Hour, current.Hour);\n            Assert.Equal(expected.Minute, current.Minute);\n            Assert.Equal(expected.Second, current.Second);\n        }\n\n        public static void ShouldBeFalse(this bool currentObject)\n        {\n            Assert.False(currentObject);\n        }\n\n        public static void ShouldBeNull(this object currentObject)\n        {\n            Assert.Null(currentObject);\n        }\n\n        public static void ShouldBeEmpty(this IEnumerable items)\n        {\n            Assert.Empty(items);\n        }\n\n        public static void ShouldNotBeEmpty(this IEnumerable items)\n        {\n            Assert.NotEmpty(items);\n        }\n\n        public static void ShouldBeTrue(this bool currentObject)\n        {\n            Assert.True(currentObject);\n        }\n\n        public static void ShouldEqual(this object compareFrom, object compareTo)\n        {\n            Assert.Equal(compareTo, compareFrom);\n        }\n\n        public static void ShouldEqual<T>(this T compareFrom, T compareTo)\n        {\n            Assert.Equal(compareTo, compareFrom);\n        }\n\n        public static void ShouldBeSameAs<T>(this T actual, T expected)\n        {\n            Assert.Same(expected, actual);\n        }\n\n        public static void ShouldNotBeSameAs<T>(this T actual, T expected)\n        {\n            Assert.NotSame(expected, actual);\n        }\n\n        public static void ShouldBeAssignableFrom<T>(this object instance) where T : class\n        {\n            Assert.IsAssignableFrom<T>(instance);\n        }\n\n        public static void ShouldBeType(this object instance, Type type)\n        {\n            Assert.IsType(type, instance);\n        }\n\n        public static void ShouldBeType<T>(this object instance)\n        {\n            Assert.IsType<T>(instance);\n        }\n\n        public static void ShouldNotBeType<T>(this object instance)\n        {\n            Assert.IsNotType<T>(instance);\n        }\n\n        public static void ShouldContain(this string current, string expectedSubstring, StringComparison comparison)\n        {\n            Assert.Contains(expectedSubstring, current, comparison);\n        }\n\n        public static void ShouldStartWith(this string current, string expectedSubstring, StringComparison comparison)\n        {\n            Assert.True(current.StartsWith(expectedSubstring, comparison));\n        }\n\n        public static void ShouldNotBeNull(this object currentObject)\n        {\n            Assert.NotNull(currentObject);\n        }\n\n        public static void ShouldNotBeNullNorEmpty(this string value)\n        {\n            Assert.NotNull(value);\n            Assert.NotEmpty(value);\n        }\n\n        public static void ShouldNotEqual(this object compareFrom, object compareTo)\n        {\n            Assert.NotEqual(compareTo, compareFrom);\n        }\n\n        public static void ShouldBeGreaterThan<T>(this T current, T other) where T : IComparable\n        {\n            Assert.True(current.CompareTo(other) > 0, current + \" is not greater than \" + other);\n        }\n\n        public static void ShouldBeLessThan<T>(this T current, T other) where T : IComparable\n        {\n            Assert.True(current.CompareTo(other) < 0, current + \" is not less than \" + other);\n        }\n\n        static string ToSafeString(this char c)\n        {\n            if (Char.IsControl(c) || Char.IsWhiteSpace(c))\n            {\n                switch (c)\n                {\n                    case '\\r':\n                        return @\"\\r\";\n                    case '\\n':\n                        return @\"\\n\";\n                    case '\\t':\n                        return @\"\\t\";\n                    case '\\a':\n                        return @\"\\a\";\n                    case '\\v':\n                        return @\"\\v\";\n                    case '\\f':\n                        return @\"\\f\";\n                    default:\n                        return String.Format(\"\\\\u{0:X};\", (int)c);\n                }\n            }\n            return c.ToString(CultureInfo.InvariantCulture);\n        }\n    }\n\n    public enum DiffStyle\n    {\n        Full,\n        Minimal\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/ExposedClass.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Dynamic;\nusing System.Reflection;\n\n// Lovingly stolen from http://exposedobject.codeplex.com/\n\nnamespace Squirrel.Tests.TestHelpers\n{\n    public class ExposedClass : DynamicObject\n    {\n        private Type m_type;\n        private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_staticMethods;\n        private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genStaticMethods;\n\n        private ExposedClass(Type type)\n        {\n            m_type = type;\n\n            m_staticMethods =\n                m_type\n                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)\n                    .Where(m => !m.IsGenericMethod)\n                    .GroupBy(m => m.Name)\n                    .ToDictionary(\n                        p => p.Key,\n                        p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));\n\n            m_genStaticMethods =\n                m_type\n                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)\n                    .Where(m => m.IsGenericMethod)\n                    .GroupBy(m => m.Name)\n                    .ToDictionary(\n                        p => p.Key,\n                        p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));\n        }\n\n        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)\n        {\n            // Get type args of the call\n            Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);\n            if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;\n\n            //\n            // Try to call a non-generic instance method\n            //\n            if (typeArgs == null\n                    && m_staticMethods.ContainsKey(binder.Name)\n                    && m_staticMethods[binder.Name].ContainsKey(args.Length)\n                    && ExposedObjectHelper.InvokeBestMethod(args, null, m_staticMethods[binder.Name][args.Length], out result))\n            {\n                return true;\n            }\n\n            //\n            // Try to call a generic instance method\n            //\n            if (m_staticMethods.ContainsKey(binder.Name)\n                    && m_staticMethods[binder.Name].ContainsKey(args.Length))\n            {\n                List<MethodInfo> methods = new List<MethodInfo>();\n\n                foreach (var method in m_genStaticMethods[binder.Name][args.Length])\n                {\n                    if (method.GetGenericArguments().Length == typeArgs.Length)\n                    {\n                        methods.Add(method.MakeGenericMethod(typeArgs));\n                    }\n                }\n\n                if (ExposedObjectHelper.InvokeBestMethod(args, null, methods, out result))\n                {\n                    return true;\n                }\n            }\n\n            result = null;\n            return false;\n        }\n        public override bool TrySetMember(SetMemberBinder binder, object value)\n        {\n            var propertyInfo = m_type.GetProperty(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);\n\n            if (propertyInfo != null)\n            {\n                propertyInfo.SetValue(null, value, null);\n                return true;\n            }\n\n            var fieldInfo = m_type.GetField(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);\n\n            if (fieldInfo != null)\n            {\n                fieldInfo.SetValue(null, value);\n                return true;\n            }\n\n            return false;\n        }\n\n        public override bool TryGetMember(GetMemberBinder binder, out object result)\n        {\n            var propertyInfo = m_type.GetProperty(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);\n\n            if (propertyInfo != null)\n            {\n                result = propertyInfo.GetValue(null, null);\n                return true;\n            }\n\n            var fieldInfo = m_type.GetField(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);\n\n            if (fieldInfo != null)\n            {\n                result = fieldInfo.GetValue(null);\n                return true;\n            }\n\n            result = null;\n            return false;\n        }\n\n        public static dynamic From(Type type)\n        {\n            return new ExposedClass(type);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/ExposedObject.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Dynamic;\nusing System.Reflection;\n\n// Lovingly stolen from http://exposedobject.codeplex.com/\n\nnamespace Squirrel.Tests.TestHelpers\n{\n    public class ExposedObject : DynamicObject\n    {\n        private object m_object;\n        private Type m_type;\n        private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_instanceMethods;\n        private Dictionary<string, Dictionary<int, List<MethodInfo>>> m_genInstanceMethods;\n\n        private ExposedObject(object obj)\n        {\n            m_object = obj;\n            m_type = obj.GetType();\n\n            m_instanceMethods =\n                m_type\n                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n                    .Where(m => !m.IsGenericMethod)\n                    .GroupBy(m => m.Name)\n                    .ToDictionary(\n                        p => p.Key,\n                        p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));\n\n            m_genInstanceMethods =\n                m_type\n                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)\n                    .Where(m => m.IsGenericMethod)\n                    .GroupBy(m => m.Name)\n                    .ToDictionary(\n                        p => p.Key,\n                        p => p.GroupBy(r => r.GetParameters().Length).ToDictionary(r => r.Key, r => r.ToList()));\n        }\n\n        public object Object { get { return m_object; } }\n\n        public static dynamic New<T>()\n        {\n            return New(typeof(T));\n        }\n\n        public static dynamic New(Type type)\n        {\n            return new ExposedObject(Activator.CreateInstance(type));\n        }\n\n        public static dynamic From(object obj)\n        {\n            return new ExposedObject(obj);\n        }\n\n        public static T Cast<T>(ExposedObject t)\n        {\n            return (T)t.m_object;\n        }\n\n        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)\n        {\n            // Get type args of the call\n            Type[] typeArgs = ExposedObjectHelper.GetTypeArgs(binder);\n            if (typeArgs != null && typeArgs.Length == 0) typeArgs = null;\n\n            //\n            // Try to call a non-generic instance method\n            //\n            if (typeArgs == null\n                    && m_instanceMethods.ContainsKey(binder.Name)\n                    && m_instanceMethods[binder.Name].ContainsKey(args.Length)\n                    && ExposedObjectHelper.InvokeBestMethod(args, m_object, m_instanceMethods[binder.Name][args.Length], out result))\n            {\n                return true;\n            }\n\n            //\n            // Try to call a generic instance method\n            //\n            if (m_instanceMethods.ContainsKey(binder.Name)\n                    && m_instanceMethods[binder.Name].ContainsKey(args.Length))\n            {\n                List<MethodInfo> methods = new List<MethodInfo>();\n\n                if (m_genInstanceMethods.ContainsKey(binder.Name) &&\n                    m_genInstanceMethods[binder.Name].ContainsKey(args.Length))\n                {\n                    foreach (var method in m_genInstanceMethods[binder.Name][args.Length])\n                    {\n                        if (method.GetGenericArguments().Length == typeArgs.Length)\n                        {\n                            methods.Add(method.MakeGenericMethod(typeArgs));\n                        }\n                    }\n                }\n\n                if (ExposedObjectHelper.InvokeBestMethod(args, m_object, methods, out result))\n                {\n                    return true;\n                }\n            }\n\n            result = null;\n            return false;\n        }\n\n        public override bool TrySetMember(SetMemberBinder binder, object value)\n        {\n            var propertyInfo = m_type.GetProperty(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n\n            if (propertyInfo != null)\n            {\n                propertyInfo.SetValue(m_object, value, null);\n                return true;\n            }\n\n            var fieldInfo = m_type.GetField(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n\n            if (fieldInfo != null)\n            {\n                fieldInfo.SetValue(m_object, value);\n                return true;\n            }\n\n            return false;\n        }\n\n        public override bool TryGetMember(GetMemberBinder binder, out object result)\n        {\n            var propertyInfo = m_object.GetType().GetProperty(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n\n            if (propertyInfo != null)\n            {\n                result = propertyInfo.GetValue(m_object, null);\n                return true;\n            }\n\n            var fieldInfo = m_object.GetType().GetField(\n                binder.Name,\n                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);\n\n            if (fieldInfo != null)\n            {\n                result = fieldInfo.GetValue(m_object);\n                return true;\n            }\n\n            result = null;\n            return false;\n        }\n\n        public override bool TryConvert(ConvertBinder binder, out object result)\n        {\n            result = m_object;\n            return true;\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/ExposedObjectHelper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Dynamic;\n\n// Lovingly stolen from http://exposedobject.codeplex.com/\n\nnamespace Squirrel.Tests.TestHelpers\n{\n    internal class ExposedObjectHelper\n    {\n        private static Type s_csharpInvokePropertyType =\n            typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)\n                .Assembly\n                .GetType(\"Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder\");\n\n        internal static bool InvokeBestMethod(object[] args, object target, List<MethodInfo> instanceMethods, out object result)\n        {\n            if (instanceMethods.Count == 1)\n            {\n                // Just one matching instance method - call it\n                if (TryInvoke(instanceMethods[0], target, args, out result))\n                {\n                    return true;\n                }\n            }\n            else if (instanceMethods.Count > 1)\n            {\n                // Find a method with best matching parameters\n                MethodInfo best = null;\n                Type[] bestParams = null;\n                Type[] actualParams = args.Select(p => p == null ? typeof(object) : p.GetType()).ToArray();\n\n                Func<Type[], Type[], bool> isAssignableFrom = (a, b) =>\n                {\n                    for (int i = 0; i < a.Length; i++)\n                    {\n                        if (!a[i].IsAssignableFrom(b[i])) return false;\n                    }\n                    return true;\n                };\n\n\n                foreach (var method in instanceMethods.Where(m => m.GetParameters().Length == args.Length))\n                {\n                    Type[] mParams = method.GetParameters().Select(x => x.ParameterType).ToArray();\n                    if (isAssignableFrom(mParams, actualParams))\n                    {\n                        if (best == null || isAssignableFrom(bestParams, mParams))\n                        {\n                            best = method;\n                            bestParams = mParams;\n                        }\n                    }\n                }\n\n                if (best != null && TryInvoke(best, target, args, out result))\n                {\n                    return true;\n                }\n            }\n\n            result = null;\n            return false;\n        }\n\n        internal static bool TryInvoke(MethodInfo methodInfo, object target, object[] args, out object result)\n        {\n            try\n            {\n                result = methodInfo.Invoke(target, args);\n                return true;\n            }\n            catch (TargetInvocationException) { }\n            catch (TargetParameterCountException) { }\n\n            result = null;\n            return false;\n\n        }\n\n        internal static Type[] GetTypeArgs(InvokeMemberBinder binder)\n        {\n            if (s_csharpInvokePropertyType.IsInstanceOfType(binder))\n            {\n                PropertyInfo typeArgsProperty = s_csharpInvokePropertyType.GetProperty(\"TypeArguments\");\n                return ((IEnumerable<Type>)typeArgsProperty.GetValue(binder, null)).ToArray();\n            }\n            return null;\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/IntegrationTestHelper.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Threading;\nusing Squirrel;\nusing Squirrel.SimpleSplat;\nusing Xunit;\nusing System.Text;\nusing SharpCompress.Archives.Zip;\nusing SharpCompress.Readers;\nusing SharpCompress.Common;\nusing System.Reflection;\n\nnamespace Squirrel.Tests.TestHelpers\n{\n    public static class IntegrationTestHelper\n    {\n        public static string GetPath(params string[] paths)\n        {\n            var ret = GetIntegrationTestRootDirectory();\n            return (new FileInfo(paths.Aggregate (ret, Path.Combine))).FullName;\n        }\n\n        public static string GetIntegrationTestRootDirectory()\n        {\n            return Path.GetDirectoryName(new Uri(Assembly.GetCallingAssembly().CodeBase).LocalPath);\n        }\n\n        public static bool SkipTestOnXPAndVista()\n        {\n            int osVersion = Environment.OSVersion.Version.Major*100 + Environment.OSVersion.Version.Minor;\n            return (osVersion < 601);\n        }\n\n        public static void RunBlockAsSTA(Action block)\n        {\n            Exception ex = null;\n            var t = new Thread(() => {\n                try {\n                    block();\n                } catch (Exception e) {\n                    ex = e;\n                }\n            });\n\n            t.SetApartmentState(ApartmentState.STA);\n            t.Start();\n            t.Join();\n\n            if (ex != null) {\n                // NB: If we don't do this, the test silently passes\n                throw new Exception(\"\", ex);\n            }\n        }\n\n        static object gate = 42;\n        public static IDisposable WithFakeInstallDirectory(string packageFileName, out string path)\n        {\n            var ret = Utility.WithTempDirectory(out path);\n\n            File.Copy(GetPath(\"fixtures\", packageFileName), Path.Combine(path, packageFileName));\n            var rp = ReleaseEntry.GenerateFromFile(Path.Combine(path, packageFileName));\n            ReleaseEntry.WriteReleaseFile(new[] { rp }, Path.Combine(path, \"RELEASES\"));\n\n            return ret;\n        }\n\n        public static string CreateFakeInstalledApp(string version, string outputDir, string nuspecFile = null)\n        {\n            var targetDir = default(string);\n\n            var nuget = IntegrationTestHelper.GetPath(\"nuget.exe\");\n            nuspecFile = nuspecFile ?? \"SquirrelInstalledApp.nuspec\";\n\n            using (var clearTemp = Utility.WithTempDirectory(out targetDir)) {\n                var nuspec = File.ReadAllText(IntegrationTestHelper.GetPath(\"fixtures\", nuspecFile), Encoding.UTF8);\n                File.WriteAllText(Path.Combine(targetDir, nuspecFile), nuspec.Replace(\"0.1.0\", version), Encoding.UTF8);\n\n                File.Copy(\n                    IntegrationTestHelper.GetPath(\"fixtures\", \"SquirrelAwareApp.exe\"), \n                    Path.Combine(targetDir, \"SquirrelAwareApp.exe\"));\n                File.Copy(\n                    IntegrationTestHelper.GetPath(\"fixtures\", \"NotSquirrelAwareApp.exe\"), \n                    Path.Combine(targetDir, \"NotSquirrelAwareApp.exe\"));\n\n                var psi = new ProcessStartInfo(nuget, \"pack \" + Path.Combine(targetDir, nuspecFile)) {\n                    RedirectStandardError = true,\n                    RedirectStandardOutput = true,\n                    UseShellExecute = false,\n                    CreateNoWindow = true,\n                    WorkingDirectory = targetDir,\n                    WindowStyle = ProcessWindowStyle.Hidden,\n                };\n\n                var pi = Process.Start(psi);\n                pi.WaitForExit();\n                var output = pi.StandardOutput.ReadToEnd();\n                var err = pi.StandardError.ReadToEnd();\n                Console.WriteLine(output);  Console.WriteLine(err);\n\n                var di = new DirectoryInfo(targetDir);\n                var pkg = di.EnumerateFiles(\"*.nupkg\").First();\n\n                var targetPkgFile = Path.Combine(outputDir, pkg.Name);\n                File.Copy(pkg.FullName, targetPkgFile);\n                return targetPkgFile;\n            }\n        }\n\n        public static IDisposable WithFakeInstallDirectory(out string path)\n        {\n            return WithFakeInstallDirectory(\"SampleUpdatingApp.1.1.0.0.nupkg\", out path);\n        }\n\n        public static IDisposable WithFakeAlreadyInstalledApp(out string path)\n        {\n            return WithFakeAlreadyInstalledApp(\"InstalledSampleUpdatingApp-1.1.0.0.zip\", out path);\n        }\n\n        public static IDisposable WithFakeAlreadyInstalledApp(string zipFile, out string path)\n        {\n            var ret = Utility.WithTempDirectory(out path);\n\n            // NB: Apparently Ionic.Zip is perfectly content to extract a Zip\n            // file that doesn't actually exist, without failing.\n            var zipPath = GetPath(\"fixtures\", zipFile);\n            Assert.True(File.Exists(zipPath));\n\n            var opts = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true };\n            using (var za = ZipArchive.Open(zipFile))\n            using (var reader = za.ExtractAllEntries()) {\n                reader.WriteEntryToDirectory(path, opts);\n            }\n\n            return ret;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/TestHelpers/StaticHttpServer.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Net;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Squirrel.Tests\n{\n    public sealed class StaticHttpServer : IDisposable\n    {\n        public int Port { get; private set; }\n        public string RootPath { get; private set; }\n\n        IDisposable inner;\n\n        public StaticHttpServer(int port, string rootPath)\n        {\n            Port = port; RootPath = rootPath;\n        }\n\n        public IDisposable Start()\n        {\n            if (inner != null) {\n                throw new InvalidOperationException(\"Already started!\");\n            }\n\n            var server = new HttpListener();\n            server.Prefixes.Add(String.Format(\"http://+:{0}/\", Port));\n            server.Start();\n\n            bool shouldStop = false;\n            var listener = Task.Run(async () => {\n                while (!shouldStop) {\n                    var ctx = await server.GetContextAsync();\n\n                    if (ctx.Request.HttpMethod != \"GET\") {\n                        closeResponseWith(ctx, 400, \"GETs only\");\n                        return;\n                    }\n\n                    var target = Path.Combine(RootPath, ctx.Request.Url.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Substring(1));\n                    var fi = new FileInfo(target);\n\n                    if (!fi.FullName.StartsWith(RootPath)) {\n                        closeResponseWith(ctx, 401, \"Not authorized\");\n                        return;\n                    }\n\n                    if (!fi.Exists) {\n                        closeResponseWith(ctx, 404, \"Not found\");\n                        return;\n                    }\n\n                    try {\n                        using (var input = File.OpenRead(target)) {\n                            ctx.Response.StatusCode = 200;\n                            input.CopyTo(ctx.Response.OutputStream);\n                            ctx.Response.Close();\n                        }\n                    } catch (Exception ex) {\n                        closeResponseWith(ctx, 500, ex.ToString());\n                    }\n                }\n            });\n\n            var ret = Disposable.Create(() => {\n                shouldStop = true;\n                server.Stop();\n                listener.Wait(2000);\n\n                inner = null;\n            });\n\n            inner = ret;\n            return ret;\n        }\n\n        static void closeResponseWith(HttpListenerContext ctx, int statusCode, string message)\n        {\n            ctx.Response.StatusCode = statusCode;\n            using (var sw = new StreamWriter(ctx.Response.OutputStream, Encoding.UTF8)) {\n                sw.WriteLine(message);\n            }\n            ctx.Response.Close();\n        }\n\n        public void Dispose()\n        {\n            var toDispose = Interlocked.Exchange(ref inner, null);\n            if (toDispose != null) {\n                toDispose.Dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/UpdateManagerTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.Win32;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\nusing System.Net;\nusing NuGet;\n\nnamespace Squirrel.Tests\n{\n    public class UpdateManagerTests\n    {\n        public class CreateUninstallerRegKeyTests\n        {\n            [Fact]\n            public async Task CallingMethodTwiceShouldUpdateInstaller()\n            {\n                string remotePkgPath;\n                string path;\n\n                using (Utility.WithTempDirectory(out path)) {\n                    using (Utility.WithTempDirectory(out remotePkgPath))\n                    using (var mgr = new UpdateManager(remotePkgPath, \"theApp\", path)) {\n                        IntegrationTestHelper.CreateFakeInstalledApp(\"1.0.0.1\", remotePkgPath);\n                        await mgr.FullInstall();\n                    }\n\n                    using (var mgr = new UpdateManager(\"http://lol\", \"theApp\", path)) {\n                        await mgr.CreateUninstallerRegistryEntry();\n                        var regKey = await mgr.CreateUninstallerRegistryEntry();\n\n                        Assert.False(String.IsNullOrWhiteSpace((string)regKey.GetValue(\"DisplayName\")));\n\n                        mgr.RemoveUninstallerRegistryEntry();\n                    }\n\n                    // NB: Squirrel-Aware first-run might still be running, slow\n                    // our roll before blowing away the temp path\n                    Thread.Sleep(1000);\n                }\n\n                var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)\n                    .OpenSubKey(@\"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\");\n\n                using (key) {\n                    Assert.False(key.GetSubKeyNames().Contains(\"theApp\"));\n                }\n            }\n        }\n\n        public class UpdateLocalReleasesTests\n        {\n            [Fact]\n            public async Task UpdateLocalReleasesSmokeTest()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir)) {\n                    var appDir = Path.Combine(tempDir, \"theApp\");\n                    var packageDir = Directory.CreateDirectory(Path.Combine(appDir, \"packages\"));\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-delta.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(tempDir, \"theApp\", \"packages\", x)));\n\n                    var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                    await fixture.updateLocalReleasesFile();\n\n                    var releasePath = Path.Combine(packageDir.FullName, \"RELEASES\");\n                    File.Exists(releasePath).ShouldBeTrue();\n\n                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));\n                    entries.Count().ShouldEqual(3);\n                }\n            }\n\n            [Fact]\n            public async Task InitialInstallSmokeTest()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir)) {\n                    var remotePackageDir = Directory.CreateDirectory(Path.Combine(tempDir, \"remotePackages\"));\n                    var localAppDir = Path.Combine(tempDir, \"theApp\");\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(remotePackageDir.FullName, x)));\n\n                    using (var fixture = new UpdateManager(remotePackageDir.FullName, \"theApp\", tempDir)) {\n                        await fixture.FullInstall();\n                    }\n\n                    var releasePath = Path.Combine(localAppDir, \"packages\", \"RELEASES\");\n                    File.Exists(releasePath).ShouldBeTrue();\n\n                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));\n                    entries.Count().ShouldEqual(1);\n\n                    new[] {\n                        \"ReactiveUI.dll\",\n                        \"NSync.Core.dll\",\n                    }.ForEach(x => File.Exists(Path.Combine(localAppDir, \"app-1.0.0.0\", x)).ShouldBeTrue());\n                }\n            }\n\n            [Fact(Skip = \"This test is currently failing in CI\")]\n            public async Task SpecialCharactersInitialInstallTest()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir))\n                {\n                    var remotePackageDir = Directory.CreateDirectory(Path.Combine(tempDir, \"remotePackages\"));\n                    var localAppDir = Path.Combine(tempDir, \"theApp\");\n\n                    new[] {\n                        \"SpecialCharacters-0.1.0-full.nupkg\",\n                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath(\"fixtures\", x), Path.Combine(remotePackageDir.FullName, x)));\n\n                    using (var fixture = new UpdateManager(remotePackageDir.FullName, \"theApp\", tempDir))\n                    {\n                        await fixture.FullInstall();\n                    }\n\n                    var releasePath = Path.Combine(localAppDir, \"packages\", \"RELEASES\");\n                    File.Exists(releasePath).ShouldBeTrue();\n\n                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));\n                    entries.Count().ShouldEqual(1);\n\n                    new[] {\n                        \"file space name.txt\"\n                    }.ForEach(x => File.Exists(Path.Combine(localAppDir, \"app-0.1.0\", x)).ShouldBeTrue());\n                }\n            }\n\n            [Fact]\n            public async Task WhenBothFilesAreInSyncNoUpdatesAreApplied()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir))\n                {\n                    var appDir = Path.Combine(tempDir, \"theApp\");\n                    var localPackages = Path.Combine(appDir, \"packages\");\n                    var remotePackages = Path.Combine(tempDir, \"releases\");\n                    Directory.CreateDirectory(localPackages);\n                    Directory.CreateDirectory(remotePackages);\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-delta.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    }.ForEach(x => {\n                        var path = IntegrationTestHelper.GetPath(\"fixtures\", x);\n                        File.Copy(path, Path.Combine(localPackages, x));\n                        File.Copy(path, Path.Combine(remotePackages, x));\n                    });\n\n                    var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n                        \n                    // sync both release files\n                    await fixture.updateLocalReleasesFile();\n                    ReleaseEntry.BuildReleasesFile(remotePackages);\n\n                    // check for an update\n                    UpdateInfo updateInfo;\n                    using (var mgr = new UpdateManager(remotePackages, \"theApp\", tempDir, new FakeUrlDownloader())) {\n                        updateInfo = await mgr.CheckForUpdate();\n                    }\n\n                    Assert.NotNull(updateInfo);\n                    Assert.Empty(updateInfo.ReleasesToApply);\n                }\n            }\n\n            [Fact]\n            public async Task WhenRemoteReleasesDoNotHaveDeltasNoUpdatesAreApplied()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir))\n                {\n                    var appDir = Path.Combine(tempDir, \"theApp\");\n                    var localPackages = Path.Combine(appDir, \"packages\");\n                    var remotePackages = Path.Combine(tempDir, \"releases\");\n                    Directory.CreateDirectory(localPackages);\n                    Directory.CreateDirectory(remotePackages);\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-delta.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    }.ForEach(x => {\n                        var path = IntegrationTestHelper.GetPath(\"fixtures\", x);\n                        File.Copy(path, Path.Combine(localPackages, x));\n                    });\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    }.ForEach(x => {\n                        var path = IntegrationTestHelper.GetPath(\"fixtures\", x);\n                        File.Copy(path, Path.Combine(remotePackages, x));\n                    });\n\n                    var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                    // sync both release files\n                    await fixture.updateLocalReleasesFile();\n                    ReleaseEntry.BuildReleasesFile(remotePackages);\n\n                    UpdateInfo updateInfo;\n                    using (var mgr = new UpdateManager(remotePackages, \"theApp\", tempDir, new FakeUrlDownloader())) {\n                        updateInfo = await mgr.CheckForUpdate();\n                    }\n\n                    Assert.NotNull(updateInfo);\n                    Assert.Empty(updateInfo.ReleasesToApply);\n                }\n            }\n\n            [Fact]\n            public async Task WhenTwoRemoteUpdatesAreAvailableChoosesDeltaVersion()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir))\n                {\n                    var appDir = Path.Combine(tempDir, \"theApp\");\n                    var localPackages = Path.Combine(appDir, \"packages\");\n                    var remotePackages = Path.Combine(tempDir, \"releases\");\n                    Directory.CreateDirectory(localPackages);\n                    Directory.CreateDirectory(remotePackages);\n\n                    new[] { \"Squirrel.Core.1.0.0.0-full.nupkg\", }.ForEach(x => {\n                        var path = IntegrationTestHelper.GetPath(\"fixtures\", x);\n                        File.Copy(path, Path.Combine(localPackages, x));\n                    });\n\n                    new[] {\n                        \"Squirrel.Core.1.0.0.0-full.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-delta.nupkg\",\n                        \"Squirrel.Core.1.1.0.0-full.nupkg\",\n                    }.ForEach(x => {\n                        var path = IntegrationTestHelper.GetPath(\"fixtures\", x);\n                        File.Copy(path, Path.Combine(remotePackages, x));\n                    });\n\n                    var fixture = new UpdateManager.ApplyReleasesImpl(appDir);\n\n                    // sync both release files\n                    await fixture.updateLocalReleasesFile();\n                    ReleaseEntry.BuildReleasesFile(remotePackages);\n\n                    using (var mgr = new UpdateManager(remotePackages, \"theApp\", tempDir, new FakeUrlDownloader())) {\n                        UpdateInfo updateInfo;\n                        updateInfo = await mgr.CheckForUpdate();\n                        Assert.True(updateInfo.ReleasesToApply.First().IsDelta);\n\n                        updateInfo = await mgr.CheckForUpdate(ignoreDeltaUpdates: true);\n                        Assert.False(updateInfo.ReleasesToApply.First().IsDelta);\n                    }\n                }\n            }\n\n            [Fact]\n            public async Task WhenFolderDoesNotExistThrowHelpfulError()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir)) {\n                    var directory = Path.Combine(tempDir, \"missing-folder\");\n                    var fixture = new UpdateManager(directory, \"MyAppName\");\n\n                    using (fixture) {\n                        await Assert.ThrowsAsync<Exception>(() => fixture.CheckForUpdate());\n                    }\n                }\n            }\n\n            [Fact]\n            public async Task WhenReleasesFileDoesntExistThrowACustomError()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir)) {\n                    var fixture = new UpdateManager(tempDir, \"MyAppName\");\n\n                    using (fixture) {\n                        await Assert.ThrowsAsync<Exception>(() => fixture.CheckForUpdate());\n                    }\n                }\n            }\n\n            [Fact]\n            public async Task WhenReleasesFileIsBlankThrowAnException()\n            {\n                string tempDir;\n                using (Utility.WithTempDirectory(out tempDir)) {\n                    var fixture = new UpdateManager(tempDir, \"MyAppName\");\n                    File.WriteAllText(Path.Combine(tempDir, \"RELEASES\"), \"\");\n\n                    using (fixture) {\n                        await Assert.ThrowsAsync(typeof(Exception), () => fixture.CheckForUpdate());\n                    }\n                }\n            }\n\n            [Fact]\n            public async Task WhenUrlResultsInWebExceptionWeShouldThrow()\n            {\n                // This should result in a WebException (which gets caught) unless you can actually access http://lol\n                using (var fixture = new UpdateManager(\"http://lol\", \"theApp\")) {\n                    await Assert.ThrowsAsync(typeof(WebException), () => fixture.CheckForUpdate());\n                }\n            }\n\n            [Theory]\n            [InlineData(\"C:\\\\Foo\\\\Bar\\\\Test.exe\", default(string))]\n            [InlineData(\"%LocalAppData%\\\\theApp\\\\app-1.0.0.1\\\\Test.exe\", \"1.0.0.1\")]\n            [InlineData(\"%LocalAppData%\\\\aDifferentApp\\\\app-1.0.0.1\\\\Test.exe\", default(string))]\n            public void CurrentlyInstalledVersionTests(string input, string expectedVersion)\n            {\n                input = Environment.ExpandEnvironmentVariables(input);\n                var expected = expectedVersion != null ? new SemanticVersion(expectedVersion) : default(SemanticVersion);\n\n                using (var fixture = new UpdateManager(\"http://lol\", \"theApp\")) {\n                    Assert.Equal(expected, fixture.CurrentlyInstalledVersion(input));\n                }\n            }\n\n            [Theory]\n            [InlineData(0, 0, 25, 0)]\n            [InlineData(12, 0, 25, 3)]\n            [InlineData(55, 0, 25, 13)]\n            [InlineData(100, 0, 25, 25)]\n            [InlineData(0, 25, 50, 25)]\n            [InlineData(12, 25, 50, 28)]\n            [InlineData(55, 25, 50, 38)]\n            [InlineData(100, 25, 50, 50)]\n            public void CalculatesPercentageCorrectly(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage, int expectedPercentage)\n            {\n                var percentage = UpdateManager.CalculateProgress(percentageOfCurrentStep, stepStartPercentage, stepEndPercentage);\n\n                Assert.Equal(expectedPercentage, percentage);\n            }\n\n            [Fact]\n            public void CalculatesPercentageCorrectlyForUpdateExe()\n            {\n                // Note: this mimicks the update.exe progress reporting of multiple steps\n\n                var progress = new List<int>();\n\n                // 3 % (3 stages), check for updates\n                foreach (var step in new [] { 0, 33, 66, 100 })\n                {\n                    progress.Add(UpdateManager.CalculateProgress(step, 0, 3));\n\n                    Assert.InRange(progress.Last(), 0, 3);\n                }\n\n                Assert.Equal(3, progress.Last());\n\n                // 3 - 30 %, download releases\n                for (var step = 0; step <= 100; step++)\n                {\n                    progress.Add(UpdateManager.CalculateProgress(step, 3, 30));\n\n                    Assert.InRange(progress.Last(), 3, 30);\n                }\n\n                Assert.Equal(30, progress.Last());\n\n                // 30 - 100 %, apply releases\n                for (var step = 0; step <= 100; step++)\n                {\n                    progress.Add(UpdateManager.CalculateProgress(step, 30, 100));\n\n                    Assert.InRange(progress.Last(), 30, 100);\n                }\n\n                Assert.Equal(100, progress.Last());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/UtilityTests.cs",
    "content": "﻿using System;\nusing System.Diagnostics;\nusing System.IO;\nusing System.Linq;\nusing System.Security.Cryptography;\nusing System.Text;\nusing Squirrel.SimpleSplat;\nusing Squirrel;\nusing Squirrel.Tests.TestHelpers;\nusing Xunit;\nusing Squirrel.Shell;\n\nnamespace Squirrel.Tests.Core\n{\n    public class UtilityTests : IEnableLogger\n    {\n        [Fact]\n        public void SetAppIdOnShortcutTest()\n        {\n            var sl = new ShellLink() {\n                Target = @\"C:\\Windows\\Notepad.exe\",\n                Description = \"It's Notepad\",\n            };\n\n            sl.SetAppUserModelId(\"org.anaïsbetts.test\");\n            var path = Path.GetFullPath(@\".\\test.lnk\");\n            sl.Save(path);\n\n            Console.WriteLine(\"Saved to \" + path);\n        }\n\n        [Theory]\n        [InlineData(10, 1)]\n        [InlineData(100, 1)]\n        [InlineData(0, 1)]\n        [InlineData(30000, 2)]\n        [InlineData(50000, 2)]\n        [InlineData(10000000, 3)]\n        public void TestTempNameGeneration(int index, int expectedLength)\n        {\n            string result = Utility.tempNameForIndex(index, \"\");\n            Assert.Equal(result.Length, expectedLength);\n        }\n\n        [Fact]\n        public void RemoveByteOrderMarkerIfPresent()\n        {\n            var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };\n            var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };\n            var utf16Be = new byte[] { 0xFE, 0xFF };\n            var utf16Le = new byte[] { 0xFF, 0xFE };\n            var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };\n\n            var utf32BeHelloWorld = combine(utf32Be, Encoding.UTF8.GetBytes(\"hello world\"));\n            var utf32LeHelloWorld = combine(utf32Le, Encoding.UTF8.GetBytes(\"hello world\"));\n            var utf16BeHelloWorld = combine(utf16Be, Encoding.UTF8.GetBytes(\"hello world\"));\n            var utf16LeHelloWorld = combine(utf16Le, Encoding.UTF8.GetBytes(\"hello world\"));\n            var utf8HelloWorld = combine(utf8, Encoding.UTF8.GetBytes(\"hello world\"));\n\n            var asciiMultipleChars = Encoding.ASCII.GetBytes(\"hello world\");\n            var asciiSingleChar = Encoding.ASCII.GetBytes(\"A\");\n\n            var emptyString = string.Empty;\n            string nullString = null;\n            byte[] nullByteArray = {};\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(emptyString));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullString));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullByteArray));\n\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Be));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Le));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Be));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Le));\n            Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf8));\n\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(utf32BeHelloWorld));\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(utf32LeHelloWorld));\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(utf16BeHelloWorld));\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(utf16LeHelloWorld));\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(utf8HelloWorld));\n\n            Assert.Equal(\"hello world\", Utility.RemoveByteOrderMarkerIfPresent(asciiMultipleChars));\n            Assert.Equal(\"A\", Utility.RemoveByteOrderMarkerIfPresent(asciiSingleChar));\n        }\n\n        [Fact]\n        public void ShaCheckShouldBeCaseInsensitive()\n        {\n            var sha1FromExternalTool = \"75255cfd229a1ed1447abe1104f5635e69975d30\";\n            var inputPackage = IntegrationTestHelper.GetPath(\"fixtures\", \"Squirrel.Core.1.0.0.0.nupkg\");\n            var stream = File.OpenRead(inputPackage);\n            var sha1 = Utility.CalculateStreamSHA1(stream);\n\n            Assert.NotEqual(sha1FromExternalTool, sha1);\n            Assert.Equal(sha1FromExternalTool, sha1, StringComparer.OrdinalIgnoreCase);\n        }\n\n        [Fact(Skip=\"This test takes forever\")]\n        public void CanDeleteDeepRecursiveDirectoryStructure()\n        {\n            string tempDir;\n            using (Utility.WithTempDirectory(out tempDir)) {\n                for (var i = 0; i < 50; i++) {\n                    var directory = Path.Combine(tempDir, newId());\n                    CreateSampleDirectory(directory);\n                }\n\n                var files = Directory.GetFiles(tempDir, \"*\", SearchOption.AllDirectories);\n\n                var count = files.Count();\n\n                this.Log().Info(\"Created {0} files under directory {1}\", count, tempDir);\n\n                var sw = new Stopwatch();\n                sw.Start();\n                Utility.DeleteDirectory(tempDir).Wait();\n                sw.Stop();\n                this.Log().Info(\"Delete took {0}ms\", sw.ElapsedMilliseconds);\n\n                Assert.False(Directory.Exists(tempDir));\n            }\n        }\n\n        [Fact]\n        public void CreateFakePackageSmokeTest()\n        {\n            string path;\n            using (Utility.WithTempDirectory(out path)) {\n                var output = IntegrationTestHelper.CreateFakeInstalledApp(\"0.3.0\", path);\n                Assert.True(File.Exists(output));\n            }\n        }\n\n        [Theory]\n        [InlineData(\"foo.dll\", true)]\n        [InlineData(\"foo.DlL\", true)]\n        [InlineData(\"C:\\\\Foo\\\\Bar\\\\foo.Exe\", true)]\n        [InlineData(\"Test.png\", false)]\n        [InlineData(\".rels\", false)]\n        public void FileIsLikelyPEImageTest(string input, bool result)\n        {\n            Assert.Equal(result, Utility.FileIsLikelyPEImage(input));\n        }\n\n        [Theory]\n        [InlineData(\"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\\\\lib\\\\net45\\\\foo.exe\", \"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\", true)]\n        [InlineData(\"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\\\\lib\\\\net45\\\\node_modules\\\\foo.exe\", \"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\", false)]\n        [InlineData(\"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\\\\lib\\\\net45\\\\node_modules\\\\foo\\\\foo.exe\", \"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\", false)]\n        [InlineData(\"foo.png\", \"C:\\\\Users\\\\bob\\\\temp\\\\pkgPath\", false)]\n        public void IsFileTopLevelInPackageTest(string input, string packagePath, bool result)\n        {\n            Assert.Equal(result, Utility.IsFileTopLevelInPackage(input, packagePath));\n        }\n\n\n\n        [Fact]\n        public void WeCanFetchAllProcesses()\n        {\n            var result = UnsafeUtility.EnumerateProcesses();\n            Assert.True(result.Count > 1);\n            Assert.True(result.Count != 2048);\n        }\n\n        static void CreateSampleDirectory(string directory)\n        {\n            Random prng = new Random();\n            while (true) {\n                Directory.CreateDirectory(directory);\n\n                for (var j = 0; j < 100; j++) {\n                    var file = Path.Combine(directory, newId());\n                    if (file.Length > 260) continue;\n                    File.WriteAllText(file, Guid.NewGuid().ToString());\n                }\n\n                if (prng.NextDouble() > 0.5) {\n                    var childDirectory = Path.Combine(directory, newId());\n                    if (childDirectory.Length > 248) return;\n                    directory = childDirectory;\n                    continue;\n                }\n\n                break;\n            }\n        }\n\n        static string newId()\n        {\n            var text = Guid.NewGuid().ToString();\n            var bytes = Encoding.Unicode.GetBytes(text);\n            var provider = new SHA1Managed();\n            var hashString = string.Empty;\n\n            foreach (var x in provider.ComputeHash(bytes)) {\n                hashString += String.Format(\"{0:x2}\", x);\n            }\n\n            if (hashString.Length > 7) {\n                return hashString.Substring(0, 7);\n            }\n\n            return hashString;\n        }\n\n        static byte[] combine(params byte[][] arrays)\n        {\n            var rv = new byte[arrays.Sum(a => a.Length)];\n            var offset = 0;\n            foreach (var array in arrays)\n            {\n                Buffer.BlockCopy(array, 0, rv, offset, array.Length);\n                offset += array.Length;\n            }\n            return rv;\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/RELEASES-OnePointOh",
    "content": "94689fede03fed7ab59c24337673a27837f0c3ec  MyCoolApp-1.0.nupkg  1004502\n"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/RELEASES-OnePointOne",
    "content": "94689fede03fed7ab59c24337673a27837f0c3ec  MyCoolApp-1.0.nupkg  1004502\n3a2eadd15dd984e4559f2b4d790ec8badaeb6a39  MyCoolApp-1.1.nupkg  1040561\n14db31d2647c6d2284882a2e101924a9c409ee67  MyCoolApp-1.1-delta.nupkg  80396\n"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/Squirrel.Core.1.1.0.0.nuspec",
    "content": "<?xml version=\"1.0\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n  <metadata>\n    <version>1.1.0.0</version>\n    <authors>Administrator</authors>\n    <owners>Administrator</owners>\n    <dependencies>\n      <dependency id=\"DotNetZip\" version=\"1.9.1.8\" />\n      <dependency id=\"Ix_Experimental-Main\" version=\"1.1.10823\" />\n      <dependency id=\"NLog\" version=\"2.0.0.2000\" />\n      <dependency id=\"reactiveui-core\" version=\"2.5.2.0\" />\n    </dependencies>\n    <id>NSync.Core</id>\n    <requireLicenseAcceptance>false</requireLicenseAcceptance>\n    <description>Description</description>\n    <releaseNotes>\n## Release Notes for 1.1\n\n1. Did some cool stuff\n1. Did another thing\n1. Did a third thing, pretty crazy!\n\nMake *sure* to refrobulate the confabulator or **terrible things will happen!**\n    </releaseNotes>\n  </metadata>\n  <files>\n    <file src=\"lib\\net40\\NSync.Core.dll\" target=\"lib\\net40\\NSync.Core.dll\" />\n  </files>\n</package>\n"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/SquirrelInstalledApp.nuspec",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd\">\n    <metadata>\n        <id>SquirrelInstalledApp</id>\n        <version>0.1.0</version>\n        <authors>Anaïs Betts</authors>\n        <requireLicenseAcceptance>false</requireLicenseAcceptance>\n        <description>My package description.</description>\n    </metadata>\n    <files>\n        <file src=\"NotSquirrelAwareApp.exe\" target=\"lib\\net45\\NotSquirrelAwareApp.exe\" />\n        <file src=\"SquirrelAwareApp.exe\" target=\"lib\\net45\\SquirrelAwareApp.exe\" />\n    </files>\n</package>"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/content-types/basic-merged.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n  <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n  <Default Extension=\"nuspec\" ContentType=\"application/octet\" />\n  <Default Extension=\"exe\" ContentType=\"application/octet\" />\n  <Default Extension=\"psmdcp\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" />\n  <Default Extension=\"diff\" ContentType=\"application/octet\" />\n  <Default Extension=\"dll\" ContentType=\"application/octet\" />\n  <Default Extension=\"shasum\" ContentType=\"text/plain\" />\n</Types>"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/content-types/basic.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n  <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n  <Default Extension=\"nuspec\" ContentType=\"application/octet\" />\n  <Default Extension=\"exe\" ContentType=\"application/octet\" />\n  <Default Extension=\"psmdcp\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" />\n</Types>"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/content-types/complex-merged.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n  <Default ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" Extension=\"rels\"/>\n  <Default ContentType=\"application/octet\" Extension=\"nuspec\"/>\n  <Default ContentType=\"application/octet\" Extension=\"html\"/>\n  <Default ContentType=\"application/octet\" Extension=\"nsi\"/>\n  <Default ContentType=\"application/octet\" Extension=\"css\"/>\n  <Default ContentType=\"application/octet\" Extension=\"otf\"/>\n  <Default ContentType=\"application/octet\" Extension=\"png\"/>\n  <Default ContentType=\"application/octet\" Extension=\"js\"/>\n  <Default ContentType=\"application/octet\" Extension=\"json\"/>\n  <Default ContentType=\"application/octet\" Extension=\"md\"/>\n  <Default ContentType=\"application/octet\" Extension=\"yml\"/>\n  <Default ContentType=\"application/octet\" Extension=\"eot\"/>\n  <Default ContentType=\"application/octet\" Extension=\"svg\"/>\n  <Default ContentType=\"application/octet\" Extension=\"ttf\"/>\n  <Default ContentType=\"application/octet\" Extension=\"woff\"/>\n  <Default ContentType=\"application/octet\" Extension=\"jpg\"/>\n  <Default ContentType=\"application/octet\" Extension=\"less\"/>\n  <Default ContentType=\"application/octet\" Extension=\"coffee\"/>\n  <Default ContentType=\"application/octet\" Extension=\"map\"/>\n  <Default ContentType=\"application/octet\" Extension=\"txt\"/>\n  <Default ContentType=\"application/octet\" Extension=\"gif\"/>\n  <Default ContentType=\"application/octet\" Extension=\"markdown\"/>\n  <Default ContentType=\"application/octet\" Extension=\"jade\"/>\n  <Default ContentType=\"application/octet\" Extension=\"sh\"/>\n  <Default ContentType=\"application/octet\" Extension=\"text\"/>\n  <Default ContentType=\"application/octet\" Extension=\"pl\"/>\n  <Default ContentType=\"application/octet\" Extension=\"dphpd\"/>\n  <Default ContentType=\"application/octet\" Extension=\"php\"/>\n  <Default ContentType=\"application/octet\" Extension=\"refine\"/>\n  <Default ContentType=\"application/octet\" Extension=\"wav\"/>\n  <Default ContentType=\"application/octet\" Extension=\"mdown\"/>\n  <Default ContentType=\"application/octet\" Extension=\"bar\"/>\n  <Default ContentType=\"application/octet\" Extension=\"template\"/>\n  <Default ContentType=\"application/octet\" Extension=\"ico\"/>\n  <Default ContentType=\"application/octet\" Extension=\"dll\"/>\n  <Default ContentType=\"application/octet\" Extension=\"pak\"/>\n  <Default ContentType=\"application/octet\" Extension=\"exe\"/>\n  <Default ContentType=\"application/octet\" Extension=\"diff\"/>\n  <Default ContentType=\"text/plain\" Extension=\"shasum\"/>\n  <Default ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" Extension=\"psmdcp\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/bootstrap/CNAME\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/bootstrap/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/hammerjs/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/iscroll/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/jqBootstrapValidation/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/jquery-ui/MANIFEST\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/page/Makefile\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/bar\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/foo\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/README\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/_sounds/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/toUrl/sub/noext\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-domready/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-plugins/examples/js/foo\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-text/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/select2/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/CNAME\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/Rakefile\"/>\n</Types>"
  },
  {
    "path": "test/Squirrel.Tests/fixtures/content-types/complex.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n  <Default ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" Extension=\"rels\"/>\n  <Default ContentType=\"application/octet\" Extension=\"nuspec\"/>\n  <Default ContentType=\"application/octet\" Extension=\"html\"/>\n  <Default ContentType=\"application/octet\" Extension=\"nsi\"/>\n  <Default ContentType=\"application/octet\" Extension=\"css\"/>\n  <Default ContentType=\"application/octet\" Extension=\"otf\"/>\n  <Default ContentType=\"application/octet\" Extension=\"png\"/>\n  <Default ContentType=\"application/octet\" Extension=\"js\"/>\n  <Default ContentType=\"application/octet\" Extension=\"json\"/>\n  <Default ContentType=\"application/octet\" Extension=\"md\"/>\n  <Default ContentType=\"application/octet\" Extension=\"yml\"/>\n  <Default ContentType=\"application/octet\" Extension=\"eot\"/>\n  <Default ContentType=\"application/octet\" Extension=\"svg\"/>\n  <Default ContentType=\"application/octet\" Extension=\"ttf\"/>\n  <Default ContentType=\"application/octet\" Extension=\"woff\"/>\n  <Default ContentType=\"application/octet\" Extension=\"jpg\"/>\n  <Default ContentType=\"application/octet\" Extension=\"less\"/>\n  <Default ContentType=\"application/octet\" Extension=\"coffee\"/>\n  <Default ContentType=\"application/octet\" Extension=\"map\"/>\n  <Default ContentType=\"application/octet\" Extension=\"txt\"/>\n  <Default ContentType=\"application/octet\" Extension=\"gif\"/>\n  <Default ContentType=\"application/octet\" Extension=\"markdown\"/>\n  <Default ContentType=\"application/octet\" Extension=\"jade\"/>\n  <Default ContentType=\"application/octet\" Extension=\"sh\"/>\n  <Default ContentType=\"application/octet\" Extension=\"text\"/>\n  <Default ContentType=\"application/octet\" Extension=\"pl\"/>\n  <Default ContentType=\"application/octet\" Extension=\"dphpd\"/>\n  <Default ContentType=\"application/octet\" Extension=\"php\"/>\n  <Default ContentType=\"application/octet\" Extension=\"refine\"/>\n  <Default ContentType=\"application/octet\" Extension=\"wav\"/>\n  <Default ContentType=\"application/octet\" Extension=\"mdown\"/>\n  <Default ContentType=\"application/octet\" Extension=\"bar\"/>\n  <Default ContentType=\"application/octet\" Extension=\"template\"/>\n  <Default ContentType=\"application/octet\" Extension=\"ico\"/>\n  <Default ContentType=\"application/octet\" Extension=\"dll\"/>\n  <Default ContentType=\"application/octet\" Extension=\"pak\"/>\n  <Default ContentType=\"application/octet\" Extension=\"exe\"/>\n  <Default ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" Extension=\"psmdcp\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/bootstrap/CNAME\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/bootstrap/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/hammerjs/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/iscroll/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/jqBootstrapValidation/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/jquery-ui/MANIFEST\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/page/Makefile\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/bar\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/foo\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/README\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/doh/_sounds/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs/tests/toUrl/sub/noext\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-domready/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-plugins/examples/js/foo\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/requirejs-text/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/select2/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/CNAME\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/LICENSE\"/>\n  <Override ContentType=\"application/octet\" PartName=\"/Content/frontend/js/library/underscore/Rakefile\"/>\n</Types>"
  },
  {
    "path": "test/test_official.cmd",
    "content": "@echo off\n\nsetlocal\npushd %~dp0\n\nset _C=Release\nset _S=src\\build_official.cmd\n\n:parse_args\nif /i \"%1\"==\"debug\" (set _C=Debug) & (set _S=devbuild.cmd)\nif not \"%1\"==\"\" shift & goto parse_args\n\n:: Init\n\nif \"%VCToolsVersion%\"==\"\" call :StartDeveloperCommandPrompt || exit /b\n\n\n:: Test\n\nif not exist ..\\build\\%_C%\\test\\net45\\Squirrel.Tests.dll (echo Run %_S% before running test\\test_official.cmd) & (exit -1)\n\nVSTest.Console.exe ..\\build\\%_C%\\test\\net45\\*.Tests.dll || exit /b\n\n\ngoto LExit\n\n:StartDeveloperCommandPrompt\nif not \"%SquirrelSkipVsDevCmd%\"==\"\" (\n  echo Skipping initializing developer command prompt\n  exit /b\n)\n\necho Initializing developer command prompt\n\nif not exist \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" (\n  \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\"\n  exit /b 2\n)\n\nfor /f \"usebackq delims=\" %%i in (`\"%ProgramFiles(x86)%\\Microsoft Visual Studio\\Installer\\vswhere.exe\" -version [16.0^,18.0^) -property installationPath`) do (\n  if exist \"%%i\\Common7\\Tools\\vsdevcmd.bat\" (\n    call \"%%i\\Common7\\Tools\\vsdevcmd.bat\" -no_logo\n    exit /b\n  )\n  echo developer command prompt not found in %%i\n)\n\necho No versions of developer command prompt found\nexit /b 2\n\n:LExit\n\npopd\nendlocal\n"
  },
  {
    "path": "vendor/wix/candle.exe.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!--\n  <copyright file=\"app.config\" company=\"Outercurve Foundation\">\n    Copyright (c) 2004, Outercurve Foundation.\n    This software is released under Microsoft Reciprocal License (MS-RL).\n    The license and further copyright text can be found in the file\n    LICENSE.TXT at the root directory of the distribution.\n  </copyright>\n-->\n<configuration>\n    <startup useLegacyV2RuntimeActivationPolicy=\"true\">\n        <supportedRuntime version=\"v4.0\" />\n        <supportedRuntime version=\"v2.0.50727\" />\n    </startup>\n    <runtime>\n        <loadFromRemoteSources enabled=\"true\"/>\n    </runtime>\n</configuration>\n"
  },
  {
    "path": "vendor/wix/light.exe.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<!--\n  <copyright file=\"app.config\" company=\"Outercurve Foundation\">\n    Copyright (c) 2004, Outercurve Foundation.\n    This software is released under Microsoft Reciprocal License (MS-RL).\n    The license and further copyright text can be found in the file\n    LICENSE.TXT at the root directory of the distribution.\n  </copyright>\n-->\n<configuration>\n    <startup useLegacyV2RuntimeActivationPolicy=\"true\">\n        <supportedRuntime version=\"v4.0\" />\n        <supportedRuntime version=\"v2.0.50727\" />\n    </startup>\n    <runtime>\n        <loadFromRemoteSources enabled=\"true\"/>\n    </runtime>\n</configuration>\n"
  },
  {
    "path": "vendor/wix/template.wxs",
    "content": "<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\" xmlns:util=\"http://schemas.microsoft.com/wix/UtilExtension\" xmlns:netfx=\"http://schemas.microsoft.com/wix/NetFxExtension\">\n  <Product Id=\"*\" Name=\"{{Title}} Deployment Tool\" Language=\"1033\" Codepage=\"{{Codepage}}\" Version=\"!(bind.FileVersion.{{Id}}.exe)\" UpgradeCode=\"{{IdAsGuid1}}\" Manufacturer=\"{{Author}}\">\n\n    <Package Description=\"This package installs a deployment tool for {{Title}}. Not {{Title}} itself. {{Title}} is only installed if a user logs into the machine.\" InstallScope=\"perMachine\" Comments=\"Comments\" InstallerVersion=\"200\" Compressed=\"yes\" Platform=\"{{Platform}}\"/>\n    <MajorUpgrade AllowSameVersionUpgrades=\"yes\" DowngradeErrorMessage=\"A later version of this product is already installed. Setup will now exit.\"/>\n    <Media Id=\"1\" Cabinet=\"contents.cab\" EmbedCab=\"yes\" CompressionLevel=\"high\"/>\n\n    <PropertyRef Id=\"NETFRAMEWORK45\" />\n\n    <Condition Message=\"This application requires .NET Framework 4.5 or higher. Please install the latest .NET Framework then run this installer again.\">\n      <![CDATA[Installed OR NETFRAMEWORK45]]>\n    </Condition>\n\n    <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">\n      <Directory Id=\"{{ProgramFilesFolder}}\">\n        <Directory Id=\"APPLICATIONROOTDIRECTORY\" Name=\"{{Title}} Deployment\" />\n      </Directory>\n    </Directory>\n\n    <DirectoryRef Id=\"APPLICATIONROOTDIRECTORY\">\n      <Component Id=\"{{Id}}.exe\" Guid=\"{{IdAsGuid2}}\" Win64=\"{{Win64YesNo}}\">\n        <File Id=\"{{Id}}.exe\" Name=\"{{Id}}DeploymentTool.exe\" Source=\"./Setup.exe\" KeyPath=\"yes\"/>\n      </Component>\n    </DirectoryRef>\n\n    <DirectoryRef Id=\"TARGETDIR\">\n      <Component Id=\"RegistryEntries\" Guid=\"{{IdAsGuid3}}\" Win64=\"{{Win64YesNo}}\">\n        <RegistryKey Root=\"HKLM\" Key=\"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\">\n          <RegistryValue Type=\"expandable\" Name=\"{{Id}}Deployment\" Value=\"&quot;[#{{Id}}.exe]&quot; --checkInstall\" />\n        </RegistryKey>\n      </Component>\n    </DirectoryRef>\n\n    <Feature Id=\"MainApplication\" Title=\"Main Application\" Level=\"1\">\n      <ComponentRef Id=\"{{Id}}.exe\" />\n      <ComponentRef Id=\"RegistryEntries\" />\n    </Feature>\n  </Product>\n</Wix>\n"
  },
  {
    "path": "version.json",
    "content": "{\n  \"version\": \"2.0.1\",\n  \"publicReleaseRefSpec\": [\n    \"^refs/heads/master$\"\n  ],\n  \"cloudBuild\": {\n    \"buildNumber\": {\n      \"enabled\": false\n    }\n  }\n}\n"
  }
]