diff --git a/src/App.js b/src/App.js index abca3ba..e83fbe1 100644 --- a/src/App.js +++ b/src/App.js @@ -173,6 +173,13 @@ class App extends IPCContainer { )); + } else if(selectedVersion !== 'unavailable') { + mainContent.push(( + + + + )); } } diff --git a/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js b/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js index d9e8149..8805341 100644 --- a/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js +++ b/src/components/ReleaseVersionDisplay/ReleaseVersionDisplay.js @@ -12,6 +12,7 @@ import {downloadItem} from '../../redux/actions/download_actions'; const mapStateToProps = state => { return { + AllowMount: state.common.AllowMount, AppPlatform: state.common.AppPlatform, DismissDependencies: state.install.DismissDependencies, DownloadActive: state.download.DownloadActive, @@ -35,6 +36,12 @@ const mapDispatchToProps = dispatch => { }; export default connect(mapStateToProps, mapDispatchToProps)(props => { + const getSelectedVersion = () => { + return (props.ReleaseVersion === -1) ? + 'unavailable' : + props.VersionLookup[Constants.RELEASE_TYPES[props.Release]][props.ReleaseVersion]; + }; + const handleDownloadRelease = () => { const fileName = props.version + '.zip'; props.downloadItem(fileName, Constants.INSTALL_TYPES.Release, props.LocationsLookup[props.version].urls); @@ -52,7 +59,10 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { }; const text = props.InstalledVersion + ' [' + props.AppPlatform + ']'; - const disabled = props.DownloadActive || props.InstallActive || props.MountsBusy; + const disabled = props.DownloadActive || + props.InstallActive || + props.MountsBusy || + (!props.AllowMount && (getSelectedVersion() !== 'unavailable')) ; const releaseExtracting = (props.InstallType === Constants.INSTALL_TYPES.Release); let optionsDisplay = []; diff --git a/src/helpers.js b/src/helpers.js index 922edc1..95b4dac 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -8,6 +8,60 @@ const spawn = require('child_process').spawn; const Constants = require('./constants'); const RandomString = require('randomstring'); +let vcRuntimeExists; + +const _vcRuntimeExists = () => { + return new Promise((resolve, reject) => { + if (os.platform() !== 'win32') { + reject('Windows OS is not being used'); + } else { + if (vcRuntimeExists) { + resolve(true); + } else { + const cmd = path.join(process.env.windir, 'system32', 'reg.exe'); + const args = ["QUERY", "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"]; + _execProcessGetOutput(cmd, null, args) + .then(lines => { + const parseLine = index => { + if (index < lines.length) { + const line = lines[index]; + if (line.startsWith('HKEY_LOCAL_MACHINE\\')) { + let args2 = JSON.parse(JSON.stringify(args)); + args2[1] = 'HKLM\\' + line.substr(19); + args2.push('/v'); + args2.push('DisplayName'); + args2.push('/t'); + args2.push('REG_SZ'); + _execProcessGetOutput(cmd, null, args2) + .then(lines => { + const value = lines[2].trim().substr(args2[3].length).trim().substr(6).trim(); + if (value.includes('Microsoft Visual C++ 2015-2019 Redistributable (x64)')) { + vcRuntimeExists = true; + resolve(true); + } else { + parseLine(++index); + } + }) + .catch(() => { + parseLine(++index); + }); + } else { + parseLine(++index); + } + } else { + resolve(false); + } + }; + parseLine(0); + }) + .catch(err => { + reject(err); + }); + } + } + }); +}; + const _executeProcess = (command, working, args=[]) => { return new Promise((resolve, reject) => { let processOptions = { @@ -542,51 +596,65 @@ module.exports.getMissingDependencies = dependencies => { }; const Registry = require('winreg'); - const checkRegistry = (dep, index) => { + const checkRegistry = (dep, index, legacyRuntimeDetection) => { if (index >= dep.registry.length) { missing.push(dep); resolveIfComplete(); } else { - let hive = null; - const hiveName = dep.registry[index].split('\\')[0]; - switch (hiveName) { - case 'HKEY_CLASSES_ROOT': - hive = Registry.HKCR; - break; - case 'HKEY_CURRENT_CONFIG': - hive = Registry.HKCC; - break; - case 'HKEY_CURRENT_USER': - hive = Registry.HKCU; - break; - case 'HKEY_LOCAL_MACHINE': - hive = Registry.HKLM; - break; - case 'HKEY_USERS': - hive = Registry.HKU; - break; - default: - throw Error('Invalid registry hive: ' + hiveName); - } - - const key = dep.registry[index].substr(hiveName.length); - const regKey = new Registry({ - hive: hive, - key: key - }); - regKey.valueExists('DisplayName', (err, exists) => { - if (err || !exists) { - regKey.valueExists('ProductName', (err, exists) => { - if (err || !exists) { - checkRegistry(dep, ++index); - } else { + if (!legacyRuntimeDetection && (dep.display === 'VC Runtime 2015-2019')) { + _vcRuntimeExists() + .then(exists => { + if (exists) { resolveIfComplete(); + } else { + checkRegistry(dep, 0, true); } - }); - } else { - resolveIfComplete(); + }) + .catch (() => { + checkRegistry(dep, 0, true); + }) + } else { + let hive = null; + const hiveName = dep.registry[index].split('\\')[0]; + switch (hiveName) { + case 'HKEY_CLASSES_ROOT': + hive = Registry.HKCR; + break; + case 'HKEY_CURRENT_CONFIG': + hive = Registry.HKCC; + break; + case 'HKEY_CURRENT_USER': + hive = Registry.HKCU; + break; + case 'HKEY_LOCAL_MACHINE': + hive = Registry.HKLM; + break; + case 'HKEY_USERS': + hive = Registry.HKU; + break; + default: + throw Error('Invalid registry hive: ' + hiveName); } - }); + + const key = dep.registry[index].substr(hiveName.length); + const regKey = new Registry({ + hive: hive, + key: key + }); + regKey.valueExists('DisplayName', (err, exists) => { + if (err || !exists) { + regKey.valueExists('ProductName', (err, exists) => { + if (err || !exists) { + checkRegistry(dep, ++index); + } else { + resolveIfComplete(); + } + }); + } else { + resolveIfComplete(); + } + }); + } } };