@@ -53,9 +53,10 @@ def _derive_windows_player_versions(self) -> Dict[str, dict]:
5353 def _query_windows_registry (self , product : str = "TouchDesigner" ) -> Dict [str , dict ]:
5454 """Query Windows registry for TouchDesigner or TouchPlayer installations.
5555
56- Registry layout: HKLM\\ SOFTWARE\\ Derivative\\ <product>
57- Values are version numbers (e.g. '2025.32280') and corresponding
58- paths stored as 'Path', 'Path_3', 'Path_6', etc.
56+ Primary: HKLM\\ SOFTWARE\\ Derivative\\ <product> — version entries matched
57+ to Path entries by substring. Fallback for any unmatched versions:
58+ HKEY_CLASSES_ROOT\\ <product>.<version>\\ shell\\ open\\ command which stores
59+ the executable path directly via file-association registration.
5960 """
6061 try :
6162 import winreg
@@ -64,6 +65,8 @@ def _query_windows_registry(self, product: str = "TouchDesigner") -> Dict[str, d
6465
6566 td_dict = {}
6667
68+ # -- Primary: HKLM path-based lookup --------------------------------
69+ versions = []
6770 try :
6871 key = winreg .OpenKey (
6972 winreg .HKEY_LOCAL_MACHINE ,
@@ -72,8 +75,6 @@ def _query_windows_registry(self, product: str = "TouchDesigner") -> Dict[str, d
7275
7376 num_values = winreg .QueryInfoKey (key )[1 ]
7477
75- # Collect all values: version numbers and their path entries
76- versions = []
7778 paths = {}
7879 for i in range (num_values ):
7980 name , value , vtype = winreg .EnumValue (key , i )
@@ -85,7 +86,6 @@ def _query_windows_registry(self, product: str = "TouchDesigner") -> Dict[str, d
8586 # Match each version to its install path
8687 for version in versions :
8788 install_path = None
88- # Check all path entries for one containing this version
8989 for path_name , path_value in paths .items ():
9090 if version in path_value :
9191 install_path = path_value
@@ -105,6 +105,33 @@ def _query_windows_registry(self, product: str = "TouchDesigner") -> Dict[str, d
105105 except (WindowsError , FileNotFoundError ):
106106 pass
107107
108+ # -- Fallback: HKCR file-association lookup for unmatched versions ---
109+ resolved_versions = {k .split ('.' , 1 )[1 ] for k in td_dict }
110+ unmatched = [v for v in versions if v not in resolved_versions ]
111+
112+ if unmatched :
113+ logger .debug (
114+ "HKLM path match missed %d version(s), falling back to HKCR: %s" ,
115+ len (unmatched ), unmatched ,
116+ )
117+ for version in unmatched :
118+ hkcr_key_path = rf"{ product } .{ version } \shell\open\command"
119+ try :
120+ command_val = winreg .QueryValue (
121+ winreg .HKEY_CLASSES_ROOT , hkcr_key_path
122+ )
123+ # Value is typically: "C:\...\TouchDesigner.exe" "%1"
124+ exe_path = command_val .split ('"' )[1 ] if '"' in command_val else None
125+ if exe_path and os .path .exists (exe_path ):
126+ td_key = f"{ product } .{ version } "
127+ install_path = os .path .dirname (os .path .dirname (exe_path ))
128+ td_dict [td_key ] = {
129+ 'install_path' : install_path ,
130+ 'executable' : exe_path ,
131+ }
132+ except OSError :
133+ pass
134+
108135 return td_dict
109136
110137 def _query_mac_applications (self , product : str = "TouchDesigner" ) -> Dict [str , dict ]:
0 commit comments