Skip to content

Commit b92a2d2

Browse files
committed
Discover vvvv installations from Windows registry and add custom path setting
- Scan Inno Setup uninstall registry entries for vvvv_gamma install locations - Add vvvvInstallationsFolder setting for non-standard install paths - Merge candidates from registry, custom folder, and default Program Files - Applied to both VS Code language server and WPF desktop app
1 parent 75cb1c4 commit b92a2d2

File tree

6 files changed

+145
-14
lines changed

6 files changed

+145
-14
lines changed

Stride.ShaderExplorer/Stride.ShaderExplorer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<OutputType>WinExe</OutputType>
88
<RootNamespace>StrideShaderExplorer</RootNamespace>
99
<AssemblyName>Stride.ShaderExplorer</AssemblyName>
10-
<Version>2.1.0</Version>
10+
<Version>2.1.1</Version>
1111
<ApplicationIcon>Assets\StrideShaderExplorerLogo.ico</ApplicationIcon>
1212
</PropertyGroup>
1313
<ItemGroup>

Stride.ShaderExplorer/VvvvPathResolver.cs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using Microsoft.Win32;
56

67
namespace StrideShaderExplorer
78
{
@@ -22,13 +23,47 @@ private VvvvPathResolver()
2223
VvvvBaseDir = Path.Combine(
2324
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "vvvv");
2425

26+
// Collect candidate directories from filesystem and registry
27+
var candidateDirs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
28+
29+
// Source 1: Default Program Files location
2530
if (Directory.Exists(VvvvBaseDir))
2631
{
27-
LatestGammaDir = Directory.GetDirectories(VvvvBaseDir)
28-
.Where(d => Path.GetFileName(d).StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
29-
.OrderByDescending(d => d)
30-
.FirstOrDefault();
32+
foreach (var dir in Directory.GetDirectories(VvvvBaseDir))
33+
{
34+
if (Path.GetFileName(dir).StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
35+
candidateDirs.Add(dir);
36+
}
3137
}
38+
39+
// Source 2: Windows registry (Inno Setup uninstall entries)
40+
try
41+
{
42+
const string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
43+
using var key = Registry.LocalMachine.OpenSubKey(uninstallKey);
44+
if (key != null)
45+
{
46+
foreach (var subKeyName in key.GetSubKeyNames())
47+
{
48+
if (!subKeyName.StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
49+
continue;
50+
51+
using var subKey = key.OpenSubKey(subKeyName);
52+
var installLocation = subKey?.GetValue("InstallLocation") as string;
53+
if (!string.IsNullOrWhiteSpace(installLocation) && Directory.Exists(installLocation))
54+
candidateDirs.Add(installLocation.TrimEnd('\\', '/'));
55+
}
56+
}
57+
}
58+
catch
59+
{
60+
// Ignore registry access errors
61+
}
62+
63+
LatestGammaDir = candidateDirs
64+
.Where(Directory.Exists)
65+
.OrderByDescending(d => d)
66+
.FirstOrDefault();
3267
}
3368

3469
/// <summary>

VSCode/language-server/Program.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ static async Task Main(string[] args)
7575
_logger?.LogInformation("Diagnostics delay set to {DelayMs}ms", delayMs);
7676
}
7777

78+
// Set custom vvvv installations folder
79+
if (initOptions.TryGetValue("vvvvInstallationsFolder", out var vvvvFolderToken))
80+
{
81+
var vvvvFolder = vvvvFolderToken.Value<string>();
82+
if (!string.IsNullOrWhiteSpace(vvvvFolder))
83+
{
84+
_workspace.SetVvvvInstallationsFolder(vvvvFolder);
85+
}
86+
}
87+
7888
// Add user-configured additional shader paths
7989
if (initOptions.TryGetValue("additionalShaderPaths", out var pathsToken))
8090
{

VSCode/language-server/Services/ShaderWorkspace.cs

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.Extensions.Logging;
2+
using Microsoft.Win32;
23

34
namespace StrideShaderLanguageServer.Services;
45

@@ -1062,28 +1063,75 @@ public string GetDisplayPath(string fullPath)
10621063
}
10631064
}
10641065

1066+
private string? _vvvvInstallationsFolder;
1067+
1068+
/// <summary>
1069+
/// Sets a custom vvvv installations folder (overrides the default Program Files location).
1070+
/// </summary>
1071+
public void SetVvvvInstallationsFolder(string folder)
1072+
{
1073+
if (!string.IsNullOrWhiteSpace(folder))
1074+
{
1075+
_vvvvInstallationsFolder = folder;
1076+
_logger.LogInformation("Custom vvvv installations folder set: {Path}", folder);
1077+
}
1078+
}
1079+
10651080
private List<string> DiscoverVvvvPaths()
10661081
{
10671082
var paths = new List<string>();
10681083

1069-
var vvvvBaseDir = Path.Combine(
1084+
// Collect all candidate vvvv_gamma directories from multiple sources
1085+
var candidateDirs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
1086+
1087+
// Source 1: Windows registry (Inno Setup uninstall entries)
1088+
try
1089+
{
1090+
DiscoverVvvvFromRegistry(candidateDirs);
1091+
}
1092+
catch (Exception ex)
1093+
{
1094+
_logger.LogWarning(ex, "Error reading vvvv installations from registry");
1095+
}
1096+
1097+
// Source 2: Custom installations folder (user setting)
1098+
if (!string.IsNullOrWhiteSpace(_vvvvInstallationsFolder) && Directory.Exists(_vvvvInstallationsFolder))
1099+
{
1100+
_logger.LogInformation("Scanning custom vvvv folder: {Path}", _vvvvInstallationsFolder);
1101+
foreach (var dir in Directory.GetDirectories(_vvvvInstallationsFolder))
1102+
{
1103+
if (Path.GetFileName(dir).StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
1104+
candidateDirs.Add(dir);
1105+
}
1106+
}
1107+
1108+
// Source 3: Default Program Files location
1109+
var defaultBaseDir = Path.Combine(
10701110
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "vvvv");
1111+
if (Directory.Exists(defaultBaseDir))
1112+
{
1113+
foreach (var dir in Directory.GetDirectories(defaultBaseDir))
1114+
{
1115+
if (Path.GetFileName(dir).StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
1116+
candidateDirs.Add(dir);
1117+
}
1118+
}
10711119

1072-
_logger.LogInformation("Looking for vvvv at: {Path}", vvvvBaseDir);
1120+
_logger.LogInformation("Found {Count} candidate vvvv installation directories", candidateDirs.Count);
10731121

1074-
if (!Directory.Exists(vvvvBaseDir))
1122+
if (candidateDirs.Count == 0)
10751123
{
1076-
_logger.LogInformation("vvvv base directory not found");
1124+
_logger.LogInformation("No vvvv gamma installations found");
10771125
return paths;
10781126
}
10791127

10801128
try
10811129
{
1082-
// Get all vvvv_gamma_* directories and parse their versions
1083-
var gammaInstalls = Directory.GetDirectories(vvvvBaseDir)
1084-
.Where(d => Path.GetFileName(d).StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
1130+
// Parse versions and pick the latest
1131+
var gammaInstalls = candidateDirs
1132+
.Where(Directory.Exists)
10851133
.Select(d => new { Path = d, Version = ParseVvvvVersion(Path.GetFileName(d)) })
1086-
.Where(v => v.Version != null) // Filter out unparseable/special versions
1134+
.Where(v => v.Version != null)
10871135
.ToList();
10881136

10891137
if (gammaInstalls.Count == 0)
@@ -1160,6 +1208,37 @@ private List<string> DiscoverVvvvPaths()
11601208
return paths;
11611209
}
11621210

1211+
/// <summary>
1212+
/// Discovers vvvv gamma installations from the Windows registry (Inno Setup uninstall entries).
1213+
/// Each installation registers under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\vvvv_gamma_*_is1
1214+
/// with an InstallLocation value pointing to the installation directory.
1215+
/// </summary>
1216+
private void DiscoverVvvvFromRegistry(HashSet<string> candidateDirs)
1217+
{
1218+
if (!OperatingSystem.IsWindows())
1219+
return;
1220+
1221+
const string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
1222+
1223+
using var key = Registry.LocalMachine.OpenSubKey(uninstallKey);
1224+
if (key == null)
1225+
return;
1226+
1227+
foreach (var subKeyName in key.GetSubKeyNames())
1228+
{
1229+
if (!subKeyName.StartsWith("vvvv_gamma_", StringComparison.OrdinalIgnoreCase))
1230+
continue;
1231+
1232+
using var subKey = key.OpenSubKey(subKeyName);
1233+
var installLocation = subKey?.GetValue("InstallLocation") as string;
1234+
if (!string.IsNullOrWhiteSpace(installLocation) && Directory.Exists(installLocation))
1235+
{
1236+
candidateDirs.Add(installLocation.TrimEnd('\\', '/'));
1237+
_logger.LogInformation("Found vvvv from registry: {Path}", installLocation);
1238+
}
1239+
}
1240+
}
1241+
11631242
/// <summary>
11641243
/// Parse a vvvv gamma directory name into version components.
11651244
/// Filters out special versions like "-hdr" and handles stable vs preview.

VSCode/vscode-extension/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Stride SDSL Shader Tools",
44
"description": "IntelliSense, (future) debugging, and assistance for Stride and vvvv SDSL shaders",
55
"icon": "icons/icon.png",
6-
"version": "0.7.1",
6+
"version": "0.7.2",
77
"publisher": "tebjan",
88
"engines": {
99
"vscode": "^1.95.0"
@@ -90,6 +90,11 @@
9090
},
9191
"description": "Additional paths to search for shader files."
9292
},
93+
"strideShaderTools.vvvvInstallationsFolder": {
94+
"type": "string",
95+
"default": "",
96+
"description": "Folder containing vvvv gamma installations (e.g. C:\\Program Files\\vvvv). Leave empty to use the default Program Files location."
97+
},
9398
"strideShaderTools.trace.server": {
9499
"type": "string",
95100
"enum": [

VSCode/vscode-extension/src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ async function startLanguageServer(context: vscode.ExtensionContext): Promise<vo
461461

462462
// Get additional shader paths from config
463463
const additionalPaths = config.get<string[]>('shaderPaths') || [];
464+
const vvvvInstallationsFolder = config.get<string>('vvvvInstallationsFolder') || '';
464465
const diagnosticsDelay = config.get<number>('diagnostics.delay') || 2000;
465466

466467
// Client options with middleware to enhance hover with clickable links
@@ -474,6 +475,7 @@ async function startLanguageServer(context: vscode.ExtensionContext): Promise<vo
474475
},
475476
initializationOptions: {
476477
additionalShaderPaths: additionalPaths,
478+
vvvvInstallationsFolder: vvvvInstallationsFolder,
477479
workspaceFolders: vscode.workspace.workspaceFolders?.map((f) => f.uri.fsPath) || [],
478480
diagnosticsDelayMs: diagnosticsDelay,
479481
},

0 commit comments

Comments
 (0)