From 642129dd5ab68e2eecdd30de5795b7e0fab8e283 Mon Sep 17 00:00:00 2001 From: Matteo Pagani Date: Wed, 10 Feb 2021 22:22:14 +0100 Subject: [PATCH] Added Context Menu sample --- .../6b3d387a/MyEmployees/MyEmployees.csproj | 145 --- .../6b3d387a/MyEmployees/NuGetUpgradeLog.html | 165 ---- .../6b3d387a/MyEmployees/packages.config | 7 - .../ExportDataLibrary.csproj | 64 -- .../ExportDataLibrary/NuGetUpgradeLog.html | 163 ---- .../ExportDataLibrary/packages.config | 5 - Docs-ContextMenuSample/.gitattributes | 63 ++ Docs-ContextMenuSample/.gitignore | 340 +++++++ .../ContextMenuSample.Package.wapproj | 121 +++ .../ExplorerCommandVerb.dll | Bin 0 -> 113152 bytes .../Images/LockScreenLogo.scale-200.png | Bin 0 -> 1430 bytes .../Images/SplashScreen.scale-200.png | Bin 0 -> 7700 bytes .../Images/Square150x150Logo.scale-200.png | Bin 0 -> 2937 bytes .../Images/Square44x44Logo.scale-200.png | Bin 0 -> 1647 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 1255 bytes .../Images/StoreLogo.png | Bin 0 -> 1451 bytes .../Images/Wide310x150Logo.scale-200.png | Bin 0 -> 3204 bytes .../Package.appxmanifest | 82 ++ Docs-ContextMenuSample/ContextMenuSample.sln | 97 ++ .../ContextMenuSample/App.xaml | 8 + .../ContextMenuSample/App.xaml.cs | 23 + .../ContextMenuSample/AssemblyInfo.cs | 10 + .../ContextMenuSample.csproj | 11 + .../ContextMenuSample/MainWindow.xaml | 21 + .../ContextMenuSample/MainWindow.xaml.cs | 31 + .../ExplorerCommandVerb/Dll.def | 5 + .../ExplorerCommandVerb/Dll.h | 25 + .../ExplorerCommandStateHandler.cpp | 149 ++++ .../ExplorerCommandVerb.cpp | 265 ++++++ .../ExplorerCommandVerb.sln | 31 + .../ExplorerCommandVerb.vcproj | 363 ++++++++ .../ExplorerCommandVerb.vcxproj | 196 ++++ .../ExplorerCommandVerb/RegisterExtension.cpp | 839 ++++++++++++++++++ .../ExplorerCommandVerb/RegisterExtension.h | 117 +++ .../ExplorerCommandVerb/ShellHelpers.h | 277 ++++++ .../ExplorerCommandVerb/dll.cpp | 166 ++++ .../ExplorerCommandVerb/readme.txt | 41 + 37 files changed, 3281 insertions(+), 549 deletions(-) delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/MyEmployees.csproj delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/NuGetUpgradeLog.html delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/packages.config delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/ExportDataLibrary.csproj delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/NuGetUpgradeLog.html delete mode 100644 Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/packages.config create mode 100644 Docs-ContextMenuSample/.gitattributes create mode 100644 Docs-ContextMenuSample/.gitignore create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/ContextMenuSample.Package.wapproj create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/ExplorerCommandVerb.dll create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/LockScreenLogo.scale-200.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/SplashScreen.scale-200.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square150x150Logo.scale-200.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.scale-200.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/StoreLogo.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Images/Wide310x150Logo.scale-200.png create mode 100644 Docs-ContextMenuSample/ContextMenuSample.Package/Package.appxmanifest create mode 100644 Docs-ContextMenuSample/ContextMenuSample.sln create mode 100644 Docs-ContextMenuSample/ContextMenuSample/App.xaml create mode 100644 Docs-ContextMenuSample/ContextMenuSample/App.xaml.cs create mode 100644 Docs-ContextMenuSample/ContextMenuSample/AssemblyInfo.cs create mode 100644 Docs-ContextMenuSample/ContextMenuSample/ContextMenuSample.csproj create mode 100644 Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml create mode 100644 Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml.cs create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/Dll.def create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/Dll.h create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandStateHandler.cpp create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.cpp create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.sln create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcproj create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcxproj create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.cpp create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.h create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/ShellHelpers.h create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/dll.cpp create mode 100644 Docs-ContextMenuSample/ExplorerCommandVerb/readme.txt diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/MyEmployees.csproj b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/MyEmployees.csproj deleted file mode 100644 index b1f9518..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/MyEmployees.csproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - - Debug - AnyCPU - {6C859FC9-03B3-4D7D-B83E-A276457C80F6} - WinExe - MyEmployees - MyEmployees - v4.7.2 - 512 - true - true - - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - contoso_5Ob_icon.ico - - - - ..\packages\CsvHelper.9.0.0\lib\net45\CsvHelper.dll - - - ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - - ..\packages\System.Data.SQLite.Core.1.0.109.2\lib\net46\System.Data.SQLite.dll - - - - - - - - ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - - - - - - - - - - - - - - Form - - - AboutForm.cs - - - - - Form - - - Form1.cs - - - - - AboutForm.cs - - - Form1.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - - Always - - - PreserveNewest - - - - Designer - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - {a8814208-9b34-41c9-b0d0-b31a6c11af27} - MyEmployees.PluginInterface - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/NuGetUpgradeLog.html b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/NuGetUpgradeLog.html deleted file mode 100644 index 1db5db2..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/NuGetUpgradeLog.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - NuGetMigrationLog -

- NuGet Migration Report - MyEmployees

Overview

Migration to PackageReference was completed successfully. Please build and run your solution to verify that all packages are available.
- If you run into any problems, have feedback, questions, or concerns, please - file an issue on the NuGet GitHub repository.

Packages processed

Top-level dependencies:

Package IdVersion
CsvHelper - v9.0.0
Newtonsoft.Json - v12.0.1
System.Data.SQLite.Core - v1.0.109.2
System.ValueTuple - v4.5.0

Transitive dependencies:

Package IdVersion
- No transitive dependencies found. -

Package compatibility issues

Description
- No issues were found. -
\ No newline at end of file diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/packages.config b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/packages.config deleted file mode 100644 index 6db7f7f..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/6b3d387a/MyEmployees/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/ExportDataLibrary.csproj b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/ExportDataLibrary.csproj deleted file mode 100644 index e2d5c81..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/ExportDataLibrary.csproj +++ /dev/null @@ -1,64 +0,0 @@ - - - - - Debug - AnyCPU - {CE812A43-7F69-4361-9B0B-43AA20739446} - Library - Properties - ExportDataLibrary - ExportDataLibrary - v4.7.2 - 512 - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\CsvHelper.9.0.0\lib\net45\CsvHelper.dll - - - - - ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - - - - - - - - - - - - - - - {a8814208-9b34-41c9-b0d0-b31a6c11af27} - MyEmployees.PluginInterface - - - - - - - - \ No newline at end of file diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/NuGetUpgradeLog.html b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/NuGetUpgradeLog.html deleted file mode 100644 index 85de8b2..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/NuGetUpgradeLog.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - NuGetMigrationLog -

- NuGet Migration Report - ExportDataLibrary

Overview

Migration to PackageReference was completed successfully. Please build and run your solution to verify that all packages are available.
- If you run into any problems, have feedback, questions, or concerns, please - file an issue on the NuGet GitHub repository.

Packages processed

Top-level dependencies:

Package IdVersion
CsvHelper - v9.0.0
System.ValueTuple - v4.5.0

Transitive dependencies:

Package IdVersion
- No transitive dependencies found. -

Package compatibility issues

