commit 13c8f89d7aff29d9b5855e0574af59508bd4f1df Author: Simone Date: Wed Apr 29 14:00:07 2026 +0200 chore: initial commit (extracted from Launchers monorepo) Plugin: nsProcess v1.6.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: zlib 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..99df832 --- /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/nsis-plugin-nsprocess/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/nsis-plugin-nsprocess/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..e2a3a38 --- /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.6.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/nsis-plugin-nsprocess/compare/v1.6.0...HEAD +[1.6.0]: https://gitea.emulab.it/Simone/nsis-plugin-nsprocess/releases/tag/v1.6.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..056fe14 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,137 @@ +# Contribuire a nsProcess + +Grazie per il tuo interesse a contribuire! + +> Repository primario: [https://gitea.emulab.it/Simone/nsis-plugin-nsprocess](https://gitea.emulab.it/Simone/nsis-plugin-nsprocess) +> Mirror GitHub: [https://github.com/systempal/nsis-plugin-nsprocess](https://github.com/systempal/nsis-plugin-nsprocess) (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/nsis-plugin-nsprocess.git +cd nsis-plugin-nsprocess +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/nsis-plugin-nsprocess/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/nsis-plugin-nsprocess/issues) con label `question`. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc3fdc5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +zlib License + +Copyright (c) 2026 Simone + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce55ca6 --- /dev/null +++ b/README.md @@ -0,0 +1,167 @@ +# nsProcess NSIS Plugin v1.6 + +**Versione personale modificata** + +--- + +## Descrizione Originale + +**2006 Shengalts Aleksander aka Instructor (Shengalts@mail.ru)** + +Source function FIND_PROC_BY_NAME based upon the Ravi Kochhar (kochhar@physiology.wisc.edu) code. +Thanks iceman_k (FindProcDLL plugin) and DITMan (KillProcDLL plugin) for direct me. +NSIS UNICODE compatible version (1.6) by brainsucker. + +## Features + +- Find a process by name +- Kill all processes with specified name (not only one) +- Close all processes with specified name (first tries to close all process windows, waits for 3 seconds for process to exit, terminates if still alive) +- The process name is case-insensitive +- Win95/98/ME/NT/2000/XP/Win7 support +- Small plugin size (4 Kb) +- NSIS UNICODE support + +## Usage + +### Find process + +```nsis +${nsProcess::FindProcess} "[file.exe]" $var +``` + +**Parameters:** +- `[file.exe]` - Process name (e.g. "notepad.exe") + +**Return values ($var):** +| Code | Description | +|------|-------------| +| 0 | Success | +| 603 | Process was not currently running | +| 604 | Unable to identify system type | +| 605 | Unsupported OS | +| 606 | Unable to load NTDLL.DLL | +| 607 | Unable to get procedure address from NTDLL.DLL | +| 608 | NtQuerySystemInformation failed | +| 609 | Unable to load KERNEL32.DLL | +| 610 | Unable to get procedure address from KERNEL32.DLL | +| 611 | CreateToolhelp32Snapshot failed | + +### Kill/Close process + +```nsis +${nsProcess::KillProcess} "[file.exe]" $var +${nsProcess::CloseProcess} "[file.exe]" $var +``` + +**Parameters:** +- `[file.exe]` - Process name (e.g. "notepad.exe") + +**Return values ($var):** +| Code | Description | +|------|-------------| +| 0 | Success | +| 601 | No permission to terminate process | +| 602 | Not all processes terminated successfully | +| 603 | Process was not currently running | +| 604 | Unable to identify system type | +| 605 | Unsupported OS | +| 606 | Unable to load NTDLL.DLL | +| 607 | Unable to get procedure address from NTDLL.DLL | +| 608 | NtQuerySystemInformation failed | +| 609 | Unable to load KERNEL32.DLL | +| 610 | Unable to get procedure address from KERNEL32.DLL | +| 611 | CreateToolhelp32Snapshot failed | + +### Direct plugin call (without macros) + +```nsis +nsProcess::_CloseProcess "notepad.exe" +Pop $R0 +``` + +### Unload plugin + +```nsis +${nsProcess::Unload} +``` + +## Example + +```nsis +!include "nsProcess.nsh" + +Section "Check Notepad" + ${nsProcess::FindProcess} "notepad.exe" $R0 + ${If} $R0 == 0 + MessageBox MB_YESNO "Notepad is running. Close it?" IDNO skip + ${nsProcess::CloseProcess} "notepad.exe" $R0 + ${If} $R0 == 0 + MessageBox MB_OK "Notepad closed successfully" + ${Else} + MessageBox MB_OK "Failed to close Notepad" + ${EndIf} + skip: + ${Else} + MessageBox MB_OK "Notepad is not running" + ${EndIf} + ${nsProcess::Unload} +SectionEnd +``` + +## Include file + +Include `nsProcess.nsh` to use the macros: + +```nsis +!include "nsProcess.nsh" +``` + +--- + +## ⚠️ Differenze nella versione personale + +### Nuova architettura supportata: x64 (amd64-unicode) + +L'originale supportava solo: +- x86-ansi (Plugins\nsProcess.dll) +- x86-unicode (nsProcessW.dll da rinominare in nsProcess.dll) + +La versione personale aggiunge il supporto per: +- **amd64-unicode** (x64) + +### Progetto Visual Studio + +L'originale includeva: +- `Source/nsProcess.sln` - Solution VS2008 +- `Source/nsProcess.vcproj` - Progetto VS2008 (solo x86) + +La versione personale converte a VS2022 con supporto x64: +- `nsProcess.sln` - Solution VS2022 +- `nsProcess/nsProcess.vcxproj` - Progetto VS2022 (x86-ansi, x86-unicode, amd64-unicode) + +### File aggiunti + +- `build_plugin.py` - Script Python per compilare il plugin per tutte le architetture +- `nsis/` - Cartella con gli header NSIS per la compilazione: + - `api.h`, `crt.c`, `nsis_tchar.h`, `pluginapi.c`, `pluginapi.h` + +### File rimossi + +I file DLL precompilati sono stati rimossi dalla distribuzione: + +- `Plugins/nsProcess.dll` (x86 ANSI) +- `nsProcessW.dll` (x86 UNICODE) + +### Compilazione + +```cmd +cd nsProcess +python build_plugin.py +``` + +I DLL vengono copiati in `plugins/{platform}/nsProcess.dll`. + +### Modifiche funzionali + +Nessuna modifica funzionale rispetto all'originale. Le modifiche riguardano solo l'infrastruttura di build e il supporto x64. \ No newline at end of file diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..88cb454 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,67 @@ +***************************************************************** +*** nsProcess NSIS plugin v1.6 *** +***************************************************************** + +2006 Shengalts Aleksander aka Instructor (Shengalts@mail.ru) + +Source function FIND_PROC_BY_NAME based + upon the Ravi Kochhar (kochhar@physiology.wisc.edu) code +Thanks iceman_k (FindProcDLL plugin) and + DITMan (KillProcDLL plugin) for direct me +NSIS UNICODE compatible version (1.6) by brainsucker + (sorry, installer missing, i'm too lazy :) + +Features: +- Find a process by name +- Kill all processes with specified name (not only one) +- Close all processes with specified name (first tries to close all process windows, +waits for 3 seconds for process to exit, terminates if still alive) +- The process name is case-insensitive +- Win95/98/ME/NT/2000/XP/Win7 support +- Small plugin size (4 Kb) +- NSIS UNICODE support (just rename nsProcessW.dll into nsProcess.dll) + +**** Find process **** +${nsProcess::FindProcess} "[file.exe]" $var + +"[file.exe]" - Process name (e.g. "notepad.exe") + +$var 0 Success + 603 Process was not currently running + 604 Unable to identify system type + 605 Unsupported OS + 606 Unable to load NTDLL.DLL + 607 Unable to get procedure address from NTDLL.DLL + 608 NtQuerySystemInformation failed + 609 Unable to load KERNEL32.DLL + 610 Unable to get procedure address from KERNEL32.DLL + 611 CreateToolhelp32Snapshot failed + + +**** Kill/Close process **** +${nsProcess::KillProcess} "[file.exe]" $var +${nsProcess::CloseProcess} "[file.exe]" $var + +"[file.exe]" - Process name (e.g. "notepad.exe") + +$var 0 Success + 601 No permission to terminate process + 602 Not all processes terminated successfully + 603 Process was not currently running + 604 Unable to identify system type + 605 Unsupported OS + 606 Unable to load NTDLL.DLL + 607 Unable to get procedure address from NTDLL.DLL + 608 NtQuerySystemInformation failed + 609 Unable to load KERNEL32.DLL + 610 Unable to get procedure address from KERNEL32.DLL + 611 CreateToolhelp32Snapshot failed + +**** Comment from brainsucker **** +I'm actually not using macros in my code, plugin calls are easy: + +nsProcess:_CloseProcess "notepad.exe" +Pop $R0 + +**** Unload plugin **** +${nsProcess::Unload} diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0de97a5 --- /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.6.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/nsis-plugin-nsprocess/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..dc1e644 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.6.0 diff --git a/build_plugin.py b/build_plugin.py new file mode 100644 index 0000000..46014f3 --- /dev/null +++ b/build_plugin.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +""" +Build script canonico per il plugin nsProcess. + +CLI standard: vedi `python build_plugin.py --help` +""" +from __future__ import annotations + +import argparse +import io +import os +import shutil +import subprocess +import sys +from pathlib import Path + +# Ensure UTF-8 output on Windows (avoids cp1252 UnicodeEncodeError) +if sys.stdout.encoding and sys.stdout.encoding.lower() != "utf-8": + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace") + +ROOT = Path(__file__).resolve().parent +SRC_DIR = ROOT / "src" +DIST_DIR = ROOT / "dist" +VERSION_FILE = ROOT / "VERSION" + +# Mapping CLI config -> (MSBuild Configuration, MSBuild Platform, dist subdir) +CONFIGS = { + "x86-ansi": ("Release", "Win32", "x86-ansi"), + "x86-unicode": ("Release Unicode", "Win32", "x86-unicode"), + "x64-unicode": ("Release Unicode", "x64", "amd64-unicode"), +} + +VCXPROJ = SRC_DIR / "nsProcess.vcxproj" +DLL_NAME = "nsProcess.dll" + + +def read_version() -> str: + # utf-8-sig strips BOM (\ufeff) automatically + return VERSION_FILE.read_text(encoding="utf-8-sig").strip() + + +def find_msbuild(toolset: str) -> Path: + """Localizza MSBuild via vswhere; toolset='2022', '2026', o 'auto'. + + In auto mode, tries 2022 before 2026 because most vcxproj files use + PlatformToolset v143 (VS2022) which may not be available in VS2026 build tools. + """ + pf86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)") + vswhere = Path(pf86) / "Microsoft Visual Studio" / "Installer" / "vswhere.exe" + if not vswhere.exists(): + sys.exit(2) + + def _query(version_range: str | None) -> list[str]: + args = [str(vswhere), "-latest", "-products", "*", + "-requires", "Microsoft.Component.MSBuild", + "-find", r"MSBuild\**\Bin\MSBuild.exe"] + if version_range: + args += ["-version", version_range] + result = subprocess.run(args, capture_output=True, text=True) + return [ln.strip() for ln in result.stdout.splitlines() if ln.strip()] + + if toolset == "2022": + paths = _query("[17.0,18.0)") + elif toolset == "2026": + paths = _query("[18.0,19.0)") + else: # auto: prefer 2022 (v143) over 2026 (v145) + paths = _query("[17.0,18.0)") or _query("[18.0,19.0)") or _query(None) + + if not paths: + sys.exit(2) + return Path(paths[0]) + + +def build_one(msbuild: Path, config: str, platform: str, jobs: int, verbose: bool) -> bool: + cmd = [ + str(msbuild), str(VCXPROJ), + f"/p:Configuration={config}", + f"/p:Platform={platform}", + f"/m:{jobs}", + "/nologo", + "/v:" + ("normal" if verbose else "minimal"), + ] + print(f"[build] {config} | {platform}") + return subprocess.run(cmd).returncode == 0 + + +def collect_dll(config: str, platform: str, dist_subdir: str) -> Path | None: + """Trova la DLL prodotta dal vcxproj e la copia in dist//.""" + plat_dir = "" if platform == "Win32" else platform + "/" + candidates = list(SRC_DIR.glob(f"**/{plat_dir}{config}/{DLL_NAME}")) + candidates += list(ROOT.glob(f"**/{plat_dir}{config}/{DLL_NAME}")) + if not candidates: + return None + src = candidates[0] + dst_dir = DIST_DIR / dist_subdir + dst_dir.mkdir(parents=True, exist_ok=True) + dst = dst_dir / DLL_NAME + shutil.copy2(src, dst) + return dst + + +def main() -> int: + parser = argparse.ArgumentParser(description=f"Build nsProcess plugin") + parser.add_argument("--config", default="all", + choices=list(CONFIGS.keys()) + ["all"]) + parser.add_argument("--toolset", default="auto", choices=["2022", "2026", "auto"]) + parser.add_argument("--jobs", type=int, default=os.cpu_count() or 4) + parser.add_argument("--clean", action="store_true") + parser.add_argument("--install-dir", type=Path, default=None) + parser.add_argument("--verbose", action="store_true") + parser.add_argument("--version", action="store_true", + help="Mostra versione e termina") + args = parser.parse_args() + + if args.version: + print(read_version()) + return 0 + + if not VCXPROJ.exists(): + print(f"ERROR: {VCXPROJ} not found", file=sys.stderr) + return 3 + + if args.clean and DIST_DIR.exists(): + shutil.rmtree(DIST_DIR) + + msbuild = find_msbuild(args.toolset) + print(f"[info] MSBuild: {msbuild}") + print(f"[info] Version: {read_version()}") + + targets = list(CONFIGS.keys()) if args.config == "all" else [args.config] + failed = [] + for cfg_name in targets: + config, platform, subdir = CONFIGS[cfg_name] + if not build_one(msbuild, config, platform, args.jobs, args.verbose): + failed.append(cfg_name) + continue + dst = collect_dll(config, platform, subdir) + if dst is None: + print(f"ERROR: DLL not found for {cfg_name}", file=sys.stderr) + failed.append(cfg_name) + else: + print(f"[ok] {dst}") + if args.install_dir: + install_path = args.install_dir / subdir + install_path.mkdir(parents=True, exist_ok=True) + shutil.copy2(dst, install_path / DLL_NAME) + print(f"[install] {install_path / DLL_NAME}") + + if failed: + print(f"FAILED: {failed}", file=sys.stderr) + return 1 + print("[done] all targets built successfully") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/dist/amd64-unicode/nsProcess.dll b/dist/amd64-unicode/nsProcess.dll new file mode 100644 index 0000000..101f759 Binary files /dev/null and b/dist/amd64-unicode/nsProcess.dll differ diff --git a/dist/x86-ansi/nsProcess.dll b/dist/x86-ansi/nsProcess.dll new file mode 100644 index 0000000..a7ee084 Binary files /dev/null and b/dist/x86-ansi/nsProcess.dll differ diff --git a/dist/x86-unicode/nsProcess.dll b/dist/x86-unicode/nsProcess.dll new file mode 100644 index 0000000..4d8a971 Binary files /dev/null and b/dist/x86-unicode/nsProcess.dll differ diff --git a/examples/nsProcessTest.nsi b/examples/nsProcessTest.nsi new file mode 100644 index 0000000..0591068 --- /dev/null +++ b/examples/nsProcessTest.nsi @@ -0,0 +1,69 @@ +Name "nsProcessTest" +OutFile "nsProcessTest.exe" + +!include "nsProcess.nsh" +!include "Sections.nsh" + +Var RADIOBUTTON + +Page components +Page instfiles + + +Section "Find process" FindProcess + ${nsProcess::FindProcess} "Calc.exe" $R0 + MessageBox MB_OK "nsProcess::FindProcess$\n$\n\ + Errorlevel: [$R0]" + + ${nsProcess::Unload} +SectionEnd + + +Section /o "Kill process" KillProcess + loop: + ${nsProcess::FindProcess} "NoTePad.exe" $R0 + StrCmp $R0 0 0 +2 + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION 'Close "notepad" before continue' IDOK loop IDCANCEL end + + ${nsProcess::KillProcess} "NoTePad.exe" $R0 + MessageBox MB_OK "nsProcess::KillProcess$\n$\n\ + Errorlevel: [$R0]" + + Exec "notepad.exe" + Exec "notepad.exe" + Exec "notepad.exe" + Sleep 1000 + BringToFront + MessageBox MB_OK "Press OK and 3 notepad's windows will be closed (TERMINATED)" + + ${nsProcess::KillProcess} "NoTePad.exe" $R0 + MessageBox MB_OK "nsProcess::KillProcess$\n$\n\ + Errorlevel: [$R0]" + + Exec "notepad.exe" + Exec "notepad.exe" + Exec "notepad.exe" + Sleep 1000 + BringToFront + MessageBox MB_OK "Press OK and 3 notepad's windows will be CLOSED" + + ${nsProcess::CloseProcess} "NoTePad.exe" $R0 + MessageBox MB_OK "nsProcess::CloseProcess$\n$\n\ + Errorlevel: [$R0]" + + + end: + ${nsProcess::Unload} +SectionEnd + + +Function .onInit + StrCpy $RADIOBUTTON ${FindProcess} +FunctionEnd + +Function .onSelChange + !insertmacro StartRadioButtons $RADIOBUTTON + !insertmacro RadioButton ${FindProcess} + !insertmacro RadioButton ${KillProcess} + !insertmacro EndRadioButtons +FunctionEnd diff --git a/include/nsProcess.nsh b/include/nsProcess.nsh new file mode 100644 index 0000000..9ef6098 --- /dev/null +++ b/include/nsProcess.nsh @@ -0,0 +1,28 @@ +!define nsProcess::FindProcess `!insertmacro nsProcess::FindProcess` + +!macro nsProcess::FindProcess _FILE _ERR + nsProcess::_FindProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + + +!define nsProcess::KillProcess `!insertmacro nsProcess::KillProcess` + +!macro nsProcess::KillProcess _FILE _ERR + nsProcess::_KillProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + +!define nsProcess::CloseProcess `!insertmacro nsProcess::CloseProcess` + +!macro nsProcess::CloseProcess _FILE _ERR + nsProcess::_CloseProcess /NOUNLOAD `${_FILE}` + Pop ${_ERR} +!macroend + + +!define nsProcess::Unload `!insertmacro nsProcess::Unload` + +!macro nsProcess::Unload + nsProcess::_Unload +!macroend diff --git a/src/nsProcess.c b/src/nsProcess.c new file mode 100644 index 0000000..78abd9d --- /dev/null +++ b/src/nsProcess.c @@ -0,0 +1,452 @@ +/***************************************************************** + * nsProcess NSIS plugin v1.6.4 * + * * + * 2006 Shengalts Aleksander aka Instructor (Shengalts@mail.ru) * + * * + * Source function FIND_PROC_BY_NAME based * + * upon the Ravi Kochhar (kochhar@physiology.wisc.edu) code * + * Thanks iceman_k (FindProcDLL plugin) and * + * DITMan (KillProcDLL plugin) for point me up * + *****************************************************************/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include "nsis/pluginapi.h" + +/* Defines */ +#define NSIS_MAX_STRLEN 1024 + +#define SystemProcessInformation 5 +#define STATUS_SUCCESS 0x00000000L +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L + +typedef struct _SYSTEM_THREAD_INFO +{ + FILETIME ftCreationTime; + DWORD dwUnknown1; + DWORD dwStartAddress; + DWORD dwOwningPID; + DWORD dwThreadID; + DWORD dwCurrentPriority; + DWORD dwBasePriority; + DWORD dwContextSwitches; + DWORD dwThreadState; + DWORD dwUnknown2; + DWORD dwUnknown3; + DWORD dwUnknown4; + DWORD dwUnknown5; + DWORD dwUnknown6; + DWORD dwUnknown7; +} SYSTEM_THREAD_INFO; + +typedef struct _SYSTEM_PROCESS_INFO +{ + DWORD dwOffset; + DWORD dwThreadCount; + DWORD dwUnkown1[6]; + FILETIME ftCreationTime; + DWORD dwUnkown2; + DWORD dwUnkown3; + DWORD dwUnkown4; + DWORD dwUnkown5; + DWORD dwUnkown6; + WCHAR *pszProcessName; + DWORD dwBasePriority; + DWORD dwProcessID; + DWORD dwParentProcessID; + DWORD dwHandleCount; + DWORD dwUnkown7; + DWORD dwUnkown8; + DWORD dwVirtualBytesPeak; + DWORD dwVirtualBytes; + DWORD dwPageFaults; + DWORD dwWorkingSetPeak; + DWORD dwWorkingSet; + DWORD dwUnkown9; + DWORD dwPagedPool; + DWORD dwUnkown10; + DWORD dwNonPagedPool; + DWORD dwPageFileBytesPeak; + DWORD dwPageFileBytes; + DWORD dwPrivateBytes; + DWORD dwUnkown11; + DWORD dwUnkown12; + DWORD dwUnkown13; + DWORD dwUnkown14; + SYSTEM_THREAD_INFO ati[ANYSIZE_ARRAY]; +} SYSTEM_PROCESS_INFO; + +/* Include conversion functions */ +// #define xatoi +// #define xitoa +// #include "ConvFunc.h" + +/* Global variables */ +TCHAR szBuf[NSIS_MAX_STRLEN]; + +/* Funtions prototypes and macros */ +int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose); + +static BOOL IsMainWindow(HWND hWnd) +{ + return GetWindow(hWnd, GW_OWNER) == (HWND)0 && IsWindowVisible(hWnd); +} + +/* NSIS functions code */ +void __declspec(dllexport) _FindProcess(HWND hwndParent, int string_size, + TCHAR *variables, stack_t **stacktop, extra_parameters *extra) +{ + EXDLL_INIT(); + { + int nError; + + popstringn(szBuf, NSIS_MAX_STRLEN); + nError = FIND_PROC_BY_NAME(szBuf, FALSE, FALSE); + pushint(nError); + } +} + +void __declspec(dllexport) _KillProcess(HWND hwndParent, int string_size, + TCHAR *variables, stack_t **stacktop, extra_parameters *extra) +{ + EXDLL_INIT(); + { + int nError = 0; + + popstringn(szBuf, NSIS_MAX_STRLEN); + nError = FIND_PROC_BY_NAME(szBuf, TRUE, FALSE); + pushint(nError); + } +} + +void __declspec(dllexport) _CloseProcess(HWND hwndParent, int string_size, + TCHAR *variables, stack_t **stacktop, extra_parameters *extra) +{ + EXDLL_INIT(); + { + int nError = 0; + + popstringn(szBuf, NSIS_MAX_STRLEN); + nError = FIND_PROC_BY_NAME(szBuf, TRUE, TRUE); + pushint(nError); + } +} + +void __declspec(dllexport) _Unload(HWND hwndParent, int string_size, + TCHAR *variables, stack_t **stacktop, extra_parameters *extra) +{ +} + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + return TRUE; +} + +BOOL CALLBACK EnumWindowsProc(HWND hwnd, + LPARAM lParam) +{ + HANDLE *data = (HANDLE *)lParam; + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + if ((HANDLE)(DWORD_PTR)pid == data[0] && IsMainWindow(hwnd)) + { + PostMessage(hwnd, WM_CLOSE, 0, 0); + data[1] = hwnd; + } + return TRUE; +} + +void NiceTerminate(DWORD id, BOOL bClose, BOOL *bSuccess, BOOL *bFailed) +{ + HANDLE hProc; + HANDLE data[2]; + DWORD ec; + BOOL bDone = FALSE; + if (hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, id)) + { + data[0] = (HANDLE)(DWORD_PTR)id; + data[1] = NULL; + + if (bClose) + EnumWindows(EnumWindowsProc, (LPARAM)&data[0]); + if (data[1] != NULL) + { + if (GetExitCodeProcess(hProc, &ec) && ec == STILL_ACTIVE) + if (WaitForSingleObject(hProc, 3000) == WAIT_OBJECT_0) + { + *bSuccess = bDone = TRUE; + } + else + ; + else + { + *bSuccess = bDone = TRUE; + } + } + if (!bDone) + { + // Open for termination + if (TerminateProcess(hProc, 0)) + *bSuccess = TRUE; + else + *bFailed = TRUE; + } + CloseHandle(hProc); + } +} + +int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose) +// Find the process "szProcessName" if it is currently running. +// This works for Win95/98/ME and also WinNT/2000/XP. +// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE" +// will both work. If bTerminate is TRUE, then process will be terminated. +// +// Return codes are as follows: +// 0 = Success +// 601 = No permission to terminate process +// 602 = Not all processes terminated successfully +// 603 = Process was not currently running +// 604 = Unable to identify system type +// 605 = Unsupported OS +// 606 = Unable to load NTDLL.DLL +// 607 = Unable to get procedure address from NTDLL.DLL +// 608 = NtQuerySystemInformation failed +// 609 = Unable to load KERNEL32.DLL +// 610 = Unable to get procedure address from KERNEL32.DLL +// 611 = CreateToolhelp32Snapshot failed +// +// Change history: +// created 06/23/2000 - Ravi Kochhar (kochhar@physiology.wisc.edu) +// http://www.neurophys.wisc.edu/ravi/software/ +// modified 03/08/2002 - Ravi Kochhar (kochhar@physiology.wisc.edu) +// - Borland-C compatible if BORLANDC is defined as +// suggested by Bob Christensen +// modified 03/10/2002 - Ravi Kochhar (kochhar@physiology.wisc.edu) +// - Removed memory leaks as suggested by +// Jonathan Richard-Brochu (handles to Proc and Snapshot +// were not getting closed properly in some cases) +// modified 14/11/2005 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Combine functions FIND_PROC_BY_NAME and KILL_PROC_BY_NAME +// - Code has been optimized +// - Now kill all processes with specified name (not only one) +// - Cosmetic improvements +// - Removed error 632 (Invalid process name) +// - Changed error 602 (Unable to terminate process for some other reason) +// - BORLANDC define not needed +// modified 04/01/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Removed CRT dependency +// modified 21/04/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Removed memory leak as suggested by {_trueparuex^} +// (handle to hSnapShot was not getting closed properly in some cases) +// modified 21/04/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Removed memory leak as suggested by {_trueparuex^} +// (handle to hSnapShot was not getting closed properly in some cases) +// modified 19/07/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Code for WinNT/2000/XP has been rewritten +// - Changed error codes +// modified 31/08/2006 - Shengalts Aleksander aka Instructor (Shengalts@mail.ru): +// - Removed memory leak as suggested by Daniel Vanesse +{ + TCHAR szName[MAX_PATH]; + OSVERSIONINFOEX osvi = {0}; + HMODULE hLib; + // HANDLE hProc; + ULONG uError; + BOOL bFound = FALSE; + BOOL bSuccess = FALSE; + BOOL bFailed = FALSE; + DWORD dwCurrentProcessID = 0; + ULONGLONG maskCondition = 0; + + // Gets Current Process ID + dwCurrentProcessID = GetCurrentProcessId(); + + // First check what version of Windows we're in + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; + maskCondition = VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL); + if (!VerifyVersionInfo(&osvi, VER_PLATFORMID, maskCondition)) + { + osvi.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + if (!VerifyVersionInfo(&osvi, VER_PLATFORMID, maskCondition)) + return 605; + } + // if (!GetVersionEx(&osvi)) return 604; + + // if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT && + // osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) + // return 605; + + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + // WinNT/2000/XP + + SYSTEM_PROCESS_INFO *spi; + SYSTEM_PROCESS_INFO *spiCount; + DWORD dwSize = 0x4000; + DWORD dwData; + ULONG(WINAPI * NtQuerySystemInformationPtr)(ULONG, PVOID, LONG, PULONG); + + if (hLib = LoadLibraryW(L"NTDLL.DLL")) + { + NtQuerySystemInformationPtr = (ULONG(WINAPI *)(ULONG, PVOID, LONG, PULONG))GetProcAddress(hLib, "NtQuerySystemInformation"); + + if (NtQuerySystemInformationPtr) + { + while (1) + { + if (spi = (SYSTEM_PROCESS_INFO *)LocalAlloc(LMEM_FIXED, dwSize)) + { + uError = (*NtQuerySystemInformationPtr)(SystemProcessInformation, spi, dwSize, &dwData); + + if (uError == STATUS_SUCCESS) + break; + + LocalFree(spi); + + if (uError != STATUS_INFO_LENGTH_MISMATCH) + { + uError = 608; + break; + } + } + else + { + uError = 608; + break; + } + dwSize *= 2; + } + } + else + uError = 607; + + FreeLibrary(hLib); + } + else + uError = 606; + + if (uError != STATUS_SUCCESS) + return uError; + + spiCount = spi; + + while (1) + { + if (spiCount->pszProcessName) + { + +#ifdef UNICODE + lstrcpyn(szName, spiCount->pszProcessName, MAX_PATH); +#else + WideCharToMultiByte(CP_ACP, 0, spiCount->pszProcessName, -1, szName, MAX_PATH, NULL, NULL); +#endif + if (spiCount->dwProcessID != dwCurrentProcessID && !lstrcmpi(szName, szProcessName)) + { + // Process found + bFound = TRUE; + + if (bTerminate == TRUE) + { + NiceTerminate(spiCount->dwProcessID, bClose, &bSuccess, &bFailed); + } + else + break; + } + } + if (spiCount->dwOffset == 0) + break; + spiCount = (SYSTEM_PROCESS_INFO *)((char *)spiCount + spiCount->dwOffset); + } + LocalFree(spi); + } + else + { +#if defined(UNICODE) +#undef Process32First +#undef Process32Next +#undef PROCESSENTRY32 +#undef PPROCESSENTRY32 +#undef LPPROCESSENTRY32 +#endif + // Win95/98/ME + PROCESSENTRY32 pe; + char *pName; + HANDLE hSnapShot; + BOOL bResult; + HANDLE(WINAPI * CreateToolhelp32SnapshotPtr)(DWORD, DWORD); + BOOL(WINAPI * Process32FirstPtr)(HANDLE, LPPROCESSENTRY32); + BOOL(WINAPI * Process32NextPtr)(HANDLE, LPPROCESSENTRY32); + + if (hLib = LoadLibrary(_TEXT("KERNEL32.DLL"))) + { + CreateToolhelp32SnapshotPtr = (HANDLE(WINAPI *)(DWORD, DWORD))GetProcAddress(hLib, "CreateToolhelp32Snapshot"); + Process32FirstPtr = (BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32))GetProcAddress(hLib, "Process32First"); + Process32NextPtr = (BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32))GetProcAddress(hLib, "Process32Next"); + + if (CreateToolhelp32SnapshotPtr && Process32NextPtr && Process32FirstPtr) + { + // Get a handle to a Toolhelp snapshot of all the systems processes. + if ((hSnapShot = (*CreateToolhelp32SnapshotPtr)(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE) + { + // Get the first process' information. + pe.dwSize = sizeof(PROCESSENTRY32); + bResult = (*Process32FirstPtr)(hSnapShot, &pe); + + // While there are processes, keep looping and checking. + while (bResult) + { + // Get file name + for (pName = pe.szExeFile + lstrlenA(pe.szExeFile) - 1; *pName != '\\' && *pName != '\0'; --pName) + ; + + ++pName; + +#ifdef UNICODE + MultiByteToWideChar(CP_ACP, 0, pName, lstrlenA(pName) + 1, szName, MAX_PATH); +#else + lstrcpyn(szName, pName, MAX_PATH); +#endif + + if (pe.th32ProcessID != dwCurrentProcessID && !lstrcmpi(szName, szProcessName)) + { + // Process found + bFound = TRUE; + + if (bTerminate == TRUE) + { + // Open for termination + NiceTerminate(pe.th32ProcessID, bClose, &bSuccess, &bFailed); + } + else + break; + } + // Keep looking + bResult = (*Process32NextPtr)(hSnapShot, &pe); + } + CloseHandle(hSnapShot); + } + else + uError = 611; + } + else + uError = 610; + + FreeLibrary(hLib); + } + else + uError = 609; + } + + if (bFound == FALSE) + return 603; + if (bTerminate == TRUE) + { + if (bSuccess == FALSE) + return 601; + if (bFailed == TRUE) + return 602; + } + return 0; +} diff --git a/src/nsProcess.sln b/src/nsProcess.sln new file mode 100644 index 0000000..4cef1c5 --- /dev/null +++ b/src/nsProcess.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsProcess", "nsProcess/nsProcess.vcxproj", "{BD73F235-28DE-40F5-B047-14222BC77FDC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug|Win32 = Debug|Win32 + Release UNICODE|Win32 = Release UNICODE|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Debug|Win32.ActiveCfg = Debug|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Debug|Win32.Build.0 = Debug|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Release UNICODE|Win32.ActiveCfg = Release UNICODE|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Release UNICODE|Win32.Build.0 = Release UNICODE|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Release|Win32.ActiveCfg = Release|Win32 + {BD73F235-28DE-40F5-B047-14222BC77FDC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/nsProcess.vcxproj b/src/nsProcess.vcxproj new file mode 100644 index 0000000..d2c8fe0 --- /dev/null +++ b/src/nsProcess.vcxproj @@ -0,0 +1,329 @@ + + + + + Release UNICODE + Win32 + + + Release UNICODE + x64 + + + Release + Win32 + + + Release + x64 + + + + {BD73F235-28DE-40F5-B047-14222BC77FDC} + nsProcess + 10.0 + + + + DynamicLibrary + false + MultiByte + v143 + + + DynamicLibrary + false + MultiByte + v143 + + + DynamicLibrary + false + Unicode + v143 + + + DynamicLibrary + false + Unicode + v143 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + true + true + false + false + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/nsProcess.tlb + + + + + Disabled + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + .\Debug/nsProcess.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + EditAndContinue + ../ + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + false + true + .\Debug/nsProcess.pdb + false + + + MachineX86 + + + true + .\Debug/nsProcess.bsc + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/nsProcess.tlb + + + + + Disabled + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + .\Debug/nsProcess.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + EditAndContinue + ../ + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + false + true + .\Debug/nsProcess.pdb + false + + + MachineX86 + + + true + .\Debug/nsProcess.bsc + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + MinSpace + OnlyExplicitInline + + WIN32;NDEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + true + ../ + Size + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + true + DllMain + false + + + MachineX86 + false + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + MinSpace + OnlyExplicitInline + + WIN32;NDEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + Level3 + true + ../ + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + true + DllMain + false + + + MachineX86 + + + + + MinSpace + OnlyExplicitInline + + WIN32;NDEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + ../ + Size + false + + + true + DllMain + false + false + false + + + + + MinSpace + OnlyExplicitInline + + WIN32;NDEBUG;_WINDOWS;_USRDLL;nsProcess_EXPORTS;%(PreprocessorDefinitions) + true + false + MultiThreaded + false + true + Level3 + ../ + Size + false + + + true + DllMain + false + false + false + + + + + + + + %(PreprocessorDefinitions) + + %(PreprocessorDefinitions) + + %(PreprocessorDefinitions) + + %(PreprocessorDefinitions) + + + + + + + + + + + \ No newline at end of file diff --git a/src/nsProcess.vcxproj.filters b/src/nsProcess.vcxproj.filters new file mode 100644 index 0000000..afe2799 --- /dev/null +++ b/src/nsProcess.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {d954431a-c29b-4c6f-a4bd-14703599718a} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {0288bee8-9623-445c-9724-de0f21d67d6a} + h;hpp;hxx;hm;inl + + + {6a350ccd-4674-4d22-adcc-e3a524ecd7b2} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {9d160ab9-1006-42e0-a9be-1183d9a4c4dc} + + + + + Source Files + + + pluginapi + + + pluginapi + + + + + pluginapi + + + pluginapi + + + pluginapi + + + \ No newline at end of file diff --git a/src/nsis/README.md b/src/nsis/README.md new file mode 100644 index 0000000..d002286 --- /dev/null +++ b/src/nsis/README.md @@ -0,0 +1,2 @@ +# nsis +The plugin api of nsis diff --git a/src/nsis/api.h b/src/nsis/api.h new file mode 100644 index 0000000..0d6b55e --- /dev/null +++ b/src/nsis/api.h @@ -0,0 +1,85 @@ +/* + * apih + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2019 Nullsoft and Contributors + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef _NSIS_EXEHEAD_API_H_ +#define _NSIS_EXEHEAD_API_H_ + +// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version +// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x)) +// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {} + +#define NSISPIAPIVER_1_0 0x00010000 +#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 + +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM); + +// extra_parameters data structure containing other interesting stuff +// besides the stack, variables and HWND passed on to plug-ins. +typedef struct +{ + int autoclose; // SetAutoClose + int all_user_var; // SetShellVarContext: User context = 0, Machine context = 1 + int exec_error; // IfErrors + int abort; // IfAbort + int exec_reboot; // IfRebootFlag (NSIS_SUPPORT_REBOOT) + int reboot_called; // NSIS_SUPPORT_REBOOT + int XXX_cur_insttype; // Deprecated + int plugin_api_version; // Plug-in ABI. See NSISPIAPIVER_CURR (Note: used to be XXX_insttype_changed) + int silent; // IfSilent (NSIS_CONFIG_SILENT_SUPPORT) + int instdir_error; // GetInstDirError + int rtl; // 1 if $LANGUAGE is a RTL language + int errlvl; // SetErrorLevel + int alter_reg_view; // SetRegView: Default View = 0, Alternative View = (sizeof(void*) > 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY) + int status_update; // SetDetailsPrint +} exec_flags_t; + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif +#if !defined(_WIN32) && !defined(LPTSTR) +# define LPTSTR TCHAR* +#endif + +typedef struct { + exec_flags_t *exec_flags; + int (NSISCALL *ExecuteCodeSegment)(int, HWND); + void (NSISCALL *validate_filename)(LPTSTR); + int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors +} extra_parameters; + +// Definitions for page showing plug-ins +// See Ui.c to understand better how they're used + +// sent to the outer window to tell it to go to the next inner window +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) + +// custom pages should send this message to let NSIS know they're ready +#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) + +// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning +#define NOTIFY_BYE_BYE 'x' + +#endif /* _NSIS_EXEHEAD_API_H_ */ diff --git a/src/nsis/crt.c b/src/nsis/crt.c new file mode 100644 index 0000000..d3c96be --- /dev/null +++ b/src/nsis/crt.c @@ -0,0 +1,27 @@ +#define WIN32_LEAN_AND_MEAN +#include + +#if defined(_MSC_VER) && _MSC_VER+0 >= 1400 +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER+0 >= 140050727 +#include +#else +EXTERN_C void __stosb(BYTE*,BYTE,size_t); +#endif +#pragma intrinsic(__stosb) +#define CRTINTRINSIC_memset(p,c,s) __stosb((BYTE*)(p),(BYTE)(c),(s)) +#endif + +#if defined(__cplusplus) +extern "C" +#endif + void* __cdecl memset(void *p, int c, size_t z) +{ +#ifdef CRTINTRINSIC_memset + CRTINTRINSIC_memset(p, c, z); +#else + BYTE *pb = reinterpret_cast(p); + for(size_t i=0; i +#include "pluginapi.h" + +#ifndef COUNTOF +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) +#endif + +// minimal tchar.h emulation +#ifndef _T +# define _T TEXT +#endif +#if !defined(TCHAR) && !defined(_TCHAR_DEFINED) +# ifdef UNICODE +# define TCHAR WCHAR +# else +# define TCHAR char +# endif +#endif + +#define isvalidnsisvarindex(varnum) ( ((unsigned int)(varnum)) < (__INST_LAST) ) + +unsigned int g_stringsize; +stack_t **g_stacktop; +LPTSTR g_variables; + +// utility functions (not required but often useful) + +int NSISCALL popstring(LPTSTR str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +int NSISCALL popstringn(LPTSTR str, int maxlen) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpyn(str,th->text,maxlen?maxlen:g_stringsize); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +void NSISCALL pushstring(LPCTSTR str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,(sizeof(stack_t)+(g_stringsize)*sizeof(*str))); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +LPTSTR NSISCALL getuservariable(const int varnum) +{ + if (!isvalidnsisvarindex(varnum)) return NULL; + return g_variables+varnum*g_stringsize; +} + +void NSISCALL setuservariable(const int varnum, LPCTSTR var) +{ + if (var && isvalidnsisvarindex(varnum)) + lstrcpy(g_variables + varnum*g_stringsize, var); +} + +#ifdef UNICODE +int NSISCALL PopStringA(LPSTR ansiStr) +{ + LPWSTR wideStr = (LPWSTR) GlobalAlloc(GPTR, g_stringsize*sizeof(WCHAR)); + int rval = popstring(wideStr); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +int NSISCALL PopStringNA(LPSTR ansiStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + LPWSTR wideStr = (LPWSTR) GlobalAlloc(GPTR, realLen*sizeof(WCHAR)); + int rval = popstringn(wideStr, realLen); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, realLen, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +void NSISCALL PushStringA(LPCSTR ansiStr) +{ + LPWSTR wideStr = (LPWSTR) GlobalAlloc(GPTR, g_stringsize*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + pushstring(wideStr); + GlobalFree((HGLOBAL)wideStr); + return; +} + +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr) +{ + lstrcpyW(wideStr, getuservariable(varnum)); +} + +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr) +{ + LPWSTR wideStr = getuservariable(varnum); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); +} + +void NSISCALL SetUserVariableA(const int varnum, LPCSTR ansiStr) +{ + if (ansiStr && isvalidnsisvarindex(varnum)) + { + LPWSTR wideStr = g_variables + varnum * g_stringsize; + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + } +} + +#else +// ANSI defs +int NSISCALL PopStringW(LPWSTR wideStr) +{ + LPSTR ansiStr = (LPSTR) GlobalAlloc(GPTR, g_stringsize); + int rval = popstring(ansiStr); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +int NSISCALL PopStringNW(LPWSTR wideStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + LPSTR ansiStr = (LPSTR) GlobalAlloc(GPTR, realLen); + int rval = popstringn(ansiStr, realLen); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, realLen); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +void NSISCALL PushStringW(LPWSTR wideStr) +{ + LPSTR ansiStr = (LPSTR) GlobalAlloc(GPTR, g_stringsize); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + pushstring(ansiStr); + GlobalFree((HGLOBAL)ansiStr); +} + +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr) +{ + LPSTR ansiStr = getuservariable(varnum); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); +} + +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr) +{ + lstrcpyA(ansiStr, getuservariable(varnum)); +} + +void NSISCALL SetUserVariableW(const int varnum, LPCWSTR wideStr) +{ + if (wideStr && isvalidnsisvarindex(varnum)) + { + LPSTR ansiStr = g_variables + varnum * g_stringsize; + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + } +} +#endif + +// playing with integers + +INT_PTR NSISCALL nsishelper_str_to_ptr(LPCTSTR s) +{ + INT_PTR v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + return v; +} + +unsigned int NSISCALL myatou(LPCTSTR s) +{ + unsigned int v=0; + + for (;;) + { + unsigned int c=*s++; + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else break; + v*=10; + v+=c; + } + return v; +} + +int NSISCALL myatoi_or(LPCTSTR s) +{ + int v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + // Support for simple ORed expressions + if (*s == _T('|')) + { + v |= myatoi_or(s+1); + } + + return v; +} + +INT_PTR NSISCALL popintptr() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return nsishelper_str_to_ptr(buf); +} + +int NSISCALL popint_or() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return myatoi_or(buf); +} + +void NSISCALL pushintptr(INT_PTR value) +{ + TCHAR buffer[30]; + wsprintf(buffer, sizeof(void*) > 4 ? _T("%Id") : _T("%d"), value); + pushstring(buffer); +} diff --git a/src/nsis/pluginapi.h b/src/nsis/pluginapi.h new file mode 100644 index 0000000..11ccfeb --- /dev/null +++ b/src/nsis/pluginapi.h @@ -0,0 +1,109 @@ +#ifndef ___NSIS_PLUGIN__H___ +#define ___NSIS_PLUGIN__H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api.h" +#include "nsis_tchar.h" // BUGBUG: Why cannot our plugins use the compilers tchar.h? + +#ifndef NSISCALL +# define NSISCALL WINAPI +#endif + +#define EXDLL_INIT() { \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; } + +typedef struct _stack_t { + struct _stack_t *next; +#ifdef UNICODE + WCHAR text[1]; // this should be the length of g_stringsize when allocating +#else + char text[1]; +#endif +} stack_t; + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +extern unsigned int g_stringsize; +extern stack_t **g_stacktop; +extern LPTSTR g_variables; + +void NSISCALL pushstring(LPCTSTR str); +void NSISCALL pushintptr(INT_PTR value); +#define pushint(v) pushintptr((INT_PTR)(v)) +int NSISCALL popstring(LPTSTR str); // 0 on success, 1 on empty stack +int NSISCALL popstringn(LPTSTR str, int maxlen); // with length limit, pass 0 for g_stringsize +INT_PTR NSISCALL popintptr(); +#define popint() ( (int) popintptr() ) +int NSISCALL popint_or(); // with support for or'ing (2|4|8) +INT_PTR NSISCALL nsishelper_str_to_ptr(LPCTSTR s); +#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer +unsigned int NSISCALL myatou(LPCTSTR s); // converts a string to an unsigned integer, decimal only +int NSISCALL myatoi_or(LPCTSTR s); // with support for or'ing (2|4|8) +LPTSTR NSISCALL getuservariable(const int varnum); +void NSISCALL setuservariable(const int varnum, LPCTSTR var); + +#ifdef UNICODE +#define PopStringW(x) popstring(x) +#define PushStringW(x) pushstring(x) +#define SetUserVariableW(x,y) setuservariable(x,y) + +int NSISCALL PopStringA(LPSTR ansiStr); +int NSISCALL PopStringNA(LPSTR ansiStr, int maxlen); +void NSISCALL PushStringA(LPCSTR ansiStr); +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr); +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr); +void NSISCALL SetUserVariableA(const int varnum, LPCSTR ansiStr); + +#else +// ANSI defs + +#define PopStringA(x) popstring(x) +#define PushStringA(x) pushstring(x) +#define SetUserVariableA(x,y) setuservariable(x,y) + +int NSISCALL PopStringW(LPWSTR wideStr); +void NSISCALL PushStringW(LPWSTR wideStr); +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr); +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr); +void NSISCALL SetUserVariableW(const int varnum, LPCWSTR wideStr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif//!___NSIS_PLUGIN__H___