Skip to content

Commit 5fa61e8

Browse files
authored
Merge pull request #107 from Microsoft/develop
Release 2.2
2 parents 03a4081 + b8ad2da commit 5fa61e8

38 files changed

+1440
-161
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@ Contributing
55

66
This project uses the following software. Newer versions may work but backward compatibility must be maintained.
77

8-
* [Visual Studio 2015](https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs.aspx)
9-
10-
### Optional
11-
12-
Some projects require optional software to open or otherwise use in Visual Studio. They are not required to build the solution using MSBuild.
13-
14-
* [NuProj Package Project](https://marketplace.visualstudio.com/items?itemName=NuProjTeam.NuGetPackageProject)
8+
* [Visual Studio 2017](https://www.visualstudio.com/downloads/) or newer
159

1610
## Coding
1711

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (C) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT license. See LICENSE.txt in the project root for license information.
33

4-
FROM heaths/vssetup:1.11.2290
4+
FROM heaths/vssetup:latest
55
SHELL ["powershell.exe", "-ExecutionPolicy", "Bypass", "-Command"]
66

77
# Download and install Remote Debugger

docker/Tests/vswhere.tests.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ Describe 'vswhere' {
219219
$instance.channelId | Should Be 'VisualStudio.15.Release/public.d15rel/15.0.26117.0'
220220
$instance.enginePath | Should Be 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\resources\app\ServiceHub\Services\Microsoft.VisualStudio.Setup.Service'
221221
}
222+
223+
It '-property productId' {
224+
$instances = C:\bin\vswhere.exe -latest -property productId -format json | ConvertFrom-Json
225+
$instances.Count | Should Be 1
226+
$instances[0].productId | Should Be 'Microsoft.VisualStudio.Product.Enterprise'
227+
}
228+
229+
It '-property productPath' {
230+
$instances = C:\bin\vswhere.exe -latest -property productPath -format json | ConvertFrom-Json
231+
$instances.Count | Should Be 1
232+
$instances[0].productPath | Should Be 'C:\VS\Enterprise\Common7\IDE\devenv.exe'
233+
}
222234
}
223235

224236
Context '-latest -all' {

docker/appveyor/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44
# Would prefer to only use "image" in docker-compose.yml, but AppVeyor version of docker-compose fails
55
# stating that a "Dockerfile" in the current directory does not exist.
6-
FROM heaths/vssetup:1.11.2290
6+
FROM heaths/vssetup:latest

inc/Common.Cpp.targets

Lines changed: 0 additions & 56 deletions
This file was deleted.

inc/VersionInfo.props

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ImportGroup Label="PropertySheets" />
4+
<PropertyGroup Label="UserMacros" />
5+
<PropertyGroup>
6+
<AssemblyCompany>Microsoft Corporation</AssemblyCompany>
7+
<AssemblyProduct>Visual Studio Setup</AssemblyProduct>
8+
<AssemblyCopyright>Copyright (C) Microsoft Corporation. All rights reserved.</AssemblyCopyright>
9+
</PropertyGroup>
10+
<ItemDefinitionGroup>
11+
<ClCompile>
12+
<AdditionalIncludeDirectories>$(IntermediateOutputPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
13+
</ClCompile>
14+
<ResourceCompile>
15+
<AdditionalIncludeDirectories>$(IntermediateOutputPath);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
16+
</ResourceCompile>
17+
</ItemDefinitionGroup>
18+
<ItemGroup />
19+
</Project>

src/vswhere.lib/Formatter.cpp

Lines changed: 121 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
using namespace std;
99
using namespace std::placeholders;
1010

11+
const std::wstring Formatter::empty_wstring;
12+
1113
Formatter::Formatter()
1214
{
1315
m_properties =
@@ -17,6 +19,8 @@ Formatter::Formatter()
1719
{ L"installationName", bind(&Formatter::GetInstallationName, this, _1, _2) },
1820
{ L"installationPath", bind(&Formatter::GetInstallationPath, this, _1, _2) },
1921
{ L"installationVersion", bind(&Formatter::GetInstallationVersion, this, _1, _2) },
22+
{ L"productId", bind(&Formatter::GetProductId, this, _1, _2) },
23+
{ L"productPath", bind(&Formatter::GetProductPath, this, _1, _2) },
2024
{ L"isPrerelease", bind(&Formatter::GetIsPrerelease, this, _1, _2) },
2125
{ L"displayName", bind(&Formatter::GetDisplayName, this, _1, _2) },
2226
{ L"description", bind(&Formatter::GetDescription, this, _1, _2) },
@@ -31,6 +35,7 @@ Formatter::FormatterMap Formatter::Formatters =
3135
{ L"xml", make_tuple(IDS_FORMAT_XML, XmlFormatter::Create) },
3236
};
3337

38+
const wstring Formatter::s_delims(L"./_");
3439
ci_equal Formatter::s_comparer;
3540

3641
std::unique_ptr<Formatter> Formatter::Create(const std::wstring& type)
@@ -111,6 +116,7 @@ wstring Formatter::FormatDate(_In_ const FILETIME& value)
111116
throw win32_error();
112117
}
113118

119+
date.reserve(cch);
114120
date.resize(cch - 1);
115121
cch = ::GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, const_cast<LPWSTR>(date.c_str()), cch);
116122
if (!cch)
@@ -125,7 +131,8 @@ wstring Formatter::FormatDate(_In_ const FILETIME& value)
125131
throw win32_error();
126132
}
127133

