From 6ac95e43cb5a3bc9b5407cfd17f64f0c3ba1c423 Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 29 Apr 2026 14:06:20 +0200 Subject: [PATCH] chore: initial commit (extracted from Launchers monorepo) Plugin: UniversalShellExt v1.0.0 Architectures: x64 License: MIT --- .editorconfig | 24 + .gitattributes | 52 ++ .github/ISSUE_TEMPLATE/bug_report.yml | 76 +++ .github/ISSUE_TEMPLATE/config.yml | 8 + .github/ISSUE_TEMPLATE/feature_request.yml | 32 + .github/PULL_REQUEST_TEMPLATE.md | 31 + .github/workflows/build.yml | 63 ++ .github/workflows/release.yml | 99 +++ .gitignore | 63 ++ CHANGELOG.md | 19 + CONTRIBUTING.md | 137 ++++ LICENSE | 21 + README.md | 171 +++++ SECURITY.md | 40 ++ VERSION | 1 + build.py | 271 ++++++++ dist/x64/UniversalShellExt64.dll | Bin 0 -> 202256 bytes src/UniversalShellExt.cpp | 700 +++++++++++++++++++++ src/UniversalShellExt.def | 6 + src/UniversalShellExt.rc | 44 ++ src/UniversalShellExt.vcxproj | 89 +++ 21 files changed, 1947 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 VERSION create mode 100644 build.py create mode 100644 dist/x64/UniversalShellExt64.dll create mode 100644 src/UniversalShellExt.cpp create mode 100644 src/UniversalShellExt.def create mode 100644 src/UniversalShellExt.rc create mode 100644 src/UniversalShellExt.vcxproj diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..55629c5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{yml,yaml,json}] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[*.{cmd,bat,ps1}] +end_of_line = crlf + +[*.{nsi,nsh,sln,vcxproj,filters}] +end_of_line = crlf + +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..20b175b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,52 @@ +# Normalizzazione line endings +* text=auto eol=lf + +# File di codice +*.c text eol=lf +*.cpp text eol=lf +*.h text eol=lf +*.hpp text eol=lf +*.def text eol=lf +*.py text eol=lf +*.ps1 text eol=lf +*.cmd text eol=crlf +*.bat text eol=crlf + +# NSIS +*.nsi text eol=crlf +*.nsh text eol=crlf + +# Markdown / docs / config +*.md text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.json text eol=lf +*.txt text eol=lf +*.xml text eol=lf + +# Visual Studio (CRLF richiesto) +*.sln text eol=crlf +*.vcxproj text eol=crlf merge=union +*.filters text eol=crlf merge=union +*.rc binary +*.rc2 binary + +# Binari +*.dll binary +*.exe binary +*.lib binary +*.obj binary +*.pdb binary +*.zip binary +*.7z binary +*.png binary +*.ico binary +*.gif binary +*.jpg binary +*.jpeg binary +*.bmp binary +*.pdf binary + +# Linguistic detection (GitHub Linguist / Gitea analogo) +*.nsi linguist-language=NSIS +*.nsh linguist-language=NSIS diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..7599f2a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,76 @@ +name: Bug Report +description: Segnala un bug riproducibile +title: "[Bug]: " +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + Grazie per la segnalazione. Compila i campi sotto per aiutarci a riprodurre il problema. + + - type: input + id: plugin-version + attributes: + label: Versione plugin + description: Contenuto del file VERSION o tag della release scaricata + placeholder: "1.6.0" + validations: + required: true + + - type: dropdown + id: architecture + attributes: + label: Architettura DLL usata + options: + - x86-ansi + - x86-unicode + - amd64-unicode + - non so / multiple + validations: + required: true + + - type: input + id: nsis-version + attributes: + label: Versione NSIS + placeholder: "3.10" + validations: + required: true + + - type: input + id: os + attributes: + label: Sistema operativo + placeholder: "Windows 11 23H2 x64" + validations: + required: true + + - type: textarea + id: repro + attributes: + label: Passi per riprodurre + description: Script .nsi minimale che riproduce il problema + render: nsis + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Comportamento atteso + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Comportamento osservato + description: Includi messaggi di errore esatti, output del log NSIS, screenshot + validations: + required: true + + - type: textarea + id: additional + attributes: + label: Note aggiuntive + description: Qualunque altra informazione utile (workaround tentati, ecc.) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..1e6f7cd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Domande generali + url: https://gitea.emulab.it/Simone/universal-shell-ext/issues?type=question + about: Per domande di utilizzo che non sono bug, apri una issue con label "question" + - name: Security + url: https://gitea.emulab.it/Simone/universal-shell-ext/security/advisories/new + about: Segnala vulnerabilità di security in privato (non aprire issue pubbliche) diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..fae6d8d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,32 @@ +name: Feature Request +description: Suggerisci una nuova funzionalità o miglioramento +title: "[Feature]: " +labels: ["enhancement"] +body: + - type: textarea + id: problem + attributes: + label: Problema / Caso d'uso + description: Quale problema vorresti risolvere? Quale workflow vuoi abilitare? + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposta + description: Come dovrebbe funzionare? Includi esempio di API/uso negli script NSIS se possibile. + render: nsis + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternative considerate + description: Altri approcci che hai valutato e perché sono stati scartati + + - type: textarea + id: additional + attributes: + label: Note aggiuntive diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..3758b50 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ +## Descrizione + + + +## Tipo di Modifica + +- [ ] Bug fix (modifica non breaking che risolve un problema) +- [ ] Feature (modifica non breaking che aggiunge funzionalità) +- [ ] Breaking change (fix o feature che rompe la compatibilità) +- [ ] Documentazione +- [ ] Build / CI + +## Architetture Testate + +- [ ] `x86-ansi` +- [ ] `x86-unicode` +- [ ] `amd64-unicode` + +## Checklist + +- [ ] Build completa senza warning: `python build_plugin.py` +- [ ] CHANGELOG.md aggiornato (sezione `[Unreleased]`) +- [ ] README / docs aggiornati se l'API è cambiata +- [ ] Esempi aggiornati se l'API è cambiata +- [ ] Conventional Commits rispettato +- [ ] Nessun file in `dist/` o `__pycache__/` committato +- [ ] Self-review completata + +## Note Aggiuntive + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a521284 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,63 @@ +# Build (GitHub) — pipeline CI primaria +# +# Strategia hosting: +# - Repo primario su Gitea (push iniziale) +# - Push mirror automatico Gitea -> GitHub +# - GitHub esegue TUTTA la CI (Gitea non esegue Actions) +# +# Trigger: +# - push su main (incluso quello propagato dal mirror Gitea) +# - PR aperte su GitHub +# - run manuale via UI + +name: Build + +on: + push: + branches: [main] + paths-ignore: + - '**.md' + - 'docs/**' + - 'examples/**' + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + config: [x86-ansi, x86-unicode, x64-unicode] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Read VERSION + id: version + shell: pwsh + run: | + $v = (Get-Content VERSION -Raw).Trim() + "version=$v" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + + - name: Build ${{ matrix.config }} + run: python build_plugin.py --config ${{ matrix.config }} --verbose + + - name: Upload DLL + uses: actions/upload-artifact@v4 + with: + name: ${{ github.event.repository.name }}-${{ steps.version.outputs.version }}-${{ matrix.config }} + path: dist/** + if-no-files-found: error + retention-days: 30 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e4cf67d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,99 @@ +# Release (GitHub) — pipeline release primaria +# +# Triggerata quando un tag v* viene propagato dal mirror Gitea. +# Costruisce gli artifact per tutte le architetture e crea la GitHub Release. + +name: Release + +on: + push: + tags: ['v*'] + workflow_dispatch: + inputs: + tag: + description: 'Tag versione (es. v1.7.0)' + required: true + +permissions: + contents: write + +jobs: + build: + runs-on: windows-latest + strategy: + fail-fast: true + matrix: + config: [x86-ansi, x86-unicode, x64-unicode] + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - uses: microsoft/setup-msbuild@v2 + + - name: Build ${{ matrix.config }} + run: python build_plugin.py --config ${{ matrix.config }} + + - name: Determine version & arch + id: meta + shell: pwsh + run: | + $tag = "${{ github.ref_name }}" + if ([string]::IsNullOrEmpty($tag) -or $tag -eq "main") { $tag = "${{ inputs.tag }}" } + $v = $tag -replace '^v','' + $map = @{ 'x86-ansi' = 'x86-ansi'; 'x86-unicode' = 'x86-unicode'; 'x64-unicode' = 'amd64-unicode' } + $dir = $map['${{ matrix.config }}'] + echo "version=$v" >> $env:GITHUB_OUTPUT + echo "tag=$tag" >> $env:GITHUB_OUTPUT + echo "dir=$dir" >> $env:GITHUB_OUTPUT + + - name: Package + shell: pwsh + run: | + $name = "${{ github.event.repository.name }}-${{ steps.meta.outputs.version }}-${{ steps.meta.outputs.dir }}" + $stage = "stage/$name" + New-Item -ItemType Directory -Force -Path $stage | Out-Null + Copy-Item "dist/${{ steps.meta.outputs.dir }}/*" $stage -Recurse + Copy-Item README.md, LICENSE, VERSION, CHANGELOG.md $stage + if (Test-Path "include") { Copy-Item "include" $stage -Recurse } + if (Test-Path "examples") { Copy-Item "examples" $stage -Recurse } + Compress-Archive -Path "$stage/*" -DestinationPath "$name.zip" -Force + + - uses: actions/upload-artifact@v4 + with: + name: pkg-${{ matrix.config }} + path: '*.zip' + + publish: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + - name: SHA256SUMS + run: | + cd artifacts + sha256sum *.zip > SHA256SUMS.txt + cat SHA256SUMS.txt + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: | + artifacts/*.zip + artifacts/SHA256SUMS.txt + generate_release_notes: true + body: | + **Repository primario**: vedi link Gitea nel README. + + Il mirror GitHub è generato automaticamente dal repo Gitea (sorgente di verità). + Per issue e PR aprire ticket sul repository primario Gitea. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c3a730 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# Build output (src/ subdirs only — dist/ is tracked, contains pre-built DLLs) +bin/ +obj/ +Build/ +build/ + +# Visual Studio +*.user +*.suo +*.ncb +*.sdf +.vs/ +ipch/ +*.VC.db +*.VC.VC.opendb +*.opendb +*.aps +*.tlog +*.idb +*.pdb +*.ilk +*.exp +*.lib +*.obj + +# Python +__pycache__/ +*.pyc +*.pyo +.pytest_cache/ +*.egg-info/ +.venv/ +venv/ + +# Editor / IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +Thumbs.db +desktop.ini +.DS_Store + +# NSIS +*.nsh.bak + +# Logs +*.log +.logs/ + +# Sensitive +.env +.env.local +*.pem +*.key + +# Migration/automation scripts (temporary, contain tokens — never commit) +tools/t*.py +tools/check_*.py +tools/legacy/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..49c81d1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +Tutte le modifiche rilevanti a questo progetto sono documentate in questo file. + +Il formato segue [Keep a Changelog](https://keepachangelog.com/it/1.0.0/), +e il progetto aderisce al [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.0.0] — 2026-04-29 + +### Added +- Prima release come repository indipendente +- Build script unificato (`build_plugin.py`) con CLI canonica +- CI/CD via GitHub Actions (mirror automatico Gitea → GitHub) +- Documentazione completa (README, CONTRIBUTING, SECURITY) + +[Unreleased]: https://gitea.emulab.it/Simone/universal-shell-ext/compare/v1.0.0...HEAD +[1.0.0]: https://gitea.emulab.it/Simone/universal-shell-ext/releases/tag/v1.0.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7b68568 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,137 @@ +# Contribuire a UniversalShellExt + +Grazie per il tuo interesse a contribuire! + +> Repository primario: [https://gitea.emulab.it/Simone/universal-shell-ext](https://gitea.emulab.it/Simone/universal-shell-ext) +> Mirror GitHub: [https://github.com/systempal/universal-shell-ext](https://github.com/systempal/universal-shell-ext) (read-only — apri PR su Gitea) + +## Prerequisiti + +| Strumento | Versione | Note | +|-----------|----------|------| +| Visual Studio | 2022 / 2026 | Workload: Desktop development with C++ (toolset v143/v145) | +| Python | 3.7+ | Per `build_plugin.py` | +| Git | 2.30+ | Con supporto submoduli se applicabile | + +## Quick Start + +```powershell +git clone https://gitea.emulab.it/Simone/universal-shell-ext.git +cd universal-shell-ext +python build_plugin.py +``` + +Output in `dist/{x86-ansi,x86-unicode,amd64-unicode}/`. + +## Workflow Sviluppo + +### 1. Branch + +```powershell +git checkout -b feat/nome-feature # nuova feature +git checkout -b fix/descrizione-bug # bugfix +git checkout -b docs/aggiornamento # solo doc +git checkout -b chore/manutenzione # build, dipendenze +``` + +### 2. Commit + +Segui [Conventional Commits](https://www.conventionalcommits.org/it/v1.0.0/): + +``` +feat: aggiunge supporto per formato XYZ +fix: corregge crash su Windows 11 ARM +docs: aggiorna esempio di utilizzo +chore: aggiorna toolset MSVC +refactor: estrae logica parsing in funzione separata +test: aggiunge test per edge case +build: aggiorna script di build +ci: aggiorna workflow GitHub Actions +``` + +Breaking changes: + +``` +feat!: rinomina API Foo() in Bar() + +BREAKING CHANGE: Foo() rinominata in Bar(); aggiornare tutti i chiamanti. +``` + +### 3. Pull Request + +PR aperte verso il branch `main` su Gitea. Verifica: + +- [ ] Build completa senza warning per tutte le architetture: `python build_plugin.py` +- [ ] Esempi aggiornati se cambia l'API +- [ ] `CHANGELOG.md` aggiornato (sezione `[Unreleased]`) +- [ ] Documentazione aggiornata (README, docs/API.md se esiste) +- [ ] Conventional Commits rispettato +- [ ] Nessun file in `dist/` o `__pycache__/` committato + +## Build Script + +``` +python build_plugin.py [opzioni] +``` + +| Opzione | Default | Descrizione | +|---------|---------|-------------| +| `--config` | `all` | Architettura: `x86-ansi`, `x86-unicode`, `x64-unicode`, `all` | +| `--toolset` | `auto` | Visual Studio: `2022`, `2026`, `auto` (rileva il più recente) | +| `--jobs` | numero CPU | Thread paralleli per la build | +| `--clean` | false | Pulisce `dist/` prima di compilare | +| `--install-dir` | none | Copia DLL anche in `/{arch}/` (es. NSIS plugin folder) | +| `--verbose` | false | Output dettagliato (mostra comandi MSBuild) | + +Exit codes: +- `0` — Successo +- `1` — Errore di build +- `2` — Prerequisiti mancanti +- `3` — Argomenti invalidi + +## Release Workflow + +Le release sono automatiche via tag Git: + +```powershell +# 1. Aggiorna VERSION e CHANGELOG.md +echo "1.7.0" > VERSION +# (modifica CHANGELOG.md spostando entry da [Unreleased] a [1.7.0]) + +# 2. Commit +git add VERSION CHANGELOG.md +git commit -m "chore(release): v1.7.0" + +# 3. Tag annotato +git tag -a v1.7.0 -m "Release v1.7.0" + +# 4. Push +git push origin main +git push origin v1.7.0 +``` + +Il workflow `.github/workflows/release.yml` compilerà tutte le architetture +e creerà la release su Gitea con gli artifact ZIP allegati. Il mirror GitHub +riceverà automaticamente il tag. + +## Code Style + +- C/C++: stile coerente con il file modificato +- Python: PEP 8 (4 spazi indent, line length flessibile) +- Header file: `#include` ordinati: stdlib → Win32 → progetto +- Encoding: UTF-8 senza BOM (eccetto `.rc` che richiede UTF-16 LE) +- Line endings: LF in repo (`.gitattributes` normalizza) + +## Reporting Bug + +Apri una [issue](https://gitea.emulab.it/Simone/universal-shell-ext/issues/new) usando il template "Bug Report". +Includi: +- Versione plugin e architettura DLL usata +- Versione NSIS +- Sistema operativo +- Script `.nsi` minimale che riproduce il problema +- Output / errore esatto + +## Domande + +Per domande generali, apri una [issue](https://gitea.emulab.it/Simone/universal-shell-ext/issues) con label `question`. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e05be1c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Simone + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8eab52 --- /dev/null +++ b/README.md @@ -0,0 +1,171 @@ +# UniversalShellExt + +Shell Extension COM generica per Windows che aggiunge una voce personalizzabile al menu contestuale di cartelle. + +## Funzionalità + +- ✅ **Menu Contestuale Personalizzabile**: + - Voce nel menu contestuale per cartelle (click destro su cartella) + - Voce nel menu contestuale per sfondo cartella (click destro su area vuota) + - Testo, icona e comando completamente configurabili via registro +- ✅ **Configurazione Flessibile**: + - Tutti i parametri letti dal registro di Windows + - Supporto per argomenti personalizzati con placeholder `%1` + - Icona estratta automaticamente dall'eseguibile +- ✅ **Sicurezza e Compatibilità**: + - Supporto UAC elevation automatico se necessario + - Compatibile con Windows 10/11 (x64) + - Accesso registro WOW64 corretto (64-bit) + - Thread-safe + +## File del Progetto + +| File | Descrizione | +|------|-------------| +| `UniversalShellExt.cpp` | Codice sorgente C++ della Shell Extension COM | +| `UniversalShellExt.def` | Definizioni esportazioni DLL | +| `UniversalShellExt.rc` | Risorse della DLL (Version Info) | +| `build.py` | Script Python per compilazione, firma e registrazione | + +## Configurazione + +La DLL legge la configurazione dal registro di Windows: + +### Chiavi di Registro + +**Percorso:** `HKEY_LOCAL_MACHINE\SOFTWARE\UniversalShellExt` + +*(Fallback: `HKEY_CURRENT_USER\SOFTWARE\UniversalShellExt`)* + +| Valore | Tipo | Descrizione | Esempio | +|--------|------|-------------|---------| +| `Command` | REG_SZ | Percorso completo dell'eseguibile | `N:\VSCode.exe` | +| `Arguments` | REG_SZ | Argomenti da passare (`%1` = path selezionato) | `"%1"` | +| `MenuText` | REG_SZ | Testo visualizzato nel menu | `Apri con VSCode` | +| `Icon` | REG_SZ | Percorso icona (exe o ico) | `N:\VSCode.exe` | + +### Template Configurazione + +```reg +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SOFTWARE\UniversalShellExt] +"Command"="N:\\VSCode.exe" +"Arguments"="\"%1\"" +"MenuText"="Apri con VSCode Portable" +"Icon"="N:\\VSCode.exe" +``` + +### Valori Default + +Se non configurati: +- `Arguments` → `"%1"` (passa il percorso selezionato) +- `MenuText` → `"Open with Application"` +- `Icon` → usa lo stesso percorso di `Command` + +## Identificatori + +| Tipo | Valore | +|------|--------| +| **CLSID** | `{5D849F86-F2A9-41FA-8A24-E01CD6D6696C}` | +| **Nome COM** | `Universal Portable Shell Extension` | + +## Compilazione + +### Prerequisiti +- **Visual Studio 2022** (con workload "Desktop development with C++") +- **Windows SDK** (per `signtool.exe` e `rc.exe`) +- **Python 3.x** +- **Certificato di firma** (opzionale, per firma digitale) + +### Build Script + +```powershell +# Build completo (compila, copia, firma, registra) +python build.py + +# Solo pulizia +python build.py --clean + +# Solo deregistrazione +python build.py --unregister + +# Build senza firma +python build.py --no-sign +``` + +### Output + +La DLL compilata viene copiata in: +``` +plugins\UniversalShellExt64.dll +``` + +## Registrazione + +### Metodo Consigliato (tramite Launcher) + +Il launcher `VSCode.exe` gestisce automaticamente la registrazione: + +```powershell +N:\VSCode.exe /register # Registra la shell extension +N:\VSCode.exe /unregister # Rimuove la shell extension +N:\VSCode.exe /register /silent # Modalità silenziosa +``` + +### Metodo Manuale (regsvr32) + +Eseguire come **Amministratore**: + +```cmd +:: Registrazione +regsvr32 "N:\Code\Workspace\Launchers\plugins\UniversalShellExt64.dll" + +:: Rimozione +regsvr32 /u "N:\Code\Workspace\Launchers\plugins\UniversalShellExt64.dll" +``` + +## Chiavi di Registro Create + +Durante la registrazione (`DllRegisterServer`): + +| Chiave | Scopo | +|--------|-------| +| `HKCR\CLSID\{5D849F86-...}` | Registrazione classe COM | +| `HKCR\CLSID\{5D849F86-...}\InprocServer32` | Percorso DLL | +| `HKCR\Directory\shellex\ContextMenuHandlers\UniversalShellExt` | Handler per cartelle | +| `HKCR\Directory\Background\shellex\ContextMenuHandlers\...` | Handler per sfondo | +| `HKLM\...\Shell Extensions\Approved` | Whitelist Microsoft | + +## Come Funziona + +1. **Inizializzazione**: Quando l'utente fa click destro, Explorer carica la DLL +2. **Configurazione**: La DLL legge `Command`, `Arguments`, `MenuText`, `Icon` dal registro +3. **Menu**: Inserisce la voce nel menu contestuale con l'icona configurata +4. **Esecuzione**: Al click, sostituisce `%1` con il percorso e lancia il comando +5. **UAC**: Se il comando richiede elevazione, la richiede automaticamente + +## Troubleshooting + +### La voce non appare nel menu +1. Verificare che la DLL sia registrata (`regsvr32`) +2. Controllare che le chiavi di registro siano configurate +3. Riavviare Explorer (`taskkill /F /IM explorer.exe && explorer.exe`) + +### Errore di registrazione +- Eseguire come Amministratore +- Verificare che la DLL sia firmata (Windows potrebbe bloccare DLL non firmate) + +### Il comando non viene eseguito +- Verificare il percorso in `Command` sia corretto +- Controllare che `Arguments` contenga `%1` per ricevere il percorso + +## Versioni + +| Versione | Note | +|----------|------| +| **1.0.0** | Prima release - Shell extension generica configurabile via registro | + +## Licenza + +Uso interno - emulab.it diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ccfc76c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,40 @@ +# Security Policy + +## Versioni Supportate + +Solo l'ultima versione minor riceve fix di security. + +| Versione | Supporto | +|----------|----------| +| Latest minor (es. 1.0.0) | ✅ | +| Versioni precedenti | ❌ | + +## Reporting di una Vulnerabilità + +**Non aprire issue pubbliche per vulnerabilità di security.** + +Per segnalare una vulnerabilità: + +1. **Preferito**: usa la funzione [Security Advisory privato](https://gitea.emulab.it/Simone/universal-shell-ext/security/advisories/new) di Gitea +2. **Alternativa**: invia email a `security@example.com` (sostituire con email reale prima del primo release) + +Includi: +- Descrizione della vulnerabilità +- Passi per riprodurla +- Versione/i affette +- Possibile mitigazione (se nota) + +## Tempo di Risposta + +- Acknowledgment iniziale: entro 7 giorni +- Valutazione: entro 14 giorni +- Patch (se confermata): tempistiche dipendono dalla severità + +## Hardening + +Questo plugin gira con i permessi del processo NSIS chiamante (tipicamente +l'utente che esegue l'installer). Non richiede privilegi elevati per la +compilazione né per l'esecuzione, salvo dove esplicitamente documentato. + +DLL distribuite tramite Releases sono compilate da CI GitHub Actions con +toolchain pinnata. Verificare hash SHA256 pubblicati nelle release. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0 diff --git a/build.py b/build.py new file mode 100644 index 0000000..3070201 --- /dev/null +++ b/build.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +""" +Build script per UniversalShellExt64.dll +Compila, copia, firma e registra la shell extension generica. +Richiede Visual Studio 2022 e Windows SDK. +""" + +import subprocess +import shutil +import sys +import os +from pathlib import Path +import winreg + +# ============================================================================= +# Configurazione +# ============================================================================= + +# Percorsi +SCRIPT_DIR = Path(__file__).parent.resolve() +SOURCE_FILE = SCRIPT_DIR / "UniversalShellExt.cpp" +DEF_FILE = SCRIPT_DIR / "UniversalShellExt.def" +RC_FILE = SCRIPT_DIR / "UniversalShellExt.rc" +RES_FILE = SCRIPT_DIR / "UniversalShellExt.res" + +OUTPUT_DIR = SCRIPT_DIR / "bin" / "x64" +OUTPUT_DLL = OUTPUT_DIR / "UniversalShellExt64.dll" + +# Destinazione finale (cartella plugins) +DEST_DLL = SCRIPT_DIR.parent.parent / "plugins" / "UniversalShellExt64.dll" + +# Visual Studio +VS_PATH = Path("C:/Program Files/Microsoft Visual Studio/2022/Community") +VCVARS_BAT = VS_PATH / "VC/Auxiliary/Build/vcvars64.bat" + +# Signtool +SIGNTOOL = Path("C:/Program Files (x86)/Windows Kits/10/bin/10.0.22621.0/x64/signtool.exe") +CERT_THUMBPRINT = "DFF03ABA0E0156D8E7823A893F9588530A364410" +TIMESTAMP_URL = "http://timestamp.digicert.com" + +# Librerie +LIBS = [ + "ole32.lib", + "uuid.lib", + "shell32.lib", + "user32.lib", + "gdi32.lib", + "advapi32.lib", + "shlwapi.lib" +] + +CLSID_STRING = "{5D849F86-F2A9-41FA-8A24-E01CD6D6696C}" + +def run_command(cmd, shell=False, check=True): + print(f" > {cmd if isinstance(cmd, str) else ' '.join(cmd)}") + result = subprocess.run(cmd, shell=shell, capture_output=True, text=True) + if result.stdout: print(result.stdout) + if result.stderr: print(result.stderr) + if check and result.returncode != 0: + print(f"ERRORE: Comando fallito con codice {result.returncode}") + sys.exit(1) + return result + +def check_prerequisites(): + print("\n=== Verifica prerequisiti ===") + errors = [] + if not SOURCE_FILE.exists(): errors.append(f"Manca sorgente: {SOURCE_FILE}") + if not DEF_FILE.exists(): errors.append(f"Manca DEF: {DEF_FILE}") + if not VCVARS_BAT.exists(): errors.append(f"Manca VS: {VCVARS_BAT}") + if not SIGNTOOL.exists(): errors.append(f"Manca Signtool: {SIGNTOOL}") + if errors: + for e in errors: print(f" ERRORE: {e}") + sys.exit(1) + print(" Prerequisiti OK") + +def update_version(): + print("\n=== Incremento Versione ===") + import re + + if not RC_FILE.exists(): + print(" ERRORE: .rc non trovato!") + return + + content = RC_FILE.read_text(encoding="utf-8") + + # Cerca VER_FILEVERSION 1,0,0,X + # Regex per catturare i primi 3 numeri e l'ultimo + pattern = r'(#define VER_FILEVERSION\s+\d+,\d+,\d+,)(\d+)' + match = re.search(pattern, content) + + if match: + prefix = match.group(1) + build_num = int(match.group(2)) + new_build_num = build_num + 1 + + # Sostituisci VER_FILEVERSION + new_content = re.sub(pattern, f'{prefix}{new_build_num}', content) + + # Aggiorna anche VER_FILEVERSION_STR "1.0.0.X\0" + str_pattern = r'(#define VER_FILEVERSION_STR\s+"[^"]*?)(\d+)(\\0")' + # Nota: questa regex assume che la stringa finisca col numero da incrementare. + # Se è "1.0.0.0\0", cattura "1.0.0." come gruppo 1, "0" come 2. + + # Miglior approccio: ricostruire la stringa in base al nuovo numero + # Ma dobbiamo parsare i primi 3 numeri per essere sicuri + v_parts = prefix.strip().replace("#define VER_FILEVERSION", "").strip().split(',') + if len(v_parts) >= 3: + major, minor, patch = v_parts[0], v_parts[1], v_parts[2] + new_ver_str = f'{major}.{minor}.{patch}.{new_build_num}' + + # Sostituisci la stringa intera con gestione corretta di virgolette e backslash + # La regex deve catturare tutto fino ai doppi apici finali + new_content = re.sub(r'(#define VER_FILEVERSION_STR\s+)"(.*?)"', f'#define VER_FILEVERSION_STR "{new_ver_str}\\\\0"', new_content) + + # Aggiorna anche VER_PRODUCTVERSION (spesso uguale) + new_content = re.sub(r'(#define VER_PRODUCTVERSION\s+).*', f'#define VER_PRODUCTVERSION {major},{minor},{patch},{new_build_num}', new_content) + + # Aggiorna VER_PRODUCTVERSION_STR (spesso solo 3 cifre, ma qui mettiamo 4 per coerenza o lasciamo stare?) + # Nel file attuale è "1.0.0\0". Se vogliamo incrementare anche quello: + # new_content = re.sub(r'#define VER_PRODUCTVERSION_STR\s+".*?"', f'#define VER_PRODUCTVERSION_STR "{major}.{minor}.{patch}\\0"', new_content) + + RC_FILE.write_text(new_content, encoding="utf-8") + print(f" Versione aggiornata a: {new_ver_str}") + else: + print(" Non riesco a parsare la versione corrente.") + else: + print(" Pattern versione non trovato.") + +def clean_build(): + print("\n=== Clean build ===") + to_remove = [ + SCRIPT_DIR / "bin", + SCRIPT_DIR / "Release", + SCRIPT_DIR / "Debug", + SCRIPT_DIR / "x64", + SCRIPT_DIR / "UniversalShellExt64.dll", + SCRIPT_DIR / "UniversalShellExt64.exp", + SCRIPT_DIR / "UniversalShellExt64.lib", + SCRIPT_DIR / "UniversalShellExt64.pdb", + SCRIPT_DIR / "UniversalShellExt.obj", + RES_FILE, + ] + for path in to_remove: + if path.exists(): + if path.is_dir(): + try: shutil.rmtree(path) + except: pass + else: + try: path.unlink() + except: pass + print(" Clean completato") + +def kill_explorer(): + print("\n=== Termina Explorer ===") + subprocess.run(["taskkill", "/F", "/IM", "explorer.exe"], capture_output=True, check=False) + import time + time.sleep(2) + +def start_explorer(): + print("\n=== Riavvia Explorer ===") + subprocess.Popen(["explorer.exe"]) + import time + time.sleep(2) + +def unregister_dll(): + print("\n=== Deregistra DLL ===") + if DEST_DLL.exists(): + run_command(["regsvr32", "/u", "/s", str(DEST_DLL)], check=False) + print(" DLL deregistrata") + else: + print(" DLL non trovata, skip") + +def compile_dll(): + print("\n=== Compilazione DLL ===") + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + + # Compile Resource + rc_cmd = f'''call "{VCVARS_BAT}" && cd /D "{SCRIPT_DIR}" && rc.exe /fo"{RES_FILE.name}" "{RC_FILE.name}"''' + subprocess.run(f'cmd /c "{rc_cmd}"', shell=True, check=True) + + # Compile DLL + libs_str = " ".join(LIBS) + compile_cmd = f'''call "{VCVARS_BAT}" && cd /D "{SCRIPT_DIR}" && cl.exe /LD /EHsc /O2 /DUNICODE /D_UNICODE "{SOURCE_FILE.name}" "{RES_FILE.name}" /Fe:"{OUTPUT_DLL}" /link /DEF:"{DEF_FILE.name}" {libs_str}''' + + result = subprocess.run(f'cmd /c "{compile_cmd}"', shell=True, capture_output=True, text=True) + if result.stdout: + for line in result.stdout.split('\n'): + if line.strip() and not line.startswith('**') and not line.startswith('['): + print(f" {line}") + if result.returncode != 0 or not OUTPUT_DLL.exists(): + print("ERRORE: Compilazione fallita") + sys.exit(1) + + print(f" Compilata: {OUTPUT_DLL}") + +def copy_dll(): + print("\n=== Copia DLL ===") + shutil.copy2(OUTPUT_DLL, DEST_DLL) + print(f" Copiata in: {DEST_DLL}") + +def sign_dll(): + print("\n=== Firma DLL ===") + cmd = [str(SIGNTOOL), "sign", "/sha1", CERT_THUMBPRINT, "/fd", "SHA256", "/t", TIMESTAMP_URL, str(DEST_DLL)] + run_command(cmd) + print(" Firma OK") + +def register_dll(): + print("\n=== Registra DLL ===") + result = run_command(["regsvr32", "/s", str(DEST_DLL)], check=False) + if result.returncode == 0: + print(" Registrazione OK") + else: + print(f" FALLITA: {result.returncode} (Serve Admin?)") + +def verify_registration(): + print("\n=== Verifica Registrazione ===") + try: + key_path = fr"SOFTWARE\Classes\CLSID\{CLSID_STRING}\InprocServer32" + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path) as key: + val, _ = winreg.QueryValueEx(key, "") + print(f" CLSID registrato: {val}") + except FileNotFoundError: + print(" ERRORE: CLSID non trovato") + return False + + try: + key_path = r"SOFTWARE\Classes\Directory\shellex\ContextMenuHandlers\UniversalShellExt" + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_path) as key: + val, _ = winreg.QueryValueEx(key, "") + print(f" Handler directory registrato: {val}") + except FileNotFoundError: + print(" ERRORE: Handler non trovato") + return False + return True + +def main(): + print("UniversalShellExt Builder") + args = sys.argv[1:] + + if "--clean" in args: + clean_build() + return + + if "--unregister" in args: + unregister_dll() + return + + # STEP 0: Clean pre-build + clean_build() + + update_version() + check_prerequisites() + unregister_dll() + kill_explorer() + compile_dll() + copy_dll() + + if "--no-sign" not in args: + sign_dll() + + start_explorer() + register_dll() + verify_registration() + clean_build() + + print("\nDONE!") + print(f"DLL: {DEST_DLL}") + print("Ricorda di configurare HKLM\\Software\\UniversalShellExt") + +if __name__ == "__main__": + main() diff --git a/dist/x64/UniversalShellExt64.dll b/dist/x64/UniversalShellExt64.dll new file mode 100644 index 0000000000000000000000000000000000000000..948b836aee8997a4a6b988592f00f8125c548163 GIT binary patch literal 202256 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 +#include +#include +#include +#include + +#pragma comment(lib, "shlwapi.lib") + +// DLL Version +#define DLL_VERSION L"1.1.0" + +// GUID for UniversalShellExt +// {5D849F86-F2A9-41FA-8A24-E01CD6D6696C} +static const CLSID CLSID_UniversalShellExt = +{ 0x5d849f86, 0xf2a9, 0x41fa, { 0x8a, 0x24, 0xe0, 0x1c, 0xd6, 0xd6, 0x69, 0x6c } }; + +// CLSID as string +#define CLSID_STRING L"{5D849F86-F2A9-41FA-8A24-E01CD6D6696C}" + +// Registry Configuration - now per-CLSID +#define REG_KEY_BASE L"Software\\UniversalShellExt\\" +#define REG_VALUE_COMMAND L"Command" +#define REG_VALUE_ARGS L"Arguments" +#define REG_VALUE_ICON L"Icon" +#define REG_VALUE_TEXT L"MenuText" +#define REG_VALUE_ENABLE_LOG L"EnableLog" + +// Global Variables +HINSTANCE g_hInst = NULL; +LONG g_cDllRef = 0; + +// Internal Helper for File Logging +void WriteLogFile(const wchar_t* buffer) { + FILE* f; + if (_wfopen_s(&f, L"C:\\Users\\Simone\\.gemini\\shellext_debug.log", L"a") == 0) { + SYSTEMTIME st; + GetLocalTime(&st); + fwprintf(f, L"[%02d:%02d:%02d.%03d] %s\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, buffer); + fclose(f); + } +} + +// Global Logger (Legacy/Global scope) +void WriteLog(const wchar_t* format, ...) { + // Global logging is now MINIMAL or DISABLED by default unless needed. + // Uncomment for deep debugging of DLL loading. + // wchar_t buffer[1024]; + // va_list args; + // va_start(args, format); + // _vswprintf_p(buffer, 1024, format, args); + // va_end(args); + // WriteLogFile(buffer); +} + +// Configuration Cache globals removed. +// They are now member variables of the class. + +//============================================================================== +// Helper: Icon to Bitmap +//============================================================================== + +//============================================================================== +// Helper: Icon to Bitmap +//============================================================================== +HBITMAP IconToBitmap(HICON hIcon) +{ + if (!hIcon) return NULL; + ICONINFO iconInfo; + if (!GetIconInfo(hIcon, &iconInfo)) return NULL; + + BITMAP bm; + GetObject(iconInfo.hbmColor ? iconInfo.hbmColor : iconInfo.hbmMask, sizeof(bm), &bm); + + int width = bm.bmWidth; + int height = bm.bmHeight; + + if (iconInfo.hbmColor) DeleteObject(iconInfo.hbmColor); + if (iconInfo.hbmMask) DeleteObject(iconInfo.hbmMask); + + HDC hdcScreen = GetDC(NULL); + HDC hdcMem = CreateCompatibleDC(hdcScreen); + + BITMAPINFO bmi = {0}; + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + void* pBits; + HBITMAP hBitmap = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0); + + if (hBitmap) + { + HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap); + RECT rc = {0, 0, width, height}; + FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); // Transparent assumes 32bit alpha + DrawIconEx(hdcMem, 0, 0, hIcon, width, height, 0, NULL, DI_NORMAL); + SelectObject(hdcMem, hOldBitmap); + } + + DeleteDC(hdcMem); + ReleaseDC(NULL, hdcScreen); + return hBitmap; +} + +//============================================================================== +// Class UniversalShellExt +//============================================================================== +class UniversalShellExt : public IShellExtInit, public IContextMenu +{ +public: + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + static const QITAB qit[] = + { + QITABENT(UniversalShellExt, IContextMenu), + QITABENT(UniversalShellExt, IShellExtInit), + { 0 }, + }; + return QISearch(this, qit, riid, ppv); + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + IFACEMETHODIMP_(ULONG) Release() + { + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) delete this; + return cRef; + } + + // IShellExtInit + IFACEMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID) + { + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + Log(L"UniversalShellExt::Initialize called. CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + if (szCLSID) CoTaskMemFree(szCLSID); + + if (pDataObj == NULL) { + Log(L"Initialize - Error: pDataObj is NULL"); + return E_INVALIDARG; + } + + FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stm; + + if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) + { + UINT nFiles = DragQueryFile((HDROP)stm.hGlobal, 0xFFFFFFFF, NULL, 0); + Log(L"Initialize - Files selected: %d", nFiles); + if (nFiles > 0) + { + DragQueryFile((HDROP)stm.hGlobal, 0, m_szSelectedPath, MAX_PATH); + Log(L"Initialize - Selected Path: %s", m_szSelectedPath); + } + ReleaseStgMedium(&stm); + } + else if (pidlFolder != NULL) + { + SHGetPathFromIDList(pidlFolder, m_szSelectedPath); + Log(L"Initialize - From PIDL: %s", m_szSelectedPath); + } + else { + Log(L"Initialize - Failed to get path data."); + } + return S_OK; + } + + // IContextMenu + IFACEMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) + { + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + Log(L"UniversalShellExt::QueryContextMenu called for CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + Log(L"QueryContextMenu - indexMenu: %d, idCmdFirst: %d, idCmdLast: %d, uFlags: 0x%X", indexMenu, idCmdFirst, idCmdLast, uFlags); + if (szCLSID) CoTaskMemFree(szCLSID); + + if (uFlags & CMF_DEFAULTONLY) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0); + + LoadConfiguration(); // Load config into member variables + + // Fixed position at top + UINT targetPosition = 0; + + Log(L"QueryContextMenu - indexMenu: %d, idCmdFirst: %d, idCmdLast: %d", indexMenu, idCmdFirst, idCmdLast); + Log(L"QueryContextMenu - Using fixed position: %d", targetPosition); + Log(L"QueryContextMenu called. MenuText: %s", m_szMenuText); + + // Dont show if no command configured + if (m_szCommand[0] == L'\0') { + Log(L"QueryContextMenu - Error: Command is empty!"); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0); + } + + HICON hIcon = NULL; + HBITMAP hBitmap = NULL; + + // Extract icon + if (m_szIcon[0] != L'\0') + { + Log(L"QueryContextMenu - Icon configured: %s", m_szIcon); + // Try to find index if comma exists e.g. "dll,1" + // Simple extraction for now + ExtractIconEx(m_szIcon, 0, NULL, &hIcon, 1); + } + + if (hIcon) + { + hBitmap = IconToBitmap(hIcon); + DestroyIcon(hIcon); + } + + if (m_hMenuBitmap) { DeleteObject(m_hMenuBitmap); m_hMenuBitmap = NULL; } + + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_BITMAP; + mii.wID = idCmdFirst; + mii.dwTypeData = m_szMenuText; + mii.fState = MFS_ENABLED; + mii.hbmpItem = hBitmap; + + if (!InsertMenuItem(hMenu, targetPosition, TRUE, &mii)) + { + if (hBitmap) DeleteObject(hBitmap); + Log(L"QueryContextMenu - InsertMenuItem FAILED. Error: %d", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + else + { + Log(L"QueryContextMenu - InsertMenuItem Success. ID: %d", idCmdFirst); + } + + m_hMenuBitmap = hBitmap; + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 1); + } + + IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici) + { + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + Log(L"UniversalShellExt::InvokeCommand called for CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + +// Debug MessageBox removed for production + + + // Debug Box (Temporary - UNCOMMENTED FOR DEBUG) + // MessageBox(NULL, L"InvokeCommand Called!", L"Debug", MB_OK); + + bool isMatch = false; + + // 1. Check for Integer Offset (Standard Right-Click) + if (HIWORD(pici->lpVerb) == 0) + { + // We only add 1 item, so offset 0 is the only valid one. + if (LOWORD(pici->lpVerb) == 0) isMatch = true; + } + // 2. Check for String Verb (Programmatic/Windows 11) + else + { + LPCSTR pszVerb = pici->lpVerb; + // Compare with our CLSID string (which we return in GetCommandString) + // Need to convert our WCHAR CLSID to MultiByte for comparison + if (szCLSID) { + // Construct EXPECTED verb: Verb_XXXX (without braces) + WCHAR szVerbW[128]; + StringCchPrintf(szVerbW, 128, L"Verb_%s", szCLSID + 1); // Skip '{' + size_t lenW = 0; + StringCchLength(szVerbW, 128, &lenW); + if (lenW > 0 && szVerbW[lenW-1] == L'}') szVerbW[lenW-1] = L'\0'; + + // Convert to ANSI for comparison + int lenA = WideCharToMultiByte(CP_ACP, 0, szVerbW, -1, NULL, 0, NULL, NULL); + char* pszVerbA = new (std::nothrow) char[lenA]; + if (pszVerbA) { + WideCharToMultiByte(CP_ACP, 0, szVerbW, -1, pszVerbA, lenA, NULL, NULL); + + if (lstrcmpiA(pszVerb, pszVerbA) == 0) isMatch = true; + else if (lstrcmpiA(pszVerb, "UniversalShellExt") == 0) isMatch = true; // Fallback + + delete[] pszVerbA; + } + } + } + + if (szCLSID) CoTaskMemFree(szCLSID); + + if (!isMatch) { + Log(L"InvokeCommand - Verb mismatch. Rejecting."); + return E_INVALIDARG; + } + + // If command is empty, try reloading config (fallback) + if (m_szCommand[0] == L'\0') { + Log(L"InvokeCommand - Command empty, reloading..."); + LoadConfiguration(); + } + + // Check if command file exists + if (m_szCommand[0] == L'\0' || GetFileAttributes(m_szCommand) == INVALID_FILE_ATTRIBUTES) + { + WCHAR szMsg[MAX_PATH + 128]; + if (m_szCommand[0] == L'\0') + { + StringCchCopy(szMsg, ARRAYSIZE(szMsg), L"Nessun comando configurato.\n\nConfigurare la chiave di registro:\nHKLM\\SOFTWARE\\UniversalShellExt\\Command"); + } + else + { + StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"File non trovato:\n\n%s\n\nVerificare la configurazione nel registro.", m_szCommand); + } + Log(L"InvokeCommand - Error: %s", szMsg); + MessageBox(NULL, szMsg, L"UniversalShellExt - Errore", MB_OK | MB_ICONERROR); + return E_FAIL; + } + + // Prepare Parameters + // Replace %1 in m_szArguments with m_szSelectedPath (quoted) + WCHAR szArgsExpanded[MAX_PATH * 2]; + WCHAR szPathQuoted[MAX_PATH + 2]; + StringCchPrintf(szPathQuoted, MAX_PATH+2, L"\"%s\"", m_szSelectedPath); + + // Simple Replace of %1 + // Note: This is a basic implementation. + // It searches for %1 and replaces it. + + // Copy arguments to buffer + WCHAR *pFound = wcsstr(m_szArguments, L"%1"); + if (pFound) + { + size_t prefixLen = pFound - m_szArguments; + wcsncpy_s(szArgsExpanded, ARRAYSIZE(szArgsExpanded), m_szArguments, prefixLen); + szArgsExpanded[prefixLen] = L'\0'; + StringCchCat(szArgsExpanded, ARRAYSIZE(szArgsExpanded), szPathQuoted); // Insert Path (quoted) + StringCchCat(szArgsExpanded, ARRAYSIZE(szArgsExpanded), pFound + 2); + } + else + { + // No %1 found, just use arguments as is. + // The provided snippet had a different logic here, appending the path if no %1. + // Sticking to the original logic for now, which means if no %1, path is not appended. + StringCchCopy(szArgsExpanded, ARRAYSIZE(szArgsExpanded), m_szArguments); + } + + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.fMask = SEE_MASK_NOCLOSEPROCESS; + sei.lpVerb = L"open"; + sei.lpFile = m_szCommand; + sei.lpParameters = szArgsExpanded; + sei.nShow = SW_SHOWNORMAL; + + // Set Working Directory to the folder containing the executable + WCHAR szDir[MAX_PATH]; + StringCchCopy(szDir, MAX_PATH, m_szCommand); + PathRemoveFileSpec(szDir); // Requires shlwapi.h and linking shlwapi.lib + sei.lpDirectory = szDir; + + Log(L"InvokeCommand - Executing: %s Params: %s Dir: %s", sei.lpFile, sei.lpParameters, sei.lpDirectory); + + if (!ShellExecuteEx(&sei)) + { + DWORD lastError = GetLastError(); + Log(L"InvokeCommand - ShellExecuteEx failed with error: %d", lastError); + if (lastError == ERROR_ELEVATION_REQUIRED) + { + sei.lpVerb = L"runas"; + Log(L"InvokeCommand - Retrying with 'runas' verb."); + ShellExecuteEx(&sei); + } else { + MessageBox(NULL, L"Failed to launch command.", L"Error", MB_ICONERROR); + return E_FAIL; + } + } + + if (sei.hProcess) CloseHandle(sei.hProcess); + Log(L"InvokeCommand - Success"); + return S_OK; + } + + IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pReserved, CHAR *pszName, UINT cchMax) + { + Log(L"GetCommandString called. uType: %d", uType); + if (idCmd != 0) return E_INVALIDARG; + + LoadConfiguration(); // Reload config + + switch (uType) + { + case GCS_HELPTEXTW: + StringCchCopyW((LPWSTR)pszName, cchMax, m_szMenuText); + return S_OK; + + case GCS_HELPTEXTA: + { + int len = WideCharToMultiByte(CP_ACP, 0, m_szMenuText, -1, NULL, 0, NULL, NULL); + if (len <= cchMax) WideCharToMultiByte(CP_ACP, 0, m_szMenuText, -1, pszName, cchMax, NULL, NULL); + } + return S_OK; + + case GCS_VERBW: + case GCS_VALIDATEW: + { + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + if (szCLSID) + { + // Sanitize Verb: replace {CLSID} with Verb_CLSID (no braces) + WCHAR szVerb[128]; + StringCchPrintf(szVerb, 128, L"Verb_%s", szCLSID + 1); // Skip '{' + size_t len = 0; + StringCchLength(szVerb, 128, &len); + if (len > 0 && szVerb[len-1] == L'}') szVerb[len-1] = L'\0'; + + Log(L"GetCommandString - Returning VERB: %s", szVerb); + + if (uType == GCS_VERBW && pszName) { + StringCchCopyW((LPWSTR)pszName, cchMax, szVerb); + } + CoTaskMemFree(szCLSID); + return S_OK; + } + return E_FAIL; + } + + case GCS_VERBA: + case GCS_VALIDATEA: + // Return "UniversalShellExt" for legacy ANSI, but maybe we should return Verb_GUID here too if possible? + // Sticking to simplified "Valid" response for now to minimize charset risk. + // If Verb is requested (ANSI), we return the generic string. + if (uType == GCS_VERBA && pszName) { + StringCchCopyA(pszName, cchMax, "UniversalShellExt"); + } + return S_OK; + + default: + Log(L"GetCommandString - Unknown uType: %d", uType); + return E_INVALIDARG; + } + } + + UniversalShellExt(REFCLSID clsid) : m_cRef(1), m_hMenuBitmap(NULL), m_clsid(clsid) + { + InterlockedIncrement(&g_cDllRef); + + // Stringify CLSID for log + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + Log(L"UniversalShellExt::Constructor - CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + if (szCLSID) CoTaskMemFree(szCLSID); + + m_szSelectedPath[0] = L'\0'; + m_szCommand[0] = L'\0'; + m_szArguments[0] = L'\0'; + m_szIcon[0] = L'\0'; + m_szMenuText[0] = L'\0'; + m_bEnableLog = FALSE; + } + +protected: + ~UniversalShellExt() + { + LPOLESTR szCLSID = NULL; + StringFromCLSID(m_clsid, &szCLSID); + Log(L"UniversalShellExt::Destructor - CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + if (szCLSID) CoTaskMemFree(szCLSID); + + if (m_hMenuBitmap) DeleteObject(m_hMenuBitmap); + InterlockedDecrement(&g_cDllRef); + } + +private: + LONG m_cRef; + WCHAR m_szSelectedPath[MAX_PATH]; + HBITMAP m_hMenuBitmap; + CLSID m_clsid; + // Member variables to store configuration for this instance + WCHAR m_szCommand[MAX_PATH]; + WCHAR m_szArguments[MAX_PATH]; + WCHAR m_szIcon[MAX_PATH]; + WCHAR m_szMenuText[128]; + BOOL m_bEnableLog; + + // Member helper for logging + void Log(const wchar_t* format, ...) { + if (!m_bEnableLog) return; + + wchar_t buffer[1024]; + va_list args; + va_start(args, format); + _vswprintf_p(buffer, 1024, format, args); + va_end(args); + + WriteLogFile(buffer); + } + + // Internal LoadConfiguration method + void LoadConfiguration() + { + m_szCommand[0] = L'\0'; + m_szArguments[0] = L'\0'; + m_szIcon[0] = L'\0'; + m_szMenuText[0] = L'\0'; + + // Build registry path: Software\UniversalShellExt\{CLSID} + WCHAR szKeyPath[256]; + WCHAR szClsid[64]; + StringFromGUID2(m_clsid, szClsid, ARRAYSIZE(szClsid)); + StringCchPrintf(szKeyPath, ARRAYSIZE(szKeyPath), L"%s%s", REG_KEY_BASE, szClsid); + + HKEY hKey; + DWORD dwSize; + DWORD dwType = REG_SZ; + + // Try to open key from HKLM (64-bit view) + LSTATUS status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyPath, 0, KEY_READ | KEY_WOW64_64KEY, &hKey); + if (status != ERROR_SUCCESS) + { + status = RegOpenKeyEx(HKEY_CURRENT_USER, szKeyPath, 0, KEY_READ, &hKey); + } + + if (status == ERROR_SUCCESS) + { + // Read Command + dwSize = sizeof(m_szCommand); + RegQueryValueEx(hKey, REG_VALUE_COMMAND, NULL, &dwType, (LPBYTE)m_szCommand, &dwSize); + + // Read Arguments + dwSize = sizeof(m_szArguments); + RegQueryValueEx(hKey, REG_VALUE_ARGS, NULL, &dwType, (LPBYTE)m_szArguments, &dwSize); + + // Read Icon + dwSize = sizeof(m_szIcon); + RegQueryValueEx(hKey, REG_VALUE_ICON, NULL, &dwType, (LPBYTE)m_szIcon, &dwSize); + + // Read MenuText + dwSize = sizeof(m_szMenuText); + dwSize = sizeof(m_szMenuText); + RegQueryValueEx(hKey, REG_VALUE_TEXT, NULL, &dwType, (LPBYTE)m_szMenuText, &dwSize); + + // Read EnableLog + DWORD dwLog = 0; + dwSize = sizeof(dwLog); + DWORD dwTypeDw = REG_DWORD; + if (RegQueryValueEx(hKey, REG_VALUE_ENABLE_LOG, NULL, &dwTypeDw, (LPBYTE)&dwLog, &dwSize) == ERROR_SUCCESS) { + m_bEnableLog = (dwLog != 0); + } + + RegCloseKey(hKey); + } + + // Defaults + if (m_szCommand[0] == L'\0') { + // Nothing to run? + } + + if (m_szArguments[0] == L'\0') { + StringCchCopy(m_szArguments, MAX_PATH, L"\"%1\""); + } + + if (m_szIcon[0] == L'\0') { + // Default icon to command exe + StringCchCopy(m_szIcon, MAX_PATH, m_szCommand); + } + + if (m_szMenuText[0] == L'\0') { + StringCchCopy(m_szMenuText, 128, L"Open with Application"); + } + } +}; + +//============================================================================== +// Class Factory +//============================================================================== +class ClassFactory : public IClassFactory +{ +public: + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + static const QITAB qit[] = { QITABENT(ClassFactory, IClassFactory), { 0 } }; + return QISearch(this, qit, riid, ppv); + } + IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_cRef); } + IFACEMETHODIMP_(ULONG) Release() + { + ULONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) delete this; + return cRef; + } + IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) + { + if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION; + UniversalShellExt *pExt = new (std::nothrow) UniversalShellExt(m_clsid); + if (pExt == NULL) return E_OUTOFMEMORY; + HRESULT hr = pExt->QueryInterface(riid, ppv); + pExt->Release(); + return hr; + } + IFACEMETHODIMP LockServer(BOOL fLock) + { + if (fLock) InterlockedIncrement(&g_cDllRef); + else InterlockedDecrement(&g_cDllRef); + return S_OK; + } + ClassFactory(const CLSID& clsid) : m_cRef(1), m_clsid(clsid) { } +protected: + ~ClassFactory() { } +private: + LONG m_cRef; + CLSID m_clsid; +}; + +//============================================================================== +// DLL Exports +//============================================================================== + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) +{ + LPOLESTR szCLSID = NULL; + StringFromCLSID(rclsid, &szCLSID); + WriteLog(L"DllGetClassObject - Requesting CLSID: %s", szCLSID ? szCLSID : L"Unknown"); + if (szCLSID) CoTaskMemFree(szCLSID); + + *ppv = NULL; + if (!IsEqualIID(riid, IID_IClassFactory)) + return CLASS_E_CLASSNOTAVAILABLE; + + ClassFactory* pFactory = new (std::nothrow) ClassFactory(rclsid); // Pass CLSID to factory + if (!pFactory) + return E_OUTOFMEMORY; + + HRESULT hr = pFactory->QueryInterface(riid, ppv); + pFactory->Release(); + return hr; +} + +STDAPI DllCanUnloadNow(void) { return g_cDllRef > 0 ? S_FALSE : S_OK; } + +HRESULT SetRegistryValue(HKEY hKeyRoot, LPCWSTR pszSubKey, LPCWSTR pszValueName, LPCWSTR pszValue) +{ + HKEY hKey; + HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyEx(hKeyRoot, pszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)); + if (SUCCEEDED(hr)) + { + if (pszValue != NULL) + { + DWORD cbData = (lstrlen(pszValue) + 1) * sizeof(WCHAR); + hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0, REG_SZ, (const BYTE*)pszValue, cbData)); + } + RegCloseKey(hKey); + } + return hr; +} + +STDAPI DllRegisterServer(void) +{ + WCHAR szModulePath[MAX_PATH]; + if (!GetModuleFileName(g_hInst, szModulePath, ARRAYSIZE(szModulePath))) return HRESULT_FROM_WIN32(GetLastError()); + + HRESULT hr = S_OK; + hr = SetRegistryValue(HKEY_CLASSES_ROOT, L"CLSID\\" CLSID_STRING, NULL, L"Universal Portable Shell Extension"); + if (FAILED(hr)) return hr; + hr = SetRegistryValue(HKEY_CLASSES_ROOT, L"CLSID\\" CLSID_STRING L"\\InprocServer32", NULL, szModulePath); + if (FAILED(hr)) return hr; + hr = SetRegistryValue(HKEY_CLASSES_ROOT, L"CLSID\\" CLSID_STRING L"\\InprocServer32", L"ThreadingModel", L"Apartment"); + if (FAILED(hr)) return hr; + + // Register Context Menu Handler + hr = SetRegistryValue(HKEY_CLASSES_ROOT, L"Directory\\shellex\\ContextMenuHandlers\\UniversalShellExt", NULL, CLSID_STRING); + if (FAILED(hr)) return hr; + hr = SetRegistryValue(HKEY_CLASSES_ROOT, L"Directory\\Background\\shellex\\ContextMenuHandlers\\UniversalShellExt", NULL, CLSID_STRING); + if (FAILED(hr)) return hr; + + // Approve + hr = SetRegistryValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", CLSID_STRING, L"Universal Shell Extension"); + return hr; +} + +STDAPI DllUnregisterServer(void) +{ + RegDeleteTree(HKEY_CLASSES_ROOT, L"CLSID\\" CLSID_STRING); + RegDeleteTree(HKEY_CLASSES_ROOT, L"Directory\\shellex\\ContextMenuHandlers\\UniversalShellExt"); + RegDeleteTree(HKEY_CLASSES_ROOT, L"Directory\\Background\\shellex\\ContextMenuHandlers\\UniversalShellExt"); + + HKEY hKey; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0, KEY_WRITE, &hKey) == ERROR_SUCCESS) + { + RegDeleteValue(hKey, CLSID_STRING); + RegCloseKey(hKey); + } + return S_OK; +} diff --git a/src/UniversalShellExt.def b/src/UniversalShellExt.def new file mode 100644 index 0000000..40a06be --- /dev/null +++ b/src/UniversalShellExt.def @@ -0,0 +1,6 @@ +LIBRARY UniversalShellExt +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/src/UniversalShellExt.rc b/src/UniversalShellExt.rc new file mode 100644 index 0000000..fcb872b --- /dev/null +++ b/src/UniversalShellExt.rc @@ -0,0 +1,44 @@ +// VSCodeShellExt.rc - Version Information Resource + +#include + +#define VER_FILEVERSION 1,0,0,6 +#define VER_FILEVERSION_STR "1.0.0.6\0" +#define VER_PRODUCTVERSION 1,0,0,6 +#define VER_PRODUCTVERSION_STR "1.0.0\0" + +#define VER_COMPANYNAME_STR "Generic Shell Ext\0" +#define VER_FILEDESCRIPTION_STR "Universal Portable Shell Extension\0" +#define VER_INTERNALNAME_STR "UniversalShellExt\0" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2024\0" +#define VER_ORIGINALFILENAME_STR "UniversalShellExt64.dll\0" +#define VER_PRODUCTNAME_STR "Universal Portable Shell Extension\0" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", VER_FILEDESCRIPTION_STR + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", VER_INTERNALNAME_STR + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR + VALUE "ProductName", VER_PRODUCTNAME_STR + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/UniversalShellExt.vcxproj b/src/UniversalShellExt.vcxproj new file mode 100644 index 0000000..900f8bd --- /dev/null +++ b/src/UniversalShellExt.vcxproj @@ -0,0 +1,89 @@ + + + + + Release + Win32 + + + Release + x64 + + + + 17.0 + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890} + VSCodeShellExt + 10.0 + + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + $(SolutionDir)bin\x86\ + $(Configuration)\x86\ + VSCodeShellExt32 + + + $(SolutionDir)bin\x64\ + $(Configuration)\x64\ + UniversalShellExt64 + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + UniversalShellExt.def + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + MultiThreaded + + + Windows + true + true + UniversalShellExt.def + + + + + + + + + +