blob: 4ec7fcfa0e58172457d751b1315485cef82c267b [file] [log] [blame]
#!/usr/bin/env python
"""Locate Visual Studio installations with Visual Studio Setup Configuration utility DLL"""
import os
import ctypes
def get_vs_installations():
class ISetupInstanceVTable(ctypes.Structure):
"""Class matching VisualStudio Setup package ISetupInstance vtable"""
pass
class ISetupInstance(ctypes.Structure):
"""COM interface for ISetupInstance"""
_fields_ = [('vtable', ctypes.POINTER(ISetupInstanceVTable))]
class IEnumSetupInstancesVTable(ctypes.Structure):
"""Class matching VisualStudio Setup package IEnumSetupInstances vtable"""
pass
class IEnumSetupInstances(ctypes.Structure):
"""COM interface for IEnumSetupInstances"""
_fields_ = [('vtable', ctypes.POINTER(IEnumSetupInstancesVTable))]
class ISetupConfigurationVTable(ctypes.Structure):
"""Class matching VisualStudio Setup package ISetupConfiguration vtable"""
pass
class ISetupConfiguration(ctypes.Structure):
"""COM interface for ISetupConfiguration"""
_fields_ = [('vtable', ctypes.POINTER(ISetupConfigurationVTable))]
proto_get_installation_path = ctypes.WINFUNCTYPE(
ctypes.c_int,
ctypes.POINTER(ISetupInstance),
ctypes.POINTER(ctypes.c_wchar_p))
proto_get_installation_version = ctypes.WINFUNCTYPE(
ctypes.c_int,
ctypes.POINTER(ISetupInstance),
ctypes.POINTER(ctypes.c_wchar_p))
ISetupInstanceVTable._fields_ = (
('QueryInterface', ctypes.c_void_p),
('AddRef', ctypes.c_void_p),
('Release', ctypes.c_void_p),
('GetInstanceId', ctypes.c_void_p),
('GetInstallDate', ctypes.c_void_p),
('GetInstallationName', ctypes.c_void_p),
('GetInstallationPath', proto_get_installation_path),
('GetInstallationVersion', proto_get_installation_version),
('GetDisplayName', ctypes.c_void_p),
('GetDescription', ctypes.c_void_p),
('ResolvePath', ctypes.c_void_p))
proto_next = ctypes.WINFUNCTYPE(
ctypes.c_int,
ctypes.POINTER(IEnumSetupInstances),
ctypes.c_int,
ctypes.POINTER(ctypes.POINTER(ISetupInstance)),
ctypes.POINTER(ctypes.c_int))
IEnumSetupInstancesVTable._fields_ = (
('QueryInterface', ctypes.c_void_p),
('AddRef', ctypes.c_void_p),
('Release', ctypes.c_void_p),
('Next', proto_next),
('Skip', ctypes.c_void_p),
('Reset', ctypes.c_void_p),
('Clone', ctypes.c_void_p))
proto_enum_instances = ctypes.WINFUNCTYPE(
ctypes.c_int,
ctypes.POINTER(ISetupConfiguration),
ctypes.POINTER(ctypes.POINTER(IEnumSetupInstances)))
ISetupConfigurationVTable._fields_ = (
('QueryInterface', ctypes.c_void_p),
('AddRef', ctypes.c_void_p),
('Release', ctypes.c_void_p),
('EnumInstances', proto_enum_instances),
('GetInstanceForCurrentProcess', ctypes.c_void_p),
('GetInstanceForPath', ctypes.c_void_p))
proto_get_setup_configuration = ctypes.WINFUNCTYPE(
ctypes.c_int,
ctypes.POINTER(ctypes.POINTER(ISetupConfiguration)),
ctypes.c_void_p)
dll_path = os.path.expandvars("$ProgramData\\Microsoft\\VisualStudio\\Setup\\x64\\Microsoft.VisualStudio.Setup.Configuration.Native.dll")
dll = ctypes.WinDLL(dll_path)
params_get_setup_configuration = (1, "configuration", 0), (1, "reserved", 0),
get_setup_configuration = proto_get_setup_configuration(("GetSetupConfiguration", dll), params_get_setup_configuration)
configuration = ctypes.POINTER(ISetupConfiguration)()
reserved = ctypes.c_void_p(0)
installations = []
result = get_setup_configuration(ctypes.byref(configuration), reserved)
if result != 0:
#print("Failed to get setup configuration: " + str(result))
return installations
enum_instances = configuration.contents.vtable.contents.EnumInstances
enum_setup_instances = ctypes.POINTER(IEnumSetupInstances)()
result = enum_instances(configuration, ctypes.byref(enum_setup_instances))
if result != 0:
#print("Failed to enum setup instances: " + str(result))
return installations
setup_instance = ctypes.POINTER(ISetupInstance)()
fetched = ctypes.c_int(0)
while True:
next = enum_setup_instances.contents.vtable.contents.Next
result = next(enum_setup_instances, 1, ctypes.byref(setup_instance), ctypes.byref(fetched))
if result == 1 or fetched == 0:
break
if result != 0:
#print("Failed to get next setup instance: " + str(result))
break
version = ctypes.c_wchar_p()
path = ctypes.c_wchar_p()
get_installation_version = setup_instance.contents.vtable.contents.GetInstallationVersion
get_installation_path = setup_instance.contents.vtable.contents.GetInstallationPath
result = get_installation_version(setup_instance, ctypes.byref(version))
if result != 0:
#print("Failed to get setup instance version: " + str(result))
break
result = get_installation_path(setup_instance, ctypes.byref(path))
if result != 0:
#print("Failed to get setup instance version: " + str(result))
break
installations.append((version.value, path.value))
return installations
if __name__ == "__main__":
installations = get_vs_installations()
for version, path in installations:
print(version + " " + path)