128-
time.reserve(cch - 1);
134+
time.reserve(cch);
135+
time.resize(cch - 1);
129136
cch = ::GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, const_cast<LPWSTR>(time.c_str()), cch);
130137
if (!cch)
131138
{
@@ -161,7 +168,28 @@ void Formatter::WriteInternal(_In_ const CommandArgs& args, _In_ Console& consol
161168

162169
if (specified.empty() || !found)
163170
{
164-
WriteProperties(args, console, pInstance);
171+
found = WriteProperties(args, console, pInstance);
172+
if (specified.empty() || !found)
173+
{
174+
ISetupInstance2Ptr instance2;
175+
176+
auto hr = pInstance->QueryInterface(&instance2);
177+
if (SUCCEEDED(hr))
178+
{
179+
ISetupPropertyStorePtr store;
180+
181+
hr = instance2->GetProperties(&store);
182+
if (SUCCEEDED(hr) && !!store)
183+
{
184+
wstring name(L"properties");
185+
StartObject(console, name);
186+
187+
WriteProperties(args, console, store, name);
188+
189+
EndObject(console);
190+
}
191+
}
192+
}
165193
}
166194

167195
EndObject(console);
@@ -191,12 +219,11 @@ void Formatter::WriteProperty(_In_ Console& console, _In_ const wstring& name, _
191219
}
192220
}
193221

194-
void Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance)
222+
bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance)
195223
{
196224
_ASSERTE(pInstance);
197225

198226
ISetupPropertyStorePtr store;
199-
LPSAFEARRAY psaNames = NULL;
200227

201228
auto hr = pInstance->QueryInterface(&store);
202229
if (FAILED(hr))
@@ -206,36 +233,67 @@ void Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& cons
206233
throw win32_error(hr);
207234
}
208235

209-
return;
236+
return false;
210237
}
211238

212-
hr = store->GetNames(&psaNames);
239+
return WriteProperties(args, console, store);
240+
}
241+
242+
bool Formatter::WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupPropertyStore* pProperties, _In_opt_ const wstring& prefix)
243+
{
244+
_ASSERTE(pProperties);
245+
246+
LPSAFEARRAY psaNames = NULL;
247+
auto found = false;
248+
249+
auto hr = pProperties->GetNames(&psaNames);
213250
if (FAILED(hr))
214251
{
215-
return;
252+
return false;
216253
}
217254

218-
const auto& specified = args.get_Property();
219-
SafeArray<BSTR> saNames(psaNames);
255+
// Trim optional nested object name from specified property if matching current scope.
256+
wstring specified = args.get_Property();
257+
if (prefix.size() > 0)
258+
{
259+
auto pos = specified.find_first_of(s_delims);
260+
if (pos != wstring::npos && (pos + 1) < specified.size() && s_comparer(prefix, specified.substr(0, pos)))
261+
{
262+
specified = specified.substr(pos + 1);
263+
}
264+
else if (s_comparer(prefix, specified))
265+
{
266+
// If the current nested object name is specified, clear the prefix to show the whole nested object.
267+
specified.clear();
268+
}
269+
}
220270

271+
SafeArray<BSTR> saNames(psaNames);
221272
for (const auto& bstrName : saNames.Elements())
222273
{
223274
wstring name(bstrName);
224-
if (specified.empty() || s_comparer(name, specified))
275+
if (specified.empty() || (found = s_comparer(name, specified)))
225276
{
226277
variant_t vtValue;
227278

228279
auto it = find_if(m_properties.begin(), m_properties.end(), bind(Formatter::PropertyEqual, name, _1));
229280
if (it == m_properties.end())
230281
{
231-
hr = store->GetValue(bstrName, vtValue.GetAddress());
282+
hr = pProperties->GetValue(bstrName, vtValue.GetAddress());
232283
if (SUCCEEDED(hr))
233284
{
234285
WriteProperty(console, name, vtValue);
235286
}
236287
}
288+
289+
if (found)
290+
{
291+
return true;
292+
}
237293
}
238294
}
295+
296+
return false;
239297
}
240298

