app
adom-desktop-altium-bridge
Public Unreviewedby barrett-land
Adom Desktop bridge for Altium Designer — add LCSC/JLCPCB-tagged parts to file-based libraries (symbols, footprints with 3D, value-only display) by driving Altium via DelphiScript.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
#!/usr/bin/env python3
"""Detect the Altium Designer install + library locations on this Windows machine.
Runs INSIDE the user's desktop (the bridge is spawned by Adom Desktop on Windows),
so it reads the registry and filesystem directly — no relay/shell round-trip.
Verified facts on the reference machine (BARRETTLAND / user barre):
- Install: C:\\Program Files\\Altium\\AD26\\X2.exe
- Uninstall key: HKLM\\...\\Uninstall\\Altium Designer {GUID} (DisplayName "Altium Designer 26",
InstallLocation, DisplayIcon → X2.exe)
- Config: %LOCALAPPDATA%\\Altium\\Altium Designer {GUID} and %APPDATA%\\Altium\\...
- Data: C:\\Users\\Public\\Documents\\Altium\\AD26\\{Library,OutputJobs,Templates,Examples}
"""
import os
import glob
try:
import winreg # type: ignore
except ImportError: # non-Windows (dev/import only)
winreg = None
UNINSTALL_PATHS = [
r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
]
def _reg_altium_uninstall():
"""Walk the Uninstall keys for an entry whose DisplayName starts with 'Altium Designer'.
Returns dict {display_name, display_version, install_location, display_icon} or None.
"""
if winreg is None:
return None
for base in UNINSTALL_PATHS:
try:
root = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base)
except OSError:
continue
i = 0
while True:
try:
sub = winreg.EnumKey(root, i)
except OSError:
break
i += 1
if "Altium Designer" not in sub:
continue
try:
k = winreg.OpenKey(root, sub)
except OSError:
continue
def _get(name):
try:
return winreg.QueryValueEx(k, name)[0]
except OSError:
return None
name = _get("DisplayName")
if not name or not str(name).startswith("Altium Designer"):
continue
return {
"display_name": name,
"display_version": _get("DisplayVersion"),
"install_location": _get("InstallLocation"),
"display_icon": _get("DisplayIcon"),
}
return None
def _scan_program_files():
"""Fallback: find the newest C:\\Program Files\\Altium\\AD<NN>\\X2.exe."""
candidates = []
for pf in (os.environ.get("ProgramFiles", r"C:\Program Files"),
os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")):
for exe in glob.glob(os.path.join(pf, "Altium", "AD*", "X2.exe")):
ad = os.path.basename(os.path.dirname(exe)) # e.g. AD26
num = "".join(ch for ch in ad if ch.isdigit())
candidates.append((int(num or 0), ad, exe))
candidates.sort(reverse=True)
return candidates[0] if candidates else None
def _config_dirs():
"""Find the Altium config dirs (carry the {GUID} and any Workspace/365 state)."""
out = []
for env in ("LOCALAPPDATA", "APPDATA"):
base = os.path.join(os.environ.get(env, ""), "Altium")
if os.path.isdir(base):
for d in os.listdir(base):
if d.startswith("Altium Designer"):
out.append(os.path.join(base, d))
return out
def detect_altium():
"""Return a structured snapshot of the Altium install on this machine.
{installed, exe, version, install_location, config_dirs[], data_dir,
library_dir, outputjobs_dir}
"""
reg = _reg_altium_uninstall()
exe = None
install_location = None
version = None
if reg:
version = reg.get("display_version") or reg.get("display_name")
install_location = reg.get("install_location")
icon = reg.get("display_icon")
if icon and icon.lower().endswith("x2.exe") and os.path.isfile(icon):
exe = icon
elif install_location:
cand = os.path.join(install_location, "X2.exe")
if os.path.isfile(cand):
exe = cand
if not exe:
scanned = _scan_program_files()
if scanned:
_, ad, exe = scanned
install_location = os.path.dirname(exe)
version = version or ad
# Public data tree — derive AD<NN> from the install dir name when possible.
ad_name = os.path.basename(install_location) if install_location else "AD26"
public = os.path.join(
os.environ.get("PUBLIC", r"C:\Users\Public"), "Documents", "Altium", ad_name
)
data_dir = public if os.path.isdir(public) else None
library_dir = os.path.join(public, "Library") if data_dir else None
outputjobs_dir = os.path.join(public, "OutputJobs") if data_dir else None
return {
"installed": bool(exe),
"exe": exe,
"version": version,
"install_location": install_location,
"config_dirs": _config_dirs(),
"data_dir": data_dir,
"library_dir": library_dir,
"outputjobs_dir": outputjobs_dir,
}
if __name__ == "__main__":
import json
print(json.dumps(detect_altium(), indent=2))