Description
- No issues were found. -
\ No newline at end of file diff --git a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/packages.config b/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/packages.config deleted file mode 100644 index d9dee1f..0000000 --- a/Blog-OptionalPackages/MyEmployees-OptionalPackages/MigrationBackup/7b3c193f/ExportDataLibrary/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Docs-ContextMenuSample/.gitattributes b/Docs-ContextMenuSample/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/Docs-ContextMenuSample/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Docs-ContextMenuSample/.gitignore b/Docs-ContextMenuSample/.gitignore new file mode 100644 index 0000000..4ce6fdd --- /dev/null +++ b/Docs-ContextMenuSample/.gitignore @@ -0,0 +1,340 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb \ No newline at end of file diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/ContextMenuSample.Package.wapproj b/Docs-ContextMenuSample/ContextMenuSample.Package/ContextMenuSample.Package.wapproj new file mode 100644 index 0000000..13b2c7e --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample.Package/ContextMenuSample.Package.wapproj @@ -0,0 +1,121 @@ + + + + 15.0 + + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + AnyCPU + + + Release + AnyCPU + + + + $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ + + + + 6378d9d6-b2ed-4fc7-a42e-e5903c700764 + 10.0.19041.0 + 10.0.18362.0 + en-US + True + ..\ContextMenuSample\ContextMenuSample.csproj + 7F0254FEC8E115DD807FEAA8553D3953E7B770E7 + False + SHA256 + True + True + 0 + ContextMenuSample.Package_TemporaryKey.pfx + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + + Designer + + + + + + PreserveNewest + + + + + + + + + + + + True + + + + \ No newline at end of file diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/ExplorerCommandVerb.dll b/Docs-ContextMenuSample/ContextMenuSample.Package/ExplorerCommandVerb.dll new file mode 100644 index 0000000000000000000000000000000000000000..f715548f2baa81a3122024a895f8d6100d159240 GIT binary patch literal 113152 zcmeFa30zdw`v-i7MMp&$6cUS+RLpY8!c2c^;WCN}Ie@4sZV5QzMliSq29A@C*GVl+ zD|f9-EqBE=R04N#smv_VG%rC#W`;@5`+d&2vob7NzyJULzAx~ZbIyJ4bDr~@=RD^* z&spxh;X@V(?t&nA;Ab`qLMCGR3t?f!K{0OEYqGbVu%p(gCo&abr=A#~9h)4Om^5ij z(x?f6qeo4gI7t`yYFuDa%EZ9269aqpj|!YHDK@Tc-MY1#%cQ>uKJ;ZqqJ8fj}#hpHzy@26=_U1Q;J2cxc+rZ+@v(s6ud6UPVvg^pP zqqRiaQWK3@5W*BSh41dRA7O#z3vN%;QPg`(_#TkU9J;MOVikT=NlH=LO%Q6ZOIs`y zE4c93?GRi5k#McCeEESwIFGx{w=0CBbURNWBzjW9=`UX)EK&+WmzfHoqth+>%c-~@ zVh`A&5Smj%mh;zE7dKUhd+Vuw#2?j_8r|+MP!LA8O^O|*8zl(mH{nJxexKoY4L`fT z5U596jwZ|lufi%+j0Cd)vE5&YAY`>2%MsUk;|6$SWxrbnFQjd|cBA9R2tqBom4yJZ z7Cv%;mz10|8n>A2AVXH}dRKUH<0k=ec5NU-rh*sZ&&uF+2lW5fe<$g$pqE|{3Vs`c z;3V3;;OnOlLI0@dz3YMKIGJL3n!vp#}uW%MhFx;q8URuD-!bVT&x3kbF^L2#e49b16l0;S9pJUtV^^XN+jTj)|uK=2Wzt~NoC zS_?sLGJ-XaAXrXix33B_7$`z2~8roDCjb-E&_qdxX1XTY@_NR7(W=n zk{$@^6P0i(NTLQH^jB8It%<#M*}>wLl79pMszT$x1w<1Y1brC#dn>ZHXWv06{8AX!a`zo}*@D^g2#J zs@YTo$gfIR-|rAc^qOsJ=_6Aor&c z9PEXl5m9bWlvh%Y_iG|h6TJnb_k~2@tK|q@BUsD}2wtGnHW9&ui3pS`1Pur_aWsNg zsBSbS6!d=|!Q8qC{^){0cniTe;=TqUM|4E6iOAO^f!!j8P7%?TBOrzvNiv;I$X{+kkUk1Qt0xeA)eXUFDlL_CGYR0A%w0RbRl#HMUiKHzNm`3`di$(AZ zv0H=caf6W43FQQFb!R?;vvUy?QSa$ZVv3}C^m!CP$r1z&S|PYk9pWrCeC&7xX1d$A z5duFdchxuqg@oM87r|BPR{Q56m_mY`NkLtzOiL;lE zxY(pYB#`jiu|{|hg76Bf%tfRitDmWUt~vPU^+Wp|WAan#^A);!30`P6jno4meYO&5 zd#T29M#^n8CeJJ|4Sg{k2q6K$C9$ZBs8;H;Job=k6nh_1b`uYA$(Bp*B$sc3y?g~^ zXVh=s2lWse^)k{G)&9A-EeN^lA|HiEdagR3t_o|3>U@2c!l=$iqO)4%t-lR0(qg!m z=zAyElS>IpT|<$UTQ zeOi%_+EKiXN@~P#-v}}Kg6JlOUx*M@=5w8IOM7pFmKy4HK~w@O`a-1GO=-@y#5 z6Lj^r2hdDb{$-2&o0C3aMrY9{ZjbcG%w&!FU@S{{79gXcHSqKYC=_&l2@26fNvR>~ zYBUfH>W~zJ5{+?8AXErM-h*>jzD0BF0gS(L^<7kZLH^1JY3{Gg7#Xt2ERa5T9oLzoPb}#^ouQok%M#5B)`v@)(+UZ5PywY==@~_Pe-6p@PXUqLfUkmVME>N{X(y zyaa`G6wLtTwx=1$X+DI#ND!o{W$EQXV&%0!#qFB_UrpAqUCS_tWqTR2ERF4~Vb;dZ z$d>Ks;0nsMG)cwsp%(DcXj}gU>k_UMeW*Re+UB!pje9@KMw^re{i+bx6`L|vWF_Un z|L7>_nxh;HiWo55#9HEQjToV1L*{HML#^aKgMEul+DwRi_E<`Z7rHt?B% zuXL5y(dxw`FJ=Pd#S6Ly+?|(7!GzI3w5elLOjsgI84bR;wz~gxff*rr_B760a4q?` z`%h5JT=Z%ALhAF}fRc+KMi-I$Uu1Fr_puf!;=X^8)%Rb=z?kSbPBUpvg+BBq-F+xM zaT2rjlFK{dTf6!3Dok&gyvcXmqjh(dw^3ben;?@fXvp%O^&MoU1(WI8=Cu_nlS%hC zG=3^XE6=~QtKdIq^I)j77b(>eDH*Ew} z=>v}FMhx3kiQVgjd#I80 zrT;*h%AxcXq=_#|Uq(79PDqLyGd5Wlm((LEZj>%glQd~`Tyip?<=n8U)&JRq{rFOL zzN1f53Az^IZS5*=9Ov*`#2rr+#EMz0WvQYB;uH$unE^uMZLYecHWc4!bo~~Z1@Tul ziLK0@lK-vLAHo!))(^71#uAMeIYsbF%zlHnvH@lSO0#!}hRLN@>XBEae9SNBk%vL^ zOJ8hE*%x#hTv0V$6~vAF#%uOQo|RYed{1dV-|LQ1%W=Mk=CRE9;E=MJpV(c+7EZ>1 znMx;s-DQp|T-LPcFR#LHwklL6FC~Oik%j&*=jZ;qwzRCj-Vb%KZ@A95riLqj>4C|h zQhqD)*T23>9mj>gevocdX&n1U3)}On zDhgYBRPOIBrwa1#U4WMN164%sVXS>CuTMBt!m+&RRVuHF^nXTcInjT#s`P0-VedcLYSR+KxPv!d z#$&bYFYpGT`2=qeq~r#{%tED+4nW>mrNF#GpXINS(l4`1=?mh~$yJnhB!-g2s?^0S zw(ddn>xFMgUh;e*0Fu*4+abcT^N9;2SeTjetZn7}JIkxe^NBZ5=aVPNW-AMlSz6wo z_{qL~9(q0zAT0z@)Um?(gz^$~e3}JV<^`0<;_XCH#p2ExXaw0Iriy)!)0y{O_S#k ze6FFJ#C`k_*f5ic;haJ>j0SRV^#>>vQu}D>wssZ;`)!EZE;=Iy^2vrX;>d3-h=r}o zP#MZvmymg zG?RA|=5S6$R;oAo>9dfAJMP#B|HZ4y`l~zv&s1P>jJrY=dl;3{6YG*P7?q-5M~XEb zV%;v32n8gBLA=Il;rR8xizg&`)uyt!bo3)}O{86`VI}m{ z52eppsFTb6Bx|>F&5WggmMbr6)+}E(`BjP$sz|fnczOQ&C8;NF`pYw8?fQFy%Ip`$ z*I!@8ZOiuM%cKZwlvF~yJ=nytEoHx*AkfhYrAFJj>H4^bU6+Oq+4x5NpBJnf zy2LWnRCLzAuMgVFUOV1kL{+h z^%OPg4qwi3Lq166rreQ)(Z6od?*LedJ)LkRdo)^HzhT|7qsKWcTKAMm?aM4{5gJex zksyfC%p_@~A;=Ca9DzYXD6B{G$jM*}>pt;Dg=JDgMMA#}U>ee@!bX?9Jc^N-^+y%) z+XYuLzq0+wRbK!ME#sw^_^BJqk(GRY)@BjJqR&=YMi3l2D(bAxpWKWcrcs)FyBVYH zILjS; z_AA%E$ns!Qd2rx`vqzI_0yu~c_ArJj>)ecfARIHu8|U%z;im1GV-xr*R-d=j7>;3F z(nv4mk!(F+x0ubsbWV)$hh@`n)AbH+8`YOZ_3hjcHuu)2UB){3pVVF;kOy^=Xk%8= zh}UFsZXOQW(>44~=#|tOYbKT#Aq;o|aoOQ=gUzI!k3bn>1P>-7Q@V&n9Bo zAm+=6`Lf~}a_V4Fy$QwTMQHOtP@9gdrp4>-o6V8ZDKrlb1&|HZHpl9d$v|)*qcXmz z%qDJ2bIza@F=lPTuD-lAww*xgY;KXWt^UR`29`J&tKag`Cw?e{=h=qadBEtdWZ@N7AK2kA|6`WK|B3gmE0 zNGDGZPaY#ACQpBP)Py+1V};R^QYPvsHR>O#q>}~vXO|V*Kkkv+TaSmrrzHkvPuKzn z9`LZ(6O55CWpv;)`V^_HD^Kz;?x4dn=ZXlSp*9n!3S$67Q!&4pp%tI@sw_X9RilnV zr`2Th>;oloI_@HHcJ0MzZ8XMTo<%+7=vaLQuwNvq?Mh8;(uM}Krevc$+PMHVt?Qn8TcDCDW~7*Vl2(Vk^h##&cO z{44oodtBc6Wzr}wV<@dy=AAs=b|0SblGr!evw=q8Y9 z6V8Jxn}n)pq~^RrJV&mYRvV$5*vB(b<_I`Jl6wwSi!L?NYNSzrKBP_Ui&5$#2-pp2 zPvJ5no2mf4G2ntE&Yl!b2R3mbU{ITfbn^6mansoNWUc-`PW%h<>xAZVlwTY20em$k z6LHT>t=SI`H`5`%b-5&zd@huVWcWEoZHo+tePJiV{rw=rMId7*!yBMym0>sBv&t|V z*cKV)A^mU5kjZbIMgL+*|2}c8e*s3dYyG7eUO4GOX|~p3qLh(or>x-K^J=mJL<5o3B!rm#QaLG4 zkTM#!0IEMgAv*`-OqHL5VN~tAjrY8*)D>K_Ei$4S?Ch3`;r{4TQ>nmGX%U)MBSw=$ zEZ1fxAQjYx)yqL#sa>INye6WFn2tzr7o&Y69lEfR*Dr{QlSVj1_b(26QBbyo@J@*9ZD__GUAG8bbEqeDp(j;ht&qkV>lhUsvO)X66@kqx` z={8!IGHQIUNl6n%>4exRQRBuY_Rx+>N=CY8+-STSBDT+jQDfqw#!inD{%uYE$EKu8 z1gdUt%Iz=5AZbSh=tK5~I)s+D@=Hg|=Ck>1rN}=5Dp!s&_ybKN4M0m*q71=Vj>-_C zfin0Yx1BP)3Nls`bda8P8D9d>fkmVQ1XD7=?aA}og5-x1ATm*EBELS1@Z_Dyu zkl#~id`J1cK>8T~X9C(-u4$SJCDTYbpI0iu4-Ys>@MI(;s7G!)30?phs|4GT`a&CF z^MwmQw#Y9Z>HmuSF5pZdUms~*iUIKtlq)-Aj_V^>K9Ht^Q|swKI-0;1XIk*N({25s zS0l7ru;8He$1T(1Eq{~8_7YPw-$H-*b2KU7H%)XiLb^oaAvif845Zye1hNo_(YJAy z2n}&NLV6mCsL%Gdmc0O6%K30#f5gkelIK%PxjzSfwdByzYj#}g zFQ1y44A&uPEG$^3r3b+c_hEr$yW`BFgyGDZp ztKU#pv-yd{F+4&o$Dav&C)vT9C4n(-b}PosXr550VKdH!f&v(%f*CZUB1jAAu*Bjo74!_o1d_o#5i{; zXAMT5J^|ohTb~ZVWkxpXANurE$^g|R|8O3VNlr@i=MzX1WrF7-O$|iwEToAYg6~H< zF)?scf|`wRk3ICvL7vAsZfk%8BmN?MRI1ADjbl+A0Z1pYC9|p%A-C(an5!lOr z(=OLl?gO|(l`S$`??hmnm4H)~yAunja=Ba36;+q7cb1|DasR~w-D%HD<=TJvFMAoo z^3x6PDeZg+i$9QhA6^8yXF9xyNNM{{s<_SVh)0$j!$^#aiX6izM7Vktkw=bUG@|qz zLoA|^IfgiXFP=wZc%(&?m}3~ruM&7Pjz{BpG=WDGc{GVfiHLl246pI4BpxO6NQcNR z$B@FWCL;>VF-+lCQxUo67^d;7={$O!N2xqYY4cI@tdW{ zQ5*1k6Y1Ib&B4!z-(37e&m8r<`Z;P7(r@86AHN0oEyV9_-yHQjh!@q&Q7=aPE`Ce! zTMAn5;rBk$AKP4!;la`v~+tM!X*UeS&xcejD-I z1X`cs_ZiZg@!NvmR{XZ%w;l9$c;u*eBE1X0-S}mm%2DsZZ!doP@Y|2y0sIc)_c?x9 zpmoSCM|~K$NASzW?+g5L@XH0gqk%c6&95#Z0%zawt4lokmPeO)^c|1BM}!it z@T+`8O>zuZ`PDTZ{lKH^h|n2t@aRVlyvZYpM+H3kiARNqJaY_1i0bDUe&)bmc=Rie zih1-Kk8UCI&oTVYujthj;N=f~b%#gvb_htm1QB?-iwGk4iv#cRh`sS5$M845y3Zps zBJd)hkppuK3fBD$Zai}5kq5u$i3l`na9~XyDS1?jN3{__W_9?L7b5UkmtWQ6kvET2 zh`^^0kLq(^10MPE$d5;l@Tego@ac~T?bnC{ALY?wJPP2^<2-7N2)s1mSAmG?v0L}dK=RdGrz@@DhRu?bnS1yYr|A zk9zWZYDA#fivxS}C=?OO>%;H$<-mSC3gb~Yk6z|ce?%xxg9znCa9|{lqIfib--||s z@&a7 zr(6wKF7lb=^#dw{uOG}QrS$_d!NkLi3+_TK!0Lja1U?NK=}7lRn%bFK{5hmabhO6M8tLTe zk#Whw=n+X{!bYV`9Ie&FB~2KcoIG~YL~*>jZf-W7@se}q@D3;flKR3=1g30;{)Lf zvw&_{$6SCkw=w^MVmu^?2b>S9AOPq2a52q?{oNhs!^=J8?@pw0uzdliatmUp5n zep+*W%EGMk2=BZa@_Nr7qw+Gr)N*DsZ@P!rEy=zD| z{JmoGit7@Hs}iYHsXTUAknIhzrf=!gB|=!q4qf7Lx#WLCAK8XwTbtFvisd4zxq!fa z$@6ul9Ax4PTk;iN97JQ7VT5Vdha<{Uqj=Qh!E6hYU&Z~2@&Am4e{NNznwARKu~o9l zV)6=~q6*ldvKru3w0LF*Rn|zS7%EmdowwuGt**4m9lAjk+g~aGbD2YREG))ZXlQRz5Y%r-$7<=8_GQ=G%%+ZKfSS z%@<3OU@wrgNBk9)N3#^r+O1{eqWWRlr-Z0TyB>P8z@g>%1(V+<%p$q`24K3lrx3-t z-cM!6ejP_P+lKu#RME~+jb^jt{`RxvOmuv{Y035nBc(@BS>|giH72&(Di4}@%tF{m zH@1?t`l-!z@Kf7B@^*ge44~otJE#q$bqN=|FOr|y8tAmOr-Z%hh;;JwKBFg1jEsx_ zm-pMM*dHuM+_lU-urvPcmop*ScLyJ9MO?I>GpLH?+xnxkf3kg983q=Br%HwaD;rfT zzufv?b5Vb}_$qA}Rk?hAR)LL2iJnkP>o~aWgE9h`51EhvDjkjF^9fb*&v5RIoU?Yc z32tY^ua=d+s_Mma|Ex;oJMO%GBKimZ}(4N0|6rQ|h?bQMe1Wxhz|VFq+@A!D%$qm-=$s>Cnk!=?>(Oe{iK zcFaD-`X=5_AP@BcPP6_vhAzL6fr(Y-xjE;#;zeg0yAJlY+~-%pug%A&_WW@{nfBZW zP!&c{d;3{#dGh)iTVuC#Z4z0j4l8WW%cYj<+OYB}Uf+=4Tv5*21-&DJ)-Lc?e>zxi zztqrRK3i%iJk3@v9;Ic9M3dR zFe!{XD!_~N-rckIt5tAlAiZ*WWfjVUKedjQtso||Uo1bA{WBzha!2CcMYg0xPL_P{ zEWg(i_toURWU$K3rmvE&{gf;ZGJoTM|dM7l{rqUB6?4hRtyar#-V^YCKfV2`#v)MhlcKg^p zycgxRR)sfaJKS5z^VLQf{DF6cz2(oqU8-lfeb!~gWFV_wHU!4T`z|!z+kL->xF82v z3OABQ<4N#5!#T@y*(7yRZpwtDi%*)|6d7mbs21a(;_^wfZ`6Ti$*<&k49sL)rQ$M< z2|`U43h71@v0!~Jyj*2A2ho>9%t7=TXLAtEyUaoKUI23tJUXTxUEU9D;HGoH%Zi@SOzhdHL z>-!ZW^hHXvrTktQ+l$$aamDg$6B)fOXd0SOvIY0T7P)GPnlSVH96@y?^Eid_>k84r z^4G4^5)Me&eeA4UIotE^oVL`bWjXcfT$et%b}Pm0){$EUJKnT^RkTH4q6Uh;iI)s_ zbWIH3>K=nBHk{M>4%%{3yf2>keS_#`?B!t`?qz%qeWdIJ6y-xe#_-aCVv2GQa`q24 zclytaK2gEninmOC1o36ORJBy}ZIqGfR!SwN)E9d;@^C*aMwe!EVNIh`nRSiuHXsj; z6vS$w?5#iI)%nHLBOp06*evFNx6!6`%}JtogGX#d&ht;rt!4R=yDjTruq%^Qt>5mDkL5=ii! zPQf#}4MGL_aT#>7mqDj8GU&u*@WgCp8hYt-y*dY{9)Z*=QViCztPuo__hTL&kUWETmYBN2l=c6#YwjRxw{kOp+Ib1s%y1gsHI8P9vw~et4-g1|^}d z@o#K+;TgOLX(cNha-+JrT*zRe0fHBw=(E@7VMjLe ztC6F|TRCvR98ZPq3df^YE#Uy5Zx=R_#97RJD)g2bLAY?F3O(5ulc;nrVIpY8;Ag^b z34RWODCYwFCEVABEQRY6@|o4>=(8n@&3RT`!akT-%s-e2ISvF9V28PJDK&$$3h2m_ zR0QeHQU92uzNwJylD=z~^=LX>&4ilL#}HJmCtcGhBmJl+?%{f+xD`fA-9S)U1Pp08 zh-kfj$IiO)7PeoMc(o4X0>{Ixu&uP0Rh|Ycx57ZJ$8U7hu^3pF@jXmnaq{FVfd{;_ zpH4@cCAu!Ghd0aq2%9^TF@6M6y$P?+BRH#YsMH2j=|hCk`TG9|x)f;mM>?twP6iu5}NM_ zd(GT`QLbEm3#u$XV;qhOVpT_FFUY4MpIr5IJJ|t8p{s$=Ed`Ia(nLvKf=dOGQGH#X zc3nvEELe|fJKR2SkF?Wro1SxYxSa|?v)lNrS}>#0hVIiVuHfVi$6c~9v_TCk^BQPb zR@fkNHBZ3wIn zw{Eh(xtq1O{}C}xf?(_#S5#lew@v=%`-!Csar>8w zu-i0HgqK=6J+t|hEsBD^gYb&(n$7l0sZ>6F6wgzNhlm_dU;CT-gqJ-wo8KnTD5Q~o zYs<`@lLrZU5$yK&>^2<2Qhi#fp!38SRoI-V#X)`t9j!k6adS#dY2X`p<(Q|m6dV*D zb{+vOlHxJw)3d!t;XG3@X1|k2X=`~1S!Ta%Bmv1n|t__z<$wsXwPXg}%TunFE#*)qR9E^}Elmgn5=|y`WCg+o@<^C-=f8 zn1@VJdnlz?kme$1@(tkfeWeYPuP0jle_FcNA>9X+DfG$6#LC4r`t^T9TudH;TpoQ| z|F6j-zfyUSDV|)H96%cXyvRfXRBv)E3>EqUg%Mvyj`q?YRv7(A7p+;Xd z1)z0%`HdXIWqFD{yawu}=BDI8%|MfS2PW;3MsfqLHWN7sqTSCDk_M>SETqlwAf)En zlSpc`!VHCKpwQu>-)iEJ2s(XTabWzq{- zBQ@-^9_;>Z%Y6q`ae2Yo!vi+e)*fgKC1&^3AigLcO`%Ipe^JoI43u6Z!dY$5*j?!* zc~kmmLs7oTPzv`&OAw88`AI<-=m5zBL>udjw--=-c5{x2X;n*Vi3GPnQPN%NirFfX z>2MP2)T#eKsHh+2=fhON=h%Wpu({Ru#$gzye2vki`Vv)=XC^cl?wgnUna+91t>*>= zd+$1;$)q(r?O?FfDpwOB6%z-*&sNQ8+#SR)S9dSmHzKEoFg!;gR5)LE7CN;rP7xlS zs|=ZSEah&i!=a8tH*1eB_3YaN9S}9}W&95`8uEUF54t=XVXomMLU1ZbA4~>^C1@9e zImLURq(~us#c>BhVAFAP6kcgk@Hc&hZ43N`uJl62vuoqx3>z<1;@1)9`SO)Qo zb`Dt6n0Hb>lY!+hr+CTU;@1W5q5!J8wl+p1lOeyvY(98_awJ%=trFS9c+%A{?IbL_ zOc(wzn?IKrR7D6rmeG-b-ir>2hxm+ytra}fJcRWRM|;IOhS=3#wpA%uJ%p)x2OfYv>pym; zYO1pddbXLfsR{x_JI5K%8&G>wwG_jHh8Er2F(mb)a=5h$J~doAk^IkE67`dACPAN4 z{LLx87^O&WQk3RI4|6+dUQ=Quz>qb~U4K+|K%LY8`SI#iXsI=;Gz;W#DA&=>ShB75 z#Tt>_65VQl$7|5T_)OzbEz!ep5j7unBsj}Pi;X>Y`GL44)FYo|LO1eArL@UmjB$h#rgC_=tBId$H88BW0xm`uZZ@;4Hihlsp$a{cHAH z2HnKFK`;WqQ47Y4pRqviw+g^ubty})v!+e>z^vJCJr^6JyZ`g7kxgU@`${iC4^U7>S}7r?)Iv|| zk3?YrEv8?iOeuJ|d}&>u-hyx_UsZ>(54Mbq5Rm>nXY`{_B;`70&gL{<|pE8=sM&2caeNuv^_J^d*skaqDux?c{l?Ee;8k?xs7IakLY5=w}R=D2vmso?g%We zl$gR){>JcPw#VDO#<-&`-NTEGc=LaBF`8KR>Ra+g?i?=ZnlZ25t8;g+q(>lNF~SS{ zyK9u4qP>#YRNtfUB#slgVAxLAT_veLxs7d|gYmDTeY+Ho=duc;SxrdQym$L#{1uLm zTj&UmMIZvYhjzhd511~Opi&tfHEJ0l09Dl=;#Dm6-tE@44n|;>6+`m_@CklmSNq#~ zFXK-sX(urEfLM7>ia~o|pN30oZwOjHIIGxuYi$TzpH?E!_DgAJbxDfH7A&(De*0WS zaw2)uVZ?PcrTgQsKvG}Y3gyAN1r=6Px--#i-lDLmR~eBaKbFjYMn)(nUoxkBsI==W zR9^CUwzdy(S9ky(O7V}BRt8WvQk>&6xtS8N5a4dDr1;};v$^JrK zO;Jn8OX`72I3g1Nq>MFlJbQw=LP|(LWv_y=O}GJ4uvKF9Ky3t zHK^0#)D}g-E~pz7s>AeLslbA_r}Q;cLi!y=1LZl!P-|Y>g^w{aB&)|8+5sejR0m)} z;RqN`m{P39;wvHO^QA_-my(Pn+Mw82m&8VW$S;f%>XNk@iV62R!<86rkr;j*t7QyV zGWrc>xJ7GY5a%%N6%W+0tP*fcPQ5G1_i~6*SSY^*q|491@ zv@I}K{bS)&?8Jzn%`>hdbGi<9Z`khMC>)Z5B?l|^^}@b#y09DnSUa|jk7lINYC#r_ zWfx$PghDL7TtEz7E|71SqyE80@&~&6@V=s>WUF=s`Aedfbyl~+2J#mY-3n_3A7h4X zc5TP*LH!5HOI-sh=!KmwFWTvXp@UA-MoaD(xeaIuxfckdLCUj5#3AbsUaLtZF@ovS zZktnDz&DDJ_QD7wFN_F%bBzWmk`0$!Y2j0aI985ham)hf87j8%fC@J(yo69oIBH3` zmW0cPm9Jb)Y7UcxrEK_-tbF=d4$3cVRM?P}Pveb-cee(-JeQO~kFSrnAIs_vDUlmP z%&-cuZi%t1ypa?6Gt?lrAE^nq!Zwfo1#}mO2aubx$0GZf)J9c zUPpZZQwgJb6Q3H>#IS~KLwatwc~1C!WHm+?^9n&LEE@u*@M1Wpv>_mmv?=wWbobHO zYeO1-@l4?5O15hKp)xF{FQExNQ9pI2Mw)?YLD;77OmKFAxy{%0*A%*1-n-Qj6pFPu zzV0r>lLO7xhD57U_@;DvIr8Pj|NJ>O|WTjix0(|w{U?6# zup!Jnnpr9t$^4pJh4cnFFU|*JWPA(uK(K{eICVD7f2^B!cb!-LLwVMP!67*tt**uz-c*q7#z`YaEKL8(9F z5h2y}p{A_pbWr8=Xuu35!jQhJ6QP#+g7vnsVBMk@7X7umzhQI*_er2sAIO05J_sEO z!)rzKh7di+^HB4dmQ_?^JATfxhIBYj)&D{AzgV_>@2ce27hycOEuBM4Ym4F7n($E| zX@WP5lC$t2MDQ!)Pa6*W0q@E9T`R(8rjqQVhd}4tF+KM%Msu&{B*D_|(a zlB?HD@YBW$A7;yGSx=XjuBFntmcl!@;%y=vE6$rkk>@PAQrzg7Df%$r4`>}%?Puu+ z4;!=g2!I1;w;wfd5Z>*UWXU!Fph5h89ov0f ztX7#pi}QYYaIa`w*b8ht1^? z?kk`?3cBM#7yDOP@>b>cVO(C=yg=q$7AjFq4R2WS1QPVVaoS%v36kcWRESLTJiii` z6ANN7_80g$xbt#3ILx|8e}J+pQbf^2CEPirNJ&3iAfDCVb@QHyMQL*%UQ&Fg_Ms+^ zP;bKsz~c2&@5ktB?}>rB#pBVp z*VI9q7gL+xNoithT3<`Yz`5TxKmh{80|Su5w+_3;{CBkUVYRz#KBn(p*rK=TJ8Znk zL{g?rSS{uj0z3wU0AfOKP2*q_zHUM*+8Sve>;QHsFynhodmGvV!2va)mPY!R-GQ}9 zK_}pMKsfxdWtd^nkfh`V^4fgLI6~hHuDGKvkB;3Fvqic!eE(G z0@!Xzrqmebl$kH@S*>tGRA=s?$v}K3rMKZx0)%!k9P@t58%g)0d^X^1P~eIdgileyDnx&%W#`n#wPWA$m8Kh*i6_e?!wq{Kx5DJz4I;git#U zbc9J_Lounf15ABcKB+IJ(CD!$1NO??BzftfAKiJm12LqV{pO))C;At2 z74`-5H^C?mv3G{#twrKD4dO=*Z^YO|T56NNFT3hUZ4}1EsW(Qqd~R zpP$ESCZ8=hOk2v8152MTdD=xu)1_q{3d#Q zuDY18DC$!uk0G7C${-VUapUXcm0hBp8-8I<_!X4MG|{Qhy$}gjOaw8^ zGv63~5erdQ@N^K~uyrx0_$9M<*Q^=}K^G;4U(C2l*BN(5)^HPa-NopO8P^!#uS5bo zYt5jk;V$5$iG2nDd>k^k3n_J1PlfnMY81;=cekF`8vqdus9Vgg&*s}i0VV;~ryZ@C z8bLLx3GSV0#PZ-=sYNsccpeLwDvE`0G>pz$^kYmMcQdjCZ&K=9a+A8TCbgAbx0tqX zF~^uiU*O{CAY?)JaEUG`y=Q#~Bs&I**-E_1d)616eMKG?^NrDYV)RL@?dz}A(B})r zXl#CG>(jDocpFv#O`n#Hxy>S^c)1w`K}u(ACy3E`8CUa>Lw`*$hG!b1_h+PK(sjz?`n3H*N<&T)j*q3%A*|BD zS(eXjWkmj8_ub0vq zc$5PUsXdMgbEQdLWj(M1a=oo`Jh?b(wK?_(&L$W!Dd;&Z!%0luc z@sKGC$se<8KeUg-cFn(VU3R^9fW9k@0g5!N=8=`6ZHlZae(9+|9M^+`IenX5iZ zGwWP@9|ak6)ma$~b3Z++lB>@2V3<3U40DT$VQvZpruS#VX#YoF{1V@{&bUe$@i@l< z?Cli}rDf@Blo^n>2+{{bWDpUxpmfBnA>%3$24o?jv|yR23_#u?2##r#22p7M%qM_5 zr1RfcbFgdf>SVP9swGe@focgP~zpAOgfz3DHsb>lS#mFor2*kIS&u67euk7{~aVlkz_gS7}nfk z#k9mNv2Q5~Y>ZTg3$YFqmzTCbP3(|M%Rq}g&pY?9YV*XDMRko+}M4K zF2v)vpLL%QZ0c-Wlih2l>gbDZ` zB}^1zg(yLXlun2f0)3%^{w|OA zBc`W}?EgldxO8C9IbK`$A(sO9Kt5~D$!=y1(xrhqs4r@sejtA}lqi;%e% zZJ>gzzk$prA@+s*yWv+C?NfkXDBzz1UR&04#vFo0a}}!9fM+0o8{F%PG~L?-_%)=H z0RJ2L2OA$oXz3@d&iJf( z3Ucn697(VVAHTTE&}5Q&^|DaE6@M8-f}P*8a>mMqHG6Dq`+@(+XT9(cmwf`QC$<=SZ~j{FV|e{5s|jVRdgUv|%mH@7d}zR+x?&aXXoWcAhAV zvCFQ;^(f(0X2Bl5J~6PSWK}1FmJVf5?=Jh-NACBLz>H^7CQC9JDcfJwWfALA7rKES zQ6zoQurelqAG&hnDh!;au+p^^;t^++^Hf%!`hd0udPG`PxkhoDN%~F}nzvCn^2P!( z-YT4j;UfyQByFWpj(T{k%oSN;vclsb8CQQj8Sja(<y>Mp`dO{>x zK1K)!&!bt6WYDDk8-u%4k62t!K^fGKQ-DErq|t-hY)h-e$bBjh+>r)pSq@u|F3Vvz za6TSf@Ub^an1&qOg7t?sC!mzkxOS{tPheB|bcf_IO(y%a9NSZ|Q0@jARHxC%YtwD2 zPg!bwl2lm04iKdNyI@U+N5^>h5IYW`$vev5UZmbQ6Jj#R78mor^wI<{WG z?^KmvTYWA3R-}ElQXiJSjRH@R$3xa@3~S*y<{6Tfq%e)LVLxnnF`!kE{3{+y9sN%m zH|6`m<>h#A{)w{~;dRI+Sa@D|0X>_nYb-{ZQ9>vDKaW&jCrR12 z2v1jyzAax<<_9%}Z)@)fRh>`AnUBR=vC*eg)p#oFrD|YdMxhO;J?JkSnnLrdv7pGU z4~ziNZJrail-Z zsXyAvs;VUDEk^X0#X?@5WzE7KMlUgr77KZMs9eB&T)^tPfHiOd^K$`v#0AV1ULzNHuJS(a z0r3ynq`xc{a#$M|u$C@hPq~2o#|13J1x%=0wtu_3fVFdx_gNRP z=Ul)-UBLRefQ7k$z3c)O;Q}^y+q+wL?0r_c;pXt7S2EIv-}6!8lu7l z%*_QXf5U+pff;9fj4P2>E3$RAt1e*IT)>`C&c7F{cuY0xXQj}pZ7wqpOuX* z%LS~i3s^lDFmD$yl?#}U3s`*@um&z*?dbJa_{(A;@2kSc2`lHEJ>~OhDB7sYGWyJs zu%L!{lQS&v`s{tquvL$AKkE$38Xx(sGfXq}@qA~PYU$bQ&agzE&n0KrmVWK-IKzbA zE$^3s?Z5ZIZ@)eY-9PhX5b>tmWH2qhj{29XT>JLRlhKIg2D zzCg(8e>mp?!E{TWs{Qhd-Af-|o^<-E=W&L2M00Cv$?mn`%S;_xxD_{VPI!l!d^gTJ zBhTkxF8a~6TF(&dE6uHV#njloTRZ)-zP7p!!^^sNaE9>QIiDSeg;mGKrm?;sThJjq z=!erjpC3ZrtM2%U4R{F{df~65XMI+}nJn@AqaDHGZcWOn^;vOfM(amXx~A^c6Kp`^ z(Mjv3=K1XZ6EfJnoh{@1x#C<@>I=T%Z}uzvk74pVuMpn&;uHDesouTz&27=SNAX>@ zkhN#}i^q@b__6QIh(Rmv1{?8adz9gVm#F2B7Tj(34~*o6$n zxWLo8fDL>sDRl9eb3R+w3+cISb!&*1qY0<`yg3Q58#b7C=9=XzOZxQv@NmRq%AqUf z5?=I`SF)Agp7q&M3o=zUxkIpevIuYq`Sa7;-YQ|F7Q@09HKj~%k$ZFAG~-EqL&m4U8C!NwYA3aKE{qetSG6s zbrQjHT+n;&wO`u}zUb9=Q}aD;b7PLvOY?*;T;Pp!QSLC$lW)D@an|R<7oaaGFP^2m z<6Yo=*6Eeg-xucjY|UVJ*@V}3(R-RbcLs&58aOZ7t>u6)f=zIdccKf}Bp0wm7qHh{ zz%s`#(A3|1*5~tKHXToLftTz8cJ}>WXD818rO!6MjZKbUKG=nL*15n-aRHm`0yf13 zY{oBxdufW#`s_LYd$2a?V=7~+3%qGAVAEZ|?(RF+xY%b_$hIb*>ev5x`7+Tvl2%{S z!FzbOk4}bdKe(_CTO>U=E#pF95z5W9mAiHPyHUNuLi zm}%JS?{&{^+kfxx%ibE(c*PS0YZv*QX0B5kHA@YR^41#En~pS5eKlpqOu}|_*s`MpOLf6tnhV&hsp%7*NIT<`9$>SH zGhE;WZ20ZR&Tl05+$J4Mo16Q16qPY@MQMk)Y~&r-Qyn#cAcF8+>YCS{cCyd2hIWZc zEIQ}2*b{P|_WfqUi#Yvl(ERa9edkWt8P=-*(dP-a^wTeXNlzcq{q3hOecttlJMR<_VdN*KX>!{fubz&yO zAHPSiv8&H+?f=EJ9vR;rym`^2V;p7|o)0YvGlyo5U8eoCd*MpLEAid%+NYD6_WE?n z+xwQ!7~7j*x*9LN*yZS8^}ZHM1Fsf-_yxgyj=39hKWfxx{xnU?Ki(Y2?6WRvYnzFQ z&vsjt`*rSHTUs)nJJmXKYUu8Ey*{6u{^#Df!LulDZB4H)3!lEDUNrOe)@jS0#b_f4 zo5v0QeZ$V3eN5v$$F>X`&3MUDe7wr%Lv!~H<7-@YUp$D}u&g(S{CQFJpRjGgKaaeA z>aR_dcj{ZU6F%CP-T&iSje}3s`f3KjKH6MVayI_MZpIJd2MyjJv;$UIJ z`;QH~rr6wT*2*Vaz4TmIFM{3uXvB?q^*zEjZXE5U+p7K#!D^2FBkJ>Ac|MD7!4@~Z z$M%MmE?~7?!0NbwdAWeqbpcbkfcdz9)pr3KdH>|o?GByu*)r3{bEEiflb%}nVfSry zUbxoixZ4)0ThXxv4ZrODd-%@H?_cS1>%~xl&FuQ=#G;`6y>|b7sQAi!4MqY%XgOE) zM)1&PD6M6a+6@oN9wyD4nNpq-;Vx%S5CJc zMX)!|uUY;_(ho0ZL>H|Z^HyhOU)pV|)x)Rmb)SU`l|rD``|*UAe>VS3V|t#?vg=CW z#db~DqKPXzx#^E3;!AFadwkmOo4%_IGY?SSm`8s9bj99}yTAQRpy$^IUVD^a_eNZc zsJ|y6bls@sL1)H^eF+xPF5sJ_w0FDBn%m*kysyrEO|a6ruXG<87uIv$ck|oM>hWp| zg8d>5*&Kg;a<4f_{X92%9~exqcP76zvtO<8VM{(3I_XN$`>cON{5&Eee9{T^tP#HR zr^HE55niv|k)21y?d!WIaM>4YgwbvUYj^JR=T0vS?6b1#_uZ8-OPKBa&#C#d->Y-1 z`>ee4zg=*T?nij>`b(#O3VyHuwrelyCB4Y{M_lb)V{Z(*7^1JyG5E^#rp)JR{LF|Y z1AiPIwrcfjsgwRni>17$78i^>+&?=s^M_6&TCMaxM6kd`o^OAgJ|T2lliYP{y02xv z-mrVUvft_bZs_`J2M4X+=dB^U8l!6~g0pY*{N&bwSr^=EvvJ|Z+~CczXS#GZ-1z-w z^U!e?{<)89QLbT}F_Q2abG%5&(qVU+jXt&=77 zhnGWkE>e5#)t)4fkk$8Xq18L%`Y!8tx#Q91Q%@7@nLkUv`l{Qshz|}9`0lUNUTm4_ z#yLIJCU9r$G@PA9Q6T8>fr< z^o&?D<7W6rAEn*fP`HcP@sleW1ss}iJ7n`OHNW}ksaWQt?|SUx%bMg?eKzDCUEMXQ z`KLs0^nRV8VVAc;7AfaGx?=rfe-Z5MXeOIU7{@!2yw)nSRtiSDO_TBvO1&JX$ zS1y^3iGIVaeBy1|%dk2hI2qn|!t{D^TepYJ5R#ZQGx zx1KoJecRreANdUb@NI&f?i_kdlU%ponlFd^{M8GaA0t?aq4m9IgnOZHeRgo>fIk;p zA=s0CXByu0-`r*7aF!gY?cr-Pt`{tqBP6an8V2#=0mBL7Is~4_-379cOFrHTrl+G!&-kfZv8Rk`|-Oz*dB5);7a(@bIds@Q9IMeTQiZg{2#M zZOwRnl6R|xY^?p@@7XInBOeQy-B&#@>Od!n@ct-VFuGGiUD&o~-W;)UxIs-YMN!zE zN4*Ax9gI%Nt8Yw(CoBjbXaerCP5xGQHm1+4(nlliY*aJ* zSNEu{=cKcrg)B~=WO#K?cjl|87uB9L@`ZgGL$mC_Hb18^`6V|ybGSvDZ+h%nemQf3 z`<+Wv#-P{s7al!-srRPuOPbC3@=tsY6gKDUqMNsGwdwnIy@s`)34QuWf-Qe;^UcRS zH}>E9N${8_sj!ID?aH#BPO*=^gOM|;mve#yp^z2Drux%X=L%Ln2vbX1>z;u*qg zk-zbo7kgd`+Z<%ds9Eptbb^I7e7fO^n-ltPNvl7<*9y0H3HHL>(~X|LFs<9J&A$14 zT8(A%x0*i=?I`8=cH6e7&!m9| z+BHbZZeNGxjoRF3QRb$WQFEda_s%X%_>%H|{6W&Oz~RdWu06YC-H%Z>_7UvEn_;!{ zue>{GUB_Sl{%dU$)<4q6ow)Gm%-4q)OS65_$PH#Ck*$WXY)$>xK(e-w`T>DOL877tkZ_>4yL?-RX(CIKF`nqO6a*fA{XmtQ{IDj!&v||7bK&m}`9z=LxoRNc9esICgPHG4iZVRi zPJMOT`<)5aXG+^^iQi4?`B~|x(>GSeG5b9CK(fNTSrfDI?XHb(XB4r%|C0J()|$6Y zN4>w-)U^Jf_Dp_HeDT-l#SIq6Y%nkB@WR~wOowiJz7W&vts6s@d_JeC*GV(8i9ddS z<;QFFeuy-*y0!S*xOZ58oA=2aso$r)2do;n@%e#IPH08EEWGw)&b9WV`@Hq@J14gM z)HRV{%{KMD;uaD%Y|RTnEq>^^gw1;r9@}(o<+*;*+ue)R&D8hVxF7%S%j3W7oAAoJ zo9g|TbufG>e&5&K|nzlOd{e{*9`+7plnIn4t`pTLXU%cDp^Qq$rme4ch z=o^DC4K~i`d~kT~kvaqu65{tp``sRv@nOw#FTGJ(NTA-nZC`U+dwlS`KacF$v3E=n z!TuUj^RpVy_-IyMef0PCs+%&lWQ+|4PV+l z!Mo?qo~(=xeHVoL$JUDZsOjpH^Pc?0On7gmyPY~QYsTP}wR3&GPU_X2U~SevKCAWG zC9llV{L%NfFMH1*SZ0ma$Fx_xJ#feD|A&#Y4vV_!{y&|9EC>P$h)RQ$Qlh}_vc%He zVIUxifJi7Q-QC^Y-6^G{5+X_ok`fjI@@3|JuHSt<&*dM#{quFb&&+)0bLN~gv$Lxd zc9moh7qCYQOamu0721Jr^qGS1Tn7LPa=$Cas$gx9TT{CGBkA%GU{@7?qe=M|kijM* z-Xt#8N`Nu=TDNS|qofnWReOCV$<6_W@ZhVf?AtNSmJ_yMw9{|U_}){-YAQ)HGy+=ImT9+9$LF))g$oRZKLj(r{349fYYU!Ag z>mAFF$KaXUCkk3pNnU2Pru#Kl(|P@2e10*J^)ky%#i(`jQ-h^x7MwpWe{$SeHYQ|A zh_VpHuq3Q~_)SIz|x3gZgj{{qSGgvWl)dc+%rt=F%@%XS7wRUhP8NREa z5#oAWLC?<$$C8;RslxO`OFh3@b>5J@PZ!v}|CHk!=sm3&6!FxlJz7lyFot;*{@gEk z2BF+C$^FLtRe;^A4l!u-(~u8fQ6<8ww>1ZhQ|%hNjSRb5>MU9FmChkPz!I~cGWTKR zwIkd2`YIa2;q#_)tnR%R+A#{-BYT%v@9-1orjHQ03uQ%mWk096c9)sU0b9Fr+bg8| zz#t{&mHlp0^DR5ar zMAf*tcj2=pEe)*UHrI5SyzjT`r~diMLbnkI*X6oYq{Lhwok3bVsm~Af=l4N-cO^Hf z=@X}A3OntN3?92N0_Ke?#gma)jLoAtc$#Q?8~S8J;9|KDsz)#6VR?==l|Ib->E`2a z3gwrKf(5)RQS2~GjbzEKjb0T2D@@$hfAB)fhIRSOAX&7MLDaiL( zvPEi9rJ~B`@Vz$uE1<)@ESnmP&Q(g_KkF`=*ac(uJ1WiwFZU98PlpE&lN71W10Bau zuj1Vvd%gV10a2#M^tpiXeP?{c$t|hgb|sUE8jysZzRT4{lb_Uoo)fqwX&YTIZ(Uz4#OQ{X_V;QlzG2dvWBbk$4PPs0xI}1J3?Rjv;wPLf4Qr`6|?YF6vGl0Fx+E5ANZ8UE6Jp7$cvH{oD z+bc3>4b+288rqILC9`ZifzD;`-TBpGTdm4chuL9s|1!YLVzfsH%9m6M@`fDMep9Oe zR!mE6!2jhs+M9DO&vl5>5wH-tp9dXywWfYqeCvdXXt>WaC{(+Ak@m7d$=g=;&+Ct1 z-m;H8GPyZHp_8Qhh6OpD2=^`{1C~}pS_^WGev2ezzwW&N?Gf-yAM}u%Rf!dvFTRhP z3u{cG5Q@@~L4CQGg<=B2ki2-*RNk( zmhy-LOx>TuKupj?y0UJxoAK%xj4xawJn|YmpD=mPKD=_Y)Pb@1B@tg5wcxCD^I1l^ z%D$XzV4Hu7fM(ExM=5R4GU8wd7uG)FT!*`cRyw9WjJe!y=X~vfuB4TS=VpS2cI`k# zA{k$GCSX(sIdg9hdZdHC_tw?sF);ylbx+@2sG3?eIK7~2=b_LWzoAoFCvgz{E)Jq~8H(k|qm+v+}nWA6L4FwrZkpiwQ7 ziD)lMFa)~QPMtWN+pkeU;=+BmQnh#h>zut?seU0)DL3-$TXIQV7YzQ;+hf_rjtboZ zRX6{~9|RQuTamF%+iQwftiy>G{{G4H7%*fs*>ghiP*l-Z=Q4KFQ0TiNZ2i)II-`~I zqnI5Y_K}DJ9nb9W$;Y5vbTbZ}l8XHm`(VvR zSm|Z>dLV@sK0M2K)I~XFd2vlPH$S)f+;JWBA)(%MseAhE@|k>%ZF^mGV!-zCZM(bp zj#jAl9;S;^VG1x;#0<8eagM#^JS~0P>9@3Dyb`n};3GarQwk4#8E)>*_0O7iHkV8z zpi!=+k{I#c5#I*w4NtBx2X7?E<)Z`ZuMY1O0!GI|K9#v+B=0S}cP$5D;RYB_F)}WJ z^*S=#virMH_auJfZJm<}@0X zyKgFlj2BiH?wr80o2WRtTi=7y<(u(-XYr9tUj?=dl$jMgpT(q`fBLzbSgRibHiOZb z>XB2$CN{hu?3X@I16ZY|qECFr9p&24iRPP%#!Y}F@AF*MsAW`Xb9`Yf`{7L;VEl*3 zj;AdmnAl35Hi2*l=%==Ukqqh)OW39>G;UgtXE8wc^z9=FzmJO88r8C-f)f-kU<(t) zg54%M(rKQX`b^z;u-=$)V+_7I#fPl0sh!`*KwbwrZz{gr*MphZ=tL?ZU#>jpf0=4O zdAlxbp>s+e8)cUzegrxyWYBlbhhnH8RPoa~xoS(m&K8L!oKUyQv{6?$*@R#h0Q+-k zC->N_$DVXBSa0e_UqFULFfdlPOIMFYbt&gWuu$-*{r|{=Ng1z{^vxx^?{m zuvKjObZy|;HEgA@^c_WK>?UAdrQeAZN_1swa;MgCg}IIZd(}rFT|wE0j=$$heP{3o ztamvrI91&+ZOH7?%EIQy8uVSUGAD%s+c)TVheswnt1_&>wpcS#47u(h8&BZc=rZsX zzTcuha<81u>&yD+tU99=mr<0v#1Q-nu;TRi!E}8#VXV<7U8~s}a7UiPMowA)cQ? zu?{f<79RG(*6M?lN(&(>@lJ;6JHV>>*7$C}nN;*VAc+uJ=!ZJ5Xm0B$gE(Y#ybi{p zj0L`<5Zt*SQ=?u~8#8g!7wzbJV5^IMxIwdHpps0;gkGNfy#d(PS8WXmDm1$C>aXy` z<*zVb=2?5F|DGJhc*dMRIluh+8`PEB#;RRyR!k4UaQ*(%90izhitD*=BDYmq<-YF` zBh_F&fA;m4o5EXD`I-&A4{_DZvp{EKY4%BmD_Y*OV^`3jo?!woHCB8R=8!a{7Bi8x z_M;Ox&!N3h12+XzFy45ww%?zg!1~Jc)4~Z+`UIw&WA}(^QVjN6I5+Jy^-v$p$V7nXebW!P5A7*$lL-HIUbe6z zXtGc-5!NMJa+DO8>{(>Oy%6-I#bgE-KKzv$|7yJ2B$O+U^Ak5(I8gA~_=ZE=GnRH$_fl6kKEq zF7EFR+D~5sZ18f()@3I}Ozvfu2gN@mZvbYMG9`PIOX@miQExnI;KB`Ee z+UA+{kjq98&hurl@Buv$N97( zd4H5({v@^vpO+&ahs%iCTeXzAbiDP^^$ehUfOA<;VtY!Z)`jZU)95p`fHg{H>AR7c z$utkVW4h``d>JqSXVmfF?Fdu=c7Hv^5^g_mZq}yzXAkwORte7(O8oYK?{YWGrr>G$ zQ^f@G1>d)WxG)a}njBGMv|cDSVJ^9HEyfsw_Q<;UokzSrqVm{?S+!dxV0~X9OBZr4 z!35Lhm`ILKiA4Y%#*h0>9MyffFyhGU74u>EE(4=i{~T}Ixv<{YCNx+ z#axnW>^1c)DZY{ebUoyRJqujnO6`vyH;pqBIRIv~wvQX`wt~qaNzNVnt@Z%0zB{9j zR_gHN5-J{B*Vy>G0j6qL<{BcOEEBsJCB>b8_82g|`*){*6m=?i*`4HB1mDjGtdQw< zx#+8hDjEA6mVu+`=K!1e_24iQzZMyvMC-J}aQbWP(@z7(fxbeOJtp8CpJj0QCz!kK zemzP3khX-(<3kp$tEa(OoH}8UvC?}*E CDL~8D6WCe{dLC&IQ%DzG^ZTf3!~PYp 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

$%dv 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 yGvCsSX*m literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/SplashScreen.scale-200.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/SplashScreen.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..023e7f1feda78d5100569825acedfd213a0d84e9 GIT binary patch literal 7700 zcmeHLYj~4Yw%(;oxoEH#Kxq-eR|+VkP17b#Vk;?4QwkI+A{L04G+#<<(x#Un1#+h5>eArRq zTw$)ZvTWW_Y?bDho0nPVTh08+s`sp!j74rJTTtXIDww0SILedFv?sZ?yb@@}GN;#8 znk_b~Q(A0YR#uV4ef!osoV1M3;vQ8N$O|fStfgf$S5;ddUNv`tWtGjM;koG#N;7M< zP*84lnx(bn_KF&9Z5Ai$)#Cs3a|$OFw>WKCT$of*L7_CqQEinflT|W{JT+aKp-E0v zsxmYg)1(T>DROm+LN1eQw8}KCTp=C!$H7`PU!t9_Hw@TsTI2`udRZv*!a5`#A9hK6Y95L(CDUX&_@QxKV z_feX{UhA#ZWlvgpL$#w^D#lq`_A4AzDqd|Zv6y9PX&DNcN|l}_D^{q@GG&H^Pg583 z8FI6N8^H7b5WjGp;urW)d7F+_lcp%KsLX0viCmE(OHH+=%ZfD_=`voUuoUxFO^L;- z;!;2{g-YiiO6m4bs89OuF9!p{FGtH-f%8<2gY!h9s)4ciN%{Kh1+`}{^}M~+TDH9N z^Z5PlgVXMC&2&k*Hw^Lb9gny#ro$MOIxIt{+r)EA10$VR3 zanN8D{TUkl+v0CQ_>ZoHP<M-x#8@8ZiT#$Kh`(uRaX1g$Bg|qy$<#7 zSSAi{Nb8Y=lvNVeio+UGLCAtoLBfL`iOv`)yoJMDJBN>4IH@(l7YRF;61@>qq1iM9 zr@b#OC~SAxSle?5Pp8Z78{VO0YFr1x7kZU64Z23eLf2T2#6J_t;-E}DkB?NufZ0Ug zi?J&byXeaB-uTNVhuiM!UVQw}bZrJ3GtAETYp->!{q#zfN7D3AS9@Q7*V^85jGx#R z(QxYV(wW#F0XF9^^s>>H8pPlVJ>)3Oz z&_X8Sf@~?cH_O*cgi$U#`v`RRfv#y3m(ZpKk^5uLup+lVs$~}FZU$r_+}#hl%?g5m z-u-}-666ssp-xWQak~>PPy$mRc|~?pVSs1_@mBEXpPVfLF6(Ktf1S* zPPh@QZ=tFMs?LM2(5P3L2;l_6XX6s&cYsP1ip#eg0`ZEP0HGYh{UmS@o`MihLLvkU zgyAG0G`b1|qjxxh1(ODKFE%AP}Dq=3vK$P7TXP4GrM1kQ72!GUVMDl`rDC&2;TA}*nF z8$nQD&6ys_nc1*E7$*1S@R8$ymy(sQV}imGSedB@{!QR5P&N_H=-^o!?LsWs+2|mH z-e=)T^SvI)=_JIm7}j4;@*Z17=(#}m=~YF~z~CLI+vdAGlJDcdF$TM?CVI1%LhUrN zaa6DJ=Yh$)$k&Oz{-~8yw^GM^8prYxSxo zvI4k#ibryMa%%*8oI-5m61Koa_A_xg=(fwp0aBX{;X4Q;NXUhtaoJDo1>TqhWtn=_ zd5~chq#&6~c%8JZK#t_&J(9EVUU&upYeIovLt1>vaHe}UUq>#RGQj!EN#5+0@T`(@ z^g~>*c`VGRiSt;!$_4+0hk^I!@O3``5=sZ8IwlxWW7km1B&_t&E*u0_9UBa#VqwY* zz>nxv?FAsVnRaD(Bui=6i==BFUw0k4n$>`umU`F2l?7CYTD^)c2X+d9X&ddS9|gj? zM?knGkGCX&W8offw8aLC2$D{PjC3nVZwd4k?eZH8*mZ)U@3Qk8RDFOz_#WUA#vnzy zyP>KrCfKwSXea7}jgJjBc}PGY+4#6%lbZyjhy`5sZd_Vy6Wz;ixa?czkN}J9It1K6 zY!eu>|AwF^fwZlLAYyQI*lM@^>O>Iu6Vf6i>Q$?v!SeUS<{>UYMwz$*%Aq?w^`j{h z!$GZbhu=^D{&ET8;))LL%ZBDZkQqRd2;u~!d9bHGmLRhLDctNgYyjsuvoSZ#iVdoB z2!f--UUA#U;<{je#?cYt^{PIyKa%hW>}uepWMyAI{{Zo7?2>?$c9;whJae%oN|I-kpTQSx_C$Z&;f zi2i)qmEn=y4U0uvk)$m;zKfjPK@oc?I`}1Jzl$Q~aoKBd3kt7L#7gyt|A_qgz6ai< z=X%D1i!d2h?rHR^R8SUj&G||dkC?DT>{o#Yau<@uqVT{Xef&XG}5*E4aPk{}~ zplx&XhaV)&1EfI3Em;Bw#O5SV^c;{twb-1Rw)+=0!e_BLbd7tYmXCH0wrlOSS+~`7He8Iqx0{CN+DVit9;*6L~JAN zD&cyT)2?h}xnYmL?^)<7YyzZ3$FHU^Eg;DLqAV{#wv#Wj7S`Jdl1pX&{3(uZ?!uh} zDc$ZTNV*7le_W6}Hju~GMTxZQ1aWCeUc%!jv3MHAzt>Y-nQK%zfT*3ebDQA5b?iGn; zBjv3B+GhLTexd_(CzZDP4|#n5^~scvB6#Pk%Ho!kQ>yYw((Dv{6=$g3jT1!u6gORW zx5#`7Wy-ZHRa~IxGHdrp(bm%lf>2%J660nj$fCqN(epv@y!l9s7@k6EvxS{AMP>WY zX4$@F8^kayphIx-RGO$+LYl9YdoI5d|4#q9##`_F5Xnx`&GPzp2fB{-{P@ATw=X@~ z_|&^UMWAKD;jjBKTK(~o?cUFRK8EX=6>cXpfzg4ZpMB>*w_^8GSiT-Jp|xBOnzM+j z*09-@-~qJ(eqWq5@R4i^u4^{McCP(!3}C|v_WsTR*bIUxN(Nx`u##3B4{sE`Z`v8w zAwIG`?1~PkID~W{uDzmqH98Pew_1(;x2%8r^vY{)_&J2K)cN{W+h5+g)ZcjP&Ci#O zgy|8K@4kyMfwilHd&6TDlhb%++Pk!>9HRld6HT7gwyZGrxS$}CsD6`>6!!2K1@Mjf z(P0WYB7V_OFZyeWrbOFb>O54BNXf~K&?}3=^v;v_wT{DKr?jN^DtN&DXwX%u?s*c6`%8>WFz z7}YW^tp0bp^NriE)AB6M2l<7rn7fzePtR*omOevpfm9n?}2V*+0iW;S)C zhg`NAjL?D=W#k*$aR{>pGf~lD-rVtD;5jW1_*Jn1j1=es@Kcx4ySM_bwcQCT=d+DV z>Sz~L=Hj@(X%31nK$mWI@7d>}ORB`K(p=+`UD)+99YUGQc7y^bHZ1F(8|tL0 zdK*DT0kSXG_{BKTpP2*2PecdKV9;dq$^ZZDP;Nyq1kp-&GI5eAyZsK!e3V zK@rPy*{(`KIfo+lc878mDKk^V#`VT05}64kBtk%DgwLrOvLMj5-;*GNKv6c6pzMuL z6EP%ob|_0IW}lLRXCP2!9wWhEw3LA7iF#1O1mIZ@Z=6&bz41F;@S_GvYAG-#CW3z{ zP3+6vHhvP&A3$##Vo9$dT^#MoGg^|MDm=Bt1d2RRwSZ<;ZHICpLBv5Xs!D?BH^(9_ z7`H=N&^v|Z-%mP}wNzG{aiFCsRgwzwq!N6obW9+7(R; z(SZ=23`|`>qil!LMGG{_Heq!BD>(Y-zV9wD)}hz25JA37YR%39;kI4y9pgtcUass6 zP24}ZY$vvYeI`zy&)A_X#nY3017ap*0&jx|mVwyGhg3;!keU53a}Uhm3BZI$N$6Se zLWlAmy1S0xKJm4G_U@sN_Tm=`$xWJSEwKU98rZ&)1R^*$$1vA3oG#&*%SMxY_~oGP zP&PFJatFLM-Ps%84IV-+Ow)T{C7cqUAvauy4C z(FRz&?6$Rypj{xO!`y=*J5o4@U8Q-(y5(*=YoKeZ+-1YdljXxkA#B)zo=FeQH#?Le zycNUmEEHWO9a=X^pb#&cOq7-`7UA87#|S22)<7RUtZo|(zibX=w;K3qur9vy#`MNV z6UUcf9ZwEnKCCp+OoBnF@OdbvH)ANXO0o~Pi9l8=x3))}L<#vO0-~O4!~--Ket?d} zJaqsj<@CD1%S2cTW%rOP{Vto%0sGW~1RMa_j^)5nil0Yw- z0EE#bP+l4#P^%PQ+N*oxu1Zq05xZ!bXfYTg>9c{(Iw*lnjR^>kz%lAN^zFce7rppy zY8zA~3GD=A6d*hze&l4D_wA~+O!56)BZTe_rEu}Ezi<4!kG|W#amBZ5{&XS2@6R~H z{9o^y*BkH4$~yX9U&@CgbOzX1bn9xqF|zh$Dh0Y5y*E0e90*$!ObrHY3Ok0`2=O~r zCuke6KrP9KOf?V(YDsM<6pX2nVoN%M$LT^q#FmtaF?1^27F*IcNX~XRB(|hCFvdcc zc)$=S-)acdk$g4?_>jRqxpI6M3vHZk?0c^3=byamYDNf;uB{3NlKW5IhnOS3DNkMV z?tK8?kJ}pmvp%&&eTVOVjHP`q34hN1@!aK}H(K!vI`~gf|Gv+FNEQD5Yd<~yX7k_l h&G-K)@HZb3BABY{)U1?^%I#E6`MGoTtustd{~yM6srvu` literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square150x150Logo.scale-200.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..af49fec1a5484db1d52a7f9b5ec90a27c7030186 GIT binary patch literal 2937 zcma)84OCO-8BSud5)jwMLRVKgX(S?$n?Ld|vrsm<$CF7)&zTbyy1FE5bU`Q17MRv`9ue$;R(@8kR;#vJ*IM0>cJIAOte!d7oRgdH zd%ySjdB6L9=gX^A6)VzH7p2l@v~3zJAMw|DFy#^)F@@F*`mqUn=Il>l)8_+ab;nOW{%+iPx z+s{Eu|&pIs)Z7{La9~?xKfyl z#43?gjEL15d4WbOZo#SiP%>DB^+BcnJ=7dHEe;r#G=tuw|ka z%q@}##Uh7;tc%L_64m(kHtw74ty%BJMb)_1)#S0j`)F8_1jF7vScpsnH=0V19bO8y zR`0SjIdCUo&=>JwMQF8KHA<{ODHTiQh}0^@5QRmCA?gOH6_H3K^-_sNB^RrdNuK-R zOO*vOrKCVvDwgUck`kF(E7j{I#iiN;b*ZdCt4m@HPA`EuEqGGf4%!K<;(=I=&Vyrw z%TwcWtxa}8mCZ%Cyf&ActJ6_$ox5z6-D!0-dvnRx6t7y3d+h6QYpKWO;8OdnvERo7 zuEf>ih5`wqY)~o@OeVt-wM?Q!>QzdGRj!bz6fzYrfw$hZfAKzr2-M+D+R>}~oT574c;_3zquHcElqKIsryILt3g8n3jcMb+j?i?-L3FpZJ z2WRVBRdDPc+G5aaYg#5hpE+6nQ|(VSoxT3|biF;BUq#==-27Xi=gihDPYP$7?=9cP zYKE$jeQ|3~_L0VG-(F~2ZPyD0=k{J4Q~h(t__{-mz_w8{JDY9{`1ouzz!Vr5!ECdE z6U~O1k8c}24V7~zzXWTV-Pe4)y}wQJS&q%H5`Fo_f_JvIU489aCX$;P`u#!I-=^4ijC2{&9!O&h>mi?9oYD=GC#%)6{GzN6nQYw+Fal50!#x^asjBBR50i`+mho*ttoqV)ubM2KD9S~k7+FR4>{29?6 z{!l6kDdyTN0YJ9LgkPWeXm|gyi@zM3?0@{&pXT12w|78&W-q!RRF)&iLCEZVH<|fR zN0fr2^t8H(>L?>K#>^+jWROLral(Qy-xoBq1U7A&DV||wClb)Otd9?(gZ|8znMF}D zf<1haWz^s0qgecz;RFGt0C-B4g`jNGHsFU+;{<%t65v^sjk^h$lmWn#B0#_)9ij&d z-~lc`A)YYExi^7sBuPM^Y|wA2g*5?`K?#7tzELQYNxGo$UB$4J8RJp1k(8Jj+~hMT zlN~>M@KTTh^--8y3PK_NZ@AC!{PT=CziBzGd+wTJ^@icH!Bd}%)g8V)%K?|c&WTUk zy}qv1C%(fjRoZ4ozC3{O%@5?)XzH35zHns$pgU*Q?fj4v?fp1Qbm+j;3l;9jam9Da zXVcKjPlQ73x78QPu|Ffm6x?`~e3oD=gl=4kYK?={kD5j~QCXU)`HSdduNNENzA*2$ zOm3PzF!lN5e*06-f1Uot67wY#{o-S1!KZ7E=!~7ynnk9_iJR#kFoNbAOT#^2Gd17F zMmvU6>lndZQGd|ax9kUoXXO+$N?|j@6qpsF&_j7YXvwo_C{JpmLw5&#e6k>atv%es z5)7r*Wvv_JkUpT}M!_o!nVlEk1Zbl=a*2hQ*<|%*K1Glj^FcF`6kTzGQ3lz~2tCc@ z&x|tj;aH&1&9HwcJBcT`;{?a+pnej;M1HO(6Z{#J!cZA04hnFl;NXA+&`=7bjW_^o zfC40u3LMG?NdPtwGl>Tq6u}*QG)}-y;)lu-_>ee3kibW(69n0$0Zy!}9rQz%*v1iO zT9_H>99yIrSPYVy6^);rR}7Yo=J_T@hi+qhTZXnVWyf;JDYm5#eYLTxr*?kiNn!+Y zQ+LUkBafNJ#rH#C(?d5^;gw9o#%daEI{mA*LHPIHPU`#|H$hD zwm>0&+kahQ)E#%~k>&5@&#Vg82H?s%71=)(soi@174pi9--2{w{1$}Sz4zGn3Du&x bht0Iza^2ykEt4(epJ78uh5nDlX8(TxzDYwP literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.scale-200.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..ce342a2ec8a61291ba76c54604aea7e9d20af11b GIT binary patch literal 1647 zcmaJ?eM}Q)7(e+G1Q(|`V9JhTI2>MkceK4;p;PR&$Pi?ejk3YQ_3o`S&|W_dsOZ8# zWPTt69g`t$ab`0cj-Y0yiBSOqmd)tG7G(}M5aP0_%&9TijB#&)I{zSE^4@#z^FF`l z`8{8`o%wlL(UI|y2!cdsuVamHH~H86F!*-15em4)NqUpCQM5?aoC_eCf@lV4wvF2a zjDQn1JBL69f&@2M3rvzJcfE!eZ8FZUBlFlC5RD)it33{mF9#B82AiyQE%w)`vlwa> zv{<1sm&kSKK$&%2jSFn7$t&P%%6Ue>R=EAnG8N7fqynWG8L3p!4801a;8{+nliO(qd(jNJ_?+9W3#hLIDLoT6~3fx9=`CC-D}-AMrpEO7HK zt3$GicGPc?GmDjy7K2P@La;eu4!$zWCZ`ym{Z$b zu-O6RM&K4JT|BIZB`E-gxqG%FzanI#+2FFmqHqXG7yxWB=w55RGOM)$xMb(>kSNR z2w=1AZi%z=AmG~yea~XaXJR!v7vLn(RUnELfiB1|6D84ICOS}^Zo2AdN}<&*h}G_u z{xZ!(%>tLT3J3<5XhWy-tg+6)0nmUUENLW8TWA{R6bgVd3X;anYFZ^IRis*_P-C-r z;i>%1^eL3UI2-{w8nuFFcs0e~7J{O2k^~Ce%+Ly4U?|=!0LH=t6()xi<^I-rs+9sF z*q{E-CxZbGPeu#a;XJwE;9S1?#R&uns>^0G3p`hEUF*v`M?@h%T%J%RChmD|EVydq zmHWh*_=S%emRC*mhxaVLzT@>Z2SX0u9v*DIJ@WC^kLVdlGV6LpK$KIrlJqc zpJ921)+3JJdTx|<`G&kXpKkjGJv=76R`yYIQ{#c-`%+`#V(7}Q;&@6U8!Td1`d;?N z_9mnI#?AA}4J!r)LN4!E-@H5eXauuB7TOawS>Y|{-P?NNx-lq+z1W-+y(;39P&&LP zL{N80?&=C*qKmdA^moMZRuPcD!B<*mq$ch=0Cnlitw#txRWhb3%TQvPqjkC`F69G4b! ze7z9MZ#+;_#l?H37UqUhDFb^l&s2{oM$3I0o^Q!yx;;V)QmCMo)Tb_ui|mit8MS?U zm##6$sZZ1$@|s%?l@>4Z<*Q}sRBSKMhb4I{e5LdEhsHIHTe8Bod5c>6QtT>$XgUBz z6MK`kO$=jmt@FqggOhJ5j~e@ygRbG;<{Vu)*+nn9aQeo0;$#j;|MS=S$&L?BeV25z xs3B`@=#`5TF{^6(A1rvdY@|-RtQ|iS5{tyX+wH?;n8E)G$kykv-D^wh{{!TZT%7;_ literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c02ce97e0a802b85f6021e822c89f8bf57d5cd GIT binary patch literal 1255 zcmaJ>TWs4@7*5+{G#S+&C!qC#> zf>5N3P6jO*Cz>ug*(_DmW=)kea&m$gZ^+nyiF`;j%w@}y8)>p*SH}C`m?DXeieF2U zyQHecc_L%Gh!7GMt+hG06y;+|p4>m~}PjA}rKViGiEnn7G0ZO<>G|7q;2?NwGCM3s?eued6%hd$B+ z*kQJ{#~$S=DFE(%=E+UkmlEI*%3llUf~8Ja9YU1Vui0IbGBkW_gHB%Rd&!!ioX zs40O?i9I{};kle7GMvE7(rk`la=gTI)47=>%?q@^iL-nUo3}h4S}N-KHn8t5mVP8w z&bSErwp+37 zNJJ8?a|{r5Q3R0Z5s-LB1WHOwYC@7pCHWND#cL1cZ?{kJ368_*(UDWUDyb<}0y@o# zfMF016iMWPCb6obAxT$JlB6(2DrlXDTB&!0`!m??4F(qWMhjVZo?JXQmz`1*58Z=& zcDmB|S-E@j?BoFGix0flckqdS4jsPNzhfWyWIM98GxcLs89C(~dw%$_t;JjX-SD}E zfiGV;{8Q%8r}w9x>EEigW81>`kvnU@pK)4+xk9@+bNj9L!AAZ@SZ@q|)&BmY3+HZx zul~BeG4|}-;L%cHViQGQX?^zFfO0&#cHwel=d`lH9sJ-@Sl@n*(8J2>%Ac`IxyY?Q z{=GhWvC#gu-~Ia7*n{=+;qM?Ul_wy1+u7ho;=`>EwP^g~R@{unBds`!#@}tluZQpS zm)M~nYEifJWJGx?_6DcTy>#uh%>!H9=hb^(v`=m3F1{L>db=<5_tm+_&knAQ2EU$s Mu9UqpbNZeC0BbUo^Z)<= literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/StoreLogo.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..7385b56c0e4d3c6b0efe3324aa1194157d837826 GIT binary patch literal 1451 zcmaJ>eN5D57_Z|bH;{0+1#mbl)eTU3{h)Wf7EZV?;HD@XL@{B`Ui%(2aMxQ~xdXSv z5nzWi(LW)U2=Vc-cY@s7nPt{i0hc6!7xN4NNHI#EQl>YNBy8l4%x9gr_W-j zEZMQmmTIy(>;lblRfh`dIyTgc9W5d!VP$L4(kKrN1c5G~(O_#xG zAJCNTstD^5SeXFB+&$h=ToJP2H>xr$iqPs-#O*;4(!Fjw25-!gEb*)mU}=)J;Iu>w zxK(5XoD0wrPSKQ~rbL^Cw6O_03*l*}i=ydbu7adJ6y;%@tjFeXIXT+ms30pmbOP%Q zX}S;+LBh8Tea~TSkHzvX6$rYb)+n&{kSbIqh|c7hmlxmwSiq5iVhU#iEQ<>a18|O^Sln-8t&+t`*{qBWo5M?wFM(JuimAOb5!K#D}XbslM@#1ZVz_;!9U zpfEpLAOz=0g@bd6Xj_ILi-x^!M}73h^o@}hM$1jflTs|Yuj9AL@A3<-?MV4!^4q`e z)fO@A;{9K^?W?DbnesnPr6kK>$zaKo&;FhFd(GYFCIU^T+OIMb%Tqo+P%oq(IdX7S zf6+HLO?7o0m+p>~Tp5UrXWh!UH!wZ5kv!E`_w)PTpI(#Iw{AS`gH4^b(bm^ZCq^FZ zY9DD7bH}rq9mg88+KgA$Zp!iWncuU2n1AuIa@=sWvUR-s`Qb{R*kk(SPU^`$6BXz8 zn#7yaFOIK%qGxyi`dYtm#&qqox0$h=pNi#u=M8zUG@bpiZ=3sT=1}Trr}39cC)H|v zbL?W)=&s4zrh)7>L(|cc%$1#!zfL?HjpeP%T+x_a+jZ16b^iKOHxFEX$7d|8${H-* zIrOJ5w&i$>*D>AKaIoYg`;{L@jM((Kt?$N$5OnuPqVvq**Nm}(f0wwOF%iX_Pba;V z;m@wxX&NcV3?<1+u?A{y_DIj7#m3Af1rCE)o`D&Y3}0%7E;iX1yMDiS)sh0wKi!36 zL!Wmq?P^Ku&rK~HJd97KkLTRl>ScGFYZNlYytWnhmuu|)L&ND8_PmkayQb{HOY640 bno1(wj@u8DCVuFR|31B*4ek@pZJqxCDDe1x literal 0 HcmV?d00001 diff --git a/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Wide310x150Logo.scale-200.png b/Docs-ContextMenuSample/ContextMenuSample.Package/Images/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..288995b397fdbef1fb7e85afd71445d5de1952c5 GIT binary patch literal 3204 zcmbVPeQXow8NYmBd90>}0NP?GhXW~VaeThm=a0tV#EwJMI!)6M3}|c4_Bl3=Kd>G0 z(GHx1wl<7(tP?FsOQkTilSo*iIvF%uArExJ73~P zSv1xEy!U(Wd4A9D`FQV@W3@F^qJ@PEF$@z`Z!*BbFsS(^?B zyiAzJ+q})bkgiQHWqEb*jJD-coHYr1^iocg)l!Qa{Xqs-l~6J}p-|##ZHYofskQ3$ zI0;xzXyhazBeXhIsg5A=%ufo@f)1yy&ScKS0;HF^!r_2UE^lpZEom(+@duma3awTv zCrCL-%D_SvYWIcdHkmI}#50(fkUi)Qgx!80ju>g1za^}ff>JI8Z@^-iCiaCgg@TgF z+vtE?Q9{VQUX&MW9SYYmGcxA14%N2@7FwBTD4N<(2{nWgV8$e3?-F=L^&FrtWn~(U_Q~~^uYiyeY6-KoTnfh9AWz@ zIKje0)u!_Lw)E}G!#kEfwKVdNt(UAf9*f>tEL_(=xco-T%jTi@7YlC3hs2ik%Le0H ztj}RTeCF(5mwvi3_56>-yB?l;J>-1%!9~=fs|QcNG3J~a@JCu`4SB460s0ZO+##4fFUSGLcj_ja^fL4&BKALfb#$6$O?>P@qx2Agl^x0i&ugt zsy5Pyu=()`7HRMG3IB7F1@`_ z+-!J%#i6e^U$e#+C%Q>_qVRzWRsG^W_n+@OcX@vzI&z;mzHNb!GQ?LWA(wtpqHqTM z1OFw_{Zn?fD)p)`c`kOgv{de=v@suGRqY{N^U7gI1VF3*F=obwaXI6ob5__Yn zVTguS!%(NI09J8x#AO_aW!9W7k*UvB;IWDFC3srwftr{kHj%g)fvnAm;&h_dnl~

MY- zf+K}sCe8qU6Ujs`3ua{U0Of$R_gVQBuUA za0v=mu#vIOqiiAZOr&h*$WyOw&k-xr$;G4Ixa!#TJNr>95(h>l%)PUy4p+^SgR(uR zta%k*?ny-+nAr8spEk1fo{J4i!b^Fia`N{_F6@zidA2ZTTrjl#^5Z-2KfB@Cu}l9s z(*|Z2jc?p~vn2f)3y9i*7zJV1L{$?|&q)4oaT;uXi6>1GkRXVTOzAz(RHEmr=eFIi z`}<>-Q?K0GN8!IYxeP1XKXO+jsJbp~o^);Bc;%b7Flpe7;1`Ny@3r7ZR;?R)aJt8C ziNlEC<@3f_lIV4TwV}&e;D!Ee5_|e#g0LUh=5vmYWYm7&2h*M>QPKvGh9-)wfMMW3 z8J9b%1k7dzPzO0_NGQy92BZ^FR6R~6;^6?lqO;-QUP4BY%cG%3vEhbm#>4vIhPBh3 z-+pZGjh$x%Hp{?=FHsMp0&wNPlj00us{&`1ZOZTqs8%4X&xH=UDr*xyBW(Zp&Em94 zf)ZSfn#yg0N)>!1kWdkqJ^S*z0FF5|fj&qcE#Na|%OY0$uO>!&hP+1ywfD_WXk@4J(?MBftK7>$Nvqh@tDuarN%PrTLQ2Uzysx>UV=V zk^RrDSvdQ?0;=hY67EgII-f4`t=+i*yS=Y~!XlqIy_4x&%+OdfbKOFPXS2X5%4R{N z$SQMX^AK6(fA + + + + + + + ContextMenu Sample + Windows AppConsult + Images\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + .foo + + + Resize file + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Docs-ContextMenuSample/ContextMenuSample.sln b/Docs-ContextMenuSample/ContextMenuSample.sln new file mode 100644 index 0000000..2cd5a05 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample.sln @@ -0,0 +1,97 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30406.217 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ContextMenuSample", "ContextMenuSample\ContextMenuSample.csproj", "{F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}" +EndProject +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "ContextMenuSample.Package", "ContextMenuSample.Package\ContextMenuSample.Package.wapproj", "{6378D9D6-B2ED-4FC7-A42E-E5903C700764}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerCommandVerb", "ExplorerCommandVerb\ExplorerCommandVerb.vcxproj", "{6ADD939C-A7C3-4FB3-B08B-8B037854E98C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|ARM.Build.0 = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|ARM64.Build.0 = Debug|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|x64.ActiveCfg = Debug|x64 + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|x64.Build.0 = Debug|x64 + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|x86.ActiveCfg = Debug|x86 + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Debug|x86.Build.0 = Debug|x86 + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|Any CPU.Build.0 = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|ARM.ActiveCfg = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|ARM.Build.0 = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|ARM64.ActiveCfg = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|ARM64.Build.0 = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|x64.ActiveCfg = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|x64.Build.0 = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|x86.ActiveCfg = Release|Any CPU + {F944BE89-7FF8-4BDB-B419-DFAD9BCDBCAC}.Release|x86.Build.0 = Release|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM.ActiveCfg = Debug|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM.Build.0 = Debug|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM.Deploy.0 = Debug|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM64.Build.0 = Debug|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x64.ActiveCfg = Debug|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x64.Build.0 = Debug|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x64.Deploy.0 = Debug|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x86.ActiveCfg = Debug|x86 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x86.Build.0 = Debug|x86 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Debug|x86.Deploy.0 = Debug|x86 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|Any CPU.Build.0 = Release|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|Any CPU.Deploy.0 = Release|Any CPU + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM.ActiveCfg = Release|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM.Build.0 = Release|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM.Deploy.0 = Release|ARM + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM64.ActiveCfg = Release|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM64.Build.0 = Release|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|ARM64.Deploy.0 = Release|ARM64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x64.ActiveCfg = Release|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x64.Build.0 = Release|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x64.Deploy.0 = Release|x64 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x86.ActiveCfg = Release|x86 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x86.Build.0 = Release|x86 + {6378D9D6-B2ED-4FC7-A42E-E5903C700764}.Release|x86.Deploy.0 = Release|x86 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|ARM.ActiveCfg = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|ARM64.ActiveCfg = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x64.ActiveCfg = Debug|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x64.Build.0 = Debug|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x86.ActiveCfg = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x86.Build.0 = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|Any CPU.ActiveCfg = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|ARM.ActiveCfg = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|ARM64.ActiveCfg = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x64.ActiveCfg = Release|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x64.Build.0 = Release|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x86.ActiveCfg = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {450CE318-9428-4582-9D15-CB639AF97509} + EndGlobalSection +EndGlobal diff --git a/Docs-ContextMenuSample/ContextMenuSample/App.xaml b/Docs-ContextMenuSample/ContextMenuSample/App.xaml new file mode 100644 index 0000000..fa0d966 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Docs-ContextMenuSample/ContextMenuSample/App.xaml.cs b/Docs-ContextMenuSample/ContextMenuSample/App.xaml.cs new file mode 100644 index 0000000..97acc03 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/App.xaml.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows; + +namespace ContextMenuSample +{ + ///

+ /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public string FilePath { get; set; } + protected override void OnStartup(StartupEventArgs e) + { + if (e.Args.Length > 0) + { + FilePath = e.Args[0]; + + } + + this.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative); + } + } +} diff --git a/Docs-ContextMenuSample/ContextMenuSample/AssemblyInfo.cs b/Docs-ContextMenuSample/ContextMenuSample/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Docs-ContextMenuSample/ContextMenuSample/ContextMenuSample.csproj b/Docs-ContextMenuSample/ContextMenuSample/ContextMenuSample.csproj new file mode 100644 index 0000000..c412d53 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/ContextMenuSample.csproj @@ -0,0 +1,11 @@ + + + + WinExe + net5.0 + true + AnyCPU;x86;x64 + win-x86;win-x64 + + + diff --git a/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml b/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml new file mode 100644 index 0000000..1bf4604 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml.cs b/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml.cs new file mode 100644 index 0000000..a288608 --- /dev/null +++ b/Docs-ContextMenuSample/ContextMenuSample/MainWindow.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace ContextMenuSample +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + string path = (Application.Current as App).FilePath; + txtFilePath.Text = path; + } + + } +} diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.def b/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.def new file mode 100644 index 0000000..76a21de --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.def @@ -0,0 +1,5 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE \ No newline at end of file diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.h b/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.h new file mode 100644 index 0000000..053437c --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/Dll.h @@ -0,0 +1,25 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +#pragma once +#include "ShellHelpers.h" +#include "RegisterExtension.h" +#include +#include // std::nothrow + +void DllAddRef(); +void DllRelease(); + +// use UUDIGEN.EXE to generate unique CLSID values for your objects + +class __declspec(uuid("CC19E147-7757-483C-B27F-3D81BCEB38FE")) CExplorerCommandVerb; +class __declspec(uuid("5A777238-07F9-42AB-B074-4004F1ED74A9")) CExplorerCommandStateHandler; + +HRESULT CExplorerCommandVerb_CreateInstance(REFIID riid, void **ppv); +HRESULT CExplorerCommandStateHandler_CreateInstance(REFIID riid, void **ppv); +HRESULT CExplorerCommandVerb_RegisterUnRegister(bool fRegister); +HRESULT CExplorerCommandStateHandler_RegisterUnRegister(bool fRegister); diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandStateHandler.cpp b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandStateHandler.cpp new file mode 100644 index 0000000..383537f --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandStateHandler.cpp @@ -0,0 +1,149 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +// ExplorerCommandState handlers are not a verb implementation method, it is a way to give a dynamic +// behavior to a static verb implementation, that is show or not. This handler is run on a background thread +// to avoid UI hangs. So, for example you can combine it with ExecuteCommand, DropTarget or CreateProcess +// verb to give them dynamic behavior. Only use this method if you cannot express your dynamic behavior +// using an AQS expression. There is a limitation to this in that this cannot be used on the default verb. + +#include "Dll.h" + +class CExplorerCommandStateHandler + : public IExplorerCommandState, public IInitializeCommand +{ +public: + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + static const QITAB qit[] = + { + QITABENT(CExplorerCommandStateHandler, IExplorerCommandState), // required + QITABENT(CExplorerCommandStateHandler, IInitializeCommand), // optional + // QITABENT(CExplorerCommandStateHandler, IObjectWithSite), // optional. the site can be used to get the explorer browser or view. not implemented in this sample + { 0 }, + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&_cRef); + if (!cRef) + { + delete this; + } + return cRef; + } + + // IExplorerCommandState + + // compute the visibility of the verb here, respect "fOkToBeSlow" if this is slow + // when called with fOkToBeSlow == FALSE return E_PENDING and this object will be called + // back on a background thread with fOkToBeSlow == TRUE + IFACEMETHODIMP GetState(IShellItemArray * /* psiItemArray */, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) + { + HRESULT hr; + if (fOkToBeSlow) + { + Sleep(4 * 1000); // simulate expensive work + *pCmdState = ECS_ENABLED; + hr = S_OK; + } + else + { + *pCmdState = ECS_DISABLED; + // returning E_PENDING requests that a new instance of this object be called back + // on a background thread so that it can do work that might be slow + hr = E_PENDING; + } + return hr; + } + + // IInitializeCommand + IFACEMETHODIMP Initialize(PCWSTR pszCommandName, IPropertyBag *ppb) + { + SetInterface(&_pPropBag, ppb); + return SHStrDup(pszCommandName, &_pszCommandName); + } + + CExplorerCommandStateHandler() : _cRef(1), _pPropBag(NULL), _pszCommandName(NULL) + { + DllAddRef(); + } + +private: + virtual ~CExplorerCommandStateHandler() + { + SafeRelease(&_pPropBag); + CoTaskMemFree(_pszCommandName); + DllRelease(); + } + long _cRef; + IPropertyBag *_pPropBag; + PWSTR _pszCommandName; +}; + +HRESULT CExplorerCommandStateHandler_CreateInstance(REFIID riid, void **ppv) +{ + *ppv = NULL; + CExplorerCommandStateHandler *pVerbState = new (std::nothrow) CExplorerCommandStateHandler(); + HRESULT hr = pVerbState ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + pVerbState->QueryInterface(riid, ppv); + pVerbState->Release(); + } + return hr; +} + +static WCHAR const c_szVerbDisplayName[] = L"CommandState Handler Verb"; +static WCHAR const c_szVerbName[] = L"Sample.ExplorerCommandStateHandlerVerb"; +static WCHAR const c_szProgID[] = L"txtfile"; + +HRESULT CExplorerCommandStateHandler_RegisterUnRegister(bool fRegister) +{ + HRESULT hr; + if (fRegister) + { + // register a create process based verb. this could also be a delegate execute + // or drop target verb + CRegisterExtension registerCreateProcess(CLSID_NULL); + hr = registerCreateProcess.RegisterCreateProcessVerb(c_szProgID, c_szVerbName, L"notepad.exe %1", c_szVerbDisplayName); + if (SUCCEEDED(hr)) + { + hr = registerCreateProcess.RegisterVerbAttribute(c_szProgID, c_szVerbName, L"NeverDefault"); + if (SUCCEEDED(hr)) + { + // now register the command state handler, this computes if this verb is enabled or not + + CRegisterExtension re(__uuidof(CExplorerCommandStateHandler)); + + hr = re.RegisterInProcServer(c_szVerbDisplayName, L"Apartment"); + if (SUCCEEDED(hr)) + { + hr = re.RegisterExplorerCommandStateHandler(c_szProgID, c_szVerbName); + } + } + } + } + else + { + // best effort + CRegisterExtension registerCreateProcess(CLSID_NULL); + hr = registerCreateProcess.UnRegisterVerb(c_szProgID, c_szVerbName); + + CRegisterExtension re(__uuidof(CExplorerCommandStateHandler)); + hr = re.UnRegisterObject(); + } + return hr; +} diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.cpp b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.cpp new file mode 100644 index 0000000..b39c190 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.cpp @@ -0,0 +1,265 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +// ExplorerCommand handlers are an inproc verb implementation method that can provide +// dynamic behavior including computing the name of the command, its icon and its visibility state. +// only use this verb implemetnation method if you are implementing a command handler on +// the commands module and need the same functionality on a context menu. +// +// each ExplorerCommand handler needs to have a unique COM object, run uuidgen to +// create new CLSID values for your handler. a handler can implement multiple +// different verbs using the information provided via IInitializeCommand (the verb name). +// your code can switch off those different verb names or the properties provided +// in the property bag + +#include "Dll.h" +#include +#include + +static WCHAR const c_szVerbDisplayName[] = L"This is a custom context menu..."; +static WCHAR const c_szVerbName[] = L"Sample.ExplorerCommandVerb"; + +class CExplorerCommandVerb : public IExplorerCommand, + public IInitializeCommand, + public IObjectWithSite +{ +public: + CExplorerCommandVerb() : _cRef(1), _punkSite(NULL), _hwnd(NULL), _pstmShellItemArray(NULL) + { + DllAddRef(); + } + + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) + { + static const QITAB qit[] = + { + QITABENT(CExplorerCommandVerb, IExplorerCommand), // required + QITABENT(CExplorerCommandVerb, IInitializeCommand), // optional + QITABENT(CExplorerCommandVerb, IObjectWithSite), // optional + { 0 }, + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&_cRef); + if (!cRef) + { + delete this; + } + return cRef; + } + + // IExplorerCommand + IFACEMETHODIMP GetTitle(IShellItemArray* /* psiItemArray */, LPWSTR* ppszName) + { + // the verb name can be computed here, in this example it is static + return SHStrDup(c_szVerbDisplayName, ppszName); + } + + IFACEMETHODIMP GetIcon(IShellItemArray* /* psiItemArray */, LPWSTR* ppszIcon) + { + // the icon ref ("dll,-") is provied here, in this case none is provieded + *ppszIcon = NULL; + return E_NOTIMPL; + } + + IFACEMETHODIMP GetToolTip(IShellItemArray* /* psiItemArray */, LPWSTR* ppszInfotip) + { + // tooltip provided here, in this case none is provieded + *ppszInfotip = NULL; + return E_NOTIMPL; + } + + IFACEMETHODIMP GetCanonicalName(GUID* pguidCommandName) + { + *pguidCommandName = __uuidof(this); + return S_OK; + } + + // compute the visibility of the verb here, respect "fOkToBeSlow" if this is slow (does IO for example) + // when called with fOkToBeSlow == FALSE return E_PENDING and this object will be called + // back on a background thread with fOkToBeSlow == TRUE + IFACEMETHODIMP GetState(IShellItemArray* /* psiItemArray */, BOOL fOkToBeSlow, EXPCMDSTATE* pCmdState) + { + //HRESULT hr; + //if (fOkToBeSlow) + //{ + // Sleep(4 * 1000); // simulate expensive work + // *pCmdState = ECS_ENABLED; + // hr = S_OK; + //} + //else + //{ + // *pCmdState = ECS_DISABLED; + // // returning E_PENDING requests that a new instance of this object be called back + // // on a background thread so that it can do work that might be slow + // hr = E_PENDING; + //} + + HRESULT hr = S_OK; + return hr; + } + + IFACEMETHODIMP Invoke(IShellItemArray* psiItemArray, IBindCtx* pbc); + + IFACEMETHODIMP GetFlags(EXPCMDFLAGS* pFlags) + { + *pFlags = ECF_DEFAULT; + return S_OK; + } + + IFACEMETHODIMP EnumSubCommands(IEnumExplorerCommand** ppEnum) + { + *ppEnum = NULL; + return E_NOTIMPL; + } + + // IInitializeCommand + IFACEMETHODIMP Initialize(PCWSTR /* pszCommandName */, IPropertyBag* /* ppb */) + { + // the verb name is in pszCommandName, this handler can vary its behavior + // based on the command name (implementing different verbs) or the + // data stored under that verb in the registry can be read via ppb + return S_OK; + } + + // IObjectWithSite + IFACEMETHODIMP SetSite(IUnknown* punkSite) + { + SetInterface(&_punkSite, punkSite); + return S_OK; + } + + IFACEMETHODIMP GetSite(REFIID riid, void** ppv) + { + *ppv = NULL; + return _punkSite ? _punkSite->QueryInterface(riid, ppv) : E_FAIL; + } + +private: + ~CExplorerCommandVerb() + { + SafeRelease(&_punkSite); + SafeRelease(&_pstmShellItemArray); + DllRelease(); + } + + DWORD _ThreadProc(); + + static DWORD __stdcall s_ThreadProc(void* pv) + { + CExplorerCommandVerb* pecv = (CExplorerCommandVerb*)pv; + const DWORD ret = pecv->_ThreadProc(); + pecv->Release(); + return ret; + } + + long _cRef; + IUnknown* _punkSite; + HWND _hwnd; + IStream* _pstmShellItemArray; +}; + +DWORD CExplorerCommandVerb::_ThreadProc() +{ + IShellItemArray* psia; + HRESULT hr = CoGetInterfaceAndReleaseStream(_pstmShellItemArray, IID_PPV_ARGS(&psia)); + _pstmShellItemArray = NULL; + if (SUCCEEDED(hr)) + { + DWORD count; + psia->GetCount(&count); + + IShellItem2* psi; + HRESULT hr = GetItemAt(psia, 0, IID_PPV_ARGS(&psi)); + if (SUCCEEDED(hr)) + { + PWSTR pszName; + hr = psi->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &pszName); + if (SUCCEEDED(hr)) + { + WCHAR szMsg[128]; + StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"%d item(s), first item is named %s", count, pszName); + + MessageBox(_hwnd, szMsg, L"ExplorerCommand Sample Verb", MB_OK); + + CoTaskMemFree(pszName); + } + + psi->Release(); + } + psia->Release(); + } + + return 0; +} + +IFACEMETHODIMP CExplorerCommandVerb::Invoke(IShellItemArray* psia, IBindCtx* /* pbc */) +{ + IUnknown_GetWindow(_punkSite, &_hwnd); + + HRESULT hr = CoMarshalInterThreadInterfaceInStream(__uuidof(psia), psia, &_pstmShellItemArray); + if (SUCCEEDED(hr)) + { + AddRef(); + if (!SHCreateThread(s_ThreadProc, this, CTF_COINIT_STA | CTF_PROCESS_REF, NULL)) + { + Release(); + } + } + return S_OK; +} + +static WCHAR const c_szProgID[] = L"txtfile"; + +HRESULT CExplorerCommandVerb_RegisterUnRegister(bool fRegister) +{ + CRegisterExtension re(__uuidof(CExplorerCommandVerb)); + + HRESULT hr; + if (fRegister) + { + hr = re.RegisterInProcServer(c_szVerbDisplayName, L"Apartment"); + if (SUCCEEDED(hr)) + { + // register this verb on .txt files ProgID + hr = re.RegisterExplorerCommandVerb(c_szProgID, c_szVerbName, c_szVerbDisplayName); + if (SUCCEEDED(hr)) + { + hr = re.RegisterVerbAttribute(c_szProgID, c_szVerbName, L"NeverDefault"); + } + } + } + else + { + // best effort + hr = re.UnRegisterVerb(c_szProgID, c_szVerbName); + hr = re.UnRegisterObject(); + } + return hr; +} + +HRESULT CExplorerCommandVerb_CreateInstance(REFIID riid, void** ppv) +{ + *ppv = NULL; + CExplorerCommandVerb* pVerb = new (std::nothrow) CExplorerCommandVerb(); + HRESULT hr = pVerb ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + pVerb->QueryInterface(riid, ppv); + pVerb->Release(); + } + return hr; +} diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.sln b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.sln new file mode 100644 index 0000000..fca9a36 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28721.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerCommandVerb", "ExplorerCommandVerb.vcxproj", "{6ADD939C-A7C3-4FB3-B08B-8B037854E98C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|Win32.ActiveCfg = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|Win32.Build.0 = Debug|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x64.ActiveCfg = Debug|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Debug|x64.Build.0 = Debug|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|Win32.ActiveCfg = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|Win32.Build.0 = Release|Win32 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x64.ActiveCfg = Release|x64 + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {75DD7178-723E-4369-92F3-73AFDA5784CC} + EndGlobalSection +EndGlobal diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcproj b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcproj new file mode 100644 index 0000000..e4d81c3 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcproj @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcxproj b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcxproj new file mode 100644 index 0000000..eef0111 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ExplorerCommandVerb.vcxproj @@ -0,0 +1,196 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {6ADD939C-A7C3-4FB3-B08B-8B037854E98C} + ExplorerCommandVerb + Win32Proj + + + + DynamicLibrary + v142 + Unicode + true + + + DynamicLibrary + v142 + Unicode + + + DynamicLibrary + v142 + Unicode + true + + + DynamicLibrary + v142 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>16.0.28707.177 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;EXPLORERCOMMANDVERB_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + false + EditAndContinue + + + libcmt;%(IgnoreSpecificDefaultLibraries) + Dll.def + true + Windows + MachineX86 + + + xcopy $(OutputPath)$(MSBuildProjectName).dll $(SolutionDir)ContextMenuSample.Package\ /y + + + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;EXPLORERCOMMANDVERB_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level4 + true + ProgramDatabase + + + libcmt;%(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;EXPLORERCOMMANDVERB_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level4 + true + ProgramDatabase + + + libcmt;%(IgnoreSpecificDefaultLibraries) + Dll.def + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;EXPLORERCOMMANDVERB_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + Level4 + true + ProgramDatabase + + + libcmt;%(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX64 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.cpp b/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.cpp new file mode 100644 index 0000000..5f33151 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.cpp @@ -0,0 +1,839 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +#include "RegisterExtension.h" +#include +#include +#include +#include + +#pragma comment(lib, "crypt32.lib") +#pragma comment(lib, "shlwapi.lib") // link to this + +__inline HRESULT ResultFromKnownLastError() { const DWORD err = GetLastError(); return err == ERROR_SUCCESS ? E_FAIL : HRESULT_FROM_WIN32(err); } + +// retrieve the HINSTANCE for the current DLL or EXE using this symbol that +// the linker provides for every module, avoids the need for a global HINSTANCE variable +// and provides access to this value for static libraries +EXTERN_C IMAGE_DOS_HEADER __ImageBase; +__inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; } + +CRegisterExtension::CRegisterExtension(REFCLSID clsid /* = CLSID_NULL */, HKEY hkeyRoot /* = HKEY_CURRENT_USER */) : _hkeyRoot(hkeyRoot), _fAssocChanged(false) +{ + SetHandlerCLSID(clsid); + GetModuleFileName(GetModuleHINSTANCE(), _szModule, ARRAYSIZE(_szModule)); +} + +CRegisterExtension::~CRegisterExtension() +{ + if (_fAssocChanged) + { + // inform Explorer, et al that file association data has changed + SHChangeNotify(SHCNE_ASSOCCHANGED, 0, 0, 0); + } +} + +void CRegisterExtension::SetHandlerCLSID(REFCLSID clsid) +{ + _clsid = clsid; + StringFromGUID2(_clsid, _szCLSID, ARRAYSIZE(_szCLSID)); +} + +void CRegisterExtension::SetInstallScope(HKEY hkeyRoot) +{ + // must be HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE + _hkeyRoot = hkeyRoot; +} + +HRESULT CRegisterExtension::SetModule(PCWSTR pszModule) +{ + return StringCchCopy(_szModule, ARRAYSIZE(_szModule), pszModule); +} + +HRESULT CRegisterExtension::SetModule(HINSTANCE hinst) +{ + return GetModuleFileName(hinst, _szModule, ARRAYSIZE(_szModule)) ? S_OK : E_FAIL; +} + +HRESULT CRegisterExtension::_EnsureModule() const +{ + return _szModule[0] ? S_OK : E_FAIL; +} + +// this sample registers its objects in the per user registry to avoid having +// to elevate + +// register the COM local server for the current running module +// this is for self registering applications + +HRESULT CRegisterExtension::RegisterAppAsLocalServer(PCWSTR pszFriendlyName, PCWSTR pszCmdLine) const +{ + HRESULT hr = _EnsureModule(); + if (SUCCEEDED(hr)) + { + WCHAR szCmdLine[MAX_PATH + 20]; + if (pszCmdLine) + { + StringCchPrintf(szCmdLine, ARRAYSIZE(szCmdLine), L"%s %s", _szModule, pszCmdLine); + } + else + { + StringCchCopy(szCmdLine, ARRAYSIZE(szCmdLine), _szModule); + } + + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s\\LocalServer32", L"", szCmdLine, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s", L"AppId", _szCLSID, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s", L"", pszFriendlyName, _szCLSID); + if (SUCCEEDED(hr)) + { + // hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\AppID\\%s", L"RunAs", L"Interactive User", _szCLSID); + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\AppID\\%s", L"", pszFriendlyName, _szCLSID); + } + } + } + } + return hr; +} + +HRESULT CRegisterExtension::RegisterElevatableLocalServer(PCWSTR pszFriendlyName, UINT idLocalizeString, UINT idIconRef) const +{ + HRESULT hr = _EnsureModule(); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", L"", pszFriendlyName, _szCLSID); + if (SUCCEEDED(hr)) + { + WCHAR szRes[MAX_PATH + 20]; + StringCchPrintf(szRes, ARRAYSIZE(szRes), L"@%s,-%d", _szModule, idLocalizeString); + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", L"LocalizedString", szRes, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\LocalServer32", L"", _szModule, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\Elevation", L"Enabled", 1, _szCLSID); + if (SUCCEEDED(hr) && idIconRef) + { + StringCchPrintf(szRes, ARRAYSIZE(szRes), L"@%s,-%d", _szModule, idIconRef); + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\Elevation", L"IconReference", szRes, _szCLSID); + } + } + } + } + } + return hr; +} + +HRESULT CRegisterExtension::RegisterElevatableInProcServer(PCWSTR pszFriendlyName, UINT idLocalizeString, UINT idIconRef) const +{ + HRESULT hr = _EnsureModule(); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\AppId\\%s", L"", pszFriendlyName, _szCLSID); + if (SUCCEEDED(hr)) + { + const unsigned char c_rgAccessPermission[] = + {0x01,0x00,0x04,0x80,0x60,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14, + 0x00,0x00,0x00,0x02,0x00,0x4c,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x03,0x00, + 0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,0x00,0x00,0x00,0x00,0x14, + 0x00,0x07,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x14,0x00,0x03,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x04, + 0x00,0x00,0x00,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0x01,0x02,0x00,0x00,0x00,0x00, + 0x00,0x05,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x00,0x00,0x00, + 0x05,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00}; + // shell32\shell32.man uses this for InProcServer32 cases + // 010004805800000068000000000000001400000002004400030000000000140003000000010100000000000504000000000014000700000001010000000000050a00000000001400030000000101000000000005120000000102000000000005200000002002000001020000000000052000000020020000 + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\AppId\\%s", L"AccessPermission", c_rgAccessPermission, sizeof(c_rgAccessPermission), _szCLSID); + + const unsigned char c_rgLaunchPermission[] = + {0x01,0x00,0x04,0x80,0x78,0x00,0x00,0x00,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14, + 0x00,0x00,0x00,0x02,0x00,0x64,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x1f,0x00, + 0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,0x00,0x00,0x00,0x00,0x18, + 0x00,0x1f,0x00,0x00,0x00,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x00,0x00,0x00, + 0x20,0x02,0x00,0x00,0x00,0x00,0x14,0x00,0x1f,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00, + 0x00,0x00,0x05,0x04,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x0b,0x00,0x00,0x00,0x01,0x01, + 0x00,0x00,0x00,0x00,0x00,0x05,0x12,0x00,0x00,0x00,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd, + 0xcd,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00, + 0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00}; + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\AppId\\%s", L"LaunchPermission", c_rgLaunchPermission, sizeof(c_rgLaunchPermission), _szCLSID); + + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", L"", pszFriendlyName, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", L"AppId", _szCLSID, _szCLSID); + if (SUCCEEDED(hr)) + { + WCHAR szRes[MAX_PATH + 20]; + StringCchPrintf(szRes, ARRAYSIZE(szRes), L"@%s,-%d", _szModule, idLocalizeString); + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", L"LocalizedString", szRes, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\InProcServer32", L"", _szModule, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\Elevation", L"Enabled", 1, _szCLSID); + if (SUCCEEDED(hr) && idIconRef) + { + StringCchPrintf(szRes, ARRAYSIZE(szRes), L"@%s,-%d", _szModule, idIconRef); + hr = RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\Elevation", L"IconReference", szRes, _szCLSID); + } + } + } + } + } + } + } + return hr; +} + +HRESULT CRegisterExtension::RegisterInProcServer(PCWSTR pszFriendlyName, PCWSTR pszThreadingModel) const +{ + HRESULT hr = _EnsureModule(); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s", L"", pszFriendlyName, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s\\InProcServer32", L"", _szModule, _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s\\InProcServer32", L"ThreadingModel", pszThreadingModel, _szCLSID); + } + } + } + return hr; +} + +// use for +// ManualSafeSave = REG_DWORD:<1> +// EnableShareDenyNone = REG_DWORD:<1> +// EnableShareDenyWrite = REG_DWORD:<1> + +HRESULT CRegisterExtension::RegisterInProcServerAttribute(PCWSTR pszAttribute, DWORD dwValue) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s", pszAttribute, dwValue, _szCLSID); +} + +HRESULT CRegisterExtension::UnRegisterObject() const +{ + // might have an AppID value, try that + HRESULT hr = RegDeleteKeyPrintf(_hkeyRoot, L"Software\\Classes\\AppID\\%s", _szCLSID); + if (SUCCEEDED(hr)) + { + hr = RegDeleteKeyPrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s", _szCLSID); + } + return hr; +} + +// +// pszProtocol values: +// "*" - all +// "http" +// "ftp" +// "shellstream" - NYI in Win7 + +HRESULT CRegisterExtension::RegisterHandlerSupportedProtocols(PCWSTR pszProtocol) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s\\SupportedProtocols", pszProtocol, L"", _szCLSID); +} + +// this enables drag drop directly onto the .exe, useful if you have a +// shortcut to the exe somewhere (or the .exe is accessable via the send to menu) + +HRESULT CRegisterExtension::RegisterAppDropTarget() const +{ + HRESULT hr = _EnsureModule(); + if (SUCCEEDED(hr)) + { + // Windows7 supports per user App Paths, downlevel requires HKLM + hr = RegSetKeyValuePrintf(_hkeyRoot, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s", + L"DropTarget", _szCLSID, PathFindFileName(_szModule)); + } + return hr; +} + +// work around the missing "NeverDefault" feature for verbs on downlevel platforms +// these ProgID values should need special treatment to keep the verbs registered there +// from becoming default + +bool CRegisterExtension::_IsBaseClassProgID(PCWSTR pszProgID) const +{ + return !StrCmpIC(pszProgID, L"AllFileSystemObjects") || + !StrCmpIC(pszProgID, L"Directory") || + !StrCmpIC(pszProgID, L"*") || + StrStrI(pszProgID, L"SystemFileAssociations\\Directory."); // SystemFileAssociations\Directory.* values +} + +HRESULT CRegisterExtension::_EnsureBaseProgIDVerbIsNone(PCWSTR pszProgID) const +{ + // putting the value of "none" that does not match any of the verbs under this key + // avoids those verbs from becoming the default. + return _IsBaseClassProgID(pszProgID) ? + RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell", L"", L"none", pszProgID) : + S_OK; +} + +HRESULT CRegisterExtension::RegisterCreateProcessVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszCmdLine, PCWSTR pszVerbDisplayName) const +{ + UnRegisterVerb(pszProgID, pszVerb); // make sure no existing registration exists, ignore failure + + HRESULT hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shell\\%s\\command", L"", pszCmdLine, pszProgID, pszVerb); + if (SUCCEEDED(hr)) + { + hr = _EnsureBaseProgIDVerbIsNone(pszProgID); + + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shell\\%s", L"", pszVerbDisplayName, pszProgID, pszVerb); + } + return hr; +} + +// create registry entries for drop target based static verb. +// the specified clsid will be + +HRESULT CRegisterExtension::RegisterDropTargetVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const +{ + UnRegisterVerb(pszProgID, pszVerb); // make sure no existing registration exists, ignore failure + + HRESULT hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s\\DropTarget", + L"CLSID", _szCLSID, pszProgID, pszVerb); + if (SUCCEEDED(hr)) + { + hr = _EnsureBaseProgIDVerbIsNone(pszProgID); + + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", + L"", pszVerbDisplayName, pszProgID, pszVerb); + } + return hr; +} + +HRESULT CRegisterExtension::RegisterExecuteCommandVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const +{ + UnRegisterVerb(pszProgID, pszVerb); // make sure no existing registration exists, ignore failure + + HRESULT hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s\\command", + L"DelegateExecute", _szCLSID, pszProgID, pszVerb); + if (SUCCEEDED(hr)) + { + hr = _EnsureBaseProgIDVerbIsNone(pszProgID); + + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", + L"", pszVerbDisplayName, pszProgID, pszVerb); + } + return hr; +} + +// must be an inproc handler registered here + +HRESULT CRegisterExtension::RegisterExplorerCommandVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const +{ + UnRegisterVerb(pszProgID, pszVerb); // make sure no existing registration exists, ignore failure + + HRESULT hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", + L"ExplorerCommandHandler", _szCLSID, pszProgID, pszVerb); + if (SUCCEEDED(hr)) + { + hr = _EnsureBaseProgIDVerbIsNone(pszProgID); + + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", + L"", pszVerbDisplayName, pszProgID, pszVerb); + } + return hr; +} + +HRESULT CRegisterExtension::RegisterExplorerCommandStateHandler(PCWSTR pszProgID, PCWSTR pszVerb) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", + L"CommandStateHandler", _szCLSID, pszProgID, pszVerb); +} + +HRESULT CRegisterExtension::UnRegisterVerb(PCWSTR pszProgID, PCWSTR pszVerb) const +{ + return RegDeleteKeyPrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell\\%s", pszProgID, pszVerb); +} + +HRESULT CRegisterExtension::UnRegisterVerbs(PCWSTR const rgpszAssociation[], UINT countAssociation, PCWSTR pszVerb) const +{ + HRESULT hr = S_OK; + for (UINT i = 0; SUCCEEDED(hr) && (i < countAssociation); i++) + { + hr = UnRegisterVerb(rgpszAssociation[i], pszVerb); + } + + if (SUCCEEDED(hr) && HasClassID()) + { + hr = UnRegisterObject(); + } + return hr; +} + +HRESULT CRegisterExtension::RegisterThumbnailHandler(PCWSTR pszExtension) const +{ + // IThumbnailHandler + // HKEY_CLASSES_ROOT\.wma\ShellEx\{e357fccd-a995-4576-b01f-234630154e96}={9DBD2C50-62AD-11D0-B806-00C04FD706EC} + + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", + L"", _szCLSID, pszExtension); +} + +// in process context menu handler for right drag context menu +// need to create new method that allows out of proc handling of this + +// pszProgID "Folder" or "Directory" +HRESULT CRegisterExtension::RegisterRightDragContextMenuHandler(PCWSTR pszProgID, PCWSTR pszDescription) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shellex\\DragDropHandlers\\%s", + L"", pszDescription, pszProgID, _szCLSID); +} + +// in process context menu handler + +HRESULT CRegisterExtension::RegisterContextMenuHandler(PCWSTR pszProgID, PCWSTR pszDescription) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shellex\\ContextMenuHandlers\\%s", + L"", pszDescription, pszProgID, _szCLSID); +} + +HRESULT CRegisterExtension::RegisterPropertyHandler(PCWSTR pszExtension) const +{ + // IPropertyHandler + // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers\.docx={993BE281-6695-4BA5-8A2A-7AACBFAAB69E} + + return RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\%s", + L"", _szCLSID, pszExtension); +} + +HRESULT CRegisterExtension::UnRegisterPropertyHandler(PCWSTR pszExtension) const +{ + return RegDeleteKeyPrintf(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PropertySystem\\PropertyHandlers\\%s", pszExtension); +} + +// IResolveShellLink handler, used for custom link resolution behavior +HRESULT CRegisterExtension::RegisterLinkHandler(PCWSTR pszProgID) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\ShellEx\\LinkHandler", L"", _szCLSID, pszProgID); +} + +// HKCR\ = +// DefaultIcon= +// =, + +HRESULT CRegisterExtension::RegisterProgID(PCWSTR pszProgID, PCWSTR pszTypeName, UINT idIcon) const +{ + HRESULT hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s", L"", pszTypeName, pszProgID); + if (SUCCEEDED(hr)) + { + if (idIcon) + { + WCHAR szIconRef[MAX_PATH]; + StringCchPrintf(szIconRef, ARRAYSIZE(szIconRef), L"\"%s\",-%d", _szModule, idIcon); + // HKCR\\DefaultIcon + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\DefaultIcon", L"", szIconRef, pszProgID); + } + } + return hr; +} + +HRESULT CRegisterExtension::UnRegisterProgID(PCWSTR pszProgID, PCWSTR pszFileExtension) const +{ + HRESULT hr = RegDeleteKeyPrintf(_hkeyRoot, L"Software\\Classes\\%s", pszProgID); + if (SUCCEEDED(hr) && pszFileExtension) + { + hr = RegDeleteKeyPrintf(_hkeyRoot, L"Software\\Classes\\%s\\%s", pszFileExtension, pszProgID); + } + return hr; +} + +// value names that do not require a value +// HKCR\ +// NoOpen - display the "No Open" dialog for this file to disable double click +// IsShortcut - report SFGAO_LINK for this item type, should have a IShellLink handler +// NeverShowExt - never show the file extension +// AlwaysShowExt - always show the file extension +// NoPreviousVersions - don't display the "Previous Versions" verb for this file type + +HRESULT CRegisterExtension::RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s", pszValueName, L"", pszProgID); +} + +// value names that require a string value +// HKCR\ +// NoOpen - display the "No Open" dialog for this file to disable double click, display this message +// FriendlyTypeName - localized resource +// ConflictPrompt +// FullDetails +// InfoTip +// QuickTip +// PreviewDetails +// PreviewTitle +// TileInfo +// ExtendedTileInfo +// SetDefaultsFor - right click.new will populate the file with these properties, example: "prop:System.Author;System.Document.DateCreated" + +HRESULT CRegisterExtension::RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName, PCWSTR pszValue) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s", pszValueName, pszValue, pszProgID); +} + +// value names that require a DWORD value +// HKCR\ +// EditFlags +// ThumbnailCutoff + +HRESULT CRegisterExtension::RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName, DWORD dwValue) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s", pszValueName, dwValue, pszProgID); +} + +// NeverDefault +// LegacyDisable +// Extended +// OnlyInBrowserWindow +// ProgrammaticAccessOnly +// SeparatorBefore +// SeparatorAfter +// CheckSupportedTypes, used SupportedTypes that is a file type filter registered under AppPaths (I think) +HRESULT CRegisterExtension::RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shell\\%s", pszValueName, L"", pszProgID, pszVerb); +} + +// MUIVerb=@dll,-resid +// MultiSelectModel=Single|Player|Document +// Position=Bottom|Top +// DefaultAppliesTo=System.ItemName:"foo" +// HasLUAShield=System.ItemName:"bar" +// AppliesTo=System.ItemName:"foo" +HRESULT CRegisterExtension::RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName, PCWSTR pszValue) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shell\\%s", pszValueName, pszValue, pszProgID, pszVerb); +} + +// BrowserFlags +// ExplorerFlags +// AttributeMask +// AttributeValue +// ImpliedSelectionModel +// SuppressionPolicy +HRESULT CRegisterExtension::RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName, DWORD dwValue) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\shell\\%s", pszValueName, dwValue, pszProgID, pszVerb); +} + +// "open explorer" is an example +HRESULT CRegisterExtension::RegisterVerbDefaultAndOrder(PCWSTR pszProgID, PCWSTR pszVerbOrderFirstIsDefault) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\Shell", L"", pszVerbOrderFirstIsDefault, pszProgID); +} + +// register a verb on an array of ProgIDs + +HRESULT CRegisterExtension::RegisterPlayerVerbs(PCWSTR const rgpszAssociation[], UINT countAssociation, + PCWSTR pszVerb, PCWSTR pszTitle) const +{ + HRESULT hr = RegisterAppAsLocalServer(pszTitle, NULL); + if (SUCCEEDED(hr)) + { + // enable this handler to work with OpenSearch results, avoiding the downlaod + // and open behavior by indicating that we can accept all URL forms + hr = RegisterHandlerSupportedProtocols(L"*"); + + for (UINT i = 0; SUCCEEDED(hr) && (i < countAssociation); i++) + { + hr = RegisterExecuteCommandVerb(rgpszAssociation[i], pszVerb, pszTitle); + if (SUCCEEDED(hr)) + { + hr = RegisterVerbAttribute(rgpszAssociation[i], pszVerb, L"NeverDefault"); + if (SUCCEEDED(hr)) + { + hr = RegisterVerbAttribute(rgpszAssociation[i], pszVerb, L"MultiSelectModel", L"Player"); + } + } + } + } + return hr; +} + +// this is where the file assocation is being taken over + +HRESULT CRegisterExtension::RegisterExtensionWithProgID(PCWSTR pszFileExtension, PCWSTR pszProgID) const +{ + // HKCR\<.ext>= + // "Content Type" + // "PerceivedType" + + // TODO: to be polite if there is an existing mapping of extension to ProgID make sure it is + // added to the OpenWith list so that users can get back to the old app using OpenWith + // TODO: verify that HKLM/HKCU settings do not already exist as if they do they will + // get in the way of the setting being made here + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s", L"", pszProgID, pszFileExtension); +} + +// adds the ProgID to a file extension assuming that this ProgID will have +// the "open" verb under it that will be used in Open With + +HRESULT CRegisterExtension::RegisterOpenWith(PCWSTR pszFileExtension, PCWSTR pszProgID) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\OpenWithProgIds", pszProgID, L"", pszFileExtension); +} + +HRESULT CRegisterExtension::RegisterNewMenuNullFile(PCWSTR pszFileExtension, PCWSTR pszProgID) const +{ + // there are 2 forms of this + // HKCR\<.ext>\ShellNew + // HKCR\<.ext>\ShellNew\ - only + // ItemName + // NullFile + // Data - REG_BINARY: + // File + // command + // iconpath + + // another way that this works + // HKEY_CLASSES_ROOT\.doc\Word.Document.8\ShellNew + HRESULT hr; + if (pszProgID) + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\%s\\ShellNew", L"NullFile", L"", pszFileExtension, pszProgID); + } + else + { + hr = RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\%s\\ShellNew", L"NullFile", L"", pszFileExtension); + } + return hr; +} + +HRESULT CRegisterExtension::RegisterNewMenuData(PCWSTR pszFileExtension, PCWSTR pszProgID, PCSTR pszBase64) const +{ + HRESULT hr; + if (pszProgID) + { + hr = RegSetKeyValueBinaryPrintf(_hkeyRoot, L"Software\\Classes\\%s\\%s\\ShellNew", L"Data", pszBase64, pszFileExtension, pszProgID); + } + else + { + hr = RegSetKeyValueBinaryPrintf(_hkeyRoot, L"Software\\Classes\\%s\\ShellNew", L"Data", pszBase64, pszFileExtension); + } + return hr; +} + +// define the kind of a file extension. this is a multi-value property, see +// HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\KindMap +HRESULT CRegisterExtension::RegisterKind(PCWSTR pszFileExtension, PCWSTR pszKindValue) const +{ + return RegSetKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", pszFileExtension, pszKindValue); +} + +HRESULT CRegisterExtension::UnRegisterKind(PCWSTR pszFileExtension) const +{ + return RegDeleteKeyValuePrintf(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\KindMap", pszFileExtension); +} + +// when indexing it is possible to override some of the file system property values, that includes the following +// use this registration helper to set the override flag for each +// +// System.ItemNameDisplay +// System.SFGAOFlags +// System.Kind +// System.FileName +// System.ItemPathDisplay +// System.ItemPathDisplayNarrow +// System.ItemFolderNameDisplay +// System.ItemFolderPathDisplay +// System.ItemFolderPathDisplayNarrow + +HRESULT CRegisterExtension::RegisterPropertyHandlerOverride(PCWSTR pszProperty) const +{ + return RegSetKeyValuePrintf(_hkeyRoot, L"Software\\Classes\\CLSID\\%s\\OverrideFileSystemProperties", pszProperty, 1, _szCLSID); +} + +HRESULT CRegisterExtension::RegisterAppShortcutInSendTo() const +{ + WCHAR szPath[MAX_PATH]; + HRESULT hr = GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) ? S_OK : ResultFromKnownLastError(); + if (SUCCEEDED(hr)) + { + // Set the shortcut target + IShellLink *psl; + hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&psl)); + if (SUCCEEDED(hr)) + { + hr = psl->SetPath(szPath); + if (SUCCEEDED(hr)) + { + WCHAR szName[MAX_PATH]; + StringCchCopy(szName, ARRAYSIZE(szName), PathFindFileName(szPath)); + PathRenameExtension(szName, L".lnk"); + + hr = SHGetFolderPath(NULL, CSIDL_SENDTO, NULL, 0, szPath); + if (SUCCEEDED(hr)) + { + hr = PathAppend(szPath, szName) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) + { + IPersistFile *ppf; + hr = psl->QueryInterface(IID_PPV_ARGS(&ppf)); + if (SUCCEEDED(hr)) + { + hr = ppf->Save(szPath, TRUE); + ppf->Release(); + } + } + } + } + psl->Release(); + } + } + return hr; +} + +HRESULT CRegisterExtension::RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, PCWSTR pszValue, ...) const +{ + va_list argList; + va_start(argList, pszValue); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegSetKeyValueW(hkey, szKeyName, pszValueName, REG_SZ, pszValue, + lstrlen(pszValue) * sizeof(*pszValue))); + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return hr; +} + +HRESULT CRegisterExtension::RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, DWORD dwValue, ...) const +{ + va_list argList; + va_start(argList, dwValue); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegSetKeyValueW(hkey, szKeyName, pszValueName, REG_DWORD, &dwValue, sizeof(dwValue))); + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return hr; +} + +HRESULT CRegisterExtension::RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, const unsigned char pc[], DWORD dwSize, ...) const +{ + va_list argList; + va_start(argList, pc); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegSetKeyValueW(hkey, szKeyName, pszValueName, REG_BINARY, pc, dwSize)); + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return hr; +} + +HRESULT CRegisterExtension::RegSetKeyValueBinaryPrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, PCSTR pszBase64, ...) const +{ + va_list argList; + va_start(argList, pszBase64); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + DWORD dwDecodedImageSize, dwSkipChars, dwActualFormat; + hr = CryptStringToBinaryA(pszBase64, NULL, CRYPT_STRING_BASE64, NULL, + &dwDecodedImageSize, &dwSkipChars, &dwActualFormat) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) + { + BYTE *pbDecodedImage = (BYTE*)LocalAlloc(LPTR, dwDecodedImageSize); + hr = pbDecodedImage ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + hr = CryptStringToBinaryA(pszBase64, lstrlenA(pszBase64), CRYPT_STRING_BASE64, + pbDecodedImage, &dwDecodedImageSize, &dwSkipChars, &dwActualFormat) ? S_OK : E_FAIL; + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegSetKeyValueW(hkey, szKeyName, pszValueName, REG_BINARY, pbDecodedImage, dwDecodedImageSize)); + } + } + } + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return hr; +} + +__inline HRESULT MapNotFoundToSuccess(HRESULT hr) +{ + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ? S_OK : hr; +} + +HRESULT CRegisterExtension::RegDeleteKeyPrintf(HKEY hkey, PCWSTR pszKeyFormatString, ...) const +{ + va_list argList; + va_start(argList, pszKeyFormatString); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDeleteTree(hkey, szKeyName)); + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return MapNotFoundToSuccess(hr); +} + +HRESULT CRegisterExtension::RegDeleteKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValue, ...) const +{ + va_list argList; + va_start(argList, pszKeyFormatString); + + WCHAR szKeyName[512]; + HRESULT hr = StringCchVPrintf(szKeyName, ARRAYSIZE(szKeyName), pszKeyFormatString, argList); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDeleteKeyValueW(hkey, szKeyName, pszValue)); + } + + va_end(argList); + + _UpdateAssocChanged(hr, pszKeyFormatString); + return MapNotFoundToSuccess(hr); +} + +void CRegisterExtension::_UpdateAssocChanged(HRESULT hr, PCWSTR pszKeyFormatString) const +{ + static const WCHAR c_szProgIDPrefix[] = L"Software\\Classes\\%s"; + if (SUCCEEDED(hr) && !_fAssocChanged && + (StrCmpNIC(pszKeyFormatString, c_szProgIDPrefix, ARRAYSIZE(c_szProgIDPrefix) - 1) == 0 || + StrStrI(pszKeyFormatString, L"PropertyHandlers") || + StrStrI(pszKeyFormatString, L"KindMap"))) + { + const_cast(this)->_fAssocChanged = true; + } +} diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.h b/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.h new file mode 100644 index 0000000..bcdd422 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/RegisterExtension.h @@ -0,0 +1,117 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +#pragma once + +#include + +// production code should use an installer technology like MSI to register its handlers +// rather than this class. +// this class is used for demontration purpouses, it encapsulate the different types +// of handler registrations, schematizes those by provding methods that have parameters +// that map to the supported extension schema and makes it easy to create self registering +// .exe and .dlls + +class CRegisterExtension +{ +public: + CRegisterExtension(REFCLSID clsid = CLSID_NULL, HKEY hkeyRoot = HKEY_CURRENT_USER); + ~CRegisterExtension(); + void SetHandlerCLSID(REFCLSID clsid); + void SetInstallScope(HKEY hkeyRoot); + HRESULT SetModule(PCWSTR pszModule); + HRESULT SetModule(HINSTANCE hinst); + + HRESULT RegisterInProcServer(PCWSTR pszFriendlyName, PCWSTR pszThreadingModel) const; + HRESULT RegisterInProcServerAttribute(PCWSTR pszAttribute, DWORD dwValue) const; + + // register the COM local server for the current running module + // this is for self registering applications + HRESULT RegisterAppAsLocalServer(PCWSTR pszFriendlyName, PCWSTR pszCmdLine = NULL) const; + HRESULT RegisterElevatableLocalServer(PCWSTR pszFriendlyName, UINT idLocalizeString, UINT idIconRef) const; + HRESULT RegisterElevatableInProcServer(PCWSTR pszFriendlyName, UINT idLocalizeString, UINT idIconRef) const; + + // remove a COM object registration + HRESULT UnRegisterObject() const; + + // this enables drag drop directly onto the .exe, useful if you have a + // shortcut to the exe somewhere (or the .exe is accessable via the send to menu) + + HRESULT RegisterAppDropTarget() const; + + // create registry entries for drop target based static verb. + // the specified clsid will be + + HRESULT RegisterCreateProcessVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszCmdLine, PCWSTR pszVerbDisplayName) const; + HRESULT RegisterDropTargetVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const; + HRESULT RegisterExecuteCommandVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const; + HRESULT RegisterExplorerCommandVerb(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszVerbDisplayName) const; + HRESULT RegisterExplorerCommandStateHandler(PCWSTR pszProgID, PCWSTR pszVerb) const; + HRESULT RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName) const; + HRESULT RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName, PCWSTR pszValue) const; + HRESULT RegisterVerbAttribute(PCWSTR pszProgID, PCWSTR pszVerb, PCWSTR pszValueName, DWORD dwValue) const; + HRESULT RegisterVerbDefaultAndOrder(PCWSTR pszProgID, PCWSTR pszVerbOrderFirstIsDefault) const; + + HRESULT RegisterPlayerVerbs(PCWSTR const rgpszAssociation[], UINT countAssociation, + PCWSTR pszVerb, PCWSTR pszTitle) const; + + HRESULT UnRegisterVerb(PCWSTR pszProgID, PCWSTR pszVerb) const; + HRESULT UnRegisterVerbs(PCWSTR const rgpszAssociation[], UINT countAssociation, PCWSTR pszVerb) const; + + HRESULT RegisterContextMenuHandler(PCWSTR pszProgID, PCWSTR pszDescription) const; + HRESULT RegisterRightDragContextMenuHandler(PCWSTR pszProgID, PCWSTR pszDescription) const; + + HRESULT RegisterAppShortcutInSendTo() const; + + HRESULT RegisterThumbnailHandler(PCWSTR pszExtension) const; + HRESULT RegisterPropertyHandler(PCWSTR pszExtension) const; + HRESULT UnRegisterPropertyHandler(PCWSTR pszExtension) const; + + HRESULT RegisterLinkHandler(PCWSTR pszProgID) const; + + HRESULT RegisterProgID(PCWSTR pszProgID, PCWSTR pszTypeName, UINT idIcon) const; + HRESULT UnRegisterProgID(PCWSTR pszProgID, PCWSTR pszFileExtension) const; + HRESULT RegisterExtensionWithProgID(PCWSTR pszFileExtension, PCWSTR pszProgID) const; + HRESULT RegisterOpenWith(PCWSTR pszFileExtension, PCWSTR pszProgID) const; + HRESULT RegisterNewMenuNullFile(PCWSTR pszFileExtension, PCWSTR pszProgID) const; + HRESULT RegisterNewMenuData(PCWSTR pszFileExtension, PCWSTR pszProgID, PCSTR pszBase64) const; + HRESULT RegisterKind(PCWSTR pszFileExtension, PCWSTR pszKindValue) const; + HRESULT UnRegisterKind(PCWSTR pszFileExtension) const; + HRESULT RegisterPropertyHandlerOverride(PCWSTR pszProperty) const; + + HRESULT RegisterHandlerSupportedProtocols(PCWSTR pszProtocol) const; + + HRESULT RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName) const; + HRESULT RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName, PCWSTR pszValue) const; + HRESULT RegisterProgIDValue(PCWSTR pszProgID, PCWSTR pszValueName, DWORD dwValue) const; + + // this should probably be private but they are useful + HRESULT RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, PCWSTR pszValue, ...) const; + HRESULT RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, DWORD dwValue, ...) const; + HRESULT RegSetKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, const unsigned char pc[], DWORD dwSize, ...) const; + HRESULT RegSetKeyValueBinaryPrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValueName, PCSTR pszBase64, ...) const; + + HRESULT RegDeleteKeyPrintf(HKEY hkey, PCWSTR pszKeyFormatString, ...) const; + HRESULT RegDeleteKeyValuePrintf(HKEY hkey, PCWSTR pszKeyFormatString, PCWSTR pszValue, ...) const; + + PCWSTR GetCLSIDString() const { return _szCLSID; }; + + bool HasClassID() const { return _clsid != CLSID_NULL ? true : false; }; + +private: + + HRESULT _EnsureModule() const; + bool _IsBaseClassProgID(PCWSTR pszProgID) const; + HRESULT _EnsureBaseProgIDVerbIsNone(PCWSTR pszProgID) const; + void _UpdateAssocChanged(HRESULT hr, PCWSTR pszKeyFormatString) const; + + CLSID _clsid; + HKEY _hkeyRoot; + WCHAR _szCLSID[39]; + WCHAR _szModule[MAX_PATH]; + bool _fAssocChanged; +}; diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/ShellHelpers.h b/Docs-ContextMenuSample/ExplorerCommandVerb/ShellHelpers.h new file mode 100644 index 0000000..d8826e7 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/ShellHelpers.h @@ -0,0 +1,277 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +#pragma once + +#define STRICT_TYPED_ITEMIDS // in case you do IDList stuff you want this on for better type saftey +#define UNICODE 1 + +#include +#include // for WM_COMMAND handling macros +#include // shell stuff +#include // QISearch, easy way to implement QI +#include +#include +#include +#include + +#pragma comment(lib, "shlwapi.lib") // link to this +#pragma comment(lib, "comctl32.lib") // link to this +#pragma comment(lib, "propsys.lib") // link to this + +// set up common controls v6 the easy way +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +__inline HRESULT ResultFromKnownLastError() { const DWORD err = GetLastError(); return err == ERROR_SUCCESS ? E_FAIL : HRESULT_FROM_WIN32(err); } + +// map Win32 APIs that follow the return BOOL/set last error protocol +// into HRESULT +// +// example: MoveFileEx() + +__inline HRESULT ResultFromWin32Bool(BOOL b) +{ + return b ? S_OK : ResultFromKnownLastError(); +} + +#if (NTDDI_VERSION >= NTDDI_VISTA) + +__inline HRESULT ShellExecuteItem(HWND hwnd, PCWSTR pszVerb, IShellItem *psi) +{ + // how to activate a shell item, use ShellExecute(). + PIDLIST_ABSOLUTE pidl; + HRESULT hr = SHGetIDListFromObject(psi, &pidl); + if (SUCCEEDED(hr)) + { + SHELLEXECUTEINFO ei = { sizeof(ei) }; + ei.fMask = SEE_MASK_INVOKEIDLIST; + ei.hwnd = hwnd; + ei.nShow = SW_NORMAL; + ei.lpIDList = pidl; + ei.lpVerb = pszVerb; + + hr = ResultFromWin32Bool(ShellExecuteEx(&ei)); + + CoTaskMemFree(pidl); + } + return hr; +} + +__inline HRESULT GetItemFromView(IFolderView2 *pfv, int iItem, REFIID riid, void **ppv) +{ + *ppv = NULL; + + HRESULT hr = S_OK; + + if (iItem == -1) + { + hr = pfv->GetSelectedItem(-1, &iItem); // Returns S_FALSE if none selected + } + + if (S_OK == hr) + { + hr = pfv->GetItem(iItem, riid, ppv); + } + else + { + hr = E_FAIL; + } + return hr; +} + +// set the icon for your window using WM_SETICON from one of the set of stock system icons +// caller must call ClearDialogIcon() to free the HICON that is created +__inline void SetDialogIcon(HWND hdlg, SHSTOCKICONID siid) +{ + SHSTOCKICONINFO sii = {sizeof(sii)}; + if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_SMALLICON, &sii))) + { + SendMessage(hdlg, WM_SETICON, ICON_SMALL, (LPARAM) sii.hIcon); + } + if (SUCCEEDED(SHGetStockIconInfo(siid, SHGFI_ICON | SHGFI_LARGEICON, &sii))) + { + SendMessage(hdlg, WM_SETICON, ICON_BIG, (LPARAM) sii.hIcon); + } +} +#endif + +// free the HICON that was set using SetDialogIcon() +__inline void ClearDialogIcon(HWND hdlg) +{ + DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_SMALL, 0)); + DestroyIcon((HICON)SendMessage(hdlg, WM_GETICON, ICON_BIG, 0)); +} + +__inline HRESULT SetItemImageImageInStaticControl(HWND hwndStatic, IShellItem *psi) +{ + HBITMAP hbmp = NULL; + HRESULT hr = S_OK; + if (psi) + { + IShellItemImageFactory *psiif; + hr = psi->QueryInterface(IID_PPV_ARGS(&psiif)); + if (SUCCEEDED(hr)) + { + RECT rc; + GetWindowRect(hwndStatic, &rc); + const UINT dxdy = min(rc.right - rc.left, rc.bottom - rc.top); // make it square + const SIZE size = { dxdy, dxdy }; + + hr = psiif->GetImage(size, SIIGBF_RESIZETOFIT, &hbmp); + psiif->Release(); + } + } + + if (SUCCEEDED(hr)) + { + HGDIOBJ hgdiOld = (HGDIOBJ) SendMessage(hwndStatic, STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) hbmp); + if (hgdiOld) + { + DeleteObject(hgdiOld); // if there was an old one clean it up + } + } + + return hr; +} + + +__inline HRESULT SHILCloneFull(PCUIDLIST_ABSOLUTE pidl, PIDLIST_ABSOLUTE *ppidl) +{ + *ppidl = ILCloneFull(pidl); + return *ppidl ? S_OK : E_OUTOFMEMORY; +} + +__inline HRESULT SHILClone(PCUIDLIST_RELATIVE pidl, PIDLIST_RELATIVE *ppidl) +{ + *ppidl = ILClone(pidl); + return *ppidl ? S_OK : E_OUTOFMEMORY; +} + +__inline HRESULT SHILCombine(PCIDLIST_ABSOLUTE pidl1, PCUIDLIST_RELATIVE pidl2, PIDLIST_ABSOLUTE *ppidl) +{ + *ppidl = ILCombine(pidl1, pidl2); + return *ppidl ? S_OK : E_OUTOFMEMORY; +} + +__inline HRESULT GetItemAt(IShellItemArray *psia, DWORD i, REFIID riid, void **ppv) +{ + *ppv = NULL; + IShellItem *psi = NULL; // avoid error C4701 + HRESULT hr = psia ? psia->GetItemAt(i, &psi) : E_NOINTERFACE; + if (SUCCEEDED(hr)) + { + hr = psi->QueryInterface(riid, ppv); + psi->Release(); + } + return hr; +} + +#define MAP_ENTRY(x) {L#x, x} + +__inline HRESULT ShellAttributesToString(SFGAOF sfgaof, PWSTR *ppsz) +{ + *ppsz = NULL; + + static const struct { PCWSTR pszName; SFGAOF sfgaof; } c_rgItemAttributes[] = + { + // note, SFGAO_HASSUBFOLDER is too expesnive to compute + // and has been excluded from this list + MAP_ENTRY(SFGAO_STREAM), + MAP_ENTRY(SFGAO_FOLDER), + MAP_ENTRY(SFGAO_FILESYSTEM), + MAP_ENTRY(SFGAO_FILESYSANCESTOR), + MAP_ENTRY(SFGAO_STORAGE), + MAP_ENTRY(SFGAO_STORAGEANCESTOR), + MAP_ENTRY(SFGAO_LINK), + MAP_ENTRY(SFGAO_CANCOPY), + MAP_ENTRY(SFGAO_CANMOVE), + MAP_ENTRY(SFGAO_CANLINK), + MAP_ENTRY(SFGAO_CANRENAME), + MAP_ENTRY(SFGAO_CANDELETE), + MAP_ENTRY(SFGAO_HASPROPSHEET), + MAP_ENTRY(SFGAO_DROPTARGET), + MAP_ENTRY(SFGAO_ENCRYPTED), + MAP_ENTRY(SFGAO_ISSLOW), + MAP_ENTRY(SFGAO_GHOSTED), + MAP_ENTRY(SFGAO_SHARE), + MAP_ENTRY(SFGAO_READONLY), + MAP_ENTRY(SFGAO_HIDDEN), + MAP_ENTRY(SFGAO_REMOVABLE), + MAP_ENTRY(SFGAO_COMPRESSED), + MAP_ENTRY(SFGAO_BROWSABLE), + MAP_ENTRY(SFGAO_NONENUMERATED), + MAP_ENTRY(SFGAO_NEWCONTENT), + }; + + WCHAR sz[512] = {}; + PWSTR psz = sz; + size_t cch = ARRAYSIZE(sz); + + StringCchPrintfEx(psz, cch, &psz, &cch, 0, L"0x%08X", sfgaof); + + for (int i = 0; i < ARRAYSIZE(c_rgItemAttributes); i++) + { + if (c_rgItemAttributes[i].sfgaof & sfgaof) + { + StringCchPrintfEx(psz, cch, &psz, &cch, 0, L", %s", c_rgItemAttributes[i].pszName); + } + } + return SHStrDup(sz, ppsz); +} + +template void SafeRelease(T **ppT) +{ + if (*ppT) + { + (*ppT)->Release(); + *ppT = NULL; + } +} + +// assign an interface pointer, release old, capture ref to new, can be used to set to zero too + +template HRESULT SetInterface(T **ppT, IUnknown *punk) +{ + SafeRelease(ppT); + return punk ? punk->QueryInterface(ppT) : E_NOINTERFACE; +} + +// remote COM methods are dispatched in the context of an exception handler that consumes +// all SEH exceptions including crahses and C++ exceptions. this is undesirable as it +// means programs will continue to run after such an exception has been thrown, +// leaving the process in a inconsistent state. +// +// this applies to COM methods like IDropTarget::Drop() +// +// this code turns off that behavior + +__inline void DisableComExceptionHandling() +{ + IGlobalOptions *pGlobalOptions; + HRESULT hr = CoCreateInstance(CLSID_GlobalOptions, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGlobalOptions)); + if (SUCCEEDED(hr)) + { +#if (NTDDI_VERSION >= NTDDI_WIN7) + hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE_ANY); +#else + hr = pGlobalOptions->Set(COMGLB_EXCEPTION_HANDLING, COMGLB_EXCEPTION_DONOT_HANDLE); +#endif + pGlobalOptions->Release(); + } +} + +__inline void GetWindowRectInClient(HWND hwnd, RECT *prc) +{ + GetWindowRect(hwnd, prc); + MapWindowPoints(GetDesktopWindow(), GetParent(hwnd), (POINT*)prc, 2); +} + +// retrieve the HINSTANCE for the current DLL or EXE using this symbol that +// the linker provides for every module, avoids the need for a global HINSTANCE variable +// and provides access to this value for static libraries +EXTERN_C IMAGE_DOS_HEADER __ImageBase; +__inline HINSTANCE GetModuleHINSTANCE() { return (HINSTANCE)&__ImageBase; } diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/dll.cpp b/Docs-ContextMenuSample/ExplorerCommandVerb/dll.cpp new file mode 100644 index 0000000..1e318af --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/dll.cpp @@ -0,0 +1,166 @@ +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved + +#include "dll.h" + + +typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject); +struct CLASS_OBJECT_INIT +{ + const CLSID *pClsid; + PFNCREATEINSTANCE pfnCreate; +}; + +// add classes supported by this module here +const CLASS_OBJECT_INIT c_rgClassObjectInit[] = +{ + { &__uuidof(CExplorerCommandVerb), CExplorerCommandVerb_CreateInstance }, + { &__uuidof(CExplorerCommandStateHandler), CExplorerCommandStateHandler_CreateInstance }, +}; + + +long g_cRefModule = 0; + +// Handle the the DLL's module +HINSTANCE g_hInst = NULL; + +// Standard DLL functions +STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + g_hInst = hInstance; + DisableThreadLibraryCalls(hInstance); + } + return TRUE; +} + +STDAPI DllCanUnloadNow() +{ + // Only allow the DLL to be unloaded after all outstanding references have been released + return (g_cRefModule == 0) ? S_OK : S_FALSE; +} + +void DllAddRef() +{ + InterlockedIncrement(&g_cRefModule); +} + +void DllRelease() +{ + InterlockedDecrement(&g_cRefModule); +} + +class CClassFactory : public IClassFactory +{ +public: + static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv) + { + *ppv = NULL; + HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; + for (size_t i = 0; i < cClassObjectInits; i++) + { + if (clsid == *pClassObjectInits[i].pClsid) + { + IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate); + hr = pClassFactory ? S_OK : E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + hr = pClassFactory->QueryInterface(riid, ppv); + pClassFactory->Release(); + } + break; // match found + } + } + return hr; + } + + CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate) + { + DllAddRef(); + } + + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv) + { + static const QITAB qit[] = + { + QITABENT(CClassFactory, IClassFactory), + { 0 } + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long cRef = InterlockedDecrement(&_cRef); + if (cRef == 0) + { + delete this; + } + return cRef; + } + + // IClassFactory + IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv) + { + return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv); + } + + IFACEMETHODIMP LockServer(BOOL fLock) + { + if (fLock) + { + DllAddRef(); + } + else + { + DllRelease(); + } + return S_OK; + } + +private: + ~CClassFactory() + { + DllRelease(); + } + + long _cRef; + PFNCREATEINSTANCE _pfnCreate; +}; + + +STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv) +{ + return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv); +} + +HRESULT RegisterUnregister(bool fRegister) +{ + HRESULT hr = CExplorerCommandStateHandler_RegisterUnRegister(fRegister); + if (SUCCEEDED(hr)) + { + hr = CExplorerCommandVerb_RegisterUnRegister(fRegister); + } + return hr; +} + +STDAPI DllRegisterServer() +{ + return RegisterUnregister(true); +} + +STDAPI DllUnregisterServer() +{ + return RegisterUnregister(false); +} diff --git a/Docs-ContextMenuSample/ExplorerCommandVerb/readme.txt b/Docs-ContextMenuSample/ExplorerCommandVerb/readme.txt new file mode 100644 index 0000000..cba07b3 --- /dev/null +++ b/Docs-ContextMenuSample/ExplorerCommandVerb/readme.txt @@ -0,0 +1,41 @@ +Explorer Command Verb Sample +================================ +Demonstrates how implement a shell verb using the ExplorerCommand and ExplorerCommandState methods. + + +Sample Language Implementations +=============================== +C++ + +Files: +============================================= +dll.cpp +dll.def +dll.h +ExplorerCommandStateHandler.cpp +ExplorerCommandVerb.cpp +ExplorerCommandVerb.sln +ExplorerCommandVerb.vcproj +RegisterExtension.cpp +RegisterExtension.h +ShellHelpers.h + + +To build the sample using the command prompt: +============================================= + 1. Open the Command Prompt window and navigate to the ExplorerCommandVerb directory. + 2. Type msbuild ExplorerCommandVerb.sln. + + +To build the sample using Visual Studio (preferred method): +=========================================================== + 1. Open Windows Explorer and navigate to the ExplorerCommandVerb directory. + 2. Double-click the icon for the ExplorerCommandVerb.sln file to open the file in Visual Studio. + 3. In the Build menu, select Build Solution. The application will be built in the default \Debug or \Release directory. + + +To run the sample: +================= + 1. Navigate to the directory that contains ExplorerCommandVerb.dll using the command prompt. Make sure you use 64-bit dll on 64-bit Windows. + 2. Type regsvr32 ExplorerCommandVerb.dll. + 3. Two new verbs will be shown on the context menu when you right-click a .txt file.