241299
bool Formatter::PropertyEqual(_In_ const std::wstring& name, _In_ PropertyArray::const_reference property)
@@ -305,6 +363,58 @@ HRESULT Formatter::GetInstallationVersion(_In_ ISetupInstance* pInstance, _Out_
305363
return GetStringProperty(bind(&ISetupInstance::GetInstallationVersion, pInstance, _1), pvtInstallationVersion);
306364
}
307365

366+
HRESULT Formatter::GetProductId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductId)
367+
{
368+
ISetupInstance2Ptr instance;
369+
370+
auto hr = pInstance->QueryInterface(&instance);
371+
if (SUCCEEDED(hr))
372+
{
373+
ISetupPackageReferencePtr reference;
374+
375+
hr = instance->GetProduct(&reference);
376+
if (SUCCEEDED(hr))
377+
{
378+
variant_t vt;
379+
380+
hr = reference->GetId(&vt.bstrVal);
381+
if (SUCCEEDED(hr))
382+
{
383+
vt.vt = VT_BSTR;
384+
*pvtProductId = vt.Detach();
385+
}
386+
}
387+
}
388+
389+
return hr;
390+
}
391+
392+
HRESULT Formatter::GetProductPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductPath)
393+
{
394+
ISetupInstance2Ptr instance;
395+
396+
auto hr = pInstance->QueryInterface(&instance);
397+
if (SUCCEEDED(hr))
398+
{
399+
bstr_t bstrProductPath;
400+
401+
hr = instance->GetProductPath(bstrProductPath.GetAddress());
402+
if (SUCCEEDED(hr))
403+
{
404+
variant_t vt;
405+
406+
hr = instance->ResolvePath(bstrProductPath, &vt.bstrVal);
407+
if (SUCCEEDED(hr))
408+
{
409+
vt.vt = VT_BSTR;
410+
*pvtProductPath = vt.Detach();
411+
}
412+
}
413+
}
414+
415+
return hr;
416+
}
417+
308418
HRESULT Formatter::GetIsPrerelease(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsPrerelease)
309419
{
310420
ISetupInstanceCatalogPtr catalog;

src/vswhere.lib/Formatter.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ class Formatter
3131
typedef std::function<HRESULT(_In_ ISetupInstance*, _Out_ VARIANT*)> PropertyFunction;
3232
typedef std::vector<std::pair<std::wstring, PropertyFunction>> PropertyArray;
3333

34+
static const std::wstring empty_wstring;
35+
3436
Formatter();
3537

3638
static std::wstring FormatDateISO8601(_In_ const FILETIME& value);
3739

3840
virtual void StartDocument(_In_ Console& console) {}
3941
virtual void StartArray(_In_ Console& console) {}
40-
virtual void StartObject(_In_ Console& console) {}
42+
virtual void StartObject(_In_ Console& console, _In_opt_ const std::wstring& name = empty_wstring) {}
4143
virtual void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const std::wstring& value) {}
4244
virtual void EndObject(_In_ Console& console) {}
4345
virtual void EndArray(_In_ Console& console) {}
@@ -59,21 +61,24 @@ class Formatter
5961
static bool PropertyEqual(_In_ const std::wstring& name, _In_ PropertyArray::const_reference property);
6062
static HRESULT GetStringProperty(_In_ std::function<HRESULT(_Out_ BSTR*)> pfn, _Out_ VARIANT* pvt);
6163

64+
static const std::wstring s_delims;
6265
static ci_equal s_comparer;
6366

6467
HRESULT GetInstanceId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstanceId);
6568
HRESULT GetInstallDate(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallDate);
6669
HRESULT GetInstallationName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationName);
6770
HRESULT GetInstallationPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationPath);
6871
HRESULT GetInstallationVersion(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationVersion);
72+
HRESULT GetProductId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductId);
73+
HRESULT GetProductPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductPath);
6974
HRESULT GetIsPrerelease(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsPrerelease);
7075
HRESULT GetDisplayName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDisplayName);
7176
HRESULT GetDescription(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDescription);
7277

73-
7478
void WriteInternal(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
7579
void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const variant_t& value);
76-
void WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
80+
bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
81+
bool WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupPropertyStore* pProperties, _In_opt_ const std::wstring& prefix = empty_wstring);
7782

7883
PropertyArray m_properties;
7984
};

0 commit comments

Comments
 (0)