Merge branch 'v2.0' into fix/traymenu-button

This commit is contained in:
Alexandr Stelnykovych
2025-04-04 11:48:09 +03:00
committed by GitHub
65 changed files with 15762 additions and 22835 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
{
"name": "portmaster",
"version": "0.8.11",
"version": "2.0.1",
"scripts": {
"ng": "ng",
"start": "npm install && npm run build-libs:dev && ng serve --proxy-config ./proxy.json",
"build-libs": "NODE_ENV=production ng build --configuration production @safing/ui && NODE_ENV=production ng build --configuration production @safing/portmaster-api",
"build-libs": "cross-env NODE_ENV=production ng build --configuration production @safing/ui && cross-env NODE_ENV=production ng build --configuration production @safing/portmaster-api",
"build-libs:dev": "ng build --configuration development @safing/ui && ng build --configuration development @safing/portmaster-api",
"serve": "npm run build-libs:dev && ng serve --proxy-config ./proxy.json",
"build:dev": "npm run build-libs:dev && ng build",
@@ -12,10 +12,10 @@
"lint": "ng lint",
"e2e": "ng e2e",
"zip-dist": "node pack.js",
"chrome-extension": "NODE_ENV=production ng build --configuration production portmaster-chrome-extension",
"chrome-extension": "cross-env NODE_ENV=production ng build --configuration production portmaster-chrome-extension",
"chrome-extension:dev": "ng build --configuration development portmaster-chrome-extension --watch",
"build": "npm run build-libs && NODE_ENV=production ng build --configuration production --base-href /ui/modules/portmaster/",
"build-tauri": "npm run build-libs && NODE_ENV=production ng build --configuration production tauri-builtin",
"build-tauri": "npm run build-libs && cross-env NODE_ENV=production ng build --configuration production tauri-builtin",
"serve-tauri-builtin": "ng serve tauri-builtin --port 4100",
"serve-app": "ng serve --port 4200 --proxy-config ./proxy.json",
"tauri-dev": "npm install && run-s build-libs:dev && run-p serve-app serve-tauri-builtin"
@@ -32,6 +32,7 @@
"@angular/platform-browser": "^16.0.1",
"@angular/platform-browser-dynamic": "^16.0.1",
"@angular/router": "^16.0.1",
"@ctrl/tinycolor": "^4.1.0",
"@fortawesome/angular-fontawesome": "^0.13.0",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-brands-svg-icons": "^6.4.0",
@@ -84,6 +85,7 @@
"@types/whatwg-encoding": "^2.0.3",
"@typescript-eslint/eslint-plugin": "^5.59.6",
"@typescript-eslint/parser": "^5.59.6",
"cross-env": "^7.0.3",
"eslint": "^8.40.0",
"jasmine-core": "^5.0.0",
"jasmine-spec-reporter": "^7.0.0",

View File

@@ -750,7 +750,7 @@ export class PortapiService {
// for data-manipulating methods success
// ends the stream.
if (data.type === 'success') {
observer.next();
observer.next(null as any);
observer.complete();
return;
}

View File

@@ -0,0 +1,4 @@
/target
/examples/*/target
Cargo.lock
.vscode

View File

@@ -0,0 +1,34 @@
[package]
name = "dark-light"
version = "1.1.1"
authors = ["Corey Farwell <coreyf@rwell.org>"]
edition = "2018"
license = "MIT/Apache-2.0"
repository = "https://github.com/frewsxcv/rust-dark-light"
description = "Detect if dark mode or light mode is enabled"
readme = "README.md"
build = "build.rs"
[dependencies]
futures = "0.3.30"
anyhow = "1.0.79"
[dev-dependencies]
tokio = { version = "1.23.0", features = ["full"] }
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
detect-desktop-environment = "1.0.0"
dconf_rs = "0.3"
zbus = "3.0"
rust-ini = "0.20"
ashpd = "0.7.0"
xdg = "2.4.1"
[target.'cfg(windows)'.dependencies]
winreg = "0.52.0"
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2"
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features = ["MediaQueryList", "Window"] }

View File

@@ -0,0 +1,39 @@
# rust-dark-light
Rust crate to detect if dark mode or light mode is enabled. Supports macOS, Windows, Linux, BSDs, and WASM. On Linux and BSDs, first the XDG Desktop Portal dbus API is checked for the `color-scheme` preference, which works in Flatpak sandboxes without needing filesystem access. If that does not work, fallback methods are used for KDE, GNOME, Cinnamon, MATE, XFCE, and Unity.
[API Documentation](https://docs.rs/dark-light/)
## Usage
```rust
fn main() {
let mode = dark_light::detect();
match mode {
// Dark mode
dark_light::Mode::Dark => {},
// Light mode
dark_light::Mode::Light => {},
// Unspecified
dark_light::Mode::Default => {},
}
}
```
## Example
```
cargo run --example detect
```
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.

View File

@@ -0,0 +1,5 @@
fn main() {
if let Ok("apple") = std::env::var("CARGO_CFG_TARGET_VENDOR").as_deref() {
println!("cargo:rustc-link-lib=framework=AppKit");
}
}

View File

@@ -0,0 +1,92 @@
use detect_desktop_environment::DesktopEnvironment;
use ini::Ini;
use std::path::{Path, PathBuf};
use zbus::blocking::Connection;
use crate::Mode;
const XDG_KDEGLOBALS: &str = "/etc/xdg/kdeglobals";
fn get_freedesktop_color_scheme() -> Option<Mode> {
let conn = Connection::session();
if conn.is_err() {
return None;
}
let reply = conn.unwrap().call_method(
Some("org.freedesktop.portal.Desktop"),
"/org/freedesktop/portal/desktop",
Some("org.freedesktop.portal.Settings"),
"Read",
&("org.freedesktop.appearance", "color-scheme"),
);
if let Ok(reply) = &reply {
let theme = reply.body().deserialize::<u32>();
if theme.is_err() {
return None;
}
match theme.unwrap() {
1 => Some(Mode::Dark),
2 => Some(Mode::Light),
_ => None,
}
} else {
None
}
}
fn detect_gtk(pattern: &str) -> Mode {
match dconf_rs::get_string(pattern) {
Ok(theme) => Mode::from(theme.to_lowercase().contains("dark")),
Err(_) => Mode::Light,
}
}
fn detect_kde(path: &str) -> Mode {
match Ini::load_from_file(path) {
Ok(cfg) => {
let section = match cfg.section(Some("Colors:Window")) {
Some(section) => section,
None => return Mode::Light,
};
let values = match section.get("BackgroundNormal") {
Some(string) => string,
None => return Mode::Light,
};
let rgb = values
.split(',')
.map(|s| s.parse::<u32>().unwrap_or(255))
.collect::<Vec<u32>>();
let rgb = if rgb.len() > 2 {
rgb
} else {
vec![255, 255, 255]
};
let (r, g, b) = (rgb[0], rgb[1], rgb[2]);
Mode::rgb(r, g, b)
}
Err(_) => Mode::Light,
}
}
pub fn detect() -> Mode {
match get_freedesktop_color_scheme() {
Some(mode) => mode,
// Other desktop environments are still being worked on, fow now, only the following implementations work.
None => match DesktopEnvironment::detect() {
DesktopEnvironment::Kde => {
let path = if Path::new(XDG_KDEGLOBALS).exists() {
PathBuf::from(XDG_KDEGLOBALS)
} else {
dirs::home_dir().unwrap().join(".config/kdeglobals")
};
detect_kde(path.to_str().unwrap())
}
DesktopEnvironment::Cinnamon => detect_gtk("/org/cinnamon/desktop/interface/gtk-theme"),
DesktopEnvironment::Gnome => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
DesktopEnvironment::Mate => detect_gtk("/org/mate/desktop/interface/gtk-theme"),
DesktopEnvironment::Unity => detect_gtk("/org/gnome/desktop/interface/gtk-theme"),
_ => Mode::Default,
},
}
}

View File

@@ -0,0 +1,73 @@
//! Detect if dark mode or light mode is enabled.
//!
//! # Examples
//!
//! ```
//! let mode = dark_light::detect();
//!
//! match mode {
//! // Dark mode
//! dark_light::Mode::Dark => {},
//! // Light mode
//! dark_light::Mode::Light => {},
//! // Unspecified
//! dark_light::Mode::Default => {},
//! }
//! ```
mod platforms;
use platforms::platform;
mod utils;
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
use utils::rgb::Rgb;
/// Enum representing dark mode, light mode, or unspecified.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Mode {
/// Dark mode
Dark,
/// Light mode
Light,
/// Unspecified
Default,
}
impl Mode {
#[allow(dead_code)]
fn from_bool(b: bool) -> Self {
if b {
Mode::Dark
} else {
Mode::Light
}
}
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
/// Convert an RGB color to [`Mode`]. The color is converted to grayscale, and if the grayscale value is less than 192, [`Mode::Dark`] is returned. Otherwise, [`Mode::Light`] is returned.
fn from_rgb(rgb: Rgb) -> Self {
let window_background_gray = (rgb.0 * 11 + rgb.1 * 16 + rgb.2 * 5) / 32;
if window_background_gray < 192 {
Self::Dark
} else {
Self::Light
}
}
}
/// Detect if light mode or dark mode is enabled. If the mode cant be detected, fall back to [`Mode::Default`].
pub use platform::detect::detect;
/// Notifies the user if the system theme has been changed.
pub use platform::notify::subscribe;

View File

@@ -0,0 +1,47 @@
use detect_desktop_environment::DesktopEnvironment;
use crate::Mode;
use super::{dconf_detect, gsetting_detect, kde_detect, CINNAMON, GNOME, MATE};
pub fn detect() -> Mode {
NonFreeDesktop::detect()
}
/// Detects the color scheme on a platform.
trait ColorScheme {
fn detect() -> Mode;
}
/// Represents the FreeDesktop platform.
struct FreeDesktop;
/// Represents non FreeDesktop platforms.
struct NonFreeDesktop;
/// Detects the color scheme on FreeDesktop platforms. It makes use of the DBus interface.
impl ColorScheme for FreeDesktop {
fn detect() -> Mode {
todo!()
}
}
/// Detects the color scheme on non FreeDesktop platforms, having a custom implementation for each desktop environment.
impl ColorScheme for NonFreeDesktop {
fn detect() -> Mode {
match DesktopEnvironment::detect() {
Some(mode) => match mode {
DesktopEnvironment::Kde => match kde_detect() {
Ok(mode) => mode,
Err(_) => Mode::Default,
},
DesktopEnvironment::Cinnamon => dconf_detect(CINNAMON),
DesktopEnvironment::Gnome => gsetting_detect(),
DesktopEnvironment::Mate => dconf_detect(MATE),
DesktopEnvironment::Unity => dconf_detect(GNOME),
_ => Mode::Default,
},
None => Mode::Default,
}
}
}

View File

@@ -0,0 +1,88 @@
use std::{process::Command, str::FromStr};
use anyhow::Context;
use ini::Ini;
use crate::{utils::rgb::Rgb, Mode};
pub mod detect;
pub mod notify;
const MATE: &str = "/org/mate/desktop/interface/gtk-theme";
const GNOME: &str = "/org/gnome/desktop/interface/gtk-theme";
const CINNAMON: &str = "/org/cinnamon/desktop/interface/gtk-theme";
fn dconf_detect(path: &str) -> Mode {
match dconf_rs::get_string(path) {
Ok(theme) => {
println!("dconf output: {}", theme);
if theme.is_empty() {
Mode::Default
} else {
if theme.to_lowercase().contains("dark") {
Mode::Dark
} else {
Mode::Light
}
}
}
Err(_) => Mode::Default,
}
}
pub fn gsetting_detect() -> Mode {
let mode = match Command::new("gsettings")
.arg("get")
.arg("org.gnome.desktop.interface")
.arg("color-scheme")
.output()
{
Ok(output) => {
if let Ok(scheme) = String::from_utf8(output.stdout) {
if scheme.contains("prefer-dark") {
Mode::Dark
} else if scheme.contains("prefer-light") {
Mode::Dark
} else {
Mode::Default
}
} else {
Mode::Default
}
}
Err(_) => Mode::Default,
};
// Fallback to dconf
if mode == Mode::Default {
return dconf_detect(GNOME);
}
mode
}
fn kde_detect() -> anyhow::Result<Mode> {
let xdg = xdg::BaseDirectories::new()?;
let path = xdg
.find_config_file("kdeglobals")
.context("Path not found")?;
let cfg = Ini::load_from_file(path)?;
let properties = cfg
.section(Some("Colors:Window"))
.context("Failed to get section Colors:Window")?;
let background = properties
.get("BackgroundNormal")
.context("Failed to get BackgroundNormal inside Colors:Window")?;
let rgb = Rgb::from_str(background).unwrap();
Ok(Mode::from_rgb(rgb))
}
impl From<ashpd::desktop::settings::ColorScheme> for Mode {
fn from(value: ashpd::desktop::settings::ColorScheme) -> Self {
match value {
ashpd::desktop::settings::ColorScheme::NoPreference => Mode::Default,
ashpd::desktop::settings::ColorScheme::PreferDark => Mode::Dark,
ashpd::desktop::settings::ColorScheme::PreferLight => Mode::Light,
}
}
}

View File

@@ -0,0 +1,42 @@
use ashpd::desktop::settings::{ColorScheme, Settings};
use futures::{stream, Stream, StreamExt};
use std::task::Poll;
use crate::{detect, Mode};
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
let stream = if get_freedesktop_color_scheme().await.is_ok() {
let proxy = Settings::new().await?;
proxy
.receive_color_scheme_changed()
.await?
.map(Mode::from)
.boxed()
} else {
let mut last_mode = detect();
stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
let current_mode = detect();
if current_mode != last_mode {
last_mode = current_mode;
Poll::Ready(Some(current_mode))
} else {
ctx.waker().wake_by_ref();
Poll::Pending
}
})
.boxed()
};
Ok(stream)
}
async fn get_freedesktop_color_scheme() -> anyhow::Result<Mode> {
let proxy = Settings::new().await?;
let color_scheme = proxy.color_scheme().await?;
let mode = match color_scheme {
ColorScheme::PreferDark => Mode::Dark,
ColorScheme::PreferLight => Mode::Light,
ColorScheme::NoPreference => Mode::Default,
};
Ok(mode)
}

View File

@@ -0,0 +1,56 @@
// Dark/light mode detection on macOS.
// Written with help from Ryan McGrath (https://rymc.io/).
use crate::Mode;
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
extern "C" {
static NSAppearanceNameAqua: *const Object;
static NSAppearanceNameAccessibilityHighContrastAqua: *const Object;
static NSAppearanceNameDarkAqua: *const Object;
static NSAppearanceNameAccessibilityHighContrastDarkAqua: *const Object;
}
fn is_dark_mode_enabled() -> bool {
unsafe {
let mut appearance: *const Object = msg_send![class!(NSAppearance), currentAppearance];
if appearance.is_null() {
appearance = msg_send![class!(NSApp), effectiveAppearance];
}
let objects = [
NSAppearanceNameAqua,
NSAppearanceNameAccessibilityHighContrastAqua,
NSAppearanceNameDarkAqua,
NSAppearanceNameAccessibilityHighContrastDarkAqua,
];
let names: *const Object = msg_send![
class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
];
// `bestMatchFromAppearancesWithNames` is only available in macOS 10.14+.
// Gracefully handle earlier versions.
let responds_to_selector: objc::runtime::BOOL = msg_send![
appearance,
respondsToSelector: sel!(bestMatchFromAppearancesWithNames:)
];
if responds_to_selector == objc::runtime::NO {
return false;
}
let style: *const Object = msg_send![
appearance,
bestMatchFromAppearancesWithNames:&*names
];
style == NSAppearanceNameDarkAqua
|| style == NSAppearanceNameAccessibilityHighContrastDarkAqua
}
}
pub fn detect() -> crate::Mode {
Mode::from_bool(is_dark_mode_enabled())
}

View File

@@ -0,0 +1,2 @@
pub mod detect;
pub mod notify;

View File

@@ -0,0 +1,23 @@
use std::task::Poll;
use futures::{stream, Stream};
use crate::{detect, Mode};
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
let mut last_mode = detect();
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
let current_mode = detect();
if current_mode != last_mode {
last_mode = current_mode;
Poll::Ready(Some(current_mode))
} else {
ctx.waker().wake_by_ref();
Poll::Pending
}
});
Ok(stream)
}

View File

@@ -0,0 +1,48 @@
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
pub use macos as platform;
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "windows")]
pub use windows as platform;
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
pub mod freedesktop;
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd"
))]
pub use freedesktop as platform;
#[cfg(target_arch = "wasm32")]
pub mod websys;
#[cfg(target_arch = "wasm32")]
pub use websys as platform;
#[cfg(not(any(
target_os = "macos",
target_os = "windows",
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_arch = "wasm32"
)))]
pub mod platform {
pub fn detect() -> crate::Mode {
super::Mode::Light
}
}

View File

@@ -0,0 +1,11 @@
use crate::Mode;
pub fn detect() -> crate::Mode {
if let Some(window) = web_sys::window() {
let query_result = window.match_media("(prefers-color-scheme: dark)");
if let Ok(Some(mql)) = query_result {
return Mode::from_bool(mql.matches());
}
}
Mode::Light
}

View File

@@ -0,0 +1,2 @@
pub mod detect;
pub mod notify;

View File

@@ -0,0 +1,23 @@
use std::task::Poll;
use futures::{stream, Stream};
use crate::{detect, Mode};
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
let mut last_mode = detect();
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
let current_mode = detect();
if current_mode != last_mode {
last_mode = current_mode;
Poll::Ready(Some(current_mode))
} else {
ctx.waker().wake_by_ref();
Poll::Pending
}
});
Ok(stream)
}

View File

@@ -0,0 +1,15 @@
use crate::Mode;
use winreg::RegKey;
const SUBKEY: &str = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
const VALUE: &str = "AppsUseLightTheme";
pub fn detect() -> Mode {
let hkcu = RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
if let Ok(subkey) = hkcu.open_subkey(SUBKEY) {
if let Ok(dword) = subkey.get_value::<u32, _>(VALUE) {
return Mode::from_bool(dword == 0);
}
}
Mode::Light
}

View File

@@ -0,0 +1,2 @@
pub mod detect;
pub mod notify;

View File

@@ -0,0 +1,23 @@
use std::task::Poll;
use futures::{stream, Stream};
use crate::{detect, Mode};
pub async fn subscribe() -> anyhow::Result<impl Stream<Item = Mode> + Send> {
let mut last_mode = detect();
let stream = stream::poll_fn(move |ctx| -> Poll<Option<Mode>> {
let current_mode = detect();
if current_mode != last_mode {
last_mode = current_mode;
Poll::Ready(Some(current_mode))
} else {
ctx.waker().wake_by_ref();
Poll::Pending
}
});
Ok(stream)
}

View File

@@ -0,0 +1 @@
pub mod rgb;

View File

@@ -0,0 +1,23 @@
use std::str::FromStr;
/// Struct representing an RGB color
pub(crate) struct Rgb(pub(crate) u32, pub(crate) u32, pub(crate) u32);
impl FromStr for Rgb {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let rgb = s
.split(',')
.map(|s| s.parse::<u32>().unwrap_or(255))
.try_fold(vec![], |mut acc, x| {
if acc.len() < 3 {
acc.push(x);
Ok(acc)
} else {
Err(anyhow::anyhow!("RGB format is invalid"))
}
})?;
Ok(Rgb(rgb[0], rgb[1], rgb[2]))
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "portmaster"
version = "0.1.0"
version = "2.0.0"
description = "Portmaster UI"
authors = ["Safing"]
license = ""
@@ -12,21 +12,20 @@ rust-version = "1.64"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "2.0.3", features = [] }
tauri-build = { version = "2.0.5", features = [] }
[dependencies]
# Tauri
tauri = { version = "2.1.1", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
tauri-plugin-shell = "2.0.2"
tauri-plugin-dialog = "2.0.3"
tauri-plugin-clipboard-manager = "2.0.2"
tauri-plugin-os = "2.0.1"
tauri-plugin-single-instance = "2.0.1"
tauri-plugin-notification = "2.0.1"
tauri-plugin-log = "2.0.2"
tauri-plugin-window-state = "2.0.2"
tauri = { version = "2.2.5", features = ["tray-icon", "image-png", "config-json5", "devtools"] }
tauri-plugin-shell = "2.2.0"
tauri-plugin-dialog = "2.2.0"
tauri-plugin-clipboard-manager = "2.1.11"
tauri-plugin-os = "2.2.0"
tauri-plugin-single-instance = "2.2.1"
tauri-plugin-notification = "2.2.1"
tauri-plugin-log = "2.2.1"
tauri-plugin-window-state = "2.2.1"
tauri-cli = "2.1.0"
clap_lex = "0.7.2"
# General
@@ -53,7 +52,7 @@ reqwest = { version = "0.12" }
rfd = { version = "*", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] }
open = "5.1.3"
dark-light = { git = "https://github.com/vlabo/rust-dark-light", rev = "1f955c84d0ea05729bb5ecab29fb1b315b9897de" }
dark-light = { path = "../rust-dark-light" }
# Linux only
[target.'cfg(target_os = "linux")'.dependencies]

View File

@@ -1,6 +1,7 @@
# Update Tauri guide
Check latest versions of tauri packages and update them accordingly:
Check latest versions of tauri packages and update them accordingly (https://crates.io/)
Cargo.toml:
```toml
[build-dependencies]
tauri-build = { version = "2.0.0-beta.19", features = [] } # Update to latest
@@ -21,21 +22,25 @@ tauri-plugin-window-state = "2.0.0-beta"
tauri-cli = "2.0.0-beta.21" # Update to latest
```
> The plugins will be auto updated based on tauri version.
Run:
```sh
cargo update
```
Update WIX installer template:
1. Get the latests [main.wxs](https://github.com/tauri-apps/tauri/blob/dev/tooling/bundler/src/bundle/windows/templates/main.wxs) template from the repository.
2. Replace the contents of `templates/main_original.wxs` with the repository version.
3. Replace the contents of `templates/main.wsx` and add the fallowing lines at the end of the file, inside the `Product` tag.
> Make sure to update the npm tauri plugin dependencies to have the same version as the rust plugins. (desktop/angular)
## Update WIX installer template
> If the migration functionality is not needed anymore remove the template, this will cause tauri to use its default template and not call the migration script.
1. Get the latest [main.wxs](https://github.com/tauri-apps/tauri/blob/dev/tooling/bundler/src/bundle/windows/templates/main.wxs) template from the repository.
2. Replace the contents of `templates/wix/main_original.wxs` with the repository version. (The file is kept only for reference)
3. Replace the contents of `templates/wix/main.wsx` and add the fallowing lines at the end of the file, inside the `Product` tag.
```xml
<!-- Service fragments -->
<CustomActionRef Id='InstallPortmasterService' />
<CustomActionRef Id='StopPortmasterService' />
<CustomActionRef Id='DeletePortmasterService' />
<CustomActionRef Id='MigrationPropertySet' />
<CustomActionRef Id='Migration' />
<!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without it, it will automatically stop and remove the old service without notifying the user. -->
<!-- <CustomActionRef Id='CheckServiceStatus' /> -->
<!-- End Service fragments -->
```

File diff suppressed because one or more lines are too long

View File

@@ -1100,6 +1100,11 @@
"type": "string",
"const": "core:webview:allow-reparent"
},
{
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:allow-set-webview-background-color"
},
{
"description": "Enables the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1180,6 +1185,11 @@
"type": "string",
"const": "core:webview:deny-reparent"
},
{
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:deny-set-webview-background-color"
},
{
"description": "Denies the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1395,6 +1405,21 @@
"type": "string",
"const": "core:window:allow-set-always-on-top"
},
{
"description": "Enables the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-background-color"
},
{
"description": "Enables the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-count"
},
{
"description": "Enables the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-label"
},
{
"description": "Enables the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1480,6 +1505,11 @@
"type": "string",
"const": "core:window:allow-set-minimizable"
},
{
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-overlay-icon"
},
{
"description": "Enables the set_position command without any pre-configured scope.",
"type": "string",
@@ -1740,6 +1770,21 @@
"type": "string",
"const": "core:window:deny-set-always-on-top"
},
{
"description": "Denies the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-background-color"
},
{
"description": "Denies the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-count"
},
{
"description": "Denies the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-label"
},
{
"description": "Denies the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1825,6 +1870,11 @@
"type": "string",
"const": "core:window:deny-set-minimizable"
},
{
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-overlay-icon"
},
{
"description": "Denies the set_position command without any pre-configured scope.",
"type": "string",

View File

@@ -1100,6 +1100,11 @@
"type": "string",
"const": "core:webview:allow-reparent"
},
{
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:allow-set-webview-background-color"
},
{
"description": "Enables the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1180,6 +1185,11 @@
"type": "string",
"const": "core:webview:deny-reparent"
},
{
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:deny-set-webview-background-color"
},
{
"description": "Denies the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1395,6 +1405,21 @@
"type": "string",
"const": "core:window:allow-set-always-on-top"
},
{
"description": "Enables the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-background-color"
},
{
"description": "Enables the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-count"
},
{
"description": "Enables the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-label"
},
{
"description": "Enables the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1480,6 +1505,11 @@
"type": "string",
"const": "core:window:allow-set-minimizable"
},
{
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-overlay-icon"
},
{
"description": "Enables the set_position command without any pre-configured scope.",
"type": "string",
@@ -1740,6 +1770,21 @@
"type": "string",
"const": "core:window:deny-set-always-on-top"
},
{
"description": "Denies the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-background-color"
},
{
"description": "Denies the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-count"
},
{
"description": "Denies the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-label"
},
{
"description": "Denies the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1825,6 +1870,11 @@
"type": "string",
"const": "core:window:deny-set-minimizable"
},
{
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-overlay-icon"
},
{
"description": "Denies the set_position command without any pre-configured scope.",
"type": "string",

View File

@@ -1100,6 +1100,11 @@
"type": "string",
"const": "core:webview:allow-reparent"
},
{
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:allow-set-webview-background-color"
},
{
"description": "Enables the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1180,6 +1185,11 @@
"type": "string",
"const": "core:webview:deny-reparent"
},
{
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:webview:deny-set-webview-background-color"
},
{
"description": "Denies the set_webview_focus command without any pre-configured scope.",
"type": "string",
@@ -1395,6 +1405,21 @@
"type": "string",
"const": "core:window:allow-set-always-on-top"
},
{
"description": "Enables the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-background-color"
},
{
"description": "Enables the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-count"
},
{
"description": "Enables the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-badge-label"
},
{
"description": "Enables the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1480,6 +1505,11 @@
"type": "string",
"const": "core:window:allow-set-minimizable"
},
{
"description": "Enables the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:allow-set-overlay-icon"
},
{
"description": "Enables the set_position command without any pre-configured scope.",
"type": "string",
@@ -1740,6 +1770,21 @@
"type": "string",
"const": "core:window:deny-set-always-on-top"
},
{
"description": "Denies the set_background_color command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-background-color"
},
{
"description": "Denies the set_badge_count command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-count"
},
{
"description": "Denies the set_badge_label command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-badge-label"
},
{
"description": "Denies the set_closable command without any pre-configured scope.",
"type": "string",
@@ -1825,6 +1870,11 @@
"type": "string",
"const": "core:window:deny-set-minimizable"
},
{
"description": "Denies the set_overlay_icon command without any pre-configured scope.",
"type": "string",
"const": "core:window:deny-set-overlay-icon"
},
{
"description": "Denies the set_position command without any pre-configured scope.",
"type": "string",

View File

@@ -39,7 +39,6 @@
}
},
"productName": "Portmaster",
"version": "0.1.0",
"identifier": "io.safing.portmaster", // this is added as a property to the shortcut on windows (ApplicationUserModelID). Used for notifications.
"app": {
"withGlobalTauri": true,
@@ -55,7 +54,7 @@
"linux": {
"deb": {
"depends": [
"libayatana-appindicator3"
"libayatana-appindicator3-1"
],
"desktopTemplate": "../../../packaging/linux/portmaster.desktop",
"files": {
@@ -63,7 +62,6 @@
"/usr/lib/systemd/system/portmaster.service": "../../../packaging/linux/portmaster.service",
// Binary files
"/usr/lib/portmaster/index.json": "binary/index.json",
"/usr/lib/portmaster/portmaster-core": "binary/portmaster-core",
"/usr/lib/portmaster/portmaster.zip": "binary/portmaster.zip",
"/usr/lib/portmaster/assets.zip": "binary/assets.zip",
@@ -77,6 +75,10 @@
"/var/lib/portmaster/intel/intermediate.dsdl": "intel/intermediate.dsdl",
"/var/lib/portmaster/intel/urgent.dsdl": "intel/urgent.dsdl",
"/var/lib/portmaster/intel/main-intel.yaml" : "intel/main-intel.yaml",
"/var/lib/portmaster/intel/notifications.yaml": "intel/notifications.yaml",
"/var/lib/portmaster/intel/news.yaml" : "intel/news.yaml",
// Shortcut
"/etc/xdg/autostart/portmaster.desktop": "../../../packaging/linux/portmaster-autostart.desktop"
},
@@ -94,7 +96,6 @@
"/usr/lib/systemd/system/portmaster.service": "../../../packaging/linux/portmaster.service",
// Binary files
"/usr/lib/portmaster/index.json": "binary/index.json",
"/usr/lib/portmaster/portmaster-core": "binary/portmaster-core",
"/usr/lib/portmaster/portmaster.zip": "binary/portmaster.zip",
"/usr/lib/portmaster/assets.zip": "binary/assets.zip",
@@ -108,6 +109,10 @@
"/var/lib/portmaster/intel/intermediate.dsdl": "intel/intermediate.dsdl",
"/var/lib/portmaster/intel/urgent.dsdl": "intel/urgent.dsdl",
"/var/lib/portmaster/intel/main-intel.yaml" : "intel/main-intel.yaml",
"/var/lib/portmaster/intel/notifications.yaml": "intel/notifications.yaml",
"/var/lib/portmaster/intel/news.yaml" : "intel/news.yaml",
// Shortcut
"/etc/xdg/autostart/portmaster.desktop": "../../../packaging/linux/portmaster-autostart.desktop"
},
@@ -118,23 +123,23 @@
"windows": {
"nsis": {
"installMode": "perMachine",
"installerHooks": "templates/nsis_install_hooks.nsh",
"installerHooks": "templates/nsis/install_hooks.nsh",
"installerIcon": "../../../assets/data/icons/pm_light.ico"
},
"wix": {
"fragmentPaths": [
"templates/service.wxs",
"templates/files.wxs"
"templates/wix/files.wxs",
"templates/wix/old_service_check.wxs",
"templates/wix/migration.wxs",
],
"componentGroupRefs": ["BinaryAndIntelFiles"],
"template": "templates/main.wxs"
"template": "templates/wix/main.wxs"
}
},
"targets": [
"deb",
"rpm",
"nsis",
"msi"
"nsis" //, "msi"
],
"icon": [
"../../../assets/data/icons/pm_dark_512.png",

View File

@@ -0,0 +1,27 @@
SimpleSC - NSIS Service Control Plugin - License Agreement
This plugin is subject to the Mozilla Public License Version 1.1 (the "License");
You may not use this plugin except in compliance with the License. You may
obtain a copy of the License at http://www.mozilla.org/MPL.
Alternatively, you may redistribute this library, use and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version. You may obtain a copy
of the LGPL at www.gnu.org/copyleft.
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
Copyright
Portions of this software are Copyright (C) 2001 - Peter Windridge, 2003 by
Bernhard Mayer, Fixed and formatted by Brett Dever http://editor.nfscheats.com/
The original code is ServiceControl.pas, released April 16, 2007.
The initial developer of the original code is Rainer Budde (http://www.speed-soft.de).
SimpleSC - NSIS Service Control Plugin is written, published and maintaned by
Rainer Budde (rainer@speed-soft.de).

View File

@@ -0,0 +1,335 @@
NSIS Simple Service Plugin
This plugin contains basic service functions like start, stop the
service or checking the service status. It also contains advanced
service functions for example setting the service description, changed
the logon account, granting or removing the service logon privilege.
== Short Reference ==
SimpleSC::InstallService [name_of_service] [display_name] [service_type] [start_type] [binary_path] [dependencies] [account] [password]
SimpleSC::RemoveService [name_of_service]
SimpleSC::StartService [name_of_service] [arguments] [timeout]
SimpleSC::StopService [name_of_service] [wait_for_file_release] [timeout]
SimpleSC::PauseService [name_of_service] [timeout]
SimpleSC::ContinueService [name_of_service] [timeout]
SimpleSC::RestartService [name_of_service] [arguments] [timeout]
SimpleSC::ExistsService [name_of_service]
SimpleSC::GetServiceDisplayName [name_of_service]
SimpleSC::GetServiceName [display_name]
SimpleSC::GetServiceStatus [name_of_service]
SimpleSC::GetServiceDescription [name_of_service]
SimpleSC::GetServiceStartType [name_of_service]
SimpleSC::GetServiceBinaryPath [name_of_service]
SimpleSC::GetServiceLogon [name_of_service]
SimpleSC::GetServiceFailure [name_of_service]
SimpleSC::GetServiceFailureFlag [name_of_service]
SimpleSC::GetServiceDelayedAutoStartInfo [name_of_service]
SimpleSC::SetServiceDescription [name_of_service] [service_description]
SimpleSC::SetServiceStartType [name_of_service] [start_type]
SimpleSC::SetServiceBinaryPath [name_of_service] [binary_path]
SimpleSC::SetServiceLogon [name_of_service] [account] [password]
SimpleSC::SetServiceFailure [name_of_service] [reset_period] [reboot_message] [command] [action_type_1] [action_delay_1] [action_type_2] [action_delay_2] [action_type_3] [action_delay_3]
SimpleSC::SetServiceFailureFlag [name_of_service] [failure_actions_on_non_crash_failures]
SimpleSC::SetServiceDelayedAutoStartInfo [name_of_service] [delayed_autostart]
SimpleSC::GrantServiceLogonPrivilege [account]
SimpleSC::RemoveServiceLogonPrivilege [account]
SimpleSC::ServiceIsPaused [name_of_service]
SimpleSC::ServiceIsRunning [name_of_service]
SimpleSC::ServiceIsStopped [name_of_service]
SimpleSC::GetErrorMessage [error_code]
Parameters:
name_of_service - The name of the service used for Start/Stop commands and all further commands
display_name - The name as shown in the service control manager applet in system control
service_type - One of the following codes
1 - SERVICE_KERNEL_DRIVER - Driver service.
2 - SERVICE_FILE_SYSTEM_DRIVER - File system driver service.
16 - SERVICE_WIN32_OWN_PROCESS - Service that runs in its own process. (Should be used in most cases)
32 - SERVICE_WIN32_SHARE_PROCESS - Service that shares a process with one or more other services.
256 - SERVICE_INTERACTIVE_PROCESS - The service can interact with the desktop.
Note: If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS,
and the service is running in the context of the LocalSystem account,
you can also specify this value.
Example: SERVICE_WIN32_OWN_PROCESS or SERVICE_INTERACTIVE_PROCESS - (16 or 256) = 272
Note: Services cannot directly interact with a user as of Windows Vista.
Therefore, this technique should not be used in new code.
See for more information: http://msdn2.microsoft.com/en-us/library/ms683502(VS.85).aspx
start_type - one of the following codes
0 - SERVICE_BOOT_START - Driver boot stage start
1 - SERVICE_SYSTEM_START - Driver scm stage start
2 - SERVICE_AUTO_START - Service auto start (Should be used in most cases)
3 - SERVICE_DEMAND_START - Driver/service manual start
4 - SERVICE_DISABLED - Driver/service disabled
service_status - one of the following codes
1 - SERVICE_STOPPED
2 - SERVICE_START_PENDING
3 - SERVICE_STOP_PENDING
4 - SERVICE_RUNNING
5 - SERVICE_CONTINUE_PENDING
6 - SERVICE_PAUSE_PENDING
7 - SERVICE_PAUSED
binary_path - The path to the binary including all necessary parameters
dependencies - Needed services, controls which services have to be started before this one; use the forward slash "/" to add more more than one service
account - The username/account which should be used
password - Password of the aforementioned account to be able to logon as a service
Note: If you do not specify account/password, the local system account will be used to run the service
arguments - Arguments passed to the service main function.
Note: Driver services do not receive these arguments.
reset_period - The time after which to reset the failure count to zero if there are no failures, in seconds. Specify 0 (INFINITE) to indicate that this value should never be reset
reboot_message - The message to be broadcast to server users before rebooting
command - The command line of the process to execute in response to the SC_ACTION_RUN_COMMAND service controller action. This process runs under the same account as the service
timeout - Timeout in seconds of the function
action_type_x - one of the following codes for the action to be performed
0 - SC_ACTION_NONE - No action
1 - SC_ACTION_RESTART - Restart the service
2 - SC_ACTION_REBOOT - Reboot the computer (Note: The service user must have the SE_SHUTDOWN_NAME privilege)
3 - SC_ACTION_RUN_COMMAND - Run a command
action_delay_x - The time to wait before performing the specified action, in milliseconds
failure_actions_on_non_crash_failures - This setting determines when failure actions are to be executed
0 - The failure actions executed only if the service terminates without reporting a status of SERVICE_STOPPED
1 - The failure actions executed if the status of a service is SERVICE_STOPPED but the exit code of the service is not 0
delayed_autostart - The delayed auto-start setting of an auto-start service
0 - The service will be started during system boot.
1 - The service will be started after other auto-start services are started plus a short delay
error_code - Error code of a function
service_description - The description as shown in the service control manager applet in system control
wait_for_file_release - Wait for file release after the service is stopped. This is useful if the binary file will be overwritten after stopping the service.
0 - NO_WAIT - No wait for file release
1 - WAIT - Wait for file release
Note: If SERVICE_WIN32_OWN_PROCESS is used this option should be set to WAIT.
If SERVICE_WIN32_SHARE_PROCESS is used this option should only be set to WAIT if the last service
in the process is stopped.
== The Sample Script ==
; Install a service - ServiceType own process - StartType automatic - NoDependencies - Logon as System Account
SimpleSC::InstallService "MyService" "My Service Display Name" "16" "2" "C:\MyPath\MyService.exe" "" "" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Install a service - ServiceType interact with desktop - StartType automatic - Dependencies on "Windows Time Service" (w32time) and "WWW Publishing Service" (w3svc) - Logon as System Account
SimpleSC::InstallService "MyService" "My Service Display Name" "272" "2" "C:\MyPath\MyService.exe" "w32time/w3svc" "" ""
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Remove a service
SimpleSC::RemoveService "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Start a service
SimpleSC::StartService "MyService" "" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Start a service with two arguments "/param1=true" "/param2=1"
SimpleSC::StartService "MyService" "/param1=true /param2=1" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Start a service with two arguments "-p param1" "-param2"
SimpleSC::StartService "MyService" '"-p param1" -param2' 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Stop a service and waits for file release
SimpleSC::StopService "MyService" 1 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Stops two services and waits for file release after the last service is stopped
SimpleSC::StopService "MyService1" 0 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
SimpleSC::StopService "MyService2" 1 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Pause a service
SimpleSC::PauseService "MyService" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Continue a service
SimpleSC::ContinueService "MyService" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Restart a service
SimpleSC::RestartService "MyService" "" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Restart a service with two arguments "/param1=true" "/param2=1"
SimpleSC::RestartService "MyService" "/param1=true /param2=1" 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Start a service with two arguments "-p param1" "-param2"
SimpleSC::RestartService "MyService" '"-p param1" -param2' 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Check if the service exists
SimpleSC::ExistsService "MyService"
Pop $0 ; returns an errorcode if the service doesn´t exists (<>0)/service exists (0)
; Get the displayname of a service
SimpleSC::GetServiceDisplayName "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the displayname of the service
; Get the servicename of a service by the displayname
SimpleSC::GetServiceName "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the servicename of the service
; Get the current status of a service
SimpleSC::GetServiceStatus "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; return the status of the service (See "service_status" in the parameters)
; Get the description of a service
SimpleSC::GetServiceDescription "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the description of the service
; Get the start type of the service
SimpleSC::GetServiceStartType "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the start type of the service (see "start_type" in the parameters)
; Get the binary path of a service
SimpleSC::GetServiceBinaryPath "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the binary path of the service
; Get the logon user of the service
SimpleSC::GetServiceLogon "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the logon username of the service
; Get the failure configuration of a service
SimpleSC::GetServiceFailure "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the reset period
Pop $2 ; returns the reboot message
Pop $3 ; returns the command
Pop $4 ; returns the first action (See "action_type_x" in the parameters)
Pop $5 ; returns the first action delay
Pop $6 ; returns the second action (See "action_type_x" in the parameters)
Pop $7 ; returns the second action delay
Pop $8 ; returns the third action (See "action_type_x" in the parameters)
Pop $9 ; returns the third action delay
; Get the failure flag configuration of a service
SimpleSC::GetServiceFailureFlag "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the service flag
; Get the delayed auto-start configuration of a service
SimpleSC::GetServiceDelayedAutoStartInfo "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns the delayed auto-start configuration
; Set the description of a service
SimpleSC::SetServiceDescription "MyService" "Sample Description"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Set the starttype to automatic of a service
SimpleSC::SetServiceStartType "MyService" "2"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Sets the service binary path
SimpleSC::SetServiceBinaryPath "MyService" "C:\MySoftware\MyService.exe"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Sets the service logon to a user and grant the user the "SeServiceLogonPrivilege"
SimpleSC::SetServiceLogon "MyService" "MyServiceUser" "MyServiceUserPassword"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 +1 Done Done ; If successful grant the service logon privilege to "MyServiceUser"
; Note: Every serviceuser must have the ServiceLogonPrivilege to start the service
SimpleSC::GrantServiceLogonPrivilege "MyServiceUser"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Done:
; Sets the service failure configuration - First action: Restart the service after one minute - Second action: Reboot the computer after five minutes
SimpleSC::SetServiceFailure "MyService" "0" "" "" "1" "60000" "2" "300000" "0" "0"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Sets the failure flag configuration of a service
SimpleSC::SetServiceFailureFlag "MyService" "1"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Sets the delayed auto-start configuration of a service
SimpleSC::SetServiceDelayedAutoStartInfo "MyService" "1"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Remove the "SeServiceLogonPrivilege" from a user
SimpleSC::RemoveServiceLogonPrivilege "MyServiceUser"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
; Check if the service is paused
SimpleSC::ServiceIsPaused "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns 1 (service is paused) - returns 0 (service is not paused)
; Check if the service is running
SimpleSC::ServiceIsRunning "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
; Check if the service is stopped
SimpleSC::ServiceIsStopped "MyService"
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
Pop $1 ; returns 1 (service is stopped) - returns 0 (service is not stopped)
; Show the error message if a function fails
SimpleSC::StopService "MyService" 1 30
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
IntCmp $0 0 Done +1 +1
Push $0
SimpleSC::GetErrorMessage
Pop $0
MessageBox MB_OK|MB_ICONSTOP "Stopping fails - Reason: $0"
Done:
== Important Notes ==
- The function "SetServiceLogon" only works if the servicetype is
"SERVICE_WIN32_OWN_PROCESS".
- The functions "GetServiceDescription", "SetServiceDescription", "GetServiceFailure" and
"SetServiceFailure" are only available on systems higher than Windows NT.
- The function "GetServiceFailureFlag", "SetServiceFailureFlag", "GetServiceDelayedAutoStartInfo" and
"SetServiceDelayedAutoStartInfo" are only available on systems higher than Windows 2003.
- If you change the logon of an service to a new user you have to grant him
the Service Logon Privilege. Otherwise the service cannot be started by
the user you have assigned.
- The functions StartService, StopService, PauseService and ContinueService uses
a timeout of 30 seconds. This means the function must be executed within 30 seconds,
otherwise the functions will return an error.

View File

@@ -0,0 +1,259 @@
{
License Agreement
This content is subject to the Mozilla Public License Version 1.1 (the "License");
You may not use this plugin except in compliance with the License. You may
obtain a copy of the License at http://www.mozilla.org/MPL.
Alternatively, you may redistribute this library, use and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version. You may obtain a copy
of the LGPL at www.gnu.org/copyleft.
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The original code is LSASecurityControl.pas, released April 16, 2007.
The initial developer of the original code is Rainer Döpke
(Formerly: Rainer Budde) (https://www.speed-soft.de).
SimpleSC - NSIS Service Control Plugin is written, published and maintained by
Rainer Döpke (rainer@speed-soft.de).
}
unit LSASecurityControl;
interface
uses
Winapi.Windows;
function GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;
function RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;
function EnablePrivilege(PrivilegeName: String): Integer;
function DisablePrivilege(PrivilegeName: String): Integer;
implementation
type
LSA_HANDLE = Pointer;
TLSAHandle = LSA_HANDLE;
LSA_UNICODE_STRING = record
Length: Word;
MaximumLength: Word;
Buffer: PWideChar;
end;
TLSAUnicodeString = LSA_UNICODE_STRING;
PLSAUnicodeString = ^TLSAUnicodeString;
LSA_OBJECT_ATTRIBUTES = record
Length: ULONG;
RootDirectory: THandle;
ObjectName: PLSAUnicodeString;
Attributes: ULONG;
SecurityDescriptor: Pointer;
SecurityQualityOfService: Pointer;
end;
TLsaObjectAttributes = LSA_OBJECT_ATTRIBUTES;
PLsaObjectAttributes = ^TLsaObjectAttributes;
function LsaOpenPolicy(SystemName: PLSAUnicodeString; var ObjectAttributes: TLsaObjectAttributes; DesiredAccess: ACCESS_MASK; var PolicyHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';
function LsaAddAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';
function LsaRemoveAccountRights(PolicyHandle: LSA_HANDLE; AccountSid: PSID; AllRights: Boolean; UserRights: PLSAUnicodeString; CountOfRights: ULONG): DWORD; stdcall; external 'advapi32.dll';
function LsaClose(ObjectHandle: LSA_HANDLE): DWORD; stdcall; external 'advapi32.dll';
function GetAccountSid(const AccountName: String; var Sid: PSID): Integer;
var
DomainSize: LongWord;
SidSize: LongWord;
Domain: String;
Use: SID_NAME_USE;
begin
Result := 0;
SidSize := 0;
DomainSize := 0;
if not LookupAccountName(nil, PChar(AccountName), nil, SidSize, nil, DomainSize, Use) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
SetLength(Domain, DomainSize);
Sid := AllocMem(SidSize);
if not LookupAccountName(nil, PChar(AccountName), Sid, SidSize, PChar(Domain), DomainSize, Use) then
begin
Result := GetLastError;
FreeMem(Sid);
Sid := nil;
end;
end
else
Result := GetLastError;
end;
function GrantPrivilege(AccountName: String; PrivilegeName: String): Integer;
const
UNICODE_NULL = WCHAR(0);
POLICY_CREATE_ACCOUNT = $00000010;
POLICY_LOOKUP_NAMES = $00000800;
var
SID: PSID;
PolicyHandle: TLSAHandle;
LSAPrivilegeName: TLSAUnicodeString;
LSAObjectAttributes: TLsaObjectAttributes;
pwszPrivilegeName: PWideChar;
PrivilegeNameLength: Cardinal;
Status: DWORD;
begin
Result := 0;
GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));
PrivilegeNameLength := Length(pwszPrivilegeName);
if PrivilegeNameLength > 0 then
begin
Result := GetAccountSid(AccountName, SID);
if Result = 0 then
begin
LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);
LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);
LSAPrivilegeName.Buffer := pwszPrivilegeName;
Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);
try
if Status = 0 then
Result := LsaAddAccountRights(PolicyHandle, Sid, @LSAPrivilegeName, 1)
else
Result := Status;
finally
LsaClose(PolicyHandle);
end;
end;
end;
FreeMem(pwszPrivilegeName);
end;
function RemovePrivilege(AccountName: String; PrivilegeName: String): Integer;
const
UNICODE_NULL = WCHAR(0);
POLICY_CREATE_ACCOUNT = $00000010;
POLICY_LOOKUP_NAMES = $00000800;
var
SID: PSID;
PolicyHandle: TLSAHandle;
LSAPrivilegeName: TLSAUnicodeString;
LSAObjectAttributes: TLsaObjectAttributes;
pwszPrivilegeName: PWideChar;
PrivilegeNameLength: Cardinal;
Status: DWORD;
begin
Result := 0;
GetMem(pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
StringToWideChar(PrivilegeName, pwszPrivilegeName, Length(PrivilegeName) * SizeOf(WideChar) + 1);
ZeroMemory(@LSAObjectAttributes, SizeOf(TLsaObjectAttributes));
PrivilegeNameLength := Length(pwszPrivilegeName);
if PrivilegeNameLength > 0 then
begin
Result := GetAccountSid(AccountName, SID);
if Result = 0 then
begin
LSAPrivilegeName.Length := PrivilegeNameLength * SizeOf(WideChar);
LSAPrivilegeName.MaximumLength := LSAPrivilegeName.Length + SizeOf(UNICODE_NULL);
LSAPrivilegeName.Buffer := pwszPrivilegeName;
Status := LsaOpenPolicy(nil, LSAObjectAttributes, POLICY_LOOKUP_NAMES or POLICY_CREATE_ACCOUNT, PolicyHandle);
try
if Status = 0 then
Result := LsaRemoveAccountRights(PolicyHandle, Sid, False, @LSAPrivilegeName, 1)
else
Result := Status;
finally
LsaClose(PolicyHandle);
end;
end;
end;
FreeMem(pwszPrivilegeName);
end;
function EnablePrivilege(PrivilegeName: String): Integer;
var
TokenHandle: THandle;
TokenPrivileges: TOKEN_PRIVILEGES;
PreviousState: TOKEN_PRIVILEGES;
ReturnLength: Cardinal;
begin
Result := 0;
if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
begin
try
if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then
begin
TokenPrivileges.PrivilegeCount := 1;
TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then
Result := System.GetLastError;
end
else
Result := System.GetLastError;
finally
CloseHandle(TokenHandle);
end;
end
else
Result := System.GetLastError;
end;
function DisablePrivilege(PrivilegeName: String): Integer;
var
TokenHandle: THandle;
TokenPrivileges: TOKEN_PRIVILEGES;
PreviousState: TOKEN_PRIVILEGES;
ReturnLength: Cardinal;
begin
Result := 0;
if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
begin
try
if LookupPrivilegeValue(nil, PWideChar(PrivilegeName), TokenPrivileges.Privileges[0].Luid) then
begin
TokenPrivileges.PrivilegeCount := 1;
TokenPrivileges.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
if not AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, SizeOf(TokenPrivileges), PreviousState, ReturnLength) then
Result := System.GetLastError;
end
else
Result := System.GetLastError;
finally
CloseHandle(TokenHandle);
end;
end
else
Result := System.GetLastError;
end;
end.

View File

@@ -0,0 +1,36 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{0AF40426-B62C-4F43-8B49-19A70AEA0832}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="SimpleSC.dproj">
<Dependencies/>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="SimpleSC">
<MSBuild Projects="SimpleSC.dproj"/>
</Target>
<Target Name="SimpleSC:Clean">
<MSBuild Projects="SimpleSC.dproj" Targets="Clean"/>
</Target>
<Target Name="SimpleSC:Make">
<MSBuild Projects="SimpleSC.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="SimpleSC"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="SimpleSC:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="SimpleSC:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@@ -0,0 +1,209 @@
{
Original Code from
(C) 2001 - Peter Windridge
Code in separate unit and some changes
2003 by Bernhard Mayer
Fixed and formatted by Brett Dever
http://editor.nfscheats.com/
simply include this unit in your plugin project and export
functions as needed
}
unit nsis;
interface
uses
Winapi.Windows, Winapi.CommCtrl, System.SysUtils;
type
VarConstants = (
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
);
TVariableList = INST_0..__INST_LAST;
type
PluginCallbackMessages = (
NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup
NSPIM_GUIUNLOAD // Called after .onGUIEnd
);
TNSPIM = NSPIM_UNLOAD..NSPIM_GUIUNLOAD;
//TPluginCallback = function (const NSPIM: Integer): Pointer; cdecl;
TExecuteCodeSegment = function (const funct_id: Integer; const parent: HWND): Integer; stdcall;
Tvalidate_filename = procedure (const filename: PChar); stdcall;
TRegisterPluginCallback = function (const DllInstance: HMODULE; const CallbackFunction: Pointer): Integer; stdcall;
pexec_flags_t = ^exec_flags_t;
exec_flags_t = record
autoclose: Integer;
all_user_var: Integer;
exec_error: Integer;
abort: Integer;
exec_reboot: Integer;
reboot_called: Integer;
XXX_cur_insttype: Integer;
plugin_api_version: Integer;
silent: Integer;
instdir_error: Integer;
rtl: Integer;
errlvl: Integer;
alter_reg_view: Integer;
status_update: Integer;
end;
pextrap_t = ^extrap_t;
extrap_t = record
exec_flags: Pointer; // exec_flags_t;
exec_code_segment: TExecuteCodeSegment; // TFarProc;
validate_filename: Pointer; // Tvalidate_filename;
RegisterPluginCallback: Pointer; //TRegisterPluginCallback;
end;
pstack_t = ^stack_t;
stack_t = record
next: pstack_t;
text: PChar;
end;
var
g_stringsize: integer;
g_stacktop: ^pstack_t;
g_variables: PChar;
g_hwndParent: HWND;
g_hwndList: HWND;
g_hwndLogList: HWND;
g_extraparameters: pextrap_t;
procedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);
function LogMessage(Msg : String): BOOL;
function Call(NSIS_func : String) : Integer;
function PopString(): string;
procedure PushString(const str: string='');
function GetUserVariable(const varnum: TVariableList): string;
procedure SetUserVariable(const varnum: TVariableList; const value: string);
procedure NSISDialog(const text, caption: string; const buttons: integer);
implementation
procedure Init(const hwndParent: HWND; const string_size: integer; const variables: PChar; const stacktop: pointer; const extraparameters: pointer = nil);
begin
g_stringsize := string_size;
g_hwndParent := hwndParent;
g_stacktop := stacktop;
g_variables := variables;
g_hwndList := FindWindowEx(FindWindowEx(g_hwndParent, 0, '#32770', nil), 0,'SysListView32', nil);
g_extraparameters := extraparameters;
end;
function Call(NSIS_func : String) : Integer;
var
codeoffset: Integer; //The ID of nsis function
begin
Result := 0;
codeoffset := StrToIntDef(NSIS_func, 0);
if (codeoffset <> 0) and (g_extraparameters <> nil) then
begin
codeoffset := codeoffset - 1;
Result := g_extraparameters.exec_code_segment(codeoffset, g_hwndParent);
end;
end;
function LogMessage(Msg : String): BOOL;
var
ItemCount : Integer;
item: TLVItem;
begin
Result := FAlse;
if g_hwndList = 0 then exit;
FillChar( item, sizeof(item), 0 );
ItemCount := SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0);
item.iItem := ItemCount;
item.mask := LVIF_TEXT;
item.pszText := PChar(Msg);
ListView_InsertItem(g_hwndList, item);
ListView_EnsureVisible(g_hwndList, ItemCount, TRUE);
end;
function PopString(): string;
var
th: pstack_t;
begin
if integer(g_stacktop^) <> 0 then begin
th := g_stacktop^;
Result := PChar(@th.text);
g_stacktop^ := th.next;
GlobalFree(HGLOBAL(th));
end;
end;
procedure PushString(const str: string='');
var
th: pstack_t;
begin
if integer(g_stacktop) <> 0 then begin
th := pstack_t(GlobalAlloc(GPTR, SizeOf(stack_t) + g_stringsize));
lstrcpyn(@th.text, PChar(str), g_stringsize);
th.next := g_stacktop^;
g_stacktop^ := th;
end;
end;
function GetUserVariable(const varnum: TVariableList): string;
begin
if (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then
Result := g_variables + integer(varnum) * g_stringsize
else
Result := '';
end;
procedure SetUserVariable(const varnum: TVariableList; const value: string);
begin
if (value <> '') and (integer(varnum) >= 0) and (integer(varnum) < integer(__INST_LAST)) then
lstrcpy(g_variables + integer(varnum) * g_stringsize, PChar(value))
end;
procedure NSISDialog(const text, caption: string; const buttons: integer);
var
hwndOwner: HWND;
begin
hwndOwner := g_hwndParent;
if not IsWindow(g_hwndParent) then hwndOwner := 0; // g_hwndParent is not valid in NSPIM_[GUI]UNLOAD
MessageBox(hwndOwner, PChar(text), PChar(caption), buttons);
end;
begin
end.

View File

@@ -0,0 +1,609 @@
library SimpleSC;
uses
Winapi.Windows,
System.SysUtils,
NSIS in 'NSIS.pas',
ServiceControl in 'ServiceControl.pas',
LSASecurityControl in 'LSASecurityControl.pas';
function BoolToStr(Value: Boolean): String;
begin
if Value then
Result := '1'
else
Result := '0';
end;
function StrToBool(Value: String): Boolean;
begin
Result := Value = '1';
end;
procedure InstallService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
DisplayName: String;
ServiceType: Cardinal;
StartType: Cardinal;
BinaryPath: String;
Dependencies: String;
Username: String;
Password: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
DisplayName := PopString;
ServiceType := StrToInt(PopString);
StartType := StrToInt(PopString);
BinaryPath := PopString;
Dependencies := PopString;
Username := PopString;
Password := PopString;
ServiceResult := IntToStr(ServiceControl.InstallService(ServiceName, DisplayName, ServiceType, StartType, BinaryPath, Dependencies, Username, Password));
PushString(ServiceResult);
end;
procedure RemoveService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.RemoveService(ServiceName));
PushString(ServiceResult);
end;
procedure StartService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ServiceArguments: String;
Timeout: Integer;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceArguments := PopString;
Timeout := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.StartService(ServiceName, ServiceArguments, Timeout));
PushString(ServiceResult);
end;
procedure StopService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
WaitForFileRelease: Boolean;
Timeout: Integer;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
WaitForFileRelease := StrToBool(PopString);
Timeout := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.StopService(ServiceName, WaitForFileRelease, Timeout));
PushString(ServiceResult);
end;
procedure PauseService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Timeout: Integer;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
Timeout := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.PauseService(ServiceName, Timeout));
PushString(ServiceResult)
end;
procedure ContinueService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Timeout: Integer;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
Timeout := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.ContinueService(ServiceName, Timeout));
PushString(ServiceResult)
end;
procedure GetServiceName(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
Var
DisplayName: String;
ServiceResult: String;
ServiceName: String;
begin
Init(hwndParent, string_size, variables, stacktop);
DisplayName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceName(DisplayName, ServiceName));
PushString(ServiceName);
PushString(ServiceResult);
end;
procedure GetServiceDisplayName(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
Var
ServiceName: String;
DisplayName: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceDisplayName(ServiceName, DisplayName));
PushString(DisplayName);
PushString(ServiceResult);
end;
procedure GetServiceStatus(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Status: DWORD;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceStatus(ServiceName, Status));
PushString(IntToStr(Status));
PushString(ServiceResult);
end;
procedure GetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
BinaryPath: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceBinaryPath(ServiceName, BinaryPath));
PushString(BinaryPath);
PushString(ServiceResult);
end;
procedure GetServiceDescription(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Description: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceDescription(ServiceName, Description));
PushString(Description);
PushString(ServiceResult);
end;
procedure GetServiceStartType(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
StartType: DWORD;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceStartType(ServiceName, StartType));
PushString(IntToStr(StartType));
PushString(ServiceResult);
end;
procedure GetServiceLogon(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Username: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceLogon(ServiceName, Username));
PushString(Username);
PushString(ServiceResult);
end;
procedure GetServiceFailure(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ResetPeriod: DWORD;
RebootMessage: String;
Command: String;
Action1: Integer;
ActionDelay1: DWORD;
Action2: Integer;
ActionDelay2: DWORD;
Action3: Integer;
ActionDelay3: DWORD;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1, Action2, ActionDelay2, Action3, ActionDelay3));
PushString(IntToStr(ActionDelay3));
PushString(IntToStr(Action3));
PushString(IntToStr(ActionDelay2));
PushString(IntToStr(Action2));
PushString(IntToStr(ActionDelay1));
PushString(IntToStr(Action1));
PushString(Command);
PushString(RebootMessage);
PushString(IntToStr(ResetPeriod));
PushString(ServiceResult);
end;
procedure GetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
FailureActionsOnNonCrashFailures: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));
PushString(BoolToStr(FailureActionsOnNonCrashFailures));
PushString(ServiceResult);
end;
procedure GetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
DelayedAutostart: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.GetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));
PushString(BoolToStr(DelayedAutostart));
PushString(ServiceResult);
end;
procedure SetServiceDescription(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Description: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
Description := PopString;
ServiceResult := IntToStr(ServiceControl.SetServiceDescription(ServiceName, Description));
PushString(ServiceResult);
end;
procedure SetServiceStartType(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ServiceStartType: DWORD;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceStartType := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.SetServiceStartType(ServiceName, ServiceStartType));
PushString(ServiceResult);
end;
procedure SetServiceLogon(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
Username: String;
Password: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
Username := PopString;
Password := PopString;
ServiceResult := IntToStr(ServiceControl.SetServiceLogon(ServiceName, Username, Password));
PushString(ServiceResult);
end;
procedure SetServiceBinaryPath(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
BinaryPath: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
BinaryPath := PopString;
ServiceResult := IntToStr(ServiceControl.SetServiceBinaryPath(ServiceName, BinaryPath));
PushString(ServiceResult);
end;
procedure SetServiceFailure(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ResetPeriod: DWORD;
RebootMessage: String;
Command: String;
Action1: Integer;
ActionDelay1: DWORD;
Action2: Integer;
ActionDelay2: DWORD;
Action3: Integer;
ActionDelay3: DWORD;
ServiceResult: Integer;
PrivilegeResult: Integer;
const
SE_SHUTDOWN_PRIVILEGE = 'SeShutdownPrivilege';
SC_ACTION_REBOOT = 2;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ResetPeriod := StrToInt(PopString);
RebootMessage := PopString;
Command := PopString;
Action1 := StrToInt(PopString);
ActionDelay1 := StrToInt(PopString);
Action2 := StrToInt(PopString);
ActionDelay2 := StrToInt(PopString);
Action3 := StrToInt(PopString);
ActionDelay3 := StrToInt(PopString);
if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then
begin
PrivilegeResult := LSASecurityControl.EnablePrivilege(SE_SHUTDOWN_PRIVILEGE);
if not PrivilegeResult = 0 then
begin
PushString(IntToStr(PrivilegeResult));
Exit;
end;
end;
ServiceResult := ServiceControl.SetServiceFailure(ServiceName, ResetPeriod, RebootMessage, Command, Action1, ActionDelay1,
Action2, ActionDelay2, Action3, ActionDelay3);
if (Action1 = SC_ACTION_REBOOT) or (Action2 = SC_ACTION_REBOOT) or (Action3 = SC_ACTION_REBOOT) then
begin
PrivilegeResult := LSASecurityControl.DisablePrivilege(SE_SHUTDOWN_PRIVILEGE);
if not PrivilegeResult = 0 then
begin
PushString(IntToStr(PrivilegeResult));
Exit;
end;
end;
PushString(IntToStr(ServiceResult));
end;
procedure SetServiceFailureFlag(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
FailureActionsOnNonCrashFailures: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
FailureActionsOnNonCrashFailures := StrToBool(PopString);
ServiceResult := IntToStr(ServiceControl.SetServiceFailureFlag(ServiceName, FailureActionsOnNonCrashFailures));
PushString(ServiceResult)
end;
procedure SetServiceDelayedAutoStartInfo(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
DelayedAutostart: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
DelayedAutostart := StrToBool(PopString);
ServiceResult := IntToStr(ServiceControl.SetServiceDelayedAutoStartInfo(ServiceName, DelayedAutostart));
PushString(ServiceResult)
end;
procedure ServiceIsRunning(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
IsRunning: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.ServiceIsRunning(ServiceName, IsRunning));
PushString(BoolToStr(IsRunning));
PushString(ServiceResult);
end;
procedure ServiceIsStopped(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
IsStopped: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.ServiceIsStopped(ServiceName, IsStopped));
PushString(BoolToStr(IsStopped));
PushString(ServiceResult);
end;
procedure ServiceIsPaused(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
IsPaused: Boolean;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.ServiceIsPaused(ServiceName, IsPaused));
PushString(BoolToStr(IsPaused));
PushString(ServiceResult);
end;
procedure RestartService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ServiceArguments: String;
Timeout: Integer;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceArguments := PopString;
Timeout := StrToInt(PopString);
ServiceResult := IntToStr(ServiceControl.RestartService(ServiceName, ServiceArguments, Timeout));
PushString(ServiceResult);
end;
procedure ExistsService(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ServiceName: String;
ServiceResult: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ServiceName := PopString;
ServiceResult := IntToStr(ServiceControl.ExistsService(ServiceName));
PushString(ServiceResult);
end;
procedure GrantServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
AccountName: String;
LSAResult: String;
const
SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';
begin
Init(hwndParent, string_size, variables, stacktop);
AccountName := PopString;
LSAResult := IntToStr(LSASecurityControl.GrantPrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));
PushString(LSAResult);
end;
procedure RemoveServiceLogonPrivilege(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
AccountName: String;
LSAResult: String;
const
SE_SERVICE_LOGON_RIGHT = 'SeServiceLogonRight';
begin
Init(hwndParent, string_size, variables, stacktop);
AccountName := PopString;
LSAResult := IntToStr(LSASecurityControl.RemovePrivilege(AccountName, SE_SERVICE_LOGON_RIGHT));
PushString(LSAResult);
end;
procedure GetErrorMessage(const hwndParent: HWND; const string_size: integer;
const variables: PChar; const stacktop: pointer); cdecl;
var
ErrorCode: Integer;
ErrorMessage: String;
begin
Init(hwndParent, string_size, variables, stacktop);
ErrorCode := StrToInt(PopString);
ErrorMessage := ServiceControl.GetErrorMessage(ErrorCode);
PushString(ErrorMessage);
end;
exports InstallService;
exports ExistsService;
exports RemoveService;
exports StartService;
exports StopService;
exports PauseService;
exports ContinueService;
exports GetServiceName;
exports GetServiceDisplayName;
exports GetServiceStatus;
exports GetServiceBinaryPath;
exports GetServiceDescription;
exports GetServiceStartType;
exports GetServiceLogon;
exports GetServiceFailure;
exports GetServiceFailureFlag;
exports GetServiceDelayedAutoStartInfo;
exports SetServiceDescription;
exports SetServiceStartType;
exports SetServiceLogon;
exports SetServiceBinaryPath;
exports SetServiceFailure;
exports SetServiceFailureFlag;
exports SetServiceDelayedAutoStartInfo;
exports ServiceIsRunning;
exports ServiceIsStopped;
exports ServiceIsPaused;
exports RestartService;
exports GrantServiceLogonPrivilege;
exports RemoveServiceLogonPrivilege;
exports GetErrorMessage;
end.

View File

@@ -0,0 +1,910 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{9A1C1FE1-FB44-40C4-9E22-99CAE6325532}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>SimpleSC.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Library</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;bindengine;soaprtl;DBXOracleDriver;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;dbexpress;DataSnapIndy10ServerTransport;IPIndyImpl;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<GenDll>true</GenDll>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<SanitizedProjectName>SimpleSC</SanitizedProjectName>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<Manifest_File>None</Manifest_File>
<DCC_ExeOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_ExeOutput>
<DCC_DcuOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_DcuOutput>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<DCC_UsePackage>frx16;TeeDB;Rave100VCL;vclib;Tee;inetdbbde;DBXOdbcDriver;svnui;ibxpress;DBXSybaseASEDriver;vclimg;frxDB16;intrawebdb_120_160;fmi;fs16;TeeUI;vclactnband;FMXTee;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;Intraweb_120_160;DBXDb2Driver;websnap;vclribbon;frxe16;fsDB16;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;CodeSiteExpressPkg;adortl;vcldbx;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>
<VerInfo_Locale>1033</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;vcltouch;DBXDb2Driver;websnap;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;VclSmp;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Manifest_File>None</Manifest_File>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<DCC_ImportedDataReferences>false</DCC_ImportedDataReferences>
<VerInfo_Locale>1031</VerInfo_Locale>
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<DCC_ExeOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_ExeOutput>
<DCC_DcuOutput>C:\Developing\NSIS Simple Service Control - Unicode\</DCC_DcuOutput>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>(Ohne)</Manifest_File>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="NSIS.pas"/>
<DCCReference Include="ServiceControl.pas"/>
<DCCReference Include="LSASecurityControl.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Delphi.Personality>
<VersionInfo>
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">1</VersionInfo>
<VersionInfo Name="MinorVer">0</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
<VersionInfo Name="PreRelease">False</VersionInfo>
<VersionInfo Name="Special">False</VersionInfo>
<VersionInfo Name="Private">False</VersionInfo>
<VersionInfo Name="DLL">False</VersionInfo>
<VersionInfo Name="Locale">1031</VersionInfo>
<VersionInfo Name="CodePage">1252</VersionInfo>
</VersionInfo>
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription"/>
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"/>
<VersionInfoKeys Name="LegalCopyright"/>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename"/>
<VersionInfoKeys Name="ProductName"/>
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
<Source>
<Source Name="MainSource">SimpleSC.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="OSX32">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
<DeployClass Name="ProjectiOSEntitlements"/>
<DeployClass Name="ProjectiOSInfoPList"/>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug"/>
<DeployClass Name="ProjectOSXEntitlements"/>
<DeployClass Name="ProjectOSXInfoPList"/>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
<ModelSupport>False</ModelSupport>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@@ -0,0 +1,192 @@
!include LogicLib.nsh
!addplugindir "..\..\..\..\templates\NSIS_Simple_Service_Plugin_Unicode_1.30"
var oldInstallationDir
var dataDir
!macro NSIS_HOOK_PREINSTALL
; Try to stop the service if it's running
SimpleSC::ServiceIsStopped "PortmasterCore"
Pop $0
Pop $1
${If} $0 == 0
${If} $1 == 0
DetailPrint "PortmasterCore service is running. Stopping service ..."
SimpleSC::StopService "PortmasterCore" 1 60
Pop $0
${If} $0 != 0
DetailPrint "Failed to stop PortmasterCore service. Error: $0"
MessageBox MB_OK "PortmasterCore service is running. Stop it and run the installer again."
Abort
${EndIf}
; wait a little (give change for service to fully stop)
Sleep 2000
${EndIf}
${EndIf}
File "..\..\..\..\binary\portmaster-core.exe"
File "..\..\..\..\binary\portmaster-kext.sys"
File "..\..\..\..\binary\portmaster-core.dll"
File "..\..\..\..\binary\WebView2Loader.dll"
File "..\..\..\..\binary\portmaster.zip"
File "..\..\..\..\binary\assets.zip"
SetOutPath "$COMMONPROGRAMDATA\Portmaster\intel"
File "..\..\..\..\intel\index.json"
File "..\..\..\..\intel\base.dsdl"
File "..\..\..\..\intel\geoipv4.mmdb"
File "..\..\..\..\intel\geoipv6.mmdb"
File "..\..\..\..\intel\index.dsd"
File "..\..\..\..\intel\intermediate.dsdl"
File "..\..\..\..\intel\urgent.dsdl"
File "..\..\..\..\intel\main-intel.yaml"
File "..\..\..\..\intel\notifications.yaml"
File "..\..\..\..\intel\news.yaml"
; restire previous state
SetOutPath "$INSTDIR"
!macroend
;--------------------------------------------------
; Post-install hook:
; - Remove old service
; - Installs the service
!macro NSIS_HOOK_POSTINSTALL
DetailPrint "Installing service"
; Remove old service
SimpleSC::RemoveService "PortmasterCore"
; Install the service:
; Parameters:
; 1. Service Name: "PortmasterCore"
; 2. Display Name: "Portmaster Core"
; 3. Service Type: "16" for SERVICE_WIN32_OWN_PROCESS
; 4. Start Type: "2" for SERVICE_AUTO_START
; 5. Binary Path: Executable with arguments.
; 6 & 7. Dependencies and account info (empty uses defaults).
SimpleSC::InstallService "PortmasterCore" "Portmaster Core" 16 2 "$INSTDIR\portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs" "" "" ""
Pop $0 ; returns error code (0 on success)
${If} $0 != 0
SimpleSC::GetErrorMessage $0
Pop $0
MessageBox MB_OK "Service creation failed. Error: $0"
Abort
${EndIf}
SimpleSC::SetServiceDescription "PortmasterCore" "Portmaster Application Firewall - Core Service"
StrCpy $oldInstallationDir "$COMMONPROGRAMDATA\Safing\Portmaster"
StrCpy $dataDir "$COMMONPROGRAMDATA\Portmaster"
; Check if the folder exists
IfFileExists "$oldInstallationDir\*.*" 0 Finish
; Stop if the migration flag(file) already exists.
IfFileExists "$oldInstallationDir\migrated.txt" Finish 0
; Copy files
DetailPrint "Migrating config from old installation: $oldInstallationDir"
CreateDirectory "$dataDir"
CreateDirectory "$dataDir\databases"
CopyFiles "$oldInstallationDir\config.json" "$dataDir"
CopyFiles "$oldInstallationDir\databases\*.*" "$dataDir\databases"
; Create empty file to indicate that the data has already been migrated.
FileOpen $0 "$oldInstallationDir\migrated.txt" w
FileClose $0
; Delete v1 shortcuts
RMDir /r "$SMPROGRAMS\Portmaster"
Delete "$SMSTARTUP\Portmaster Notifier.lnk"
; Delete v1 old binaries
Delete "$oldInstallationDir\portmaster-uninstaller.exe"
Delete "$oldInstallationDir\portmaster-start.exe"
Delete "$oldInstallationDir\portmaster.ico"
RMDir /r "$oldInstallationDir\exec"
RMDir /r "$oldInstallationDir\updates"
RMDir /r "$oldInstallationDir\databases\cache"
RMDir /r "$oldInstallationDir\intel"
; Delete the link to the ProgramData folder
RMDir /r "$PROGRAMFILES64\Safing"
; Delete v1 user shortcut if its there.
SetShellVarContext current
Delete "$AppData\Microsoft\Windows\Start Menu\Programs\Portmaster.lnk"
SetShellVarContext all
; Delete v1 registry values
DeleteRegKey HKLM "SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Portmaster"
Finish:
!macroend
;--------------------------------------------------
; Pre-uninstall hook:
; - Stops and removes the service.
!macro NSIS_HOOK_PREUNINSTALL
DetailPrint "Stopping service"
; Trigger service stop. In the worst case the service should stop in ~60 seconds.
SimpleSC::StopService "PortmasterCore" 1 60
Pop $0
${If} $0 != 0
DetailPrint "Failed to stop PortmasterCore service. Error: $0"
${Else}
DetailPrint "Service PortmasterCore stopped successfully."
${EndIf}
DetailPrint "Removing service"
SimpleSC::RemoveService "PortmasterCore"
Pop $0
${If} $0 != 0
DetailPrint "Failed to remove PortmasterCore service. Error: $0"
${Else}
DetailPrint "Service PortmasterCore removed successfully."
${EndIf}
!macroend
;--------------------------------------------------
; Post-uninstall hook:
; - Delete files
!macro NSIS_HOOK_POSTUNINSTALL
; Delete binaries
Delete /REBOOTOK "$INSTDIR\index.json"
Delete /REBOOTOK "$INSTDIR\portmaster-core.exe"
Delete /REBOOTOK "$INSTDIR\portmaster-kext.sys"
Delete /REBOOTOK "$INSTDIR\portmaster-core.dll"
Delete /REBOOTOK "$INSTDIR\WebView2Loader.dll"
Delete /REBOOTOK "$INSTDIR\portmaster.zip"
Delete /REBOOTOK "$INSTDIR\assets.zip"
RMDir /r /REBOOTOK "$INSTDIR"
; delete data files
Delete /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\databases\history.db"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\databases\cache"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\databases\icons"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\intel"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\download_intel"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\download_binaries"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\exec"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster\logs"
; Remove PMv1 migration flag
Delete /REBOOTOK "$COMMONPROGRAMDATA\Safing\Portmaster\migrated.txt"
${If} $DeleteAppDataCheckboxState = 1
DetailPrint "Deleting the application data..."
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Portmaster"
RMDir /r /REBOOTOK "$COMMONPROGRAMDATA\Safing"
${Else}
DetailPrint "Application data kept as requested by the user."
${EndIf}
!macroend

View File

@@ -1,37 +0,0 @@
!macro NSIS_HOOK_PREINSTALL
; Current working directory is <project-dir>\desktop\tauri\src-tauri\target\release\nsis\x64
SetOutPath "$INSTDIR"
File "..\..\..\..\binary\index.json"
File "..\..\..\..\binary\portmaster-core.exe"
File "..\..\..\..\binary\portmaster-kext.sys"
File "..\..\..\..\binary\portmaster-core.dll"
File "..\..\..\..\binary\WebView2Loader.dll"
File "..\..\..\..\binary\portmaster.zip"
File "..\..\..\..\binary\assets.zip"
SetOutPath "$COMMONPROGRAMDATA\Portmaster\intel"
File "..\..\..\..\intel\index.json"
File "..\..\..\..\intel\base.dsdl"
File "..\..\..\..\intel\geoipv4.mmdb"
File "..\..\..\..\intel\geoipv6.mmdb"
File "..\..\..\..\intel\index.dsd"
File "..\..\..\..\intel\intermediate.dsdl"
File "..\..\..\..\intel\urgent.dsdl"
; restire previous state
SetOutPath "$INSTDIR"
!macroend
!macro NSIS_HOOK_POSTINSTALL
ExecWait 'sc.exe create PortmasterCore binPath= "$INSTDIR\portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs"'
!macroend
!macro NSIS_HOOK_PREUNINSTALL
ExecWait 'sc.exe stop PortmasterCore'
ExecWait 'sc.exe delete PortmasterCore'
!macroend

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<CustomAction Id="InstallPortmasterService"
Directory="INSTALLDIR"
ExeCommand="sc.exe create PortmasterCore binPath= &quot;[INSTALLDIR]portmaster-core.exe --log-dir=%PROGRAMDATA%\Portmaster\logs&quot;"
Execute="commit"
Return="check"
Impersonate="no"
/>
<CustomAction Id="StopPortmasterService"
Directory="INSTALLDIR"
ExeCommand="sc.exe stop PortmasterCore"
Execute="commit"
Return="ignore"
Impersonate="no"
/>
<CustomAction Id="DeletePortmasterService"
Directory="INSTALLDIR"
ExeCommand="sc.exe delete PortmasterCore"
Execute="commit"
Return="ignore"
Impersonate="no"
/>
<InstallExecuteSequence>
<Custom Action="InstallPortmasterService" Before='InstallFinalize'>
<![CDATA[NOT Installed]]>
</Custom>
<Custom Action="StopPortmasterService" Before='InstallFinalize'>
REMOVE
</Custom>
<Custom Action="DeletePortmasterService" Before='InstallFinalize'>
REMOVE
</Custom>
</InstallExecuteSequence>
</Fragment>
</Wix>

View File

@@ -0,0 +1,44 @@
Option Explicit
Dim objShell, objExec, strOutput, arrLines, i, arrStatus
' Create an instance of the WScript.Shell object
Set objShell = CreateObject("WScript.Shell")
' Run the sc.exe command to query the service
Set objExec = objShell.Exec("cmd /c sc.exe query PortmasterCore")
' Initialize an empty string to store the output
strOutput = ""
' Read all output from the command line
Do While Not objExec.StdOut.AtEndOfStream
strOutput = strOutput & objExec.StdOut.ReadLine() & vbCrLf
Loop
' Split the output into lines
arrLines = Split(strOutput, vbCrLf)
' Example Output
' SERVICE_NAME: PortmasterCore
' TYPE : 10 WIN32_OWN_PROCESS
' STATE : 1 STOPPED
' WIN32_EXIT_CODE : 1077 (0x435)
' SERVICE_EXIT_CODE : 0 (0x0)
' CHECKPOINT : 0x0
' WAIT_HINT : 0x0
For i = LBound(arrLines) To UBound(arrLines)
' Example line: STATE : 1 STOPPED
If InStr(arrLines(i), "STATE") > 0 Then
' Extract and display the service state
' Example string: "1 STOPPED"
arrStatus = Split(Trim(Mid(arrLines(i), InStr(arrLines(i), ":") + 1)), " ")
' Anything other the STOPPED consider as running
If Not arrStatus(2) = "STOPPED" Then
MsgBox("Portmaster service is running. Stop it and run the installer again.")
' Notify the installer that it should fail.
WScript.Quit 1
End If
End If
Next

View File

@@ -0,0 +1,78 @@
Dim FSO
Set FSO = CreateObject("Scripting.FileSystemObject")
Dim customData, args, oldInstallationDir, migrationFlagFile, newDataDir, doMigration
customData = Session.Property("CustomActionData")
' Split the string by commas
args = Split(customData, ",")
' Access individual arguments
Dim commonAppDataFolder, programMenuFolder, startupFolder, appDataFolder
commonAppDataFolder = Trim(args(0))
programMenuFolder = Trim(args(1))
startupFolder = Trim(args(2))
appDataFolder = Trim(args(3))
' Read variables from the session object
oldInstallationDir = commonAppDataFolder & "Safing\Portmaster\"
newDataDir = commonAppDataFolder & "Portmaster"
migrationFlagFile = oldInstallationDir & "migrated.txt"
doMigration = true
' Check for existing installtion
If Not fso.FolderExists(oldInstallationDir) Then
doMigration = false
End If
' Check if migration was already done
If fso.FileExists(migrationFlagFile) Then
doMigration = false
End If
If doMigration Then
' Copy the config file
dim configFile
configFile = "config.json"
If fso.FileExists(oldInstallationDir & configFile) Then
fso.CopyFile oldInstallationDir & configFile, newDataDir & configFile
End If
' Copy the database folder
dim databaseFolder
databaseFolder = "databases"
If fso.FolderExists(oldInstallationDir & databaseFolder) Then
fso.CopyFolder oldInstallationDir & databaseFolder, newDataDir & databaseFolder
End If
' Delete shortcuts
dim shortcutsFolder
notifierShortcut = programMenuFolder & "Portmaster/Portmaster Notifier.lnk"
If fso.FileExists(notifierShortcut) Then
fso.DeleteFile notifierShortcut, True
End If
' Delete startup shortcut
dim srartupFile
srartupFile = startupFolder & "Portmaster Notifier.lnk"
If fso.FileExists(srartupFile) Then
fso.DeleteFile srartupFile, True
End If
' Delete shortuct in user folder
dim userShortcut
userShortcut = appDataFolder & "Microsoft\Windows\Start Menu\Programs\Portmaster.lnk"
If fso.FileExists(userShortcut) Then
fso.DeleteFile userShortcut, True
End If
' Delete the old installer
dim oldUninstaller
oldUninstaller = oldInstallationDir & "portmaster-uninstaller.exe"
If fso.FileExists(oldUninstaller) Then
fso.DeleteFile oldUninstaller, True
End If
' Set the migration flag file
fso.CreateTextFile(migrationFlagFile).Close
End If

View File

@@ -12,8 +12,6 @@
<Fragment>
<Component Id="BinaryFiles" Directory="INSTALLDIR" Guid="850cdd31-424d-45f5-b8f0-95df950ebd0d">
<File Id="BinIndexJson" Source="..\..\..\..\binary\index.json" />
<File Id="PortmasterCoreExe" Source="..\..\..\..\binary\portmaster-core.exe" />
<File Id="PortmasterCoreDLL" Source="..\..\..\..\binary\portmaster-core.dll" />
<File Id="PortmasterKextSys" Source="..\..\..\..\binary\portmaster-kext.sys" />
<File Id="WebView2Loader" Source="..\..\..\..\binary\WebView2Loader.dll" />
@@ -29,6 +27,33 @@
<File Id="IndexDsd" Source="..\..\..\..\intel\index.dsd" />
<File Id="IntermediateDsdl" Source="..\..\..\..\intel\intermediate.dsdl" />
<File Id="UrgentDsdl" Source="..\..\..\..\intel\urgent.dsdl" />
<File Id="MainIntelYaml" Source="..\..\..\..\intel\main-intel.yaml" />
<File Id="NotificationsYaml" Source="..\..\..\..\intel\notifications.yaml" />
<File Id="NewsYaml" Source="..\..\..\..\intel\news.yaml" />
</Component>
<Component Id="PortmasterCoreService" Directory="INSTALLDIR" Guid="76ebd748-d620-484b-9035-5a64bbe2c26d">
<File Id="PortmasterCoreExe" Source="..\..\..\..\binary\portmaster-core.exe" />
<ServiceInstall
Id="PortmasterServiceInstall"
Type="ownProcess"
Name="PortmasterCore"
DisplayName="Portmaster Core"
Description="Portmaster Application Firewall - Core Service"
Start="auto"
ErrorControl="normal"
Vital="yes"
Interactive="no"
Arguments="--log-dir=%PROGRAMDATA%\Portmaster\logs"
Account="LocalSystem" />
<ServiceControl
Id="PortmasterServiceDeleteExisting"
Name="PortmasterCore"
Remove="uninstall"
Stop="both"
Wait="yes"
/>
</Component>
</Fragment>
@@ -36,6 +61,7 @@
<ComponentGroup Id="BinaryAndIntelFiles">
<ComponentRef Id="BinaryFiles" />
<ComponentRef Id="IntelFiles" />
<ComponentRef Id="PortmasterCoreService" />
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -70,9 +70,12 @@
<Property Id="ARPURLUPDATEINFO" Value="{{homepage}}"/>
{{/if}}
<!-- initialize with previous InstallDir -->
<Property Id="INSTALLDIR">
<RegistrySearch Id="PrevInstallDirReg" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw"/>
<!-- First attempt: Search for "InstallDir" -->
<RegistrySearch Id="PrevInstallDirWithName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw" />
<!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->
<RegistrySearch Id="PrevInstallDirNoName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Type="raw" />
</Property>
<!-- launch app checkbox -->
@@ -161,6 +164,7 @@
</Component>
<Component Id="UpdateTaskInstaller" Guid="011F25ED-9BE3-50A7-9E9B-3519ED2B9932" Win64="$(var.Win64)">
<File Id="UpdateTaskInstaller" Source="install-task.ps1" KeyPath="yes" Checksum="yes"/>
</Component>
<Component Id="UpdateTaskUninstaller" Guid="D4F6CC3F-32DC-5FD0-95E8-782FFD7BBCE1" Win64="$(var.Win64)">
<File Id="UpdateTaskUninstaller" Source="uninstall-task.ps1" KeyPath="yes" Checksum="yes"/>
@@ -323,6 +327,7 @@
Execute="commit"
Impersonate="yes"
ExeCommand="powershell.exe -WindowStyle hidden .\install-task.ps1" />
<InstallExecuteSequence>
<Custom Action='CreateUpdateTask' Before='InstallFinalize'>
NOT(REMOVE)
@@ -348,9 +353,11 @@
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize"/>
<!-- Service fragments -->
<CustomActionRef Id='InstallPortmasterService' />
<CustomActionRef Id='StopPortmasterService' />
<CustomActionRef Id='DeletePortmasterService' />
<CustomActionRef Id='MigrationPropertySet' />
<CustomActionRef Id='Migration' />
<!-- Uncommenting the next line will cause the installer to check if the old service is running and fail. Without, it will automatically stop and remove the old service without notifing the user. -->
<!-- <CustomActionRef Id='CheckServiceStatus' /> -->
<!-- End Service fragments -->
</Product>
</Wix>

View File

@@ -70,9 +70,12 @@
<Property Id="ARPURLUPDATEINFO" Value="{{homepage}}"/>
{{/if}}
<!-- initialize with previous InstallDir -->
<Property Id="INSTALLDIR">
<RegistrySearch Id="PrevInstallDirReg" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw"/>
<!-- First attempt: Search for "InstallDir" -->
<RegistrySearch Id="PrevInstallDirWithName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Name="InstallDir" Type="raw" />
<!-- Second attempt: If the first fails, search for the default key value (this is how the nsis installer currently stores the path) -->
<RegistrySearch Id="PrevInstallDirNoName" Root="HKCU" Key="Software\\{{manufacturer}}\\{{product_name}}" Type="raw" />
</Property>
<!-- launch app checkbox -->

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<!-- Load the VBscript -->
<Binary Id="Migration.vbs" SourceFile="..\..\..\..\templates\wix\Migration.vbs" />
<!-- VBscript script to copy the files from the old installation -->
<CustomAction
Id="Migration"
VBScriptCall=""
BinaryKey="Migration.vbs"
Return="check"
Impersonate="no"
Execute="deferred"
/>
<!-- This passes the path to CommonAppDataFolder path (usually "C:\ProgramData\") to the vbscirt custom action -->
<CustomAction Id="MigrationPropertySet" Property="Migration" Value="[CommonAppDataFolder], [ProgramMenuFolder], [StartupFolder], [AppDataFolder]" />
<!-- Check if service is running -->
<InstallExecuteSequence>
<Custom Action="MigrationPropertySet" Before="Migration">NOT(REMOVE)</Custom>
<Custom Action="Migration" Before="InstallFinalize">NOT(REMOVE)</Custom>
</InstallExecuteSequence>
</Fragment>
</Wix>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<!-- Load the VBscript -->
<Binary Id="CheckServiceStatusScript" SourceFile="..\..\..\..\templates\wix\CheckServiceStatus.vbs" />
<!-- VBscript script custom action to check if the service is running -->
<CustomAction
Id="CheckServiceStatus"
VBScriptCall=""
BinaryKey="CheckServiceStatusScript"
Return="check" />
<!-- Check if service is running -->
<InstallExecuteSequence>
<Custom Action="CheckServiceStatus" Before="InstallInitialize">NOT(REMOVE)</Custom>
</InstallExecuteSequence>
</Fragment>
</Wix>