Last active
August 22, 2018 07:45
-
-
Save vbfox/5c8aad940132ad7a762c1d7024ffb0ec to your computer and use it in GitHub Desktop.
F# vswhere
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Microsoft.VisualStudio.Setup.Configuration.Interop.dll | |
module VsInstances = | |
open System.Runtime.InteropServices | |
[<Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupInstance = | |
abstract member GetInstanceId: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallDate: unit -> [<MarshalAs(UnmanagedType.Struct)>] System.Runtime.InteropServices.ComTypes.FILETIME | |
abstract member GetInstallationName : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallationPath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallationVersion : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDisplayName : [<MarshalAs(UnmanagedType.U4)>][<In>] lcid: int -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDescription : [<MarshalAs(UnmanagedType.U4)>][<In>] lcid: int -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member ResolvePath : [<MarshalAs(UnmanagedType.LPWStr)>][<In>] pwszRelativePath: string -> [<MarshalAs(UnmanagedType.BStr)>] string | |
[<Flags>] | |
type InstanceState = | |
| None = 0u | |
| Local = 1u | |
| Registered = 2u | |
| NoRebootRequired = 4u | |
| NoErrors = 8u | |
| Complete = 0xFFFFFFFFu | |
[<Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupPackageReference = | |
abstract member GetId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetVersion : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetChip : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetLanguage : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetBranch : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetType : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetUniqueId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetIsExtension : unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
[<Guid("E73559CD-7003-4022-B134-27DC650B280F")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupFailedPackageReference = | |
inherit ISetupPackageReference | |
abstract member GetId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetVersion : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetChip : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetLanguage : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetBranch : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetType : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetUniqueId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetIsExtension : unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
[<Guid("E73559CD-7003-4022-B134-27DC650B280F")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupFailedPackageReference2 = | |
inherit ISetupFailedPackageReference | |
abstract member GetId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetVersion : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetChip : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetLanguage : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetBranch : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetType : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetUniqueId : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetIsExtension : unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
abstract member GetLogFilePath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDescription : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetSignature : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDetails: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)>] string[] | |
abstract member GetAffectedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupPackageReference[] | |
[<Guid("2A2F3292-958E-4905-B36E-013BE84E27AB")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupErrorInfo = | |
abstract member GetErrorHResult: unit -> int | |
abstract member GetErrorClassName: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetErrorMessage: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
[<Guid("46DCCD94-A287-476A-851E-DFBC2FFDBC20")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupErrorState = | |
abstract member GetFailedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupFailedPackageReference[] | |
abstract member GetSkippedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupPackageReference[] | |
[<Guid("9871385B-CA69-48F2-BC1F-7A37CBF0B1EF")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupErrorState2 = | |
inherit ISetupErrorState | |
abstract member GetFailedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupFailedPackageReference[] | |
abstract member GetSkippedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupPackageReference[] | |
abstract member GetErrorLogFilePath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetLogFilePath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
[<Guid("290019AD-28E2-46D5-9DE5-DA4B6BCF8057")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupErrorState3 = | |
inherit ISetupErrorState2 | |
abstract member GetFailedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupFailedPackageReference[] | |
abstract member GetSkippedPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupPackageReference[] | |
abstract member GetErrorLogFilePath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetLogFilePath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetRuntimeError : unit -> ISetupErrorInfo | |
[<Guid("c601c175-a3be-44bc-91f6-4568d230fc83")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupPropertyStore = | |
abstract member GetNames : unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)>] string[] | |
abstract member GetValue: [<MarshalAs(UnmanagedType.LPWStr)>][<In>] pwszName: string -> obj | |
[<Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupInstance2 = | |
inherit ISetupInstance | |
abstract member GetInstanceId: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallDate: unit -> [<MarshalAs(UnmanagedType.Struct)>] System.Runtime.InteropServices.ComTypes.FILETIME | |
abstract member GetInstallationName : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallationPath : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetInstallationVersion : unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDisplayName : [<MarshalAs(UnmanagedType.U4)>][<In>] lcid: int -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetDescription : [<MarshalAs(UnmanagedType.U4)>][<In>] lcid: int -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member ResolvePath : [<MarshalAs(UnmanagedType.LPWStr)>][<In>] pwszRelativePath: string -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetState: unit -> [<MarshalAs(UnmanagedType.U4)>] InstanceState | |
abstract member GetPackages: unit -> [<MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)>] ISetupPackageReference[] | |
abstract member GetProduct: unit -> ISetupPackageReference | |
abstract member GetProductPath: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
abstract member GetErrors: unit -> ISetupErrorState | |
abstract member IsLaunchable: unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
abstract member IsComplete: unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
abstract member GetProperties: unit -> ISetupPropertyStore | |
abstract member GetEnginePath: unit -> [<MarshalAs(UnmanagedType.BStr)>] string | |
[<Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private IEnumSetupInstances = | |
abstract member Next: | |
[<MarshalAs(UnmanagedType.U4)>][<In>] celt: int | |
* [<MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface)>][<Out>] rgelt: ISetupInstance[] | |
* [<MarshalAs(UnmanagedType.U4)>][<Out>] pceltFetched: byref<int> | |
-> unit | |
abstract member Skip: [<MarshalAs(UnmanagedType.U4)>][<In>] celt: int -> unit | |
abstract member Reset: unit -> unit | |
abstract member Clone: unit -> [<MarshalAs(UnmanagedType.Interface)>] IEnumSetupInstances | |
[<Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupConfiguration = | |
abstract member EnumInstances: unit -> [<MarshalAs(UnmanagedType.Interface)>] IEnumSetupInstances | |
abstract member GetInstanceForCurrentProcess: unit -> [<MarshalAs(UnmanagedType.Interface)>] ISetupInstance | |
abstract member GetInstanceForPath: [<MarshalAs(UnmanagedType.LPWStr)>][<In>] path: string -> [<MarshalAs(UnmanagedType.Interface)>] ISetupInstance | |
[<Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
[<AllowNullLiteral>] | |
type private ISetupConfiguration2 = | |
inherit ISetupConfiguration | |
abstract member EnumInstances: unit -> [<MarshalAs(UnmanagedType.Interface)>] IEnumSetupInstances | |
abstract member GetInstanceForCurrentProcess: unit -> [<MarshalAs(UnmanagedType.Interface)>] ISetupInstance | |
abstract member GetInstanceForPath: [<MarshalAs(UnmanagedType.LPWStr)>][<In>] path: string -> [<MarshalAs(UnmanagedType.Interface)>] ISetupInstance | |
abstract member EnumAllInstances: unit -> [<MarshalAs(UnmanagedType.Interface)>] IEnumSetupInstances | |
[<Guid("9AD8E40F-39A2-40F1-BF64-0A6C50DD9EEB")>] | |
[<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>] | |
[<ComImport>] | |
type private ISetupInstanceCatalog = | |
abstract member GetCatalogInfo: unit -> ISetupPropertyStore | |
abstract member IsPrerelease: unit -> [<MarshalAs(UnmanagedType.VariantBool)>] bool | |
let private setupConfiguration = lazy( | |
let configType = System.Type.GetTypeFromCLSID (System.Guid "177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") | |
Activator.CreateInstance configType :?> ISetupConfiguration | |
) | |
let private enumAllInstances () = | |
let instancesEnumerator = | |
let v1 = setupConfiguration.Value | |
match v1 with | |
| :? ISetupConfiguration2 as v2 -> v2.EnumAllInstances() | |
| _ -> v1.EnumInstances() | |
let instances = Array.zeroCreate<ISetupInstance> 1 | |
let fetched = ref 1 | |
seq { | |
while !fetched = 1 do | |
instancesEnumerator.Next(1, instances, fetched) | |
if !fetched = 1 then | |
yield instances.[0] | |
} | |
type VsSetupPackage = | |
{ Id: string | |
Version: string | |
Chip: string | |
Language: string | |
Branch: string | |
Type: string | |
UniqueId: string | |
IsExtension: bool } | |
type VsSetupErrorInfo = | |
{ HResult: int | |
ErrorClassName: string | |
ErrorMessage: string } | |
type VsSetupErrorState = | |
{ FailedPackages: VsSetupPackage list | |
SkippedPackages: VsSetupPackage list | |
ErrorLogFilePath: string option | |
LogFilePath: string option | |
RuntimeError: VsSetupErrorInfo option } | |
type VsSetupInstance = | |
{ | |
InstanceId: string | |
InstallDate: DateTimeOffset | |
InstallationName: string | |
InstallationPath: string | |
InstallationVersion: string | |
DisplayName: string | |
Description: string | |
State: InstanceState option | |
Packages: VsSetupPackage list | |
Product: VsSetupPackage option | |
ProductPath: string option | |
Errors: VsSetupErrorState option | |
IsLaunchable: bool option | |
IsComplete: bool option | |
Properties: Map<string, obj> | |
EnginePath: string option | |
IsPrerelease: bool option | |
CatalogInfo: Map<string, obj> | |
} | |
let private parseErrorInfo (error: ISetupErrorInfo) = | |
{ | |
HResult = error.GetErrorHResult() | |
ErrorClassName = error.GetErrorClassName() | |
ErrorMessage = error.GetErrorMessage() | |
} | |
let private parsePackageReference (instance: ISetupPackageReference) = | |
{ | |
Id = instance.GetId() | |
Version = instance.GetId() | |
Chip = instance.GetChip() | |
Language = instance.GetLanguage() | |
Branch = instance.GetBranch() | |
Type = instance.GetType() | |
UniqueId = instance.GetUniqueId() | |
IsExtension = instance.GetIsExtension() | |
} | |
let private parseErrorState (state: ISetupErrorState) = | |
let result = | |
{ | |
FailedPackages = state.GetFailedPackages() |> Seq.map parsePackageReference |> List.ofSeq | |
SkippedPackages = state.GetSkippedPackages() |> Seq.map parsePackageReference |> List.ofSeq | |
ErrorLogFilePath = None | |
LogFilePath = None | |
RuntimeError = None | |
} | |
match state with | |
| :? ISetupErrorState2 as state2 -> | |
let result2 = | |
{ result with | |
ErrorLogFilePath = state2.GetErrorLogFilePath() |> Some | |
LogFilePath = state2.GetLogFilePath() |> Some | |
} | |
match state2 with | |
| :? ISetupErrorState3 as state3 -> | |
{ result2 with | |
RuntimeError = state3.GetRuntimeError() |> parseErrorInfo |> Some | |
} | |
| _-> result2 | |
| _ -> result | |
let private parseDate (date: System.Runtime.InteropServices.ComTypes.FILETIME) = | |
let high = uint64 (uint32 date.dwHighDateTime) | |
let low = uint64 (uint32 date.dwLowDateTime) | |
let composed = (high <<< 32) ||| low | |
DateTimeOffset.FromFileTime(int64 composed) | |
let private parseProperties (store: ISetupPropertyStore) = | |
store.GetNames() | |
|> Seq.map(fun name -> | |
let value = store.GetValue(name) | |
name, value) | |
|> Map.ofSeq | |
let private parseInstance (instance: ISetupInstance) = | |
let mutable result = | |
{ InstanceId = instance.GetInstanceId() | |
InstallDate = parseDate (instance.GetInstallDate()) | |
InstallationName = instance.GetInstallationName() | |
InstallationPath = instance.GetInstallationPath() | |
InstallationVersion = instance.GetInstallationVersion() | |
DisplayName = instance.GetDisplayName(0) | |
Description = instance.GetDescription(0) | |
State = None | |
Packages = [] | |
Product = None | |
ProductPath = None | |
Errors = None | |
IsLaunchable = None | |
IsComplete = None | |
Properties = Map.empty | |
EnginePath = None | |
IsPrerelease = None | |
CatalogInfo = Map.empty } | |
match instance with | |
| :? ISetupInstanceCatalog as catalog -> | |
result <- { result with | |
IsPrerelease = catalog.IsPrerelease() |> Some | |
CatalogInfo = catalog.GetCatalogInfo() |> parseProperties } | |
| _ -> () | |
match instance with | |
| :? ISetupInstance2 as v2 -> | |
{ result with | |
State = v2.GetState() |> Some | |
Packages = v2.GetPackages() |> Seq.map parsePackageReference |> List.ofSeq | |
Product = parsePackageReference (v2.GetProduct()) |> Some | |
ProductPath = v2.GetProductPath() |> Some | |
Errors = v2.GetErrors() |> Option.ofObj |> Option.map parseErrorState | |
IsLaunchable = v2.IsLaunchable() |> Some | |
IsComplete = v2.IsComplete() |> Some | |
Properties = parseProperties (v2.GetProperties()) | |
EnginePath = v2.GetEnginePath() |> Some } | |
| _ -> result | |
let getAll () = | |
try | |
enumAllInstances () | |
|> Seq.map parseInstance | |
|> List.ofSeq | |
with | |
| :? COMException -> | |
[] | |
VsInstances.getAll () |> Dump |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment