Skip to content

Commit 05d412d

Browse files
committed
Write productId and productPath to output
Partly resolves #104
1 parent 079cd80 commit 05d412d

File tree

7 files changed

+157
-4
lines changed

7 files changed

+157
-4
lines changed

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' {

src/vswhere.lib/Formatter.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Formatter::Formatter()
1717
{ L"installationName", bind(&Formatter::GetInstallationName, this, _1, _2) },
1818
{ L"installationPath", bind(&Formatter::GetInstallationPath, this, _1, _2) },
1919
{ L"installationVersion", bind(&Formatter::GetInstallationVersion, this, _1, _2) },
20+
{ L"productId", bind(&Formatter::GetProductId, this, _1, _2) },
21+
{ L"productPath", bind(&Formatter::GetProductPath, this, _1, _2) },
2022
{ L"isPrerelease", bind(&Formatter::GetIsPrerelease, this, _1, _2) },
2123
{ L"displayName", bind(&Formatter::GetDisplayName, this, _1, _2) },
2224
{ L"description", bind(&Formatter::GetDescription, this, _1, _2) },
@@ -305,6 +307,58 @@ HRESULT Formatter::GetInstallationVersion(_In_ ISetupInstance* pInstance, _Out_
305307
return GetStringProperty(bind(&ISetupInstance::GetInstallationVersion, pInstance, _1), pvtInstallationVersion);
306308
}
307309

310+
HRESULT Formatter::GetProductId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductId)
311+
{
312+
ISetupInstance2Ptr instance;
313+
314+
auto hr = pInstance->QueryInterface(&instance);
315+
if (SUCCEEDED(hr))
316+
{
317+
ISetupPackageReferencePtr reference;
318+
319+
hr = instance->GetProduct(&reference);
320+
if (SUCCEEDED(hr))
321+
{
322+
variant_t vt;
323+
324+
hr = reference->GetId(&vt.bstrVal);
325+
if (SUCCEEDED(hr))
326+
{
327+
vt.vt = VT_BSTR;
328+
*pvtProductId = vt.Detach();
329+
}
330+
}
331+
}
332+
333+
return hr;
334+
}
335+
336+
HRESULT Formatter::GetProductPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductPath)
337+
{
338+
ISetupInstance2Ptr instance;
339+
340+
auto hr = pInstance->QueryInterface(&instance);
341+
if (SUCCEEDED(hr))
342+
{
343+
bstr_t bstrProductPath;
344+
345+
hr = instance->GetProductPath(bstrProductPath.GetAddress());
346+
if (SUCCEEDED(hr))
347+
{
348+
variant_t vt;
349+
350+
hr = instance->ResolvePath(bstrProductPath, &vt.bstrVal);
351+
if (SUCCEEDED(hr))
352+
{
353+
vt.vt = VT_BSTR;
354+
*pvtProductPath = vt.Detach();
355+
}
356+
}
357+
}
358+
359+
return hr;
360+
}
361+
308362
HRESULT Formatter::GetIsPrerelease(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsPrerelease)
309363
{
310364
ISetupInstanceCatalogPtr catalog;

src/vswhere.lib/Formatter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ class Formatter
6666
HRESULT GetInstallationName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationName);
6767
HRESULT GetInstallationPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationPath);
6868
HRESULT GetInstallationVersion(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtInstallationVersion);
69+
HRESULT GetProductId(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductId);
70+
HRESULT GetProductPath(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtProductPath);
6971
HRESULT GetIsPrerelease(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtIsPrerelease);
7072
HRESULT GetDisplayName(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDisplayName);
7173
HRESULT GetDescription(_In_ ISetupInstance* pInstance, _Out_ VARIANT* pvtDescription);
7274

73-
7475
void WriteInternal(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);
7576
void WriteProperty(_In_ Console& console, _In_ const std::wstring& name, _In_ const variant_t& value);
7677
void WriteProperties(_In_ const CommandArgs& args, _In_ Console& console, _In_ ISetupInstance* pInstance);

test/vswhere.test/TestInstance.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#pragma once
77

