├── .config
└── tsaoptions.json
├── .gitattributes
├── .gitignore
├── .nuget
└── packages.config
├── .vscode
└── settings.json
├── .vsconfig
├── .vsts-ci.yml
├── .vsts-compliance.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── SECURITY.md
├── azure-pipelines.yml
├── docker
├── Debug.dockerfile
├── Dockerfile
├── Instances
│ ├── 1
│ │ └── state.json
│ ├── 2
│ │ └── state.json
│ ├── 3
│ │ └── state.json
│ ├── 4
│ │ └── state.json
│ └── 5
│ │ └── state.json
├── Tests
│ ├── .gitignore
│ ├── find.tests.ps1
│ ├── legacy.tests.ps1
│ └── vswhere.tests.ps1
├── docker-compose.debug.yml
└── docker-compose.yml
├── inc
├── Common.Debug.props
├── Common.props
├── References.props
└── VersionInfo.props
├── pipelines
└── templates
│ ├── 1es-publish-task.yml
│ ├── ado-publish-task.yml
│ └── build.yml
├── pkg
└── vswhere
│ ├── .gitignore
│ ├── build
│ └── vswhere.props
│ ├── tools
│ └── VERIFICATION.txt
│ ├── vswhere.nuspec
│ └── vswhere.signproj
├── src
├── vswhere.lib
│ ├── CoInitializer.h
│ ├── CommandArgs.cpp
│ ├── CommandArgs.h
│ ├── CommandParser.cpp
│ ├── CommandParser.h
│ ├── Console.cpp
│ ├── Console.h
│ ├── Exceptions.cpp
│ ├── Exceptions.h
│ ├── Formatter.cpp
│ ├── Formatter.h
│ ├── Glob.cpp
│ ├── Glob.h
│ ├── ILegacyProvider.h
│ ├── InstanceSelector.cpp
│ ├── InstanceSelector.h
│ ├── JsonFormatter.cpp
│ ├── JsonFormatter.h
│ ├── JsonScope.cpp
│ ├── JsonScope.h
│ ├── LegacyInstance.cpp
│ ├── LegacyInstance.h
│ ├── LegacyProvider.cpp
│ ├── LegacyProvider.h
│ ├── Module.cpp
│ ├── Module.h
│ ├── ResourceManager.cpp
│ ├── ResourceManager.h
│ ├── SafeArray.h
│ ├── Scope.h
│ ├── TextFormatter.cpp
│ ├── TextFormatter.h
│ ├── Utilities.cpp
│ ├── Utilities.h
│ ├── ValueFormatter.cpp
│ ├── ValueFormatter.h
│ ├── VersionRange.cpp
│ ├── VersionRange.h
│ ├── XmlFormatter.cpp
│ ├── XmlFormatter.h
│ ├── XmlScope.cpp
│ ├── XmlScope.h
│ ├── packages.config
│ ├── resource.h
│ ├── stdafx.cpp
│ ├── stdafx.h
│ ├── targetver.h
│ ├── vswhere.lib.rc
│ ├── vswhere.lib.vcxproj
│ └── vswhere.lib.vcxproj.filters
└── vswhere
│ ├── Program.cpp
│ ├── packages.config
│ ├── resource.h
│ ├── stdafx.cpp
│ ├── stdafx.h
│ ├── targetver.h
│ ├── vswhere.exe.manifest
│ ├── vswhere.vcxproj
│ └── vswhere.vcxproj.filters
├── test
└── vswhere.test
│ ├── CommandArgsTests.cpp
│ ├── ExceptionsTests.cpp
│ ├── GlobTests.cpp
│ ├── InstanceSelectorTests.cpp
│ ├── JsonFormatterTests.cpp
│ ├── ModuleTests.cpp
│ ├── TestConsole.cpp
│ ├── TestConsole.h
│ ├── TestEnumInstances.h
│ ├── TestHelper.cpp
│ ├── TestHelper.h
│ ├── TestInstance.h
│ ├── TestLegacyProvider.cpp
│ ├── TestLegacyProvider.h
│ ├── TestModule.cpp
│ ├── TestModule.h
│ ├── TestPackageReference.h
│ ├── TestPropertyStore.h
│ ├── TextFormatterTests.cpp
│ ├── UtilitiesTests.cpp
│ ├── ValueFormatterTests.cpp
│ ├── VersionRangeTests.cpp
│ ├── XmlFormatterTests.cpp
│ ├── packages.config
│ ├── resource.h
│ ├── stdafx.cpp
│ ├── stdafx.h
│ ├── targetver.h
│ ├── vswhere.test.vcxproj
│ └── vswhere.test.vcxproj.filters
├── tools
├── test.cmd
└── test.ps1
├── version.json
└── vswhere.sln
/.config/tsaoptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "codebaseName": "VSWhere",
3 | "instanceUrl": "https://devdiv.visualstudio.com/defaultcollection",
4 | "projectName": "DevDiv",
5 | "areaPath": "DevDiv\\VS Setup",
6 | "iterationPath": "DevDiv",
7 | "allTools": true
8 | }
9 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/.nuget/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.insertSpaces": true,
3 | "editor.tabSize": 4,
4 | "files.associations": {
5 | "functional": "cpp",
6 | "string": "cpp",
7 | "unordered_map": "cpp"
8 | }
9 | }
--------------------------------------------------------------------------------
/.vsconfig:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0",
3 | "components": [
4 | "Microsoft.VisualStudio.Component.CoreEditor",
5 | "Microsoft.VisualStudio.Component.NuGet",
6 | "Microsoft.Component.MSBuild",
7 | "Microsoft.VisualStudio.Component.TextTemplating",
8 | "Microsoft.VisualStudio.Component.VC.CoreIde",
9 | "Microsoft.Component.VC.Runtime.UCRTSDK",
10 | "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
11 | "Microsoft.VisualStudio.Component.Graphics.Tools",
12 | "Microsoft.VisualStudio.Component.VC.DiagnosticTools",
13 | "Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
14 | "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
15 | "Microsoft.VisualStudio.Component.Windows10SDK.19041",
16 | "Microsoft.VisualStudio.Component.VC.v141.x86.x64",
17 | "Microsoft.VisualStudio.Workload.NativeDesktop",
18 | "Microsoft.VisualStudio.Component.Git",
19 | "Microsoft.VisualStudio.Component.WinXP"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/.vsts-ci.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | trigger:
5 | batch: true
6 | branches:
7 | include:
8 | - main
9 | paths:
10 | exclude:
11 | - README.md
12 | tags:
13 | include:
14 | - "*"
15 |
16 | pr: none
17 |
18 | resources:
19 | repositories:
20 | - repository: MicroBuildTemplate
21 | type: git
22 | name: 1ESPipelineTemplates/MicroBuildTemplate
23 | ref: refs/tags/release
24 |
25 | extends:
26 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
27 | parameters:
28 | pool:
29 | name: VSEngSS-MicroBuild2022-1ES
30 | sdl:
31 | sourceAnalysisPool:
32 | name: AzurePipelines-EO
33 | image: 1ESPT-Windows2022
34 | policheck:
35 | enabled: true
36 | binskim:
37 | enabled: true
38 | scanOutputDirectoryOnly: true # BinSkim scans whole source tree but we only need to scan the output dir.
39 | analyzeTargetGlob: +:f|$(Build.ArtifactStagingDirectory)\out\**;-:f|$(Build.ArtifactStagingDirectory)\out\**\*.test.*
40 | tsa:
41 | enabled: true
42 | configFile: $(Build.SourcesDirectory)\.config\tsaoptions.json
43 | onboard: false
44 |
45 | stages:
46 | - stage: Build
47 | jobs:
48 | - job: Build
49 | templateContext:
50 | mb:
51 | signing:
52 | enabled: true
53 | signType: $(SignType)
54 |
55 | steps:
56 | - template: /pipelines/templates/build.yml@self
57 | parameters:
58 | BuildConfiguration: $(BuildConfiguration)
59 | BuildPlatform: $(BuildPlatform)
60 | Sign: true
61 | PublishArtifactTemplate: /pipelines/templates/1es-publish-task.yml@self
--------------------------------------------------------------------------------
/.vsts-compliance.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | trigger:
5 | batch: true
6 | branches:
7 | include:
8 | - main
9 | paths:
10 | exclude:
11 | - README.md
12 |
13 | schedules:
14 | - cron: "0 18 * * Mon"
15 | displayName: Monday 11am PDT (6pm UTC) build
16 | branches:
17 | include:
18 | - main
19 | always: true
20 |
21 | pr: none
22 |
23 | variables:
24 | - group: vssetup-apiscan
25 |
26 | resources:
27 | repositories:
28 | - repository: MicroBuildTemplate
29 | type: git
30 | name: 1ESPipelineTemplates/MicroBuildTemplate
31 | ref: refs/tags/release
32 |
33 | extends:
34 | template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate
35 | parameters:
36 | pool:
37 | name: VSEngSS-MicroBuild2022-1ES
38 | sdl:
39 | sourceAnalysisPool:
40 | name: AzurePipelines-EO
41 | image: 1ESPT-Windows2022
42 | antimalwareScan:
43 | enabled: true
44 | armory:
45 | enabled: true
46 | binskim:
47 | enabled: true
48 | scanOutputDirectoryOnly: true
49 | analyzeTargetGlob: +:f|$(Build.ArtifactStagingDirectory)\out\**;-:f|$(Build.ArtifactStagingDirectory)\out\**\*.test.*
50 | codeql:
51 | compiled:
52 | enabled: true
53 | credscan:
54 | enabled: true
55 | policheck:
56 | enabled: true
57 | psscriptanalyzer:
58 | enabled: true
59 | prefast:
60 | enabled: true
61 | tsa:
62 | enabled: true
63 | configFile: $(Build.SourcesDirectory)\.config\tsaoptions.json
64 | onboard: false
65 |
66 | stages:
67 | - stage: Compliance
68 | jobs:
69 | - job: Compliance
70 | steps:
71 | - template: /pipelines/templates/build.yml@self
72 | parameters:
73 | BuildConfiguration: $(BuildConfiguration)
74 | BuildPlatform: $(BuildPlatform)
75 | Sign: false
76 | PublishArtifactTemplate: /pipelines/templates/1es-publish-task.yml@self
77 |
78 | - task: CopyFiles@2
79 | displayName: Copy files for API scan
80 | inputs:
81 | SourceFolder: $(Build.SourcesDirectory)\bin\$(BuildConfiguration)
82 | Contents: |
83 | **\*.?(exe|dll|pdb|xml)
84 | !**\*.test.?(exe|dll|pdb|xml)
85 | TargetFolder: $(Build.StagingDirectory)\apiscan-inputs
86 |
87 | - task: APIScan@2
88 | displayName: Run APIScan
89 | inputs:
90 | softwareFolder: $(Build.StagingDirectory)\apiscan-inputs
91 | softwareName: 'Microsoft.VSWhere'
92 | softwareVersionNum: '3'
93 | toolVersion: Latest
94 | env:
95 | AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId)
96 |
97 | - task: PublishSecurityAnalysisLogs@3
98 | displayName: Publish 'SDLAnalysis-APIScan' artifact
99 | condition: succeededOrFailed()
100 | inputs:
101 | ArtifactName: SDLAnalysis-APIScan
102 | AllTools: false
103 | APIScan: true
104 |
105 | - task: PostAnalysis@2
106 | displayName: Post Analysis
107 | inputs:
108 | GdnBreakAllTools: false
109 | GdnBreakGdnToolApiScan: true
110 |
111 | - task: TSAUpload@2
112 | displayName: Upload APIScan results to TSA
113 | inputs:
114 | GdnPublishTsaOnboard: false
115 | GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\.config\tsaoptions.json'
116 | GdnPublishTsaExportedResultsPublishable: true
117 | continueOnError: true
118 | condition: succeededOrFailed()
119 | enabled: true
120 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Code of Conduct
2 | ===============
3 |
4 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | ## Prerequisites
5 |
6 | This project uses the following software. Newer versions may work but backward compatibility must be maintained.
7 |
8 | * [Visual Studio 2017](https://www.visualstudio.com/downloads/) or newer
9 |
10 | ## Coding
11 |
12 | This project uses a GitHub flow model with development and releases based on the `main` branch. You can view current build status in the [README](README.md) document.
13 |
14 | Please follow project code styles including,
15 |
16 | * All requires headers are in the precompiled headers, _stdafx.h_.
17 | * Copyright header including proper file name at top of all non-generated source.
18 | * Tabs are 4 spaces.
19 |
20 | In general, any new code should be stylistically indistinguishable from existing code.
21 |
22 | ## Building
23 |
24 | Before you can build this project from the command line with MSBuild or within Visual Studio, you must restore packages.
25 |
26 | * In Visual Studio, make sure Package Restore is enabled.
27 | * On the command line and assuming _nuget.exe_ is in your `PATH`, in the solution directory run: `nuget restore`
28 |
29 | Note again that to build the full solution in Visual Studio some optional software may be required.
30 |
31 | ## Testing
32 |
33 | All available tests are discovered after a complete build in Test Explorer within Visual Studio.
34 |
35 | On the command line, you can run the following commands from the solution directory. Replace `` with whatever version was downloaded.
36 |
37 | ```batch
38 | nuget install xunit.runner.console -outputdirectory packages
39 | packages\xunit.runner.console.\tools\xunit.runner.console test\VSSetup.PowerShell.Test\bin\Debug\Microsoft.VisualStudio.Setup.PowerShell.Test.dll
40 | ```
41 |
42 | If your machine supports it, you can install [Docker for Windows][docker], switch to Windows containers, and test in isolated containers for runtime behavior. You can run functional tests and runtime tests together.
43 |
44 | ```batch
45 | tools\test.cmd
46 | ```
47 |
48 | You can also run tests directly with `docker-compose`:
49 |
50 | ```batch
51 | docker-compose -f docker\docker-compose.yml run test
52 | ```
53 |
54 | ### Debugging
55 |
56 | You can use the following steps to start an environment for exploratory testing or to run and debug tests. The Visual Studio Remote Debugger will launch by default and should be discoverable on your private network.
57 |
58 | 1. Run:
59 | ```batch
60 | docker-compose -f docker\docker-compose.yml -f docker\docker-compose.debug.yml up -d
61 |
62 | REM Start an interactive shell
63 | docker-compose -f docker\docker-compose.yml -f docker\docker-compose.debug.yml exec test powershell.exe
64 | ```
65 | 2. Click *Debug -> Attach to Process*
66 | 3. Change *Transport* to "Remote (no authentication)"
67 | 4. Click *Find*
68 | 5. Click *Select* on the container (host name will be the container name)
69 | 6. Select "powershell" under *Available Processes*
70 | 7. Click *Attach*
71 | 8. Run any commands you like in the interactive shell, or run all tests:
72 | ```powershell
73 | Invoke-Pester C:\Tests -EnableExit
74 | ```
75 | 9. When finished, run:
76 | ```batch
77 | docker-compose -f docker\docker-compose.yml -f docker\docker-compose.debug.yml down
78 | ```
79 |
80 | If you know the host name (by default, the container name) or IP address (depending on your network configuration for the container), you can type it into the *Qualifier* directory along with port 4022, e.g. "172.22.0.1:4022".
81 |
82 | ## Pull Requests
83 |
84 | We welcome pull requests for both bug fixes and new features that solve a common enough problem to benefit the community. Please note the following requirements.
85 |
86 | 1. Code changes for bug fixes and new features are accompanied by new tests or, only if required, modifications to existing tests. Modifying existing tests when not required may introduce regressions.
87 | 2. All tests must pass. We have automated PR builds that will verify any PRs before they can be merged, but you are encouraged to run all tests in your development environment prior to pushing to your remote.
88 |
89 | Thank you for your contributions!
90 |
91 | [docker]: https://www.docker.com/products/overview
92 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (C) Microsoft Corporation. All rights reserved.
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Visual Studio Locator
2 | =====================
3 |
4 | 
5 | [](https://github.com/Microsoft/vswhere/releases/latest)
6 | [](https://github.com/Microsoft/vswhere/releases)
7 | [](https://nuget.org/packages/vswhere)
8 | [](https://chocolatey.org/packages/vswhere)
9 |
10 | Over the years Visual Studio could be discovered using registry keys, but with recent changes to the deployment and extensibility models a new method is needed to discover possibly more than one installed instance. These changes facilitate a smaller, faster default install complimented by on-demand install of other workloads and components.
11 |
12 | _vswhere_ is designed to be a redistributable, single-file executable that can be used in build or deployment scripts to find where Visual Studio - or other products in the Visual Studio family - is located. For example, if you know the relative path to MSBuild, you can find the root of the Visual Studio install and combine the paths to find what you need.
13 |
14 | You can emit different formats for information based on what your scripts can consume, including plain text, JSON, and XML. Pull requests may be accepted for other common formats as well.
15 |
16 | _vswhere_ is included with the installer as of Visual Studio 2017 version 15.2 and later, and can be found at the following location: `%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe`. The binary may be executed from that location as needed, [installed using popular package managers including WinGet](https://github.com/Microsoft/vswhere/wiki/Installing), or the latest version may be [downloaded from the releases page](https://github.com/Microsoft/vswhere/releases).
17 |
18 | ## Example
19 |
20 | If you wanted to find MSBuild - now installed under the Visual Studio 2017 and newer installation root - you could script a command like the following to run the latest version of MSBuild installed. This example uses the new `-find` parameter in our [latest release](https://github.com/Microsoft/vswhere/releases/latest) that searches selected instances for matching file name patterns. You can tailor what instances you select with parameters like `-version` or `-prerelease` to find specific versions you support, optionally including prereleases.
21 |
22 | ```batch
23 | @echo off
24 | setlocal enabledelayedexpansion
25 |
26 | for /f "usebackq tokens=*" %%i in (`vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do (
27 | "%%i" %*
28 | exit /b !errorlevel!
29 | )
30 | ```
31 |
32 | You can find more [examples](https://github.com/Microsoft/vswhere/wiki/Examples) in our wiki.
33 |
34 | ## Feedback
35 |
36 | To file issues or suggestions, please use the [Issues](https://github.com/Microsoft/vswhere/issues) page for this project on GitHub.
37 |
38 | ## License
39 |
40 | This project is licensed under the [MIT license](LICENSE.txt).
41 |
42 | ## Code of Conduct
43 |
44 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
45 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | trigger: none
5 |
6 | pr:
7 | branches:
8 | include:
9 | - main
10 | paths:
11 | exclude:
12 | - README.md
13 |
14 | pool:
15 | vmImage: windows-2022
16 |
17 | variables:
18 | BuildConfiguration: Release
19 | BuildPlatform: x86
20 |
21 | steps:
22 | - template: /pipelines/templates/build.yml@self
23 | parameters:
24 | BuildConfiguration: $(BuildConfiguration)
25 | BuildPlatform: $(BuildPlatform)
26 | Docker: true
27 | PublishArtifactTemplate: /pipelines/templates/ado-publish-task.yml@self
--------------------------------------------------------------------------------
/docker/Debug.dockerfile:
--------------------------------------------------------------------------------
1 | #escape=`
2 |
3 | # Copyright (C) Microsoft Corporation. All rights reserved.
4 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
5 |
6 | # Based on latest image cached by Azure Pipelines: https://docs.microsoft.com/azure/devops/pipelines/agents/hosted#software
7 | FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2022
8 | SHELL ["powershell.exe", "-ExecutionPolicy", "Bypass", "-Command"]
9 |
10 | ENV INSTALLER_VERSION=1.14.190.31519 `
11 | INSTALLER_URI=https://download.visualstudio.microsoft.com/download/pr/100516681/d68d54e233c956ff79799fdf63753c54/Microsoft.VisualStudio.Setup.Configuration.msi `
12 | INSTALLER_HASH=8917aa7b4116e574856d43e8e62862c1d6f25512be54917f2ef95f9cac103810
13 |
14 | # Download and register the query API
15 | RUN $ErrorActionPreference = 'Stop' ; `
16 | $VerbosePreference = 'Continue' ; `
17 | $null = New-Item C:\TEMP -ItemType Directory -ea SilentlyContinue; `
18 | Invoke-WebRequest -Uri $env:INSTALLER_URI -OutFile C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi; `
19 | if ((Get-FileHash -Path C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi -Algorithm SHA256).Hash -ne $env:INSTALLER_HASH) { throw 'Download hash does not match' }; `
20 | Start-Process -Wait -FilePath C:\Windows\System32\msiexec.exe -ArgumentList '/i C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi /qn /l*vx C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.log'
21 |
22 | ENTRYPOINT ["powershell.exe", "-ExecutionPolicy", "Bypass"]
23 | CMD ["-NoExit"]
24 |
25 | # Download and install Remote Debugger
26 | RUN $ErrorActionPreference = 'Stop' ; `
27 | $ProgressPreference = 'SilentlyContinue' ; `
28 | $VerbosePreference = 'Continue' ; `
29 | New-Item -Path C:\Downloads -Type Directory | Out-Null ; `
30 | Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/?LinkId=746570&clcid=0x409' -OutFile C:\Downloads\vs_remotetools.exe ; `
31 | Start-Process -Wait -FilePath C:\Downloads\vs_remotetools.exe -ArgumentList '-q' ; `
32 | Remove-Item -Path C:\Downloads\vs_remotetools.exe
33 |
34 | # Configure Remote Debugger
35 | EXPOSE 3702 4022 4023
36 | RUN $ErrorActionPreference = 'Stop' ; `
37 | $VerbosePreference = 'Continue' ; `
38 | Start-Process -Wait -FilePath 'C:\Program Files\Microsoft Visual Studio 15.0\Common7\IDE\Remote Debugger\x64\msvsmon.exe' -ArgumentList '/prepcomputer', '/private', '/quiet'
39 |
40 | HEALTHCHECK --interval=10s CMD ["powershell.exe", "-ExecutionPolicy", "Bypass", "-Command", "&{ if (Get-Process msvsmon) { exit 0 } else { exit 1 } }"]
41 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | #escape=`
2 |
3 | # Copyright (C) Microsoft Corporation. All rights reserved.
4 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
5 |
6 | # Based on latest image cached by Azure Pipelines: https://docs.microsoft.com/azure/devops/pipelines/agents/hosted#software
7 | FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2022
8 | SHELL ["powershell.exe", "-ExecutionPolicy", "Bypass", "-Command"]
9 |
10 | ENV INSTALLER_VERSION=1.14.190.31519 `
11 | INSTALLER_URI=https://download.visualstudio.microsoft.com/download/pr/100516681/d68d54e233c956ff79799fdf63753c54/Microsoft.VisualStudio.Setup.Configuration.msi `
12 | INSTALLER_HASH=8917aa7b4116e574856d43e8e62862c1d6f25512be54917f2ef95f9cac103810
13 |
14 | # Download and register the query API
15 | RUN $ErrorActionPreference = 'Stop' ; `
16 | $VerbosePreference = 'Continue' ; `
17 | $null = New-Item C:\TEMP -ItemType Directory -ea SilentlyContinue; `
18 | Invoke-WebRequest -Uri $env:INSTALLER_URI -OutFile C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi; `
19 | if ((Get-FileHash -Path C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi -Algorithm SHA256).Hash -ne $env:INSTALLER_HASH) { throw 'Download hash does not match' }; `
20 | Start-Process -Wait -FilePath C:\Windows\System32\msiexec.exe -ArgumentList '/i C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.msi /qn /l*vx C:\TEMP\Microsoft.VisualStudio.Setup.Configuration.log'
21 |
22 | ENTRYPOINT ["powershell.exe", "-ExecutionPolicy", "Bypass"]
23 | CMD ["-NoExit"]
24 |
--------------------------------------------------------------------------------
/docker/Instances/1/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "channelId": "VisualStudio.15.Release/public.d15rel/15.0.26116.0",
3 | "installationName": "VisualStudio/public.d15rel/15.0.26116.0",
4 | "installationVersion": "15.0.26116",
5 | "installationPath": "C:\\VS\\Community",
6 | "installDate": "2017-01-17T03:45:00Z",
7 | "product": {
8 | "id": "Microsoft.VisualStudio.Product.Community",
9 | "version": "15.0.26116.0",
10 | "type": "Product"
11 | },
12 | "localizedResources": [
13 | {
14 | "language": "en-us",
15 | "title": "Visual Studio Community 2017",
16 | "description": "Free, fully-featured IDE for students, open-source and individual developers"
17 | },
18 | {
19 | "language": "de-de",
20 | "title": "Visual Studio Community 2017",
21 | "description": "Kostenlose, voll funktionsfähige IDE für Studenten, Open Source- und einzelne Entwickler."
22 | },
23 | {
24 | "language": "ja-jp",
25 | "title": "Visual Studio Community 2017",
26 | "description": "学生、オープン ソース、および個々の開発者のための無料で完全な機能を備えた IDE"
27 | }
28 | ],
29 | "launchParams": {
30 | "fileName": "Common7\\IDE\\devenv.exe"
31 | },
32 | "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
33 | "properties": {
34 | "nickname": "Community"
35 | },
36 | "selectedPackages": [
37 | {
38 | "id": "Microsoft.VisualStudio.Product.Community",
39 | "version": "15.0.26116.0",
40 | "type": "Product",
41 | "selectedState": "IndividuallySelected"
42 | }
43 | ],
44 | "packages": [
45 | {
46 | "id": "Microsoft.VisualStudio.Workload.ManagedDesktop",
47 | "version": "15.0.26116.0",
48 | "type": "Workload"
49 | },
50 | {
51 | "id": "Microsoft.VisualStudio.Workload.CoreEditor",
52 | "version": "15.0.26116.0",
53 | "type": "Workload"
54 | },
55 | {
56 | "id": "Microsoft.VisualStudio.Branding.Community",
57 | "version": "15.0.26116.0",
58 | "type": "Vsix"
59 | },
60 | {
61 | "id": "Microsoft.VisualStudio.Product.Community",
62 | "version": "15.0.26116.0",
63 | "type": "Product"
64 | }
65 | ]
66 | }
--------------------------------------------------------------------------------
/docker/Instances/2/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "channelId": "VisualStudio.15.Release/public.d15rel/15.0.26117.0",
3 | "installationName": "VisualStudio/public.d15rel/15.0.26117.0",
4 | "installationVersion": "15.0.26117",
5 | "installationPath": "C:\\VS\\Enterprise",
6 | "installDate": "2017-01-18T03:15:00Z",
7 | "product": {
8 | "id": "Microsoft.VisualStudio.Product.Enterprise",
9 | "version": "15.0.26117.0",
10 | "type": "Product"
11 | },
12 | "localizedResources": [
13 | {
14 | "language": "en-us",
15 | "title": "Visual Studio Enterprise 2017",
16 | "description": "Microsoft DevOps solution for productivity and coordination across teams of any size"
17 | },
18 | {
19 | "language": "de-de",
20 | "title": "Visual Studio Enterprise 2017",
21 | "description": "Microsoft DevOps-Lösung für Produktivität und Koordination von Teams beliebiger Größe"
22 | },
23 | {
24 | "language": "ja-jp",
25 | "title": "Visual Studio Enterprise 2017",
26 | "description": "生産性向上と、さまざまな規模のチーム間の調整のための Microsoft DevOps ソリューション"
27 | }
28 | ],
29 | "launchParams": {
30 | "fileName": "Common7\\IDE\\devenv.exe"
31 | },
32 | "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
33 | "properties": {
34 | "nickname": "Enterprise"
35 | },
36 | "selectedPackages": [
37 | {
38 | "id": "Microsoft.VisualStudio.Product.Enterprise",
39 | "version": "15.0.26117.0",
40 | "type": "Product",
41 | "selectedState": "IndividuallySelected"
42 | }
43 | ],
44 | "packages": [
45 | {
46 | "id": "Microsoft.VisualStudio.Workload.ManagedDesktop",
47 | "version": "15.0.26117.0",
48 | "type": "Workload"
49 | },
50 | {
51 | "id": "Microsoft.VisualStudio.Workload.NativeDesktop",
52 | "version": "15.0.26117.0",
53 | "type": "Workload"
54 | },
55 | {
56 | "id": "Microsoft.VisualStudio.Workload.CoreEditor",
57 | "version": "15.0.26117.0",
58 | "type": "Workload"
59 | },
60 | {
61 | "id": "Microsoft.VisualStudio.Branding.Enterprise",
62 | "version": "15.0.26117.0",
63 | "type": "Vsix"
64 | },
65 | {
66 | "id": "Microsoft.VisualStudio.Product.Enterprise",
67 | "version": "15.0.26117.0",
68 | "type": "Product"
69 | }
70 | ],
71 | "errors": {
72 | "errorLogFilePath": "C:\\TEMP\\dd_setup_201601180315_errors.log",
73 | "failedPackages": [
74 | {
75 | "id": "Microsoft.VisualStudio.Workload.Office",
76 | "version": "15.0.26009.0",
77 | "type": "Workload",
78 | "logFilePath": "C:\\TEMP\\dd_setup_201601180315_003_Microsoft.VisualStudio.Workload.Office_errors.log",
79 | "description": "Failed to install Microsoft.VisualStudio.Workload.Office"
80 | }
81 | ],
82 | "skippedPackages": [
83 | {
84 | "id": "Microsoft.VisualStudio.Component.Sharepoint.Tools",
85 | "version": "15.0.260009.0",
86 | "type": "Component"
87 | }
88 | ]
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/docker/Instances/3/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "channelId": "VisualStudio.15.Release/public.d15rel/15.0.26117.0",
3 | "installationName": "VisualStudio/public.d15rel/15.0.26117.0",
4 | "installationVersion": "15.0.26117",
5 | "installationPath": "C:\\VS\\Professional",
6 | "installDate": "2017-01-18T03:30:00Z",
7 | "product": {
8 | "id": "Microsoft.VisualStudio.Product.Professional",
9 | "version": "15.0.26117.0",
10 | "type": "Product"
11 | },
12 | "localizedResources": [
13 | {
14 | "language": "en-us",
15 | "title": "Visual Studio Professional 2017",
16 | "description": "Professional developer tools and services for small teams"
17 | },
18 | {
19 | "language": "de-de",
20 | "title": "Visual Studio Professional 2017",
21 | "description": "Professionelle Entwicklertools und -dienste für kleine Teams"
22 | },
23 | {
24 | "language": "ja-jp",
25 | "title": "Visual Studio Professional 2017",
26 | "description": "小規模なチーム向けのプロフェッショナルな開発者向けツールおよびサービス"
27 | }
28 | ],
29 | "launchParams": {
30 | "fileName": "Common7\\IDE\\devenv.exe"
31 | },
32 | "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
33 | "properties": {
34 | "nickname": "Professional"
35 | },
36 | "selectedPackages": [
37 | {
38 | "id": "Microsoft.VisualStudio.Product.Professional",
39 | "version": "15.0.26117.0",
40 | "type": "Product",
41 | "selectedState": "IndividuallySelected"
42 | }
43 | ],
44 | "packages": [
45 | {
46 | "id": "Microsoft.VisualStudio.Workload.ManagedDesktop",
47 | "version": "15.0.26117.0",
48 | "type": "Workload"
49 | },
50 | {
51 | "id": "Microsoft.VisualStudio.Workload.CoreEditor",
52 | "version": "15.0.26117.0",
53 | "type": "Workload"
54 | },
55 | {
56 | "id": "Microsoft.VisualStudio.Branding.Professional",
57 | "version": "15.0.26117.0",
58 | "type": "Vsix"
59 | },
60 | {
61 | "id": "Microsoft.VisualStudio.Product.Professional",
62 | "version": "15.0.26117.0",
63 | "type": "Product"
64 | }
65 | ]
66 | }
--------------------------------------------------------------------------------
/docker/Instances/4/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "channelId": "VisualStudio.15.Release/public.d15rel/15.0.26117.0",
3 | "installationName": "VisualStudio/public.d15rel/15.0.26117.0",
4 | "installationVersion": "15.0.26117",
5 | "installationPath": "C:\\BuildTools",
6 | "installDate": "2017-01-18T03:45:00Z",
7 | "product": {
8 | "id": "Microsoft.VisualStudio.Product.BuildTools",
9 | "version": "15.0.26117.0",
10 | "type": "Product"
11 | },
12 | "localizedResources": [
13 | {
14 | "language": "en-us",
15 | "title": "Visual Studio Build Tools 2017",
16 | "description": "The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support."
17 | },
18 | {
19 | "language": "de-de",
20 | "title": "Visual Studio-Buildtools 2017",
21 | "description": "Die Visual Studio-Buildtools ermöglichen Ihnen die Erstellung nativer und verwalteter MSBuild-basierter Anwendungen, ohne dass die Visual Studio-IDE erforderlich ist. Es stehen Optionen zur Installation von Visual C++-Compilern und -Bibliotheken, MFC, ATL sowie C++/CLI-Unterstützung zur Verfügung."
22 | },
23 | {
24 | "language": "ja-jp",
25 | "title": "Visual Studio Build Tools 2017",
26 | "description": "Visual Studio Build Tools では、Visual Studio IDE を必要とせずに、MSBuild ベースのネイティブ マネージド アプリケーションをビルドできます。また、Visual C++ のコンパイラやライブラリ、MFC、ATL、および C++/CLI サポートをインストールするオプションも用意されています。"
27 | }
28 | ],
29 | "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
30 | "selectedPackages": [
31 | {
32 | "id": "Microsoft.VisualStudio.Product.BuildTools",
33 | "version": "15.0.26117.0",
34 | "type": "Product",
35 | "selectedState": "IndividuallySelected"
36 | }
37 | ],
38 | "packages": [
39 | {
40 | "id": "Microsoft.VisualStudio.Workload.MSBuildTools",
41 | "version": "15.0.26117.0",
42 | "type": "Workload"
43 | },
44 | {
45 | "id": "Microsoft.VisualStudio.Product.BuildTools",
46 | "version": "15.0.26117.0",
47 | "type": "Product"
48 | }
49 | ]
50 | }
--------------------------------------------------------------------------------
/docker/Instances/5/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "channelId": "VisualStudio.15.Preview",
3 | "installationName": "VisualStudioPreview/15.3.0-pre.3.0+26612.0.d15rel",
4 | "installationVersion": "15.3.26612.0",
5 | "installationPath": "C:\\VS\\Preview",
6 | "installDate": "2017-04-17T10:00:00Z",
7 | "catalogInfo": {
8 | "id": "VisualStudioPreview/15.3.0-pre.3.0+26612.0.d15rel",
9 | "buildBranch": "d15rel",
10 | "buildVersion": "15.3.26612.0",
11 | "manifestName": "VisualStudioPreview",
12 | "manifestType": "installer",
13 | "productDisplayVersion": "15.3.0 Preview 3.0 [26612.0.d15rel]",
14 | "productLineVersion": "2017",
15 | "productMilestone": "Preview",
16 | "productMilestoneIsPreRelease": "True",
17 | "productName": "Visual Studio",
18 | "productPatchVersion": "0",
19 | "productPreReleaseMilestoneSuffix": "3.0",
20 | "productSemanticVersion": "15.3.0-pre.3.0+26612.0.d15rel"
21 | },
22 | "product": {
23 | "id": "Microsoft.VisualStudio.Product.Enterprise",
24 | "version": "15.0.26612.0",
25 | "type": "Product"
26 | },
27 | "localizedResources": [
28 | {
29 | "language": "en-us",
30 | "title": "Visual Studio Enterprise 2017",
31 | "description": "Microsoft DevOps solution for productivity and coordination across teams of any size"
32 | },
33 | {
34 | "language": "de-de",
35 | "title": "Visual Studio Enterprise 2017",
36 | "description": "Microsoft DevOps-Lösung für Produktivität und Koordination von Teams beliebiger Größe"
37 | },
38 | {
39 | "language": "ja-jp",
40 | "title": "Visual Studio Enterprise 2017",
41 | "description": "生産性向上と、さまざまな規模のチーム間の調整のための Microsoft DevOps ソリューション"
42 | }
43 | ],
44 | "launchParams": {
45 | "fileName": "Common7\\IDE\\devenv.exe"
46 | },
47 | "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
48 | "properties": {
49 | "nickname": "Preview"
50 | },
51 | "selectedPackages": [
52 | {
53 | "id": "Microsoft.VisualStudio.Product.Enterprise",
54 | "version": "15.0.26117.0",
55 | "type": "Product",
56 | "selectedState": "IndividuallySelected"
57 | }
58 | ],
59 | "packages": [
60 | {
61 | "id": "Microsoft.VisualStudio.Workload.ManagedDesktop",
62 | "version": "15.0.26117.0",
63 | "type": "Workload"
64 | },
65 | {
66 | "id": "Microsoft.VisualStudio.Workload.NativeDesktop",
67 | "version": "15.0.26117.0",
68 | "type": "Workload"
69 | },
70 | {
71 | "id": "Microsoft.VisualStudio.Workload.CoreEditor",
72 | "version": "15.0.26117.0",
73 | "type": "Workload"
74 | },
75 | {
76 | "id": "Microsoft.VisualStudio.Branding.Enterprise",
77 | "version": "15.0.26117.0",
78 | "type": "Vsix"
79 | },
80 | {
81 | "id": "Microsoft.VisualStudio.Product.Enterprise",
82 | "version": "15.0.26117.0",
83 | "type": "Product"
84 | }
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/docker/Tests/.gitignore:
--------------------------------------------------------------------------------
1 | [Rr]esults.xml
2 |
--------------------------------------------------------------------------------
/docker/Tests/find.tests.ps1:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | # Instances and results are sorted for consistency.
5 | Describe 'vswhere -sort -find' {
6 | BeforeAll {
7 | # Always write to 32-bit registry key.
8 | $key = New-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\Setup\Reboot -Force
9 | $null = $key | New-ItemProperty -Name 3 -Value 1 -Force
10 |
11 | $files = @(
12 | 'MSBuild\15.0\Bin\MSBuild.exe'
13 | 'MSBuild\15.0\Bin\MSBuild.exe.config'
14 | 'MSBuild\15.0\Bin\amd64\MSBuild.exe'
15 | 'MSBuild\15.0\Bin\amd64\MSBuild.exe.config'
16 | )
17 | # Populate each instance with files to find.
18 | $instances = C:\bin\vswhere.exe -all -prerelease -products * -format json | ConvertFrom-Json
19 | foreach ($file in $files) {
20 | $filePath = Join-Path -Path $instances.installationPath -ChildPath $file
21 | $null = New-Item -Path $filePath -ItemType 'File' -Value '1' -Force
22 | }
23 | }
24 |
25 | Context 'msbuild\15.0\bin\msbuild.exe' {
26 | It 'returns 2 matches' {
27 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\15.0\bin\msbuild.exe'
28 |
29 | $files.Count | Should Be 2
30 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
31 | $files[1] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
32 | }
33 |
34 | It '-format json returns 2 matches' {
35 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\15.0\bin\msbuild.exe' -format json | ConvertFrom-Json
36 |
37 | $files.Count | Should Be 2
38 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
39 | $files[1] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
40 | }
41 |
42 | It '-format xml returns 2 matches' {
43 | $doc = [xml](C:\bin\vswhere.exe -sort -find 'msbuild\15.0\bin\msbuild.exe' -format xml)
44 |
45 | $doc.files.file.Count | Should Be 2
46 | $doc.files.file[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
47 | $doc.files.file[1] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
48 | }
49 | }
50 |
51 | Context 'msbuild\**\msbuild.exe' {
52 | It 'returns 4 matches' {
53 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.exe'
54 |
55 | $files.Count | Should Be 4
56 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
57 | $files[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
58 | $files[2] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\amd64\MSBuild.exe'
59 | $files[3] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
60 | }
61 |
62 | It '-format json returns 4 matches' {
63 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.exe' -format json | ConvertFrom-Json
64 |
65 | $files.Count | Should Be 4
66 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
67 | $files[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
68 | $files[2] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\amd64\MSBuild.exe'
69 | $files[3] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
70 | }
71 |
72 | It '-format xml returns 4 matches' {
73 | $doc = [xml](C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.exe' -format xml)
74 |
75 | $doc.files.file.Count | Should Be 4
76 | $doc.files.file[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
77 | $doc.files.file[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
78 | $doc.files.file[2] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\amd64\MSBuild.exe'
79 | $doc.files.file[3] | Should Be 'C:\VS\Community\MSBuild\15.0\Bin\MSBuild.exe'
80 | }
81 | }
82 |
83 | Context 'msbuild\**\msbuild.* -latest' {
84 | It 'returns 4 matches' {
85 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.*' -latest
86 |
87 | $files.Count | Should Be 4
88 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
89 | $files[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe.config'
90 | $files[2] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
91 | $files[3] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.config'
92 | }
93 |
94 | It '-format json returns 4 matches' {
95 | $files = C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.*' -latest -format json | ConvertFrom-Json
96 |
97 | $files.Count | Should Be 4
98 | $files[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
99 | $files[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe.config'
100 | $files[2] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
101 | $files[3] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.config'
102 | }
103 |
104 | It '-format xml returns 4 matches' {
105 | $doc = [xml](C:\bin\vswhere.exe -sort -find 'msbuild\**\msbuild.*' -latest -format xml)
106 |
107 | $doc.files.file.Count | Should Be 4
108 | $doc.files.file[0] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe'
109 | $doc.files.file[1] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\amd64\MSBuild.exe.config'
110 | $doc.files.file[2] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe'
111 | $doc.files.file[3] | Should Be 'C:\VS\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.config'
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/docker/Tests/legacy.tests.ps1:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | Describe 'vswhere -legacy' {
5 | BeforeAll {
6 | # Always write to 32-bit registry key.
7 | $key = New-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\Setup\Reboot -Force
8 | $null = $key | New-ItemProperty -Name 3 -Value 1 -Force
9 | }
10 |
11 | BeforeEach {
12 | # Make sure localized values are returned consistently across machines.
13 | $enu = [System.Globalization.CultureInfo]::GetCultureInfo('en-US')
14 |
15 | [System.Globalization.CultureInfo]::CurrentCulture = $enu
16 | [System.Globalization.CultureInfo]::CurrentUICulture = $enu
17 | }
18 |
19 | AfterEach {
20 | # Make sure the registry is cleaned up.
21 | Remove-Item HKLM:\Software\WOW6432Node\Microsoft\VisualStudio\SxS\VS7 -Force -ErrorAction 'SilentlyContinue'
22 | }
23 |
24 | Context 'no legacy' {
25 | It 'returns 2 instances' {
26 | $instances = C:\bin\vswhere.exe -legacy -format json | ConvertFrom-Json
27 | $instances.Count | Should Be 2
28 | }
29 | }
30 |
31 | Context 'has legacy' {
32 | BeforeEach {
33 | New-Item HKLM:\Software\WOW6432Node\Microsoft\VisualStudio\SxS\VS7 -Force | ForEach-Object {
34 | foreach ($version in '10.0', '14.0') {
35 | $_ | New-ItemProperty -Name $version -Value "C:\VisualStudio\$version" -Force
36 | }
37 | }
38 | }
39 |
40 | It 'returns 4 instances' {
41 | $instances = C:\bin\vswhere.exe -legacy -format json | ConvertFrom-Json
42 | $instances.Count | Should Be 4
43 | }
44 |
45 | It '-version "10.0" returns 4 instances' {
46 | $instances = C:\bin\vswhere.exe -legacy -version '10.0' -format json | ConvertFrom-Json
47 | $instances.Count | Should Be 4
48 | }
49 |
50 | It '-version "14.0" returns 3 instances' {
51 | $instances = C:\bin\vswhere.exe -legacy -version '14.0' -format json | ConvertFrom-Json
52 | $instances.Count | Should Be 3
53 | }
54 |
55 | It '-version "[10.0,15.0)" returns 2 instances' {
56 | $instances = C:\bin\vswhere.exe -legacy -version '[10.0,15.0)' -format json | ConvertFrom-Json
57 | $instances.Count | Should Be 2
58 | }
59 | }
60 |
61 | Context 'no instances' {
62 | BeforeEach {
63 | New-Item HKLM:\Software\WOW6432Node\Microsoft\VisualStudio\SxS\VS7 -Force | ForEach-Object {
64 | foreach ($version in '10.0', '14.0') {
65 | $_ | New-ItemProperty -Name $version -Value "C:\VisualStudio\$version" -Force
66 | }
67 | }
68 |
69 | Rename-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Classes\CLSID\{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}\InprocServer32' -Name '(Default)' -NewName '_Default'
70 | }
71 |
72 | AfterEach {
73 | Rename-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Classes\CLSID\{177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D}\InprocServer32' -Name '_Default' -NewName '(Default)'
74 | }
75 |
76 | It 'returns 2 instances' {
77 | $instances = C:\bin\vswhere.exe -legacy -format json | ConvertFrom-Json
78 | $instances.Count | Should Be 2
79 | }
80 |
81 | It '-latest returns latest instance' {
82 | $instances = C:\bin\vswhere.exe -legacy -latest -format json | ConvertFrom-Json
83 | $instances.Count | Should Be 1
84 | $instances[0].instanceId | Should Be 'VisualStudio.14.0'
85 | $instances[0].installationPath | Should Be 'C:\VisualStudio\14.0'
86 | }
87 |
88 | It '-version is supported' {
89 | $instances = C:\bin\vswhere.exe -legacy -latest -format json | ConvertFrom-Json
90 | $instances.Count | Should Be 1
91 | $instances[0].instanceId | Should Be 'VisualStudio.14.0'
92 | $instances[0].installationPath | Should Be 'C:\VisualStudio\14.0'
93 | }
94 | }
95 |
96 | Context '-legacy' {
97 | It '-products "any" is not supported' {
98 | C:\bin\vswhere.exe -legacy -products any
99 | $LASTEXITCODE | Should Be 87
100 | }
101 |
102 | It '-requires "any" is not supported' {
103 | C:\bin\vswhere.exe -legacy -requires any
104 | $LASTEXITCODE | Should Be 87
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/docker/docker-compose.debug.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | version: "2.1"
5 | services:
6 | test:
7 | image: microsoft/vssetup:debug
8 | build:
9 | context: .
10 | dockerfile: Debug.dockerfile
11 | network_mode: nat
12 | expose:
13 | - "3702/udp"
14 | - "4022-4023"
15 | command: >
16 | -Command "&'C:\Program Files\Microsoft Visual Studio 15.0\Common7\IDE\Remote Debugger\x64\msvsmon.exe' /silent /noauth /anyuser"
17 |
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | version: "2.1"
5 | services:
6 | test:
7 | image: microsoft/vssetup:test
8 | build: .
9 | volumes:
10 | - ../bin/${CONFIGURATION:-Debug}:C:/bin:ro
11 | - ./Instances:C:/ProgramData/Microsoft/VisualStudio/Packages/_Instances:ro
12 | - ./Tests:C:/Tests
13 | - C:/VS/Community
14 | - C:/VS/Professional
15 | - C:/VS/Enterprise
16 | - C:/BuildTools
17 | - C:/VS/Preview
18 | network_mode: none
19 | command: -Command Invoke-Pester C:\Tests -EnableExit
20 |
--------------------------------------------------------------------------------
/inc/Common.Debug.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(SolutionDir)bin\$(Configuration)\
7 |
8 |
9 |
10 | stdcpp14
11 | MultiThreadedDebug
12 | Guard
13 | ProgramDatabase
14 | /ZH:SHA_256 %(AdditionalOptions)
15 |
16 |
17 | shell32.lib
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/inc/Common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(SolutionDir)bin\$(Configuration)\
7 |
8 |
9 |
10 | stdcpp14
11 | MultiThreaded
12 | Guard
13 | ProgramDatabase
14 | /ZH:SHA_256 %(AdditionalOptions)
15 |
16 |
17 | shell32.lib
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/inc/References.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | $(SolutionDir)src\vswhere.lib;$(IncludePath)
7 | $(OutDir);$(LibraryPath)
8 |
9 |
10 |
11 | vswhere.lib;vswhere.lib.res;%(AdditionalDependencies)
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/inc/VersionInfo.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Microsoft Corporation
7 | Visual Studio Setup
8 | Copyright (C) Microsoft Corporation. All rights reserved.
9 |
10 |
11 |
12 | $(IntermediateOutputPath);%(AdditionalIncludeDirectories)
13 |
14 |
15 | $(IntermediateOutputPath);%(AdditionalIncludeDirectories)
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/pipelines/templates/1es-publish-task.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: path
3 | type: string
4 |
5 | - name: artifactName
6 | type: string
7 |
8 | - name: displayName
9 | type: string
10 | default: 'Publish artifact'
11 |
12 | - name: condition
13 | type: string
14 | default: succeeded()
15 |
16 | steps:
17 | - task: 1ES.PublishPipelineArtifact@1
18 | displayName: ${{ parameters.displayName }}
19 | condition: ${{ parameters.condition }}
20 | inputs:
21 | targetPath: ${{ parameters.path }}
22 | artifactName: ${{ parameters.artifactName }}
--------------------------------------------------------------------------------
/pipelines/templates/ado-publish-task.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: path
3 | type: string
4 |
5 | - name: artifactName
6 | type: string
7 |
8 | - name: displayName
9 | type: string
10 | default: 'Publish artifact'
11 |
12 | - name: condition
13 | type: string
14 | default: succeeded()
15 |
16 | steps:
17 | - task: PublishBuildArtifacts@1
18 | displayName: ${{ parameters.displayName }}
19 | condition: ${{ parameters.condition }}
20 | inputs:
21 | PathtoPublish: ${{ parameters.path }}
22 | ArtifactName: ${{ parameters.artifactName }}
--------------------------------------------------------------------------------
/pipelines/templates/build.yml:
--------------------------------------------------------------------------------
1 | # Copyright (C) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information.
3 |
4 | parameters:
5 | BuildConfiguration: Release
6 | BuildPlatform: x86
7 | Docker: false
8 | Sign: false
9 | PublishArtifactTemplate: /pipelines/template/1es-publish-task.yml@self
10 |
11 | steps:
12 | - powershell: |
13 | dotnet tool install --tool-path "${env:AGENT_TOOLSDIRECTORY}\nbgv" nbgv
14 | $version = & "${env:AGENT_TOOLSDIRECTORY}\nbgv\nbgv.exe" get-version --variable SemVer1
15 | & "${env:AGENT_TOOLSDIRECTORY}\nbgv\nbgv.exe" cloud --version $version
16 | displayName: Set cloud build version
17 |
18 | - task: NuGetToolInstaller@0
19 | displayName: Install nuget
20 |
21 | - task: NuGetCommand@2
22 | displayName: Restore packages
23 |
24 | - task: VSBuild@1
25 | displayName: Build
26 | inputs:
27 | configuration: ${{ parameters.BuildConfiguration }}
28 | platform: ${{ parameters.BuildPlatform }}
29 | maximumCpuCount: true
30 | env:
31 | TreatWarningsAsErrors: true
32 |
33 | - task: VSTest@2
34 | displayName: Functional tests
35 | inputs:
36 | configuration: ${{ parameters.BuildConfiguration }}
37 | platform: ${{ parameters.BuildPlatform }}
38 | testAssemblyVer2: |
39 | bin\${{ parameters.BuildConfiguration }}\*.test.dll
40 | runInParallel: true
41 | codeCoverageEnabled: true
42 | testRunTitle: Functional tests (${{ parameters.BuildConfiguration }}|${{ parameters.BuildPlatform }})
43 |
44 | - ${{ if eq(parameters.Docker, 'true') }}:
45 | # Make sure service images are rebuilt if Dockerfiles changed.
46 | - task: DockerCompose@1
47 | displayName: Build images
48 | inputs:
49 | dockerComposeFile: docker/docker-compose.yml
50 | action: Build services
51 | projectName: microsoft-vswhere
52 | env:
53 | CONFIGURATION: ${{ parameters.BuildConfiguration }}
54 |
55 | - task: DockerCompose@1
56 | displayName: Runtime tests
57 | inputs:
58 | dockerComposeFile: docker/docker-compose.yml
59 | action: Run a specific service
60 | serviceName: test
61 | containerCommand: -Command Invoke-Pester C:\Tests -EnableExit -OutputFile C:\Tests\Results.xml -OutputFormat NUnitXml
62 | detached: false
63 | projectName: microsoft-vswhere
64 | env:
65 | CONFIGURATION: ${{ parameters.BuildConfiguration }}
66 |
67 | - task: PublishTestResults@2
68 | displayName: Publish test results
69 | inputs:
70 | buildConfiguration: ${{ parameters.BuildConfiguration }}
71 | buildPlatform: ${{ parameters.BuildPlatform }}
72 | testRunTitle: Runtime tests (${{ parameters.BuildConfiguration }}|${{ parameters.BuildPlatform }})
73 | testResultsFormat: NUnit
74 | testResultsFiles: '**\*Results.xml'
75 | searchFolder: $(Build.SourcesDirectory)\docker\Tests
76 | mergeTestResults: true
77 | condition: succeededOrFailed()
78 |
79 | - script: |
80 | choco pack pkg\vswhere\vswhere.nuspec --out "bin\${{ parameters.BuildConfiguration }}" --version "%NBGV_NuGetPackageVersion%" "Configuration=${{ parameters.BuildConfiguration }}" "CommitId=$(Build.SourceVersion)" "Tag=$(Build.BuildNumber)"
81 | displayName: Package
82 | workingDirectory: $(Build.SourcesDirectory)
83 |
84 | - ${{ if eq(parameters.Sign, 'true') }}:
85 | - task: VSBuild@1
86 | displayName: Sign package
87 | inputs:
88 | solution: pkg\vswhere\vswhere.signproj
89 | configuration: ${{ parameters.BuildConfiguration }}
90 | platform: ${{ parameters.BuildPlatform }}
91 |
92 | - task: CopyFiles@2
93 | displayName: Copy build artifacts
94 | inputs:
95 | SourceFolder: $(Build.SourcesDirectory)
96 | Contents: |
97 | bin\${{ parameters.BuildConfiguration }}\**
98 | TargetFolder: $(Build.ArtifactStagingDirectory)\out
99 |
100 | - template: ${{ parameters.PublishArtifactTemplate }}
101 | parameters:
102 | displayName: Publish build artifacts
103 | path: $(Build.ArtifactStagingDirectory)\out
104 | artifactName: drop
105 |
--------------------------------------------------------------------------------
/pkg/vswhere/.gitignore:
--------------------------------------------------------------------------------
1 | !build
2 |
--------------------------------------------------------------------------------
/pkg/vswhere/build/vswhere.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildThisFileDirectory)..\tools\
5 |
6 |
7 |
--------------------------------------------------------------------------------
/pkg/vswhere/tools/VERIFICATION.txt:
--------------------------------------------------------------------------------
1 | VERIFICATION
2 | Verification is intended to assist the Chocolatey moderators and community
3 | in verifying that this package's contents are trustworthy.
4 |
5 | tools\vswhere.exe is produced by us from the same repository as this package: https://github.com/Microsoft/vswhere
6 |
--------------------------------------------------------------------------------
/pkg/vswhere/vswhere.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | vswhere
5 | $Version$
6 | Visual Studio Locator
7 | Microsoft
8 | Microsoft
9 | false
10 | https://go.microsoft.com/fwlink/?linkid=839265
11 | https://github.com/Microsoft/vswhere/tree/$CommitId$/LICENSE.txt
12 | https://github.com/Microsoft/vswhere
13 | Locate Visual Studio 2017 and newer installations
14 | Locate Visual Studio 2017 and newer installations
15 | © Microsoft Corporation. All rights reserved.
16 | vs vs2017 visualstudio
17 | true
18 | https://github.com/Microsoft/vswhere/tree/$CommitId$
19 | https://github.com/Microsoft/vswhere/tree/$CommitId$/pkg/vswhere
20 | https://github.com/Microsoft/vswhere/wiki
21 | https://github.com/Microsoft/vswhere/issues
22 | https://github.com/Microsoft/vswhere/releases/tag/$Tag$
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/pkg/vswhere/vswhere.signproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | ..\..\
7 | $(SolutionDir)\
8 | $(SolutionDir)bin\$(BuildConfiguration)\
9 | $(OutDir)\
10 | $(SolutionDir)obj\$(BuildConfiguration)\
11 | $(IntermediateOutputPath)\
12 |
13 | PrepareForBuild;
14 | $(SignDependsOn);
15 |
16 |
17 |
18 |
19 |
20 |
21 | NuGet
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 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}.
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/vswhere.lib/CoInitializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class CoInitializer
9 | {
10 | public:
11 | CoInitializer()
12 | {
13 | auto hr = ::CoInitialize(NULL);
14 | if (FAILED(hr))
15 | {
16 | throw win32_error(hr);
17 | }
18 | }
19 |
20 | ~CoInitializer()
21 | {
22 | ::CoUninitialize();
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/vswhere.lib/CommandArgs.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class Console;
9 |
10 | class CommandArgs
11 | {
12 | public:
13 | CommandArgs() noexcept :
14 | m_all(false),
15 | m_productsAll(false),
16 | m_requiresAny(false),
17 | m_latest(false),
18 | m_legacy(false),
19 | m_sort(false),
20 | m_prerelease(false),
21 | m_includePackages(false),
22 | m_nocolor(false),
23 | m_nologo(false),
24 | m_utf8(false),
25 | m_help(false)
26 | {
27 | }
28 |
29 | CommandArgs(const CommandArgs& obj) :
30 | m_applicationPath(obj.m_applicationPath),
31 | m_all(obj.m_all),
32 | m_productsAll(obj.m_productsAll),
33 | m_products(obj.m_products),
34 | m_requires(obj.m_requires),
35 | m_requiresPattern(obj.m_requiresPattern),
36 | m_version(obj.m_version),
37 | m_latest(obj.m_latest),
38 | m_legacy(obj.m_legacy),
39 | m_path(obj.m_path),
40 | m_sort(obj.m_sort),
41 | m_prerelease(obj.m_prerelease),
42 | m_format(obj.m_format),
43 | m_property(obj.m_property),
44 | m_includePackages(obj.m_includePackages),
45 | m_find(obj.m_find),
46 | m_nocolor(obj.m_nocolor),
47 | m_nologo(obj.m_nologo),
48 | m_utf8(obj.m_utf8),
49 | m_help(obj.m_help)
50 | {
51 | }
52 |
53 | const std::wstring& get_ApplicationPath() const noexcept
54 | {
55 | return m_applicationPath;
56 | }
57 |
58 | const bool get_All() const noexcept
59 | {
60 | return m_all;
61 | }
62 |
63 | const std::vector& get_Products() const noexcept
64 | {
65 | if (!m_productsAll && m_products.empty())
66 | {
67 | return s_Products;
68 | }
69 |
70 | return m_products;
71 | }
72 |
73 | const std::vector& get_Requires() const noexcept
74 | {
75 | return m_requires;
76 | }
77 |
78 | const std::vector& get_RequiresPattern() const noexcept
79 | {
80 | return m_requiresPattern;
81 | }
82 |
83 | const bool get_RequiresAny() const noexcept
84 | {
85 | return m_requiresAny;
86 | }
87 |
88 | const std::wstring& get_Version() const noexcept
89 | {
90 | return m_version;
91 | }
92 |
93 | const bool get_Latest() const noexcept
94 | {
95 | return m_latest;
96 | }
97 |
98 | const bool get_Legacy() const noexcept
99 | {
100 | return m_legacy;
101 | }
102 |
103 | const std::wstring& get_Path() const noexcept
104 | {
105 | return m_path;
106 | }
107 |
108 | const bool get_Sort() const noexcept
109 | {
110 | return m_sort;
111 | }
112 |
113 | const bool get_Prerelease() const noexcept
114 | {
115 | return m_prerelease;
116 | }
117 |
118 | const std::wstring& get_Format() const noexcept
119 | {
120 | if (m_format.empty())
121 | {
122 | return s_Format;
123 | }
124 |
125 | return m_format;
126 | }
127 |
128 | const std::wstring& get_Property() const noexcept
129 | {
130 | return m_property;
131 | }
132 |
133 | const bool get_IncludePackages() const noexcept
134 | {
135 | return m_includePackages;
136 | }
137 |
138 | const std::wstring& get_Find() const noexcept
139 | {
140 | return m_find;
141 | }
142 |
143 | const bool get_Color() const noexcept
144 | {
145 | return !m_nocolor;
146 | }
147 |
148 | const bool get_Logo() const noexcept
149 | {
150 | return !m_nologo;
151 | }
152 |
153 | const bool get_UTF8() const noexcept
154 | {
155 | return m_utf8;
156 | }
157 |
158 | const bool get_Help() const noexcept
159 | {
160 | return m_help;
161 | }
162 |
163 |
164 | void Parse(_In_ LPCWSTR wszCommandLine);
165 | void Parse(_In_ int argc, _In_ LPCWSTR argv[]);
166 | void Usage(_In_ Console& console) const;
167 |
168 | static std::wregex ParseRegex(_In_ const std::wstring& pattern) noexcept;
169 |
170 | private:
171 | static const std::vector s_Products;
172 | static const std::wstring s_Format;
173 |
174 | void Parse(_In_ std::vector args);
175 |
176 | std::wstring m_applicationPath;
177 | bool m_all;
178 | bool m_productsAll;
179 | std::vector m_products;
180 | std::vector m_requires;
181 | std::vector m_requiresPattern;
182 | bool m_requiresAny;
183 | std::wstring m_version;
184 | bool m_latest;
185 | bool m_legacy;
186 | std::wstring m_path;
187 | bool m_sort;
188 | bool m_prerelease;
189 | std::wstring m_format;
190 | std::wstring m_property;
191 | bool m_includePackages;
192 | std::wstring m_find;
193 | bool m_nocolor;
194 | bool m_nologo;
195 | bool m_utf8;
196 | bool m_help;
197 | };
198 |
--------------------------------------------------------------------------------
/src/vswhere.lib/CommandParser.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | vector CommandParser::Parse(_In_ LPCWSTR wszCommandLine)
11 | {
12 | _ASSERT(wszCommandLine && *wszCommandLine);
13 |
14 | int argc = 0;
15 | auto argv = ::CommandLineToArgvW(wszCommandLine, &argc);
16 |
17 | if (!argv)
18 | {
19 | throw win32_error();
20 | }
21 |
22 | // Make sure the argument array is released when it falls out of scope.
23 | unique_ptr args(&argv, [](_In_opt_ LPWSTR** ppwsz)
24 | {
25 | if (ppwsz)
26 | {
27 | ::LocalFree(*ppwsz);
28 | }
29 | });
30 |
31 | return Parse(argc, const_cast(*args));
32 | }
33 |
34 | vector CommandParser::Parse(_In_ int argc, _In_ LPCWSTR argv[])
35 | {
36 | vector tokens;
37 |
38 | // Parse program path from first argument.
39 | if (argc < 1)
40 | {
41 | // TODO: Provide localized error message.
42 | throw win32_error(ERROR_INVALID_PARAMETER, "missing program argument");
43 | }
44 |
45 | m_path = argv[0];
46 |
47 | // Parse remaining arguments.
48 | for (auto i = 1; i < argc; ++i)
49 | {
50 | auto arg = argv[i];
51 |
52 | if (!arg || !*arg)
53 | {
54 | // TODO: Provide localized error message.
55 | throw win32_error(ERROR_INVALID_PARAMETER, "empty argument");
56 | }
57 |
58 | if (L'-' == arg[0] || L'/' == arg[0])
59 | {
60 | tokens.push_back({ Token::eParameter, &arg[1] });
61 | }
62 | else
63 | {
64 | tokens.push_back({ Token::eArgument, arg });
65 | }
66 | }
67 |
68 | return tokens;
69 | }
70 |
--------------------------------------------------------------------------------
/src/vswhere.lib/CommandParser.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class CommandParser
9 | {
10 | public:
11 | struct Token
12 | {
13 | enum { eNone, eParameter, eArgument } Type;
14 | std::wstring Value;
15 | };
16 |
17 | CommandParser() noexcept
18 | {
19 | }
20 |
21 | CommandParser(const CommandParser& obj) :
22 | m_path(obj.m_path)
23 | {
24 | }
25 |
26 | const std::wstring& get_Path() const noexcept
27 | {
28 | return m_path;
29 | }
30 |
31 | std::vector Parse(_In_ LPCWSTR wszCommandLine);
32 | std::vector Parse(_In_ int argc, _In_ LPCWSTR argv[]);
33 |
34 | private:
35 | std::wstring m_path;
36 | };
37 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Console.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void Console::Initialize() noexcept
11 | {
12 | if (!m_fInitialized)
13 | {
14 | if (m_args.get_UTF8())
15 | {
16 | static_cast(::_setmode(_fileno(stdout), _O_U8TEXT));
17 | }
18 | else if (IsConsole(stdout))
19 | {
20 | static_cast(::_setmode(_fileno(stdout), _O_WTEXT));
21 | }
22 | else
23 | {
24 | char sz[10];
25 | ::sprintf_s(sz, ".%u", ::GetConsoleCP());
26 |
27 | ::setlocale(LC_CTYPE, sz);
28 | }
29 |
30 | m_fColorSupported = IsVirtualTerminal(stdout);
31 | m_fInitialized = true;
32 | }
33 | }
34 |
35 | LPCWSTR Console::Color(_In_ LPCWSTR wzColor) const
36 | {
37 | if (IsColorSupported())
38 | {
39 | return wzColor;
40 | }
41 |
42 | return L"";
43 | }
44 |
45 | LPCWSTR Console::ResetColor() const
46 | {
47 | if (IsColorSupported())
48 | {
49 | return L"\033[0m";
50 | }
51 |
52 | return L"";
53 | }
54 |
55 | void __cdecl Console::Write(_In_ LPCWSTR wzFormat, ...)
56 | {
57 | va_list args;
58 |
59 | va_start(args, wzFormat);
60 | Write(wzFormat, args);
61 | va_end(args);
62 | }
63 |
64 | void __cdecl Console::Write(_In_ const std::wstring& value)
65 | {
66 | Write(value.c_str(), NULL);
67 | }
68 |
69 | void __cdecl Console::WriteLine(_In_opt_ LPCWSTR wzFormat, ...)
70 | {
71 | if (wzFormat)
72 | {
73 | va_list args;
74 |
75 | va_start(args, wzFormat);
76 | Write(wzFormat, args);
77 | va_end(args);
78 | }
79 |
80 | Write(L"\n", NULL);
81 | }
82 |
83 | void __cdecl Console::WriteLine(_In_ const std::wstring& value)
84 | {
85 | Write(L"%ls\n", value.c_str());
86 | }
87 |
88 | void Console::Write(_In_ LPCWSTR wzFormat, va_list args)
89 | {
90 | _ASSERTE(m_fInitialized);
91 | ::_vwprintf_p(wzFormat, args);
92 | }
93 |
94 | bool Console::IsConsole(_In_ FILE* f) noexcept
95 | {
96 | auto fno = ::_fileno(f);
97 | auto hFile = (HANDLE)::_get_osfhandle(fno);
98 | auto dwType = ::GetFileType(hFile);
99 |
100 | dwType &= ~FILE_TYPE_REMOTE;
101 |
102 | if (FILE_TYPE_CHAR != dwType)
103 | {
104 | return false;
105 | }
106 |
107 | DWORD dwMode;
108 | if (!::GetConsoleMode(hFile, &dwMode))
109 | {
110 | return false;
111 | }
112 |
113 | return true;
114 | }
115 |
116 | bool Console::IsVirtualTerminal(_In_ FILE* f) noexcept
117 | {
118 | auto fno = ::_fileno(f);
119 | auto hFile = (HANDLE)::_get_osfhandle(fno);
120 |
121 | DWORD dwMode;
122 | if (::GetConsoleMode(hFile, &dwMode))
123 | {
124 | return 0 != ::SetConsoleMode(hFile, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
125 | }
126 |
127 | return false;
128 | }
--------------------------------------------------------------------------------
/src/vswhere.lib/Console.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class Console
9 | {
10 | public:
11 | Console(_In_ const CommandArgs& args) :
12 | m_args(args),
13 | m_fInitialized(false),
14 | m_fColorSupported(false)
15 | {
16 | }
17 |
18 | Console(_In_ const Console& obj) :
19 | m_args(obj.m_args),
20 | m_fInitialized(obj.m_fInitialized),
21 | m_fColorSupported(obj.m_fColorSupported)
22 | {
23 | }
24 |
25 | virtual void Initialize() noexcept;
26 |
27 | LPCWSTR Color(_In_ LPCWSTR wzColor) const;
28 | LPCWSTR ResetColor() const;
29 |
30 | void __cdecl Write(_In_ LPCWSTR wzFormat, ...);
31 | void __cdecl Write(_In_ const std::wstring& value);
32 | void __cdecl WriteLine(_In_opt_ LPCWSTR wzFormat = NULL, ...);
33 | void __cdecl WriteLine(_In_ const std::wstring& value);
34 |
35 | virtual bool IsColorSupported() const
36 | {
37 | _ASSERTE(m_fInitialized);
38 | return m_fColorSupported && m_args.get_Color();
39 | }
40 |
41 | protected:
42 | virtual void Write(_In_ LPCWSTR wzFormat, va_list args);
43 |
44 | const CommandArgs& Args() const noexcept
45 | {
46 | return m_args;
47 | }
48 |
49 | bool m_fInitialized;
50 |
51 | private:
52 | bool static IsConsole(_In_ FILE* f) noexcept;
53 | bool static IsVirtualTerminal(_In_ FILE* f) noexcept;
54 |
55 | const CommandArgs& m_args;
56 | bool m_fColorSupported;
57 | };
--------------------------------------------------------------------------------
/src/vswhere.lib/Exceptions.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | wstring win32_error::format_message(_In_ int code)
11 | {
12 | const size_t max = 65536;
13 |
14 | wstring err(max, wstring::value_type());
15 | if (auto ch = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, 0, const_cast(err.c_str()), err.size(), NULL))
16 | {
17 | err.resize(ch);
18 | return err;
19 | }
20 |
21 | return L"unknown error";
22 | }
23 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Exceptions.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class win32_error :
9 | public std::system_error
10 | {
11 | public:
12 | win32_error() :
13 | win32_error(::GetLastError())
14 | {
15 | }
16 |
17 | win32_error(_In_ int code, _In_ const std::string message = "") :
18 | system_error(code, std::system_category(), message),
19 | m_message(format_message(code))
20 | {
21 | }
22 |
23 | win32_error(_In_ int code, _In_ const std::wstring message) :
24 | system_error(code, std::system_category(), to_string(message)),
25 | m_message(message)
26 | {
27 | }
28 |
29 | const wchar_t* wwhat() const
30 | {
31 | return m_message.c_str();
32 | }
33 |
34 | private:
35 | static std::wstring format_message(_In_ int code);
36 |
37 | std::wstring m_message;
38 | };
39 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Formatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class Formatter
9 | {
10 | public:
11 | typedef std::function(CommandArgs&, Console&)> FormatterFactory;
12 | typedef std::map, ci_less> FormatterMap;
13 |
14 | static std::unique_ptr Create(_In_ const std::wstring& type, _In_ CommandArgs& args, _In_ Console& console);
15 | static FormatterMap Formatters;
16 |
17 | Formatter(_In_ const Formatter& obj) :
18 | m_args(obj.m_args),
19 | m_console(obj.m_console),
20 | m_properties(obj.m_properties)
21 | {
22 | }
23 |
24 | void Write(_In_ const std::wstring& root, _In_ const std::wstring& name, _In_ const std::vector values);
25 | void Write(_In_ ISetupInstance* pInstance);
26 | void Write(_In_ std::vector instances);
27 | void WriteFiles(_In_ std::vector instances);
28 |
29 | virtual bool ShowLogo() const
30 | {
31 | return true;
32 | }
33 |
34 | virtual bool SupportsPackages() const
35 | {
36 | return false;
37 | }
38 |
39 | static const LPCWSTR ColorName;
40 | static const LPCWSTR ColorValue;
41 |
42 | protected:
43 | typedef std::function PropertyFunction;
44 | typedef std::vector> PropertyArray;
45 |
46 | static const std::wstring empty_wstring;
47 |
48 | Formatter(_In_ CommandArgs& args, _In_ Console& console);
49 |
50 | static std::wstring FormatDateISO8601(_In_ const FILETIME& value);
51 |
52 | virtual void StartDocument() {}
53 | virtual void StartArray(_In_opt_ const std::wstring& name = empty_wstring) {}
54 | virtual void StartObject(_In_opt_ const std::wstring& name = empty_wstring) {}
55 | virtual void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) {}
56 | virtual void EndObject() {}
57 | virtual void EndArray() {}
58 | virtual void EndDocument() {}
59 |
60 | virtual void WriteProperty(_In_ const std::wstring& name, _In_ bool value)
61 | {
62 | WriteProperty(name, std::to_wstring(value));
63 | }
64 |
65 | virtual void WriteProperty(_In_ const std::wstring& name, _In_ long long value)
66 | {
67 | WriteProperty(name, std::to_wstring(value));
68 | }
69 |
70 | virtual std::wstring FormatDate(_In_ const FILETIME& value);
71 |
72 | CommandArgs& Args() const noexcept
73 | {
74 | return m_args;
75 | }
76 |
77 | Console& Console() const noexcept
78 | {
79 | return m_console;
80 | }
81 |
82 | private:
83 | static bool PropertyEqual(_In_ const std::wstring& name, _In_ PropertyArray::const_reference property);
84 | static HRESULT GetStringProperty(_In_ std::function pfn, _Out_ VARIANT* pvt);
85 |
86 | static const std::wstring s_delims;
87 | static ci_equal s_comparer;
88 |
89 | HRESULT GetInstanceId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstanceId);
90 | HRESULT GetInstallDate(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallDate);
91 | HRESULT GetInstallationName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationName);
92 | HRESULT GetInstallationPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationPath);
93 | HRESULT GetInstallationVersion(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationVersion);
94 | HRESULT GetProductId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductId);
95 | HRESULT GetProductPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductPath);
96 | HRESULT GetState(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtState);
97 | HRESULT GetIsComplete(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsComplete);
98 | HRESULT GetIsLaunchable(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsLaunchable);
99 | HRESULT GetIsPrerelease(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsPrerelease);
100 | HRESULT GetIsRebootRequired(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsRebootRequired);
101 | HRESULT GetDisplayName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDisplayName);
102 | HRESULT GetDescription(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDescription);
103 |
104 | void WriteInternal(_In_ ISetupInstance* pInstance);
105 | void WritePackage(_In_ ISetupPackageReference* pPackage);
106 | void WritePackages(_In_ ISetupInstance* pInstance);
107 | void WriteProperty(_In_ const std::wstring& name, _In_ const variant_t& value);
108 | bool WriteProperties(_In_ ISetupInstance* pInstance);
109 | bool WriteProperties(_In_ ISetupPropertyStore* pProperties, _In_opt_ const std::wstring& prefix = empty_wstring);
110 |
111 | CommandArgs& m_args;
112 | ::Console& m_console;
113 | PropertyArray m_properties;
114 | };
115 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Glob.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 | using namespace std::filesystem;
10 |
11 | std::wstring rtrim(const std::wstring& value);
12 |
13 | Glob::Glob(_In_ const wstring& root, _In_ const wstring& pattern) :
14 | m_root(rtrim(root))
15 | {
16 | wstring value;
17 | wstring value_raw;
18 | wstring accumulator = L"^\\\\";
19 | bool found_globstar = false;
20 | bool found_wildcard = false;
21 |
22 | wchar_t lastch = 0;
23 | for (auto ch : pattern)
24 | {
25 | switch (ch)
26 | {
27 | // Append directories to root until wildcard found, then accumulate to optimize match.
28 | case L'/':
29 | case L'\\':
30 | if (lastch == L'/' || lastch == L'\\')
31 | {
32 | // Ignore subsequent directory separators.
33 | continue;
34 | }
35 |
36 | if (value.length())
37 | {
38 | if (found_globstar)
39 | {
40 | // Replace globstar with any character match plus directory separator.
41 | accumulator += L"(.*\\\\)?";
42 | }
43 | else if (value_raw.length() == 1 && value_raw == L".")
44 | {
45 | // Ignore current directory references.
46 | value.clear();
47 | value_raw.clear();
48 |
49 | continue;
50 | }
51 | else if (value_raw.length() == 2 && value_raw == L"..")
52 | {
53 | // Block parent directory references.
54 | ThrowError(pattern);
55 | }
56 | else if (found_wildcard)
57 | {
58 | // A single star (asterisk) searches the any subdirectory not including the current directory.
59 | if (value.length() == 1 && value[0] == L'*')
60 | {
61 | accumulator += L"[^\\]*";
62 | }
63 | else
64 | {
65 | accumulator += value;
66 | }
67 | }
68 | else
69 | {
70 | m_root /= value_raw;
71 | }
72 |
73 | value.clear();
74 | value_raw.clear();
75 | }
76 |
77 | if (found_wildcard)
78 | {
79 | if (found_globstar)
80 | {
81 | found_globstar = false;
82 | }
83 | else
84 | {
85 | // Only match directory separator if we didn't find a globstar.
86 | accumulator += L"\\\\";
87 | }
88 | }
89 |
90 | break;
91 |
92 | case L'*':
93 | if (found_globstar)
94 | {
95 | ThrowError(pattern);
96 | }
97 |
98 | found_wildcard = true;
99 |
100 | if (value.length() == 1 && value[0] == L'*')
101 | {
102 | found_globstar = true;
103 | value += L'*';
104 | }
105 | else if (value.length() > 0)
106 | {
107 | if (lastch == L'*')
108 | {
109 | // Invalid trailing globstar after non-separator.
110 | ThrowError(pattern);
111 | }
112 |
113 | value += L"[^\\]*";
114 | }
115 | else
116 | {
117 | value += L'*';
118 | }
119 | break;
120 |
121 | // Convert single character match.
122 | case L'?':
123 | if (found_globstar)
124 | {
125 | ThrowError(pattern);
126 | }
127 |
128 | found_wildcard = true;
129 | value += L"[^\\]";
130 | break;
131 |
132 | default:
133 | if (found_globstar || IsInvalid(ch))
134 | {
135 | // Invalid leading globstar before non-separator or invalid character.
136 | ThrowError(pattern);
137 | }
138 | else if (found_wildcard)
139 | {
140 | // A single star (asterisk) searches the any subdirectory not including the current directory.
141 | if (value.length() == 1 && value[0] == L'*')
142 | {
143 | accumulator += L"[^\\]*";
144 | }
145 | else
146 | {
147 | accumulator += value;
148 | }
149 |
150 | value.clear();
151 | }
152 |
153 | if (RequiresEscape(ch))
154 | {
155 | value += L'\\';
156 | }
157 |
158 | value += ch;
159 | value_raw += ch;
160 |
161 | break;
162 | }
163 |
164 | lastch = ch;
165 | }
166 |
167 | // Do not skip the directory separator: verify it as part of the regex.
168 | m_root_length = m_root.native().length();
169 |
170 | if (value.length())
171 | {
172 | if (found_globstar && value.length() == 2)
173 | {
174 | // Match anything after the directory separator for a trailing globstar.
175 | accumulator += L".*";
176 | }
177 | else
178 | {
179 | accumulator += value;
180 | }
181 | }
182 |
183 | accumulator += L"$";
184 |
185 | #ifdef _DEBUG
186 | m_pattern = accumulator;
187 | #endif
188 |
189 | try
190 | {
191 | m_re = wregex(accumulator, wregex::extended | wregex::icase | wregex::nosubs | wregex::optimize);
192 | }
193 | catch (const regex_error& ex)
194 | {
195 | _RPTN(_CRT_ERROR, "regex parse error: %s", ex.what());
196 | ThrowError(pattern);
197 | }
198 | }
199 |
200 | const vector Glob::Entries(_In_ bool sort) const
201 | {
202 | vector entries;
203 |
204 | const auto& root = m_root.native();
205 | for (const auto& entry : recursive_directory_iterator(m_root))
206 | {
207 | const auto& path = entry.path().native();
208 | if (Match(path))
209 | {
210 | entries.push_back(path);
211 | }
212 | }
213 |
214 | if (sort)
215 | {
216 | static ci_less less;
217 | std::sort(entries.begin(), entries.end(), less);
218 | }
219 |
220 | return entries;
221 | }
222 |
223 | bool Glob::Match(_In_ const wstring& value) const
224 | {
225 | if (m_root_length < value.length())
226 | {
227 | return regex_match(value.begin() + m_root_length, value.end(), m_re);
228 | }
229 |
230 | return false;
231 | }
232 |
233 | bool Glob::IsInvalid(_In_ const wchar_t ch)
234 | {
235 | return ch < 32 || ch == 124;
236 | }
237 |
238 | bool Glob::RequiresEscape(_In_ const wchar_t ch)
239 | {
240 | static const wchar_t escape[] =
241 | {
242 | L'.',
243 | L'(',
244 | L')',
245 | L'$',
246 | L'[',
247 | L']',
248 | L'{',
249 | L'}',
250 | L'+',
251 | };
252 | static const size_t escape_len = sizeof(escape) / sizeof(*escape);
253 |
254 | for (unsigned char i = 0; i < escape_len; ++i)
255 | {
256 | if (ch == escape[i])
257 | {
258 | return true;
259 | }
260 | }
261 |
262 | return false;
263 | }
264 |
265 | void Glob::ThrowError(_In_ const wstring& pattern)
266 | {
267 | auto message = ResourceManager::FormatString(IDS_E_INVALIDPATTERN, pattern.c_str());
268 | throw win32_error(ERROR_INVALID_PARAMETER, message);
269 | }
270 |
271 | std::wstring rtrim(const std::wstring& value)
272 | {
273 | if (value.back() != L'\\' && value.back() != L'/')
274 | {
275 | return value;
276 | }
277 |
278 | wstring copy(value);
279 | wstring::reverse_iterator it = copy.rbegin();
280 | while (it != copy.rend() && (*it == L'\\' || *it == L'/'))
281 | {
282 | it++;
283 | }
284 |
285 | copy.erase(it.base(), copy.end());
286 | return copy;
287 | }
--------------------------------------------------------------------------------
/src/vswhere.lib/Glob.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class Glob
9 | {
10 | public:
11 | Glob(_In_ const std::wstring& root, _In_ const std::wstring& pattern);
12 | Glob(_In_ const Glob& obj) noexcept :
13 | m_root(obj.m_root),
14 | m_root_length(obj.m_root_length),
15 | #ifdef _DEBUG
16 | m_pattern(obj.m_pattern),
17 | #endif
18 | m_re(obj.m_re)
19 | {
20 | }
21 |
22 | const std::wstring& Root() const noexcept
23 | {
24 | return m_root.native();
25 | }
26 |
27 | const std::vector Entries(_In_ bool sort = false) const;
28 | bool Match(_In_ const std::wstring& value) const;
29 |
30 | private:
31 | static bool IsInvalid(_In_ const wchar_t ch);
32 | static bool RequiresEscape(_In_ const wchar_t ch);
33 | static void ThrowError(_In_ const std::wstring& pattern);
34 |
35 | std::filesystem::path m_root;
36 | size_t m_root_length;
37 | std::wregex m_re;
38 |
39 | #ifdef _DEBUG
40 | public:
41 | const std::wstring& Pattern() const noexcept
42 | {
43 | return m_pattern;
44 | }
45 |
46 | private:
47 | std::wstring m_pattern;
48 | #endif
49 | };
50 |
--------------------------------------------------------------------------------
/src/vswhere.lib/ILegacyProvider.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class ILegacyProvider
9 | {
10 | public:
11 | virtual bool HasLegacyInstances() const = 0;
12 | virtual bool TryGetLegacyInstance(_In_ LPCWSTR wzVersion, _Out_ ISetupInstance** ppInstance) const = 0;
13 | };
14 |
--------------------------------------------------------------------------------
/src/vswhere.lib/InstanceSelector.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class InstanceSelector
9 | {
10 | public:
11 | InstanceSelector(_In_ const CommandArgs& args, _In_opt_ ISetupHelper* pHelper = NULL) :
12 | InstanceSelector(args, LegacyProvider::Instance, pHelper)
13 | {
14 | }
15 |
16 | InstanceSelector(_In_ const CommandArgs& args, _In_ ILegacyProvider& provider, _In_opt_ ISetupHelper* pHelper = NULL);
17 | InstanceSelector(_In_ const InstanceSelector& obj) :
18 | m_args(obj.m_args),
19 | m_provider(obj.m_provider),
20 | m_helper(obj.m_helper),
21 | m_ullMinimumVersion(obj.m_ullMinimumVersion),
22 | m_ullMaximumVersion(obj.m_ullMaximumVersion)
23 | {
24 | }
25 |
26 | bool Less(const ISetupInstancePtr& a, const ISetupInstancePtr& b) const;
27 | std::vector Select(_In_opt_ IEnumSetupInstances* pEnum) const;
28 |
29 | private:
30 | static ci_equal s_comparer;
31 |
32 | static std::wstring GetId(_In_ ISetupPackageReference* pPackageReference);
33 | bool IsMatch(_In_ ISetupInstance* pInstance) const;
34 | bool IsProductMatch(_In_ ISetupInstance2* pInstance) const;
35 | bool IsWorkloadMatch(_In_ ISetupInstance2* pInstance) const;
36 | bool IsVersionMatch(_In_ ISetupInstance* pInstance) const;
37 | bool HasVersionRange() const
38 | {
39 | return m_ullMinimumVersion != 0 && m_ullMaximumVersion != 0;
40 | }
41 |
42 | const CommandArgs& m_args;
43 | const ILegacyProvider& m_provider;
44 | ULONGLONG m_ullMinimumVersion;
45 | ULONGLONG m_ullMaximumVersion;
46 | ISetupHelperPtr m_helper;
47 | };
48 |
--------------------------------------------------------------------------------
/src/vswhere.lib/JsonFormatter.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | const LPCWSTR JsonFormatter::ColorBool = L"\033[38;2;86;156;214m";
11 | const LPCWSTR JsonFormatter::ColorNumber = L"\033[38;2;181;206;168m";
12 |
13 | wstring JsonFormatter::Escape(_In_ const wstring& value)
14 | {
15 | wstring buffer;
16 | wstring::size_type pos = 0;
17 | wstring::size_type last = 0;
18 |
19 | while ((pos = value.find_first_of(L"\"\\", last)) != wstring::npos)
20 | {
21 | buffer.append(value, last, pos - last);
22 | buffer.push_back(L'\\');
23 | buffer.push_back(value[pos]);
24 |
25 | last = ++pos;
26 | }
27 |
28 | buffer += value.substr(last);
29 | return buffer;
30 | }
31 |
32 | void JsonFormatter::StartArray(_In_opt_ const std::wstring& name)
33 | {
34 | StartScope(JsonScope::Type::array, name);
35 | }
36 |
37 | void JsonFormatter::StartObject(_In_opt_ const wstring& name)
38 | {
39 | StartScope(JsonScope::Type::object, name);
40 | }
41 |
42 | void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ const wstring& value)
43 | {
44 | StartProperty(name);
45 |
46 | auto escaped = Escape(value);
47 | Console().Write(L"%ls\"%ls\"%ls", Console().Color(ColorValue), escaped.c_str(), Console().ResetColor());
48 | }
49 |
50 | void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ bool value)
51 | {
52 | StartProperty(name);
53 | Console().Write(L"%ls%ls%ls", Console().Color(ColorBool), value ? L"true" : L"false", Console().ResetColor());
54 | }
55 |
56 | void JsonFormatter::WriteProperty(_In_ const wstring& name, _In_ long long value)
57 | {
58 | StartProperty(name);
59 | Console().Write(L"%ls%I64d%ls", Console().Color(ColorNumber), value, Console().ResetColor());
60 | }
61 |
62 | void JsonFormatter::EndObject()
63 | {
64 | EndScope();
65 | }
66 |
67 | void JsonFormatter::EndArray()
68 | {
69 | EndScope();
70 | }
71 |
72 | void JsonFormatter::EndDocument()
73 | {
74 | Console().WriteLine();
75 | }
76 |
77 | wstring JsonFormatter::FormatDate(_In_ const FILETIME& value)
78 | {
79 | return FormatDateISO8601(value);
80 | }
81 |
82 | void JsonFormatter::Push()
83 | {
84 | m_padding += std::wstring(padding_size, L' ');
85 | }
86 |
87 | void JsonFormatter::Pop()
88 | {
89 | if (m_padding.size() > 0)
90 | {
91 | m_padding.resize(m_padding.size() - padding_size);
92 | }
93 | }
94 |
95 | void JsonFormatter::StartScope(_In_ JsonScope::Type type, _In_ const std::wstring& name)
96 | {
97 | JsonScope* pParent = nullptr;
98 | if (m_scopes.size())
99 | {
100 | auto& top = m_scopes.top();
101 | top.StartScope();
102 |
103 | pParent = ⊤
104 | }
105 |
106 | m_scopes.push(JsonScope(pParent, Console(), m_padding, type, name));
107 |
108 | // Always write the root scope.
109 | if (m_scopes.size() == 1)
110 | {
111 | m_scopes.top().WriteStart();
112 | }
113 |
114 | Push();
115 | }
116 |
117 | void JsonFormatter::StartProperty(_In_ const std::wstring& name)
118 | {
119 | m_scopes.top().StartProperty();
120 |
121 | Console().Write(L"\n%ls", m_padding.c_str());
122 | if (m_scopes.top().IsObject())
123 | {
124 | Console().Write(L"%ls\"%ls\"%ls: ", Console().Color(ColorName), name.c_str(), Console().ResetColor());
125 | }
126 | }
127 |
128 | void JsonFormatter::EndScope()
129 | {
130 | Pop();
131 |
132 | m_scopes.top().WriteEnd();
133 | m_scopes.pop();
134 | }
135 |
--------------------------------------------------------------------------------
/src/vswhere.lib/JsonFormatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class JsonFormatter :
9 | public Formatter
10 | {
11 | public:
12 | static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console)
13 | {
14 | return std::unique_ptr(new JsonFormatter(args, console));
15 | }
16 |
17 | JsonFormatter(_In_ CommandArgs& args, _In_ ::Console& console) :
18 | Formatter(args, console)
19 | {
20 | }
21 |
22 | JsonFormatter(_In_ const JsonFormatter& obj) :
23 | Formatter(obj),
24 | m_padding(obj.m_padding),
25 | m_scopes(obj.m_scopes)
26 | {
27 | }
28 |
29 | static std::wstring Escape(_In_ const std::wstring& value);
30 |
31 | bool ShowLogo() const override
32 | {
33 | return false;
34 | }
35 |
36 | bool SupportsPackages() const override
37 | {
38 | return true;
39 | }
40 |
41 | static const LPCWSTR ColorBool;
42 | static const LPCWSTR ColorNumber;
43 |
44 | protected:
45 | void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override;
46 | void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override;
47 | void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override;
48 | void WriteProperty(_In_ const std::wstring& name, _In_ bool value) override;
49 | void WriteProperty(_In_ const std::wstring& name, _In_ long long value) override;
50 | void EndObject() override;
51 | void EndArray() override;
52 | void EndDocument() override;
53 | std::wstring FormatDate(_In_ const FILETIME& value) override;
54 |
55 | private:
56 | static const size_t padding_size = 2;
57 |
58 | void Push();
59 | void Pop();
60 |
61 | void StartScope(_In_ JsonScope::Type type, _In_ const std::wstring& name);
62 | void StartProperty(_In_ const std::wstring& name);
63 | void EndScope();
64 |
65 | std::wstring m_padding;
66 | std::stack m_scopes;
67 | };
68 |
--------------------------------------------------------------------------------
/src/vswhere.lib/JsonScope.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void JsonScope::StartScope()
11 | {
12 | WriteSeparator();
13 | }
14 |
15 | void JsonScope::StartProperty()
16 | {
17 | // Delay writing the parent scope until we write a property.
18 | WriteStart();
19 |
20 | WriteSeparator();
21 | RequireSeparator();
22 | }
23 |
24 | void JsonScope::WriteStartImpl()
25 | {
26 | bool writeKey = false;
27 |
28 | WriteSeparator();
29 |
30 | if (Parent())
31 | {
32 | if (Parent()->IsObject())
33 | {
34 | writeKey = true;
35 | }
36 |
37 | // Write new line if not the root scope.
38 | Console().WriteLine();
39 | }
40 |
41 | if (writeKey && Name().length())
42 | {
43 | Console().Write(
44 | L"%ls%ls\"%ls\"%ls: %lc",
45 | Padding().c_str(),
46 | Console().Color(JsonFormatter::ColorName),
47 | Name().c_str(),
48 | Console().ResetColor(),
49 | StartChar());
50 | }
51 | else
52 | {
53 | Console().Write(L"%ls%lc", Padding().c_str(), StartChar());
54 | }
55 | }
56 |
57 | void JsonScope::WriteEndImpl()
58 | {
59 | if (m_requireSep)
60 | {
61 | // Write new line and padding only if elements were written.
62 | // This keeps empty arrays and objects looking like [] and {}.
63 | Console().Write(L"\n%ls", Padding().c_str());
64 | }
65 |
66 | Console().Write(L"%lc", EndChar());
67 | }
68 |
69 | void JsonScope::RequireSeparator() noexcept
70 | {
71 | m_requireSep = true;
72 |
73 | if (auto p = Parent())
74 | {
75 | p->RequireSeparator();
76 | }
77 | }
78 |
79 | void JsonScope::WriteSeparator()
80 | {
81 | if (m_requireSep)
82 | {
83 | Console().Write(L",");
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/vswhere.lib/JsonScope.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class JsonScope :
9 | public Scope
10 | {
11 | public:
12 | typedef enum { array, object } Type;
13 |
14 | JsonScope(_In_opt_ JsonScope* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ Type type, _In_ const std::wstring& name) :
15 | Scope(pParent, console, padding, name),
16 | m_type(type),
17 | m_requireSep(false)
18 | {
19 | }
20 |
21 | JsonScope(_In_ const JsonScope& obj) :
22 | Scope(obj),
23 | m_type(obj.m_type),
24 | m_requireSep(obj.m_requireSep)
25 | {
26 | }
27 |
28 | bool IsArray() const noexcept
29 | {
30 | return m_type == Type::array;
31 | }
32 |
33 | bool IsObject() const noexcept
34 | {
35 | return m_type == Type::object;
36 | }
37 |
38 | void StartScope();
39 | void StartProperty();
40 |
41 | protected:
42 | void WriteStartImpl() override;
43 | void WriteEndImpl() override;
44 |
45 | private:
46 | void RequireSeparator() noexcept;
47 | void WriteSeparator();
48 |
49 | wchar_t StartChar() const noexcept
50 | {
51 | if (m_type == Type::array)
52 | {
53 | return L'[';
54 | }
55 |
56 | return L'{';
57 | }
58 |
59 | wchar_t EndChar() const noexcept
60 | {
61 | if (m_type == Type::array)
62 | {
63 | return L']';
64 | }
65 |
66 | return L'}';
67 | }
68 |
69 | const Type m_type;
70 | bool m_requireSep;
71 | };
72 |
--------------------------------------------------------------------------------
/src/vswhere.lib/LegacyInstance.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | template
11 | inline HRESULT NotImplemented(_Out_opt_ T* p)
12 | {
13 | if (!p)
14 | {
15 | return E_POINTER;
16 | }
17 |
18 | *p = NULL;
19 | return E_NOTFOUND;
20 | }
21 |
22 | template<>
23 | inline HRESULT NotImplemented(_Out_opt_ LPFILETIME pft)
24 | {
25 | if (!pft)
26 | {
27 | return E_POINTER;
28 | }
29 |
30 | ::SecureZeroMemory(pft, sizeof(FILETIME));
31 | return E_NOTFOUND;
32 | }
33 |
34 | STDMETHODIMP LegacyInstance::GetInstanceId(
35 | _Out_ BSTR* pbstrInstanceId
36 | )
37 | {
38 | if (!pbstrInstanceId)
39 | {
40 | return E_POINTER;
41 | }
42 |
43 | *pbstrInstanceId = NULL;
44 |
45 | // Let exceptions throw since we're not a "true" COM object.
46 | wstring instanceId(L"VisualStudio.");
47 | instanceId += m_version;
48 |
49 | *pbstrInstanceId = ::SysAllocString(instanceId.c_str());
50 | if (!pbstrInstanceId)
51 | {
52 | return E_OUTOFMEMORY;
53 | }
54 |
55 | return S_OK;
56 | }
57 |
58 | STDMETHODIMP LegacyInstance::GetInstallDate(
59 | _Out_ LPFILETIME pInstallDate
60 | )
61 | {
62 | return NotImplemented(pInstallDate);
63 | }
64 |
65 | STDMETHODIMP LegacyInstance::GetInstallationName(
66 | _Out_ BSTR* pbstrInstallationName
67 | )
68 | {
69 | return NotImplemented(pbstrInstallationName);
70 | }
71 |
72 | STDMETHODIMP LegacyInstance::GetInstallationPath(
73 | _Out_ BSTR* pbstrInstallationPath
74 | )
75 | {
76 | if (!pbstrInstallationPath)
77 | {
78 | return E_POINTER;
79 | }
80 |
81 | *pbstrInstallationPath = ::SysAllocString(m_path.c_str());
82 | if (!pbstrInstallationPath)
83 | {
84 | return E_OUTOFMEMORY;
85 | }
86 |
87 | return S_OK;
88 | }
89 |
90 | STDMETHODIMP LegacyInstance::GetInstallationVersion(
91 | _Out_ BSTR* pbstrInstallationVersion
92 | )
93 | {
94 | if (!pbstrInstallationVersion)
95 | {
96 | return E_POINTER;
97 | }
98 |
99 | *pbstrInstallationVersion = ::SysAllocString(m_version.c_str());
100 | if (!pbstrInstallationVersion)
101 | {
102 | return E_OUTOFMEMORY;
103 | }
104 |
105 | return S_OK;
106 | }
107 |
108 | STDMETHODIMP LegacyInstance::GetDisplayName(
109 | _In_ LCID lcid,
110 | _Out_ BSTR* pbstrDisplayName
111 | )
112 | {
113 | return NotImplemented(pbstrDisplayName);
114 | }
115 |
116 | STDMETHODIMP LegacyInstance::GetDescription(
117 | _In_ LCID lcid,
118 | _Out_ BSTR* pbstrDescription
119 | )
120 | {
121 | return NotImplemented(pbstrDescription);
122 | }
123 |
124 | STDMETHODIMP LegacyInstance::ResolvePath(
125 | _In_opt_z_ LPCOLESTR pwszRelativePath,
126 | _Out_ BSTR* pbstrAbsolutePath
127 | )
128 | {
129 | return NotImplemented(pbstrAbsolutePath);
130 | }
131 |
--------------------------------------------------------------------------------
/src/vswhere.lib/LegacyInstance.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class LegacyInstance :
9 | public ISetupInstance
10 | {
11 | public:
12 | LegacyInstance(_In_ LPCWSTR wzVersion, _In_ LPCWSTR wzPath) :
13 | m_version(wzVersion),
14 | m_path(wzPath),
15 | m_ulRef(1)
16 | {
17 | }
18 |
19 | // IUnknown
20 | STDMETHODIMP QueryInterface(
21 | _In_ REFIID riid,
22 | _Outptr_ LPVOID *ppvObject)
23 | {
24 | if (!ppvObject)
25 | {
26 | return E_POINTER;
27 | }
28 |
29 | HRESULT hr = S_OK;
30 | if (riid == __uuidof(ISetupInstance))
31 | {
32 | AddRef();
33 | *ppvObject = static_cast(this);
34 | }
35 | else if (riid == __uuidof(IUnknown))
36 | {
37 | AddRef();
38 | *ppvObject = static_cast(this);
39 | }
40 | else
41 | {
42 | hr = E_NOINTERFACE;
43 | }
44 |
45 | return hr;
46 | }
47 |
48 | STDMETHODIMP_(ULONG) AddRef(void)
49 | {
50 | return ::InterlockedIncrement(&m_ulRef);
51 | }
52 |
53 | STDMETHODIMP_(ULONG) Release(void)
54 | {
55 | auto ulRef = ::InterlockedDecrement(&m_ulRef);
56 | if (!ulRef)
57 | {
58 | delete this;
59 | }
60 |
61 | return ulRef;
62 | }
63 |
64 | public:
65 | // SetupInstance
66 | STDMETHOD(GetInstanceId)(
67 | _Out_ BSTR* pbstrInstanceId
68 | );
69 |
70 | STDMETHOD(GetInstallDate)(
71 | _Out_ LPFILETIME pInstallDate
72 | );
73 |
74 | STDMETHOD(GetInstallationName)(
75 | _Out_ BSTR* pbstrInstallationName
76 | );
77 |
78 | STDMETHOD(GetInstallationPath)(
79 | _Out_ BSTR* pbstrInstallationPath
80 | );
81 |
82 | STDMETHOD(GetInstallationVersion)(
83 | _Out_ BSTR* pbstrInstallationVersion
84 | );
85 |
86 | STDMETHOD(GetDisplayName)(
87 | _In_ LCID lcid,
88 | _Out_ BSTR* pbstrDisplayName
89 | );
90 |
91 | STDMETHOD(GetDescription)(
92 | _In_ LCID lcid,
93 | _Out_ BSTR* pbstrDescription
94 | );
95 |
96 | STDMETHOD(ResolvePath)(
97 | _In_opt_z_ LPCOLESTR pwszRelativePath,
98 | _Out_ BSTR* pbstrAbsolutePath
99 | );
100 |
101 | private:
102 | const std::wstring m_version;
103 | const std::wstring m_path;
104 | ULONG m_ulRef;
105 | };
106 |
--------------------------------------------------------------------------------
/src/vswhere.lib/LegacyProvider.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | ILegacyProvider& LegacyProvider::Instance = LegacyProvider();
11 |
12 | bool LegacyProvider::HasLegacyInstances() const
13 | {
14 | return NULL != m_hKey;
15 | }
16 |
17 | bool LegacyProvider::TryGetLegacyInstance(_In_ LPCWSTR wzVersion, _Out_ ISetupInstance** ppInstance) const
18 | {
19 | _ASSERT(ppInstance);
20 |
21 | *ppInstance = NULL;
22 |
23 | if (!m_hKey)
24 | {
25 | return false;
26 | }
27 |
28 | DWORD dwType = 0;
29 | DWORD cbData = 0;
30 |
31 | auto err = ::RegQueryValueExW(m_hKey, wzVersion, NULL, &dwType, NULL, &cbData);
32 | if (ERROR_FILE_NOT_FOUND == err || REG_SZ != dwType)
33 | {
34 | return false;
35 | }
36 | else if (ERROR_SUCCESS != err)
37 | {
38 | throw win32_error(err);
39 | }
40 |
41 | wstring sz(cbData / sizeof(wstring::value_type), wstring::value_type());
42 | auto lpData = reinterpret_cast(const_cast(sz.c_str()));
43 |
44 | err = ::RegQueryValueExW(m_hKey, wzVersion, NULL, NULL, lpData, &cbData);
45 | if (ERROR_SUCCESS != err)
46 | {
47 | throw win32_error(err);
48 | }
49 |
50 | *ppInstance = new (nothrow) LegacyInstance(wzVersion, sz.c_str());
51 | if (!*ppInstance)
52 | {
53 | throw win32_error(E_OUTOFMEMORY);
54 | }
55 |
56 | return true;
57 | }
58 |
--------------------------------------------------------------------------------
/src/vswhere.lib/LegacyProvider.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class LegacyProvider :
9 | public ILegacyProvider
10 | {
11 | public:
12 | static ILegacyProvider& Instance;
13 |
14 | LegacyProvider() :
15 | m_hKey(NULL)
16 | {
17 | auto err = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &m_hKey);
18 | if (ERROR_SUCCESS != err && ERROR_FILE_NOT_FOUND != err)
19 | {
20 | throw win32_error(err);
21 | }
22 | }
23 |
24 | LegacyProvider(const LegacyProvider& obj) = delete;
25 |
26 | ~LegacyProvider()
27 | {
28 | if (m_hKey)
29 | {
30 | ::CloseHandle(m_hKey);
31 | m_hKey = NULL;
32 | }
33 | }
34 |
35 | bool HasLegacyInstances() const override;
36 | bool TryGetLegacyInstance(_In_ LPCWSTR wzVersion, _Out_ ISetupInstance** ppInstance) const override;
37 |
38 | private:
39 | HKEY m_hKey;
40 | };
41 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Module.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void Module::FromIUnknown(_In_opt_ const IUnknown* pUnk) noexcept
11 | {
12 | typedef struct IUnknownVtbl
13 | {
14 | HRESULT(STDMETHODCALLTYPE *QueryInterface)(ISetupConfiguration*, REFIID, LPVOID*);
15 | ULONG(STDMETHODCALLTYPE *AddRef)(ISetupConfiguration*);
16 | ULONG(STDMETHODCALLTYPE *Release)(ISetupConfiguration*);
17 | } IUnknownVtbl;
18 |
19 | if (pUnk)
20 | {
21 | auto pVtbl = reinterpret_cast(pUnk);
22 | ::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast(pVtbl->QueryInterface), &m_hModule);
23 | }
24 | }
25 |
26 | const wstring& Module::get_Path() noexcept
27 | {
28 | if (m_hModule && m_path.empty())
29 | {
30 | m_path.resize(MAX_PATH);
31 | ::GetModuleFileNameW(m_hModule, const_cast(m_path.data()), m_path.size());
32 | }
33 |
34 | return m_path;
35 | }
36 |
37 | const wstring& Module::get_FileVersion() noexcept
38 | {
39 | auto& path = get_Path();
40 | if (path.empty())
41 | {
42 | return m_fileVersion;
43 | }
44 |
45 | DWORD dwHandle = 0;
46 | DWORD cbVersionInfo = ::GetFileVersionInfoSizeW(path.c_str(), &dwHandle);
47 | if (!cbVersionInfo)
48 | {
49 | return m_fileVersion;
50 | }
51 |
52 | vector buffer(cbVersionInfo);
53 | if (!::GetFileVersionInfoW(path.c_str(), 0, buffer.size(), buffer.data()))
54 | {
55 | return m_fileVersion;
56 | }
57 |
58 | VS_FIXEDFILEINFO* pFileInfo = NULL;
59 | UINT cbFileInfo = 0;
60 | if (!::VerQueryValueW(buffer.data(), L"\\", reinterpret_cast(&pFileInfo), &cbFileInfo))
61 | {
62 | return m_fileVersion;
63 | }
64 |
65 | auto cch = _scwprintf(
66 | L"%u.%u.%u.%u",
67 | (pFileInfo->dwFileVersionMS >> 16) & 0xffff,
68 | pFileInfo->dwFileVersionMS & 0xffff,
69 | (pFileInfo->dwFileVersionLS >> 16) & 0xffff,
70 | pFileInfo->dwFileVersionLS & 0xffff);
71 | if (!cch)
72 | {
73 | return m_fileVersion;
74 | }
75 |
76 | m_fileVersion.resize(++cch);
77 | swprintf_s(
78 | const_cast(m_fileVersion.c_str()),
79 | m_fileVersion.size(),
80 | L"%u.%u.%u.%u",
81 | (pFileInfo->dwFileVersionMS >> 16) & 0xffff,
82 | pFileInfo->dwFileVersionMS & 0xffff,
83 | (pFileInfo->dwFileVersionLS >> 16) & 0xffff,
84 | pFileInfo->dwFileVersionLS & 0xffff);
85 |
86 | // Trim terminating null character.
87 | m_fileVersion.resize(--cch);
88 |
89 | return m_fileVersion;
90 | }
91 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Module.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class Module
9 | {
10 | public:
11 | Module() :
12 | m_hModule(NULL)
13 | {
14 | }
15 |
16 | Module(_In_ const Module& obj) :
17 | m_hModule(obj.m_hModule),
18 | m_path(obj.m_path),
19 | m_fileVersion(obj.m_fileVersion)
20 | {
21 | }
22 |
23 | ~Module()
24 | {
25 | if (m_hModule)
26 | {
27 | ::FreeLibrary(m_hModule);
28 | }
29 | }
30 |
31 | // Avoid throwing non-catastrophic exceptions since information is for diagnostics only.
32 | void FromIUnknown(_In_opt_ const IUnknown* pUnk) noexcept;
33 | const std::wstring& get_Path() noexcept;
34 | const std::wstring& get_FileVersion() noexcept;
35 |
36 | private:
37 | HMODULE m_hModule;
38 | std::wstring m_path;
39 | std::wstring m_fileVersion;
40 | };
41 |
--------------------------------------------------------------------------------
/src/vswhere.lib/ResourceManager.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | HINSTANCE ResourceManager::s_hInstance = ::GetModuleHandleW(NULL);
11 |
12 | wstring ResourceManager::GetString(_In_ DWORD nID)
13 | {
14 | LPCWSTR wsz = NULL;
15 |
16 | auto ch = ::LoadStringW(s_hInstance, nID, (LPWSTR)&wsz, 0);
17 | if (!ch)
18 | {
19 | throw win32_error();
20 | }
21 |
22 | return wstring(wsz, wsz + ch);
23 | }
24 |
25 | wstring ResourceManager::FormatString(_In_ DWORD nID, _In_ va_list args)
26 | {
27 | auto fmt = GetString(nID);
28 |
29 | auto ch = _vscwprintf_p(fmt.c_str(), args);
30 | if (0 > ch)
31 | {
32 | throw win32_error(ERROR_INVALID_PARAMETER);
33 | }
34 |
35 | wstring wsz;
36 | wsz.resize(++ch);
37 |
38 | if (0 > _vswprintf_p(&wsz[0], ch, fmt.c_str(), args))
39 | {
40 | throw win32_error(ERROR_INVALID_PARAMETER);
41 | }
42 |
43 | // trim the terminating null
44 | wsz.resize(ch - 1);
45 |
46 | return wsz;
47 | }
48 |
--------------------------------------------------------------------------------
/src/vswhere.lib/ResourceManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class ResourceManager
9 | {
10 | public:
11 | static void SetInstance(_In_ HINSTANCE hInstance)
12 | {
13 | s_hInstance = hInstance;
14 | }
15 |
16 | static std::wstring GetString(_In_ DWORD nID);
17 | static std::wstring __cdecl FormatString(_In_ DWORD nID, ...)
18 | {
19 | va_list args;
20 |
21 | va_start(args, nID);
22 | auto wsz = FormatString(nID, args);
23 | va_end(args);
24 |
25 | return wsz;
26 | }
27 |
28 | private:
29 | ResourceManager() {}
30 | ResourceManager(const ResourceManager& obj) {}
31 | ResourceManager(ResourceManager&& obj) noexcept {}
32 |
33 | static std::wstring FormatString(_In_ DWORD nID, _In_ va_list args);
34 |
35 | static HINSTANCE s_hInstance;
36 | };
37 |
--------------------------------------------------------------------------------
/src/vswhere.lib/SafeArray.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | // Simple container for a single-dimension SAFEARRAY.
9 | template
10 | class SafeArray
11 | {
12 | public:
13 | SafeArray(_In_ const LPSAFEARRAY psa) :
14 | m_psa(psa)
15 | {
16 | Lock();
17 | }
18 |
19 | SafeArray(_In_ const SafeArray& obj) :
20 | m_psa(obj.m_psa)
21 | {
22 | Lock();
23 | }
24 |
25 | ~SafeArray()
26 | {
27 | Unlock();
28 | Destroy();
29 | }
30 |
31 | const std::vector<_Element>& Elements() const
32 | {
33 | return m_elements;
34 | }
35 |
36 | private:
37 | void Lock()
38 | {
39 | if (m_psa)
40 | {
41 | auto hr = ::SafeArrayLock(m_psa);
42 | if (FAILED(hr))
43 | {
44 | throw win32_error(hr);
45 | }
46 |
47 | auto pvData = (_Element*)m_psa->pvData;
48 | auto celt = m_psa->rgsabound[0].cElements;
49 |
50 | m_elements.assign(pvData, pvData + celt);
51 | }
52 | }
53 |
54 | void Unlock()
55 | {
56 | if (m_psa)
57 | {
58 | ::SafeArrayUnlock(m_psa);
59 | }
60 | }
61 |
62 | void Destroy()
63 | {
64 | if (m_psa)
65 | {
66 | ::SafeArrayDestroy(m_psa);
67 | }
68 | }
69 |
70 | LPSAFEARRAY m_psa;
71 | std::vector<_Element> m_elements;
72 | };
73 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Scope.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | template
9 | class Scope
10 | {
11 | public:
12 | Scope(_In_opt_ _Type* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ const std::wstring& name) :
13 | m_pParent(pParent),
14 | m_console(console),
15 | m_padding(padding),
16 | m_name(name),
17 | m_writeStart(true),
18 | m_writeEnd(false)
19 | {
20 | }
21 |
22 | Scope(_In_opt_ _Type* pParent, _In_ ::Console& console, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) :
23 | m_pParent(pParent),
24 | m_console(console),
25 | m_padding(padding),
26 | m_name(name),
27 | m_writeStart(true),
28 | m_writeEnd(false)
29 | {
30 | }
31 |
32 | Scope(_In_ const Scope& obj) :
33 | m_pParent(obj.m_pParent),
34 | m_console(obj.m_console),
35 | m_padding(obj.m_padding),
36 | m_name(obj.m_name),
37 | m_writeStart(obj.m_writeStart),
38 | m_writeEnd(obj.m_writeEnd)
39 | {
40 | }
41 |
42 | void WriteStart()
43 | {
44 | if (m_writeStart)
45 | {
46 | // Write the parent scope first (may have already been written to console).
47 | if (m_pParent)
48 | {
49 | m_pParent->WriteStart();
50 | }
51 |
52 | WriteStartImpl();
53 | m_writeStart = false;
54 | m_writeEnd = true;
55 | }
56 | }
57 |
58 | void WriteEnd()
59 | {
60 | if (m_writeEnd)
61 | {
62 | WriteEndImpl();
63 | }
64 | }
65 |
66 | protected:
67 | _Type* Parent() const noexcept
68 | {
69 | return m_pParent;
70 | }
71 |
72 | ::Console& Console() const noexcept
73 | {
74 | return m_console;
75 | }
76 |
77 | const std::wstring& Padding() const noexcept
78 | {
79 | return m_padding;
80 | }
81 |
82 | const std::wstring& Name() const noexcept
83 | {
84 | return m_name;
85 | }
86 |
87 | virtual void WriteStartImpl() = 0;
88 | virtual void WriteEndImpl() = 0;
89 |
90 | private:
91 | _Type* m_pParent;
92 | ::Console& m_console;
93 | const std::wstring m_padding;
94 | const std::wstring m_name;
95 | bool m_writeStart;
96 | bool m_writeEnd;
97 | };
98 |
--------------------------------------------------------------------------------
/src/vswhere.lib/TextFormatter.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void TextFormatter::StartArray(_In_opt_ const std::wstring& name)
11 | {
12 | m_first = true;
13 | }
14 |
15 | void TextFormatter::StartObject(_In_opt_ const wstring& name)
16 | {
17 | if (!m_first && m_scopes.empty())
18 | {
19 | Console().WriteLine();
20 | }
21 |
22 | m_first = false;
23 |
24 | if (!m_scopes.empty())
25 | {
26 | m_scopes.push(m_scopes.top() + name + L"_");
27 | }
28 | else if (!name.empty())
29 | {
30 | m_scopes.push(name + L"_");
31 | }
32 | else
33 | {
34 | m_scopes.push(name);
35 | }
36 | }
37 |
38 | void TextFormatter::WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value)
39 | {
40 | wstring prefix = L"";
41 | if (!m_scopes.empty())
42 | {
43 | prefix = m_scopes.top();
44 | }
45 |
46 | Console().Write(L"%ls%ls%ls%ls: ", Console().Color(ColorName), prefix.c_str(), name.c_str(), Console().ResetColor());
47 | Console().WriteLine(L"%ls%ls%ls", Console().Color(ColorValue), value.c_str(), Console().ResetColor());
48 | }
49 |
50 | void TextFormatter::EndObject()
51 | {
52 | m_scopes.pop();
53 | }
--------------------------------------------------------------------------------
/src/vswhere.lib/TextFormatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class TextFormatter :
9 | public Formatter
10 | {
11 | public:
12 | static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console)
13 | {
14 | return std::unique_ptr(new TextFormatter(args, console));
15 | }
16 |
17 | TextFormatter(_In_ CommandArgs& args, _In_ ::Console& console) :
18 | Formatter(args, console),
19 | m_first(false)
20 | {
21 | }
22 |
23 | TextFormatter(_In_ const TextFormatter& obj) :
24 | Formatter(obj),
25 | m_first(obj.m_first),
26 | m_scopes(obj.m_scopes)
27 | {
28 | }
29 |
30 | protected:
31 | void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override;
32 | void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override;
33 | void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override;
34 | void EndObject() override;
35 |
36 | private:
37 | bool m_first;
38 | std::stack m_scopes;
39 | };
40 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Utilities.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | std::string to_string(const std::wstring& value) {
9 | if (value.empty()) return std::string();
10 | int size_needed = WideCharToMultiByte(CP_UTF8, 0, value.data(), (int)value.size(), NULL, 0, NULL, NULL);
11 | std::string result(size_needed, 0);
12 | WideCharToMultiByte(CP_UTF8, 0, value.data(), (int)value.size(), result.data(), size_needed, NULL, NULL);
13 | return result;
14 | }
15 |
--------------------------------------------------------------------------------
/src/vswhere.lib/Utilities.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | std::string to_string(const std::wstring& value);
9 |
10 | struct ci_equal
11 | {
12 | bool operator()(const std::wstring& lhs, const std::wstring& rhs) const
13 | {
14 | return CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lhs.c_str(), lhs.size(), rhs.c_str(), rhs.size());
15 | }
16 | };
17 |
18 | struct ci_less
19 | {
20 | bool operator()(const std::wstring& lhs, const std::wstring& rhs) const
21 | {
22 | return CSTR_EQUAL > ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lhs.c_str(), lhs.size(), rhs.c_str(), rhs.size());
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/vswhere.lib/ValueFormatter.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void ValueFormatter::WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value)
11 | {
12 | Console().WriteLine(value);
13 | }
14 |
--------------------------------------------------------------------------------
/src/vswhere.lib/ValueFormatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class ValueFormatter :
9 | public Formatter
10 | {
11 | public:
12 | static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console)
13 | {
14 | return std::unique_ptr(new ValueFormatter(args, console));
15 | }
16 |
17 | ValueFormatter(_In_ CommandArgs& args, _In_ ::Console& console) :
18 | Formatter(args, console)
19 | {
20 | }
21 |
22 | ValueFormatter(_In_ const ValueFormatter& obj) :
23 | Formatter(obj)
24 | {
25 | }
26 |
27 | bool ShowLogo() const override
28 | {
29 | return false;
30 | }
31 |
32 | protected:
33 | void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override;
34 | };
35 |
--------------------------------------------------------------------------------
/src/vswhere.lib/VersionRange.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class VersionRange :
9 | public ISetupHelper
10 | {
11 | public:
12 | VersionRange() noexcept :
13 | m_ulRef(1)
14 | {
15 | }
16 |
17 | private:
18 | ~VersionRange()
19 | {
20 | }
21 |
22 | public:
23 | // IUnknown
24 | STDMETHODIMP QueryInterface(
25 | _In_ REFIID iid,
26 | _Out_ LPVOID* ppUnk
27 | )
28 | {
29 | HRESULT hr = S_OK;
30 | IUnknown* pUnk = NULL;
31 |
32 | if (!ppUnk)
33 | {
34 | return E_POINTER;
35 | }
36 |
37 | *ppUnk = NULL;
38 | if (iid == __uuidof(ISetupHelper))
39 | {
40 | pUnk = static_cast(this);
41 | }
42 | else if (iid == IID_IUnknown)
43 | {
44 | pUnk = static_cast(this);
45 | }
46 | else
47 | {
48 | hr = E_NOINTERFACE;
49 | }
50 |
51 | if (pUnk)
52 | {
53 | pUnk->AddRef();
54 | *ppUnk = pUnk;
55 | }
56 |
57 | return hr;
58 | }
59 |
60 | STDMETHODIMP_(ULONG) AddRef()
61 | {
62 | return ::InterlockedIncrement(&m_ulRef);
63 | }
64 |
65 | STDMETHODIMP_(ULONG) Release()
66 | {
67 | ULONG ulRef = ::InterlockedDecrement(&m_ulRef);
68 | if (ulRef == 0)
69 | {
70 | delete this;
71 | }
72 |
73 | return ulRef;
74 | }
75 |
76 | public:
77 | // ISetupHelper
78 | STDMETHOD(ParseVersion)(
79 | _In_ LPCOLESTR pwszVersion,
80 | _Out_ PULONGLONG pullVersion
81 | ) noexcept;
82 |
83 | STDMETHOD(ParseVersionRange)(
84 | _In_ LPCOLESTR pwszVersionRange,
85 | _Out_ PULONGLONG pullMinVersion,
86 | _Out_ PULONGLONG pullMaxVersion
87 | );
88 |
89 | static const ULONGLONG MinVersion = 0;
90 | static const ULONGLONG MaxVersion = 18446744073709551615;
91 |
92 | private:
93 | static HRESULT ParseVersionString(
94 | _In_ const LPCWSTR pwszVersionBegin,
95 | _In_ const LPCWSTR pwszVersionEnd,
96 | _Out_ PULONGLONG pullVersion
97 | );
98 |
99 | static LPWSTR Trim(
100 | _In_ const LPCWSTR pwszValue,
101 | _Out_ LPWSTR* ppwszEnd
102 | ) noexcept;
103 |
104 | ULONG m_ulRef;
105 | };
106 |
--------------------------------------------------------------------------------
/src/vswhere.lib/XmlFormatter.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | const LPCWSTR XmlFormatter::ColorTag = L"\033[38;2;86;156;214m";
11 |
12 | void XmlFormatter::StartDocument()
13 | {
14 | Console().WriteLine(
15 | L"%1$ls%4$ls",
16 | Console().Color(ColorTag),
17 | Console().Color(ColorName),
18 | Console().Color(ColorValue),
19 | Console().ResetColor());
20 | }
21 |
22 | void XmlFormatter::StartArray(_In_opt_ const wstring& name)
23 | {
24 | StartScope(name, L"instances");
25 | }
26 |
27 | void XmlFormatter::StartObject(_In_opt_ const wstring& name)
28 | {
29 | StartScope(name, L"instance");
30 | }
31 |
32 | void XmlFormatter::WriteProperty(_In_ const wstring& name, _In_ const wstring& value)
33 | {
34 | m_scopes.top().WriteStart();
35 |
36 | Console().WriteLine(
37 | L"%1$ls%4$ls<%2$ls>%5$ls%3$ls%4$ls%2$ls>%5$ls",
38 | m_padding.c_str(),
39 | name.c_str(),
40 | value.c_str(),
41 | Console().Color(ColorTag),
42 | Console().ResetColor());
43 | }
44 |
45 | void XmlFormatter::EndObject()
46 | {
47 | EndScope();
48 | }
49 |
50 | void XmlFormatter::EndArray()
51 | {
52 | EndScope();
53 | }
54 |
55 | wstring XmlFormatter::FormatDate(_In_ const FILETIME& value)
56 | {
57 | return FormatDateISO8601(value);
58 | }
59 |
60 | void XmlFormatter::Push()
61 | {
62 | m_padding += std::wstring(padding_size, L' ');
63 | }
64 |
65 | void XmlFormatter::Pop()
66 | {
67 | if (m_padding.size() > 0)
68 | {
69 | m_padding.resize(m_padding.size() - padding_size);
70 | }
71 | }
72 |
73 | void XmlFormatter::StartScope(_In_opt_ const wstring& name, _In_ std::wstring::const_pointer fallback)
74 | {
75 | XmlScope* pParent = nullptr;
76 | if (m_scopes.size())
77 | {
78 | pParent = &m_scopes.top();
79 | }
80 |
81 | if (name.empty())
82 | {
83 | m_scopes.push(XmlScope(pParent, Console(), m_padding, fallback));
84 | }
85 | else
86 | {
87 | m_scopes.push(XmlScope(pParent, Console(), m_padding, name));
88 | }
89 |
90 | // Always write the root scope.
91 | if (m_scopes.size() == 1)
92 | {
93 | m_scopes.top().WriteStart();
94 | }
95 |
96 | Push();
97 | }
98 |
99 | void XmlFormatter::EndScope()
100 | {
101 | Pop();
102 |
103 | m_scopes.top().WriteEnd();
104 | m_scopes.pop();
105 | }
106 |
--------------------------------------------------------------------------------
/src/vswhere.lib/XmlFormatter.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class XmlFormatter :
9 | public Formatter
10 | {
11 | public:
12 | static std::unique_ptr Create(_In_ CommandArgs& args, _In_ ::Console& console)
13 | {
14 | return std::unique_ptr(new XmlFormatter(args, console));
15 | }
16 |
17 | XmlFormatter(_In_ CommandArgs& args, _In_ ::Console& console) :
18 | Formatter(args, console)
19 | {
20 | }
21 |
22 | XmlFormatter(_In_ const XmlFormatter& obj) :
23 | Formatter(obj),
24 | m_padding(obj.m_padding),
25 | m_scopes(obj.m_scopes)
26 | {
27 | }
28 |
29 | bool ShowLogo() const override
30 | {
31 | return false;
32 | }
33 |
34 | bool SupportsPackages() const override
35 | {
36 | return true;
37 | }
38 |
39 | static const LPCWSTR ColorTag;
40 |
41 | protected:
42 | void StartDocument() override;
43 | void StartArray(_In_opt_ const std::wstring& name = empty_wstring) override;
44 | void StartObject(_In_opt_ const std::wstring& name = empty_wstring) override;
45 | void WriteProperty(_In_ const std::wstring& name, _In_ const std::wstring& value) override;
46 | void EndObject() override;
47 | void EndArray() override;
48 | std::wstring FormatDate(_In_ const FILETIME& value) override;
49 |
50 | private:
51 | static const size_t padding_size = 2;
52 |
53 | void Push();
54 | void Pop();
55 |
56 | void StartScope(_In_opt_ const std::wstring& name, _In_ std::wstring::const_pointer fallback);
57 | void EndScope();
58 |
59 | std::wstring m_padding;
60 | std::stack m_scopes;
61 | };
62 |
--------------------------------------------------------------------------------
/src/vswhere.lib/XmlScope.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace std;
9 |
10 | void XmlScope::WriteStartImpl()
11 | {
12 | Console().Write(Padding());
13 | Console().WriteLine(L"%ls<%ls>%ls", Console().Color(XmlFormatter::ColorTag), Name().c_str(), Console().ResetColor());
14 | }
15 |
16 | void XmlScope::WriteEndImpl()
17 | {
18 | Console().Write(Padding());
19 | Console().WriteLine(L"%ls%ls>%ls", Console().Color(XmlFormatter::ColorTag), Name().c_str(), Console().ResetColor());
20 | }
21 |
--------------------------------------------------------------------------------
/src/vswhere.lib/XmlScope.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | class XmlScope :
9 | public Scope
10 | {
11 | public:
12 | XmlScope(_In_opt_ XmlScope* pParent, _In_ ::Console& console, _In_ const std::wstring& padding, _In_ const std::wstring& name) :
13 | Scope(pParent, console, padding, name)
14 | {
15 | }
16 |
17 | XmlScope(_In_opt_ XmlScope* pParent, _In_ ::Console& console, _In_ std::wstring& padding, _In_ std::wstring::const_pointer name) :
18 | Scope(pParent, console, padding, name)
19 | {
20 | }
21 |
22 | XmlScope(_In_ const XmlScope& obj) :
23 | Scope(obj)
24 | {
25 | }
26 |
27 | protected:
28 | void WriteStartImpl() override;
29 | void WriteEndImpl() override;
30 | };
31 |
--------------------------------------------------------------------------------
/src/vswhere.lib/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/vswhere.lib/resource.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/vswhere/f1ecd0826a66cdfc843eec5bfd651b085d5328df/src/vswhere.lib/resource.h
--------------------------------------------------------------------------------
/src/vswhere.lib/stdafx.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #include "stdafx.h"
7 |
--------------------------------------------------------------------------------
/src/vswhere.lib/stdafx.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (C) Microsoft Corporation. All rights reserved.
3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information.
4 | //
5 |
6 | #pragma once
7 |
8 | #include "targetver.h"
9 |
10 | #define WIN32_LEAN_AND_MEAN
11 |
12 | // Windows headers
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | // CRT header files
19 | #include
20 |
21 | // COM support header files
22 | #include
23 | #include
24 |
25 | // STL headers
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include