terminal/src/cascadia/TerminalSettingsModel/VsSetupConfiguration.h

235 lines
8.3 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- VsSetupConfiguration
Abstract:
- Encapsulates the Visual Studio Setup Configuration COM APIs
Author(s):
- Charles Willis - October 2020
--*/
#pragma once
#include "Setup.Configuration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
/// <summary>
/// See https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2019
/// </summary>
class VsSetupConfiguration
{
typedef wil::com_ptr<ISetupConfiguration2> ComPtrSetupQuery;
typedef wil::com_ptr<ISetupHelper> ComPtrSetupHelper;
typedef wil::com_ptr<ISetupInstance> ComPtrSetupInstance;
typedef wil::com_ptr<ISetupInstance2> ComPtrSetupInstance2;
typedef wil::com_ptr<ISetupPropertyStore> ComPtrPropertyStore;
typedef wil::com_ptr<ISetupPackageReference> ComPtrPackageReference;
typedef wil::com_ptr<ISetupInstanceCatalog> ComPtrInstanceCatalog;
typedef ComPtrPropertyStore ComPtrCustomPropertyStore;
typedef ComPtrPropertyStore ComPtrCatalogPropertyStore;
public:
struct VsSetupInstance
{
std::wstring ResolvePath(std::wstring_view relativePath) const
{
return VsSetupConfiguration::ResolvePath(inst.get(), relativePath);
}
std::wstring GetDevShellModulePath() const
{
// The path of Microsoft.VisualStudio.DevShell.dll changed in 16.3
if (VersionInRange(L"[16.3,"))
{
return ResolvePath(L"Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll");
}
return ResolvePath(L"Common7\\Tools\\vsdevshell\\Microsoft.VisualStudio.DevShell.dll");
}
std::wstring GetDevCmdScriptPath() const
{
return ResolvePath(L"Common7\\Tools\\VsDevCmd.bat");
}
bool VersionInRange(std::wstring_view range) const
{
return InstallationVersionInRange(query.get(), inst.get(), range);
}
std::wstring GetVersion() const
{
return GetInstallationVersion(inst.get());
}
std::wstring GetInstallationPath() const
{
return VsSetupConfiguration::GetInstallationPath(inst.get());
}
std::wstring GetInstanceId() const
{
return VsSetupConfiguration::GetInstanceId(inst.get());
}
ComPtrPropertyStore GetInstancePropertyStore() const
{
ComPtrPropertyStore properties;
inst.query_to<ISetupPropertyStore>(&properties);
return properties;
}
ComPtrCustomPropertyStore GetCustomPropertyStore() const
{
ComPtrSetupInstance2 instance2;
inst.query_to<ISetupInstance2>(&instance2);
ComPtrCustomPropertyStore properties;
if (FAILED(instance2->GetProperties(&properties)))
{
return nullptr;
}
return properties;
}
ComPtrCatalogPropertyStore GetCatalogPropertyStore() const
{
ComPtrInstanceCatalog instanceCatalog;
inst.query_to<ISetupInstanceCatalog>(&instanceCatalog);
ComPtrCatalogPropertyStore properties;
if (FAILED(instanceCatalog->GetCatalogInfo(&properties)))
{
return nullptr;
}
return properties;
}
std::wstring GetProfileNameSuffix() const
{
return profileNameSuffix;
}
private:
friend class VsSetupConfiguration;
VsSetupInstance(ComPtrSetupQuery pQuery, ComPtrSetupInstance pInstance) :
query(std::move(pQuery)),
inst(std::move(pInstance)),
profileNameSuffix(BuildProfileNameSuffix())
{
}
ComPtrSetupQuery query;
ComPtrSetupInstance inst;
std::wstring profileNameSuffix;
std::wstring BuildProfileNameSuffix() const
{
ComPtrCatalogPropertyStore catalogProperties = GetCatalogPropertyStore();
if (catalogProperties != nullptr)
{
std::wstring suffix;
std::wstring productLine{ GetProductLineVersion(catalogProperties.get()) };
suffix.append(productLine);
ComPtrCustomPropertyStore customProperties = GetCustomPropertyStore();
if (customProperties != nullptr)
{
std::wstring nickname{ GetNickname(customProperties.get()) };
if (!nickname.empty())
{
suffix.append(L" (" + nickname + L")");
}
else
{
ComPtrPropertyStore instanceProperties = GetInstancePropertyStore();
suffix.append(GetChannelNameSuffixTag(instanceProperties.get()));
}
}
else
{
ComPtrPropertyStore instanceProperties = GetInstancePropertyStore();
suffix.append(GetChannelNameSuffixTag(instanceProperties.get()));
}
return suffix;
}
return GetVersion();
}
static std::wstring GetChannelNameSuffixTag(ISetupPropertyStore* instanceProperties)
{
std::wstring tag;
std::wstring channelName{ GetChannelName(instanceProperties) };
if (channelName.empty())
{
return channelName;
}
if (channelName != L"Release")
{
tag.append(L" [" + channelName + L"]");
}
return tag;
}
static std::wstring GetChannelId(ISetupPropertyStore* instanceProperties)
{
return GetStringProperty(instanceProperties, L"channelId");
}
static std::wstring GetChannelName(ISetupPropertyStore* instanceProperties)
{
std::wstring channelId{ GetChannelId(instanceProperties) };
if (channelId.empty())
{
return channelId;
}
std::wstring channelName;
// channelId is in the format <ProductName>.<MajorVersion>.<ChannelName>
size_t pos = channelId.rfind(L".");
if (pos != std::wstring::npos)
{
channelName.append(channelId.substr(pos + 1));
}
return channelName;
}
static std::wstring GetNickname(ISetupPropertyStore* customProperties)
{
return GetStringProperty(customProperties, L"nickname");
}
static std::wstring GetProductLineVersion(ISetupPropertyStore* customProperties)
{
return GetStringProperty(customProperties, L"productLineVersion");
}
};
static std::vector<VsSetupInstance> QueryInstances();
private:
static bool InstallationVersionInRange(ISetupConfiguration2* pQuery, ISetupInstance* pInst, std::wstring_view range);
static std::wstring ResolvePath(ISetupInstance* pInst, std::wstring_view relativePath);
static std::wstring GetInstallationVersion(ISetupInstance* pInst);
static std::wstring GetInstallationPath(ISetupInstance* pInst);
static std::wstring GetInstanceId(ISetupInstance* pInst);
static std::wstring GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name);
};
};