terminal/src/cascadia/TerminalSettingsModel/VsSetupConfiguration.cpp
Heath Stewart 37e8769b37
Show only latest VS, VC prompts by default (#11326)
## Summary of the Pull Request

Similar to `vswhere -latest`, show only the latest Visual Studio command prompts / developer PowerShell. This was tested by deleting the local package state and testing against fresh state with both VS2019 and VS2022 Preview installed, and indeed VS2022 Preview (both cmd and powershell) show. The other profiles were generated but hidden by default.

## References

Modification of PR #7774

## PR Checklist
* [x] Closes #11307
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

The sort algorithm is the same basic algorithm I used in https://github.com/microsoft/vswhere. It sorts first by installation version with a secondary sort based on the install date in case the installation versions are the same.

## Validation Steps Performed

With both VS2019 and VS2022 Preview installed, I made sure the initial state was expected, and tried different combinations of hiding and unhiding generated entries, and restarted Terminal to make sure my settings "stuck".
2021-09-29 22:03:05 +00:00

133 lines
4.5 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "VsSetupConfiguration.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryInstances()
{
std::vector<VsSetupInstance> instances;
// SetupConfiguration is only registered if Visual Studio is installed
ComPtrSetupQuery pQuery{ wil::CoCreateInstanceNoThrow<SetupConfiguration, ISetupConfiguration2>() };
if (pQuery == nullptr)
{
return instances;
}
// Enumerate all valid instances of Visual Studio
wil::com_ptr<IEnumSetupInstances> e;
THROW_IF_FAILED(pQuery->EnumInstances(&e));
ComPtrSetupInstance rgpInstance;
auto result = e->Next(1, &rgpInstance, nullptr);
while (S_OK == result)
{
// wrap the COM pointers in a friendly interface
instances.emplace_back(VsSetupInstance{ pQuery, rgpInstance });
result = e->Next(1, &rgpInstance, nullptr);
}
THROW_IF_FAILED(result);
// Sort instances based on version and install date from latest to oldest.
std::sort(instances.begin(), instances.end(), [](const VsSetupInstance& a, const VsSetupInstance& b) {
auto const aVersion = a.GetComparableVersion();
auto const bVersion = b.GetComparableVersion();
if (aVersion == bVersion)
{
return a.GetComparableInstallDate() > b.GetComparableInstallDate();
}
return aVersion > bVersion;
});
return instances;
}
/// <summary>
/// Takes a relative path under a Visual Studio installation and returns the absolute path.
/// </summary>
std::wstring VsSetupConfiguration::ResolvePath(ISetupInstance* pInst, std::wstring_view relativePath)
{
wil::unique_bstr bstrAbsolutePath;
THROW_IF_FAILED(pInst->ResolvePath(relativePath.data(), &bstrAbsolutePath));
return bstrAbsolutePath.get();
}
/// <summary>
/// Determines whether a Visual Studio installation version falls within a specified range.
/// The range is specified as a string, ex: "[15.0.0.0,)", "[15.0.0.0, 16.7.0.0)
/// </summary>
bool VsSetupConfiguration::InstallationVersionInRange(ISetupConfiguration2* pQuery, ISetupInstance* pInst, std::wstring_view range)
{
const auto helper = wil::com_query<ISetupHelper>(pQuery);
// VS versions in a string format such as "16.3.0.0" can be easily compared
// by parsing them into 64-bit unsigned integers using the stable algorithm
// provided by ParseVersion and ParseVersionRange
unsigned long long minVersion{ 0 };
unsigned long long maxVersion{ 0 };
THROW_IF_FAILED(helper->ParseVersionRange(range.data(), &minVersion, &maxVersion));
wil::unique_bstr bstrVersion;
THROW_IF_FAILED(pInst->GetInstallationVersion(&bstrVersion));
unsigned long long ullVersion{ 0 };
THROW_IF_FAILED(helper->ParseVersion(bstrVersion.get(), &ullVersion));
return ullVersion >= minVersion && ullVersion <= maxVersion;
}
std::wstring VsSetupConfiguration::GetInstallationVersion(ISetupInstance* pInst)
{
wil::unique_bstr bstrInstallationVersion;
THROW_IF_FAILED(pInst->GetInstallationVersion(&bstrInstallationVersion));
return bstrInstallationVersion.get();
}
std::wstring VsSetupConfiguration::GetInstallationPath(ISetupInstance* pInst)
{
wil::unique_bstr bstrInstallationPath;
THROW_IF_FAILED(pInst->GetInstallationPath(&bstrInstallationPath));
return bstrInstallationPath.get();
}
/// <summary>
/// The instance id is unique for each Visual Studio installation on a system.
/// The instance id is generated by the Visual Studio setup engine and varies from system to system.
/// </summary>
std::wstring VsSetupConfiguration::GetInstanceId(ISetupInstance* pInst)
{
wil::unique_bstr bstrInstanceId;
THROW_IF_FAILED(pInst->GetInstanceId(&bstrInstanceId));
return bstrInstanceId.get();
}
unsigned long long VsSetupConfiguration::GetInstallDate(ISetupInstance* pInst)
{
FILETIME ftInstallDate{ 0 };
THROW_IF_FAILED(pInst->GetInstallDate(&ftInstallDate));
return wil::filetime::to_int64(ftInstallDate);
}
std::wstring VsSetupConfiguration::GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name)
{
if (pProps == nullptr)
{
return std::wstring{};
}
wil::unique_variant var;
if (FAILED(pProps->GetValue(name.data(), &var)))
{
return std::wstring{};
}
return var.bstrVal;
}