From 13c8f89d7aff29d9b5855e0574af59508bd4f1df Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 29 Apr 2026 14:00:07 +0200 Subject: [PATCH] chore: initial commit (extracted from Launchers monorepo) Plugin: nsProcess v1.6.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: zlib --- .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 | 167 ++++++++ Readme.txt | 67 +++ SECURITY.md | 40 ++ VERSION | 1 + build_plugin.py | 158 +++++++ dist/amd64-unicode/nsProcess.dll | Bin 0 -> 6144 bytes dist/x86-ansi/nsProcess.dll | Bin 0 -> 7168 bytes dist/x86-unicode/nsProcess.dll | Bin 0 -> 5120 bytes examples/nsProcessTest.nsi | 69 ++++ include/nsProcess.nsh | 28 ++ src/nsProcess.c | 452 +++++++++++++++++++++ src/nsProcess.sln | 26 ++ src/nsProcess.vcxproj | 329 +++++++++++++++ src/nsProcess.vcxproj.filters | 42 ++ src/nsis/README.md | 2 + src/nsis/api.h | 85 ++++ src/nsis/crt.c | 27 ++ src/nsis/nsis_tchar.h | 229 +++++++++++ src/nsis/pluginapi.c | 305 ++++++++++++++ src/nsis/pluginapi.h | 109 +++++ 32 files changed, 2761 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 Readme.txt create mode 100644 SECURITY.md create mode 100644 VERSION create mode 100644 build_plugin.py create mode 100644 dist/amd64-unicode/nsProcess.dll create mode 100644 dist/x86-ansi/nsProcess.dll create mode 100644 dist/x86-unicode/nsProcess.dll create mode 100644 examples/nsProcessTest.nsi create mode 100644 include/nsProcess.nsh create mode 100644 src/nsProcess.c create mode 100644 src/nsProcess.sln create mode 100644 src/nsProcess.vcxproj create mode 100644 src/nsProcess.vcxproj.filters create mode 100644 src/nsis/README.md create mode 100644 src/nsis/api.h create mode 100644 src/nsis/crt.c create mode 100644 src/nsis/nsis_tchar.h create mode 100644 src/nsis/pluginapi.c create mode 100644 src/nsis/pluginapi.h 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 0000000000000000000000000000000000000000..101f759cc576feff8cf799928356f42e1b582548 GIT binary patch literal 6144 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 HzeE28Y@x=w literal 0 HcmV?d00001 diff --git a/dist/x86-ansi/nsProcess.dll b/dist/x86-ansi/nsProcess.dll new file mode 100644 index 0000000000000000000000000000000000000000..a7ee084915ddd04a0d74317b5b1ec8dfa155aa14 GIT binary patch literal 7168 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 literal 0 HcmV?d00001 diff --git a/dist/x86-unicode/nsProcess.dll b/dist/x86-unicode/nsProcess.dll new file mode 100644 index 0000000000000000000000000000000000000000..4d8a97107dc7880a735ee719cf73bdb65c018299 GIT binary patch literal 5120 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 EUp0xGPXGV_ literal 0 HcmV?d00001 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___