8-
98
class TestInstance :
109
public ISetupInstance2
1110
{
@@ -151,7 +150,34 @@ class TestInstance :
151150
_Out_ BSTR* pbstrAbsolutePath
152151
)
153152
{
154-
return E_NOTIMPL;
153+
if (!pbstrAbsolutePath)
154+
{
155+
return E_POINTER;
156+
}
157+
158+
bstr_t bstrPath;
159+
160+
auto hr = GetInstallationPath(bstrPath.GetAddress());
161+
if (SUCCEEDED(hr))
162+
{
163+
std::experimental::filesystem::v1::path absolutePath((LPWSTR)bstrPath);
164+
165+
hr = GetProductPath(bstrPath.GetAddress());
166+
if (SUCCEEDED(hr))
167+
{
168+
absolutePath.append((LPWSTR)bstrPath);
169+
170+
*pbstrAbsolutePath = ::SysAllocString(absolutePath.c_str());
171+
if (!*pbstrAbsolutePath)
172+
{
173+
return E_OUTOFMEMORY;
174+
}
175+
176+
return S_OK;
177+
}
178+
}
179+
180+
return E_FAIL;
155181
}
156182

157183
// ISetupInstance2
@@ -277,6 +303,10 @@ class TestInstance :
277303
if (SUCCEEDED(hr))
278304
{
279305
*pbstrValue = ::SysAllocString(value.c_str());
306+
if (!*pbstrValue)
307+
{
308+
return E_OUTOFMEMORY;
309+
}
280310
}
281311

282312
return hr;

test/vswhere.test/TextFormatterTests.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,59 @@ TEST_CLASS(TextFormatterTests)
6767

6868
Assert::AreEqual(expected, console);
6969
}
70+
71+
BEGIN_TEST_METHOD_ATTRIBUTE(Writes_ProductId)
72+
TEST_WORKITEM(104)
73+
END_TEST_METHOD_ATTRIBUTE()
74+
TEST_METHOD(Writes_ProductId)
75+
{
76+
CommandArgs args;
77+
TestConsole console(args);
78+
79+
TestPackageReference product =
80+
{
81+
{ L"Id", L"Microsoft.VisualStudio.Product.Enterprise" },
82+
};
83+
84+
TestInstance::MapType properties =
85+
{
86+
{ L"InstanceId", L"a1b2c3" },
87+
};
88+
89+
TestInstance instance(&product, {}, properties);
90+
91+
TextFormatter sut;
92+
sut.Write(args, console, &instance);
93+
94+
auto expected =
95+
L"instanceId: a1b2c3\n"
96+
L"productId: Microsoft.VisualStudio.Product.Enterprise\n";
97+
98+
Assert::AreEqual(expected, console);
99+
}
100+
101+
BEGIN_TEST_METHOD_ATTRIBUTE(Writes_ProductPath)
102+
TEST_WORKITEM(104)
103+
END_TEST_METHOD_ATTRIBUTE()
104+
TEST_METHOD(Writes_ProductPath)
105+
{
106+
CommandArgs args;
107+
TestConsole console(args);
108+
TestInstance instance =
109+
{
110+
{ L"InstanceId", L"a1b2c3" },
111+
{ L"InstallationPath", L"C:\\ShouldNotExist" },
112+
{ L"ProductPath", L"Common7\\IDE\\devenv.exe" },
113+
};
114+
115+
TextFormatter sut;
116+
sut.Write(args, console, &instance);
117+
118+
auto expected =
119+
L"instanceId: a1b2c3\n"
120+
L"installationPath: C:\\ShouldNotExist\n"
121+
L"productPath: C:\\ShouldNotExist\\Common7\\IDE\\devenv.exe\n";
122+
123+
Assert::AreEqual(expected, console);
124+
}
70125
};

test/vswhere.test/stdafx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <windows.h>
1515

1616
// STL headers
17+
#include <filesystem>
1718
#include <unordered_map>
1819

1920
// Project headers

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3-
"version": "2.1",
3+
"version": "2.2",
44
"publicReleaseRefSpec": [
55
"^refs/heads/master$",
66
"^refs/heads/release/",

0 commit comments

Comments
 (0)