Compare commits

...

9 Commits

Author SHA1 Message Date
duffyduck d3b28c0dcc Release v0.0.0.1 2026-04-03 10:52:54 +02:00
duffyduck abd52b351a Fix Inno Setup compile error and release script sed pattern
- Declare ErrorCode variable in InitializeSetup function
- Remove orphan var block at end of Code section
- Fix sed pattern in release.sh to only match version inside quotes
- Restore AboutForm.cs variable name damaged by previous sed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:52:21 +02:00
duffyduck 8ac4c12b46 Add sudo to docker command in release script
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:48:12 +02:00
duffyduck 574c1923f9 Add release script documentation to README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:45:15 +02:00
duffyduck b1658c8d3c Use basic auth instead of token for Gitea release upload
Prompts for username and password at script start instead
of requiring a pre-configured API token.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:41:58 +02:00
duffyduck 6a9a73106d Add release script for automated build and Gitea upload
Handles version bump, build, Inno Setup via Docker, git tag,
push, Gitea release creation and setup.exe upload in one step.

Usage: ./release.sh 0.1.0.0 "Release description"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:40:32 +02:00
duffyduck ec51dc8fc6 Restructure README: Docker as preferred installer build method
Reorder installer section with Docker first (recommended),
Windows second, Wine as fallback. Add one-liner build command.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:37:48 +02:00
duffyduck a831ec6f81 Update README with Linux build instructions
Add .NET SDK install, build and Inno Setup instructions for
both Windows and Linux (Docker or Wine).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:34:52 +02:00
duffyduck ad649ad319 Switch to .NET 8 for cross-platform build support
- Target net8.0-windows instead of net4.8
- EnableWindowsTargeting for Linux build
- Replace Marshal.GetActiveObject with P/Invoke (not in .NET 8)
- Use NuGet package for Outlook Interop instead of local DLL ref
- Update Inno Setup script for .NET 8 runtime check
- Builds successfully on Linux, runs on Windows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:33:21 +02:00
6 changed files with 391 additions and 33 deletions
+107 -5
View File
@@ -19,7 +19,7 @@ Windows-Anwendung zur bidirektionalen Synchronisation von Kontakten zwischen Mic
## Voraussetzungen
- Windows 10/11
- .NET Framework 4.8 (in Windows 10/11 bereits enthalten)
- .NET 8 Desktop Runtime (Setup prueft und verlinkt die Download-Seite falls noetig)
- Microsoft Outlook (Classic oder Neu, beliebige Version)
- Starface Telefonanlage ab Version 6.7 (REST-API)
@@ -49,19 +49,121 @@ Benutzerdaten (Profile, Mappings) werden mit entfernt.
## Entwicklung
### Voraussetzungen (Build)
- .NET 8 SDK (laeuft auf Windows, Linux und macOS)
- Fuer den Installer: Inno Setup 6 (Windows) oder Docker (Linux)
### .NET SDK installieren
**Windows:**
```
winget install Microsoft.DotNet.SDK.8
```
**Debian/Ubuntu:**
```bash
# Ueber das offizielle Install-Script:
wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh
chmod +x dotnet-install.sh
./dotnet-install.sh --channel 8.0
export PATH="$HOME/.dotnet:$PATH"
```
### Bauen
Das Projekt kann sowohl unter Windows als auch unter Linux gebaut werden.
Die fertige EXE laeuft nur auf Windows (WinForms + COM Interop).
```bash
# In Visual Studio oeffnen und bauen, oder:
# Release-Build
dotnet build src/StarfaceOutlookSync/StarfaceOutlookSync.csproj -c Release
# Oder publish (mit allen Abhaengigkeiten):
dotnet publish src/StarfaceOutlookSync/StarfaceOutlookSync.csproj -c Release
```
Build-Ausgabe: `src/StarfaceOutlookSync/bin/Release/net8.0-windows/win-x64/`
### Installer erstellen
Die Setup-EXE wird mit Inno Setup 6 erstellt.
**Linux (Docker - empfohlen):**
Einfachster Weg unter Linux. Baut und packt alles in einem Schritt:
```bash
# 1. Release bauen
dotnet build src/StarfaceOutlookSync/StarfaceOutlookSync.csproj -c Release
# 2. Installer erstellen
docker run --rm -v "$PWD:/work" amake/innosetup installer/setup.iss
```
Die fertige Setup-EXE liegt danach in `dist/`.
Komplett als Einzeiler (Build + Installer):
```bash
dotnet build src/StarfaceOutlookSync/StarfaceOutlookSync.csproj -c Release && docker run --rm -v "$PWD:/work" amake/innosetup installer/setup.iss
```
**Windows:**
1. [Inno Setup 6](https://jrsoftware.org/isinfo.php) installieren
2. Release-Build erstellen
3. `installer/setup.iss` in Inno Setup oeffnen und kompilieren
4. Setup-EXE wird in `dist/` erstellt
2. `installer/setup.iss` oeffnen und kompilieren
3. Setup-EXE wird in `dist/` erstellt
Oder per Kommandozeile:
```cmd
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer\setup.iss
```
**Linux (Wine - Alternative falls kein Docker vorhanden):**
```bash
# Einmalig: Inno Setup in Wine installieren
sudo apt install wine
wine ~/Downloads/innosetup-6.x.exe
# Kompilieren
wine "$HOME/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe" installer/setup.iss
```
### Release erstellen
Das Release-Script automatisiert den kompletten Release-Prozess:
Versionsnummer aktualisieren, bauen, Installer erstellen, Git Tag + Push
und Gitea Release mit Setup-EXE als Download hochladen.
```bash
./release.sh <version> ["beschreibung"]
```
Beispiele:
```bash
# Release mit Standard-Beschreibung
./release.sh 0.1.0.0
# Release mit eigener Beschreibung
./release.sh 0.2.0.0 "Neues Feature: Auto-Sync"
```
Das Script fragt beim Start nach Gitea-Benutzername und Kennwort
und fuehrt dann folgende Schritte automatisch aus:
1. Prueft Voraussetzungen (dotnet, docker, curl, sauberes git)
2. Aktualisiert Versionsnummer in `.csproj`, `AboutForm.cs` und `setup.iss`
3. Baut das Projekt (`dotnet build -c Release`)
4. Erstellt den Installer via Docker (`amake/innosetup`)
5. Git Commit + Tag (`vX.X.X.X`)
6. Push zu Gitea (main + tag)
7. Erstellt Gitea Release mit Setup-EXE als Download-Anhang
Voraussetzungen:
- .NET 8 SDK
- Docker
- curl
- Gitea-Account mit Push-Rechten auf das Repository
## Projektstruktur
+19 -11
View File
@@ -36,7 +36,7 @@ Name: "autostart"; Description: "Bei Windows-Anmeldung automatisch starten"; Gro
[Files]
; Hauptanwendung - Pfad anpassen nach Build
Source: "..\src\StarfaceOutlookSync\bin\Release\net4.8\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\src\StarfaceOutlookSync\bin\Release\net8.0-windows\win-x64\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
@@ -57,26 +57,34 @@ Filename: "taskkill"; Parameters: "/F /IM {#MyAppExeName}"; Flags: runhidden; Ru
Type: filesandordirs; Name: "{userappdata}\StarfaceOutlookSync"
[Code]
// Pruefe ob .NET Framework 4.8 installiert ist
function IsDotNetInstalled(): Boolean;
// Pruefe ob .NET 8 Desktop Runtime installiert ist
function IsDotNet8Installed(): Boolean;
var
Version: Cardinal;
ResultCode: Integer;
begin
Result := RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', Version);
// dotnet --list-runtimes enthaelt "Microsoft.WindowsDesktop.App 8.x"
Result := Exec('dotnet', '--list-runtimes', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
if Result then
Result := Version >= 528040; // .NET 4.8
Result := ResultCode = 0;
// Einfacher Check: dotnet.exe muss existieren
Result := FileExists(ExpandConstant('{commonpf}\dotnet\dotnet.exe')) or
FileExists(ExpandConstant('{commonpf64}\dotnet\dotnet.exe'));
end;
function InitializeSetup(): Boolean;
var
ErrorCode: Integer;
begin
Result := True;
if not IsDotNetInstalled() then
if not IsDotNet8Installed() then
begin
MsgBox('.NET Framework 4.8 oder hoeher wird benoetigt.' + #13#10 +
'Bitte installieren Sie es von:' + #13#10 +
'https://dotnet.microsoft.com/download/dotnet-framework/net48',
mbError, MB_OK);
if MsgBox('.NET 8 Desktop Runtime wird benoetigt.' + #13#10 + #13#10 +
'Soll die Download-Seite geoeffnet werden?',
mbConfirmation, MB_YESNO) = IDYES then
begin
ShellExec('open', 'https://dotnet.microsoft.com/download/dotnet/8.0/runtime', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
Result := False;
end;
end;
Executable
+244
View File
@@ -0,0 +1,244 @@
#!/bin/bash
#
# Release-Script fuer Starface Outlook Sync
#
# Aktualisiert Versionsnummer, baut die App, erstellt den Installer
# und laedt das Release auf Gitea hoch.
#
# Voraussetzungen:
# - .NET 8 SDK (dotnet)
# - Docker (fuer Inno Setup)
# - curl (fuer Gitea API)
# - Gitea-Zugangsdaten (werden beim Start abgefragt)
#
# Verwendung:
# ./release.sh 0.1.0.0
# ./release.sh 0.1.0.0 "Erster Beta-Release"
set -e
# ============================================================
# Konfiguration
# ============================================================
GITEA_URL="https://git.hacker-net.de"
REPO_OWNER="Hacker-Software"
REPO_NAME="starface-outlook-sync-addin"
DOTNET_PATH="${DOTNET_PATH:-$HOME/.dotnet}"
PROJECT="src/StarfaceOutlookSync/StarfaceOutlookSync.csproj"
ABOUT_FORM="src/StarfaceOutlookSync/UI/AboutForm.cs"
INNO_SCRIPT="installer/setup.iss"
DIST_DIR="dist"
# ============================================================
# Argumente pruefen
# ============================================================
VERSION="${1}"
RELEASE_NOTE="${2:-Release v${VERSION}}"
if [ -z "$VERSION" ]; then
echo "Verwendung: $0 <version> [release-beschreibung]"
echo "Beispiel: $0 0.1.0.0 \"Erster Beta-Release\""
echo ""
echo "Aktuelle Version in .csproj:"
grep '<Version>' "$PROJECT" | head -1 | sed 's/.*<Version>/ /;s/<.*//'
exit 1
fi
# Versionsformat pruefen (x.x.x.x)
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Fehler: Version muss im Format x.x.x.x sein (z.B. 0.1.0.0)"
exit 1
fi
# ============================================================
# Gitea-Zugangsdaten abfragen
# ============================================================
read -p "Gitea Benutzername: " GITEA_USER
read -s -p "Gitea Kennwort: " GITEA_PASS
echo ""
if [ -z "$GITEA_USER" ] || [ -z "$GITEA_PASS" ]; then
echo "Fehler: Benutzername und Kennwort erforderlich."
exit 1
fi
GITEA_AUTH="${GITEA_USER}:${GITEA_PASS}"
# ============================================================
# Tools pruefen
# ============================================================
export PATH="$DOTNET_PATH:$PATH"
echo "=== Starface Outlook Sync - Release v${VERSION} ==="
echo ""
echo "[1/7] Pruefe Voraussetzungen..."
if ! command -v dotnet &> /dev/null; then
echo " Fehler: dotnet nicht gefunden."
echo " Install: wget https://dot.net/v1/dotnet-install.sh -O- | bash /dev/stdin --channel 8.0"
exit 1
fi
echo " dotnet $(dotnet --version)"
if ! command -v docker &> /dev/null; then
echo " Fehler: docker nicht gefunden."
echo " Install: https://docs.docker.com/engine/install/debian/"
exit 1
fi
echo " docker $(docker --version | cut -d' ' -f3 | tr -d ',')"
if ! command -v curl &> /dev/null; then
echo " Fehler: curl nicht gefunden."
exit 1
fi
# Pruefen ob Git sauber ist
if [ -n "$(git status --porcelain)" ]; then
echo ""
echo " Warnung: Uncommitted changes vorhanden!"
git status --short
echo ""
read -p " Trotzdem fortfahren? (j/n) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[jJyY]$ ]]; then
exit 1
fi
fi
# ============================================================
# Versionsnummern aktualisieren
# ============================================================
echo ""
echo "[2/7] Aktualisiere Versionsnummer auf ${VERSION}..."
# .csproj
sed -i "s|<Version>.*</Version>|<Version>${VERSION}</Version>|g" "$PROJECT"
sed -i "s|<AssemblyVersion>.*</AssemblyVersion>|<AssemblyVersion>${VERSION}</AssemblyVersion>|g" "$PROJECT"
sed -i "s|<FileVersion>.*</FileVersion>|<FileVersion>${VERSION}</FileVersion>|g" "$PROJECT"
# AboutForm.cs - nur den Text im String-Literal ersetzen, nicht Variablennamen
sed -i "s|\"Version [0-9.]*\"|\"Version ${VERSION}\"|g" "$ABOUT_FORM"
# Inno Setup
sed -i "s|#define MyAppVersion \".*\"|#define MyAppVersion \"${VERSION}\"|g" "$INNO_SCRIPT"
echo " .csproj, AboutForm.cs, setup.iss aktualisiert."
# ============================================================
# Bauen
# ============================================================
echo ""
echo "[3/7] Baue Release..."
dotnet build "$PROJECT" -c Release --nologo -v quiet
echo " Build erfolgreich."
# ============================================================
# Installer erstellen
# ============================================================
echo ""
echo "[4/7] Erstelle Installer mit Docker..."
mkdir -p "$DIST_DIR"
sudo docker run --rm -v "$PWD:/work" amake/innosetup "$INNO_SCRIPT"
SETUP_FILE="${DIST_DIR}/StarfaceOutlookSync_Setup_${VERSION}.exe"
if [ ! -f "$SETUP_FILE" ]; then
echo " Fehler: Setup-Datei nicht gefunden: $SETUP_FILE"
exit 1
fi
SETUP_SIZE=$(du -h "$SETUP_FILE" | cut -f1)
echo " Installer erstellt: $SETUP_FILE ($SETUP_SIZE)"
# ============================================================
# Git Commit + Tag
# ============================================================
echo ""
echo "[5/7] Git Commit und Tag..."
git add "$PROJECT" "$ABOUT_FORM" "$INNO_SCRIPT"
git commit -m "Release v${VERSION}" --allow-empty
git tag -a "v${VERSION}" -m "Release v${VERSION}"
echo " Commit und Tag v${VERSION} erstellt."
# ============================================================
# Git Push
# ============================================================
echo ""
echo "[6/7] Push zu Gitea..."
git push origin main
git push origin "v${VERSION}"
echo " Push erfolgreich."
# ============================================================
# Gitea Release erstellen
# ============================================================
echo ""
echo "[7/7] Erstelle Gitea Release..."
API_URL="${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}"
# Release erstellen
RELEASE_RESPONSE=$(curl -s -X POST \
-u "${GITEA_AUTH}" \
-H "Content-Type: application/json" \
-d "{
\"tag_name\": \"v${VERSION}\",
\"name\": \"v${VERSION}\",
\"body\": \"${RELEASE_NOTE}\",
\"draft\": false,
\"prerelease\": false
}" \
"${API_URL}/releases")
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2)
if [ -z "$RELEASE_ID" ]; then
echo " Fehler beim Erstellen des Release:"
echo " $RELEASE_RESPONSE"
exit 1
fi
echo " Release erstellt (ID: $RELEASE_ID)"
# Setup-EXE als Attachment hochladen
echo " Lade Installer hoch..."
UPLOAD_RESPONSE=$(curl -s -X POST \
-u "${GITEA_AUTH}" \
-F "attachment=@${SETUP_FILE}" \
"${API_URL}/releases/${RELEASE_ID}/assets?name=$(basename $SETUP_FILE)")
ASSET_URL=$(echo "$UPLOAD_RESPONSE" | grep -o '"browser_download_url":"[^"]*"' | cut -d'"' -f4)
if [ -z "$ASSET_URL" ]; then
echo " Warnung: Upload-Antwort:"
echo " $UPLOAD_RESPONSE"
else
echo " Upload erfolgreich: $ASSET_URL"
fi
# ============================================================
# Zusammenfassung
# ============================================================
echo ""
echo "=== Release v${VERSION} abgeschlossen ==="
echo ""
echo " Release: ${GITEA_URL}/${REPO_OWNER}/${REPO_NAME}/releases/tag/v${VERSION}"
echo " Installer: $SETUP_FILE ($SETUP_SIZE)"
echo " Tag: v${VERSION}"
echo ""
@@ -11,6 +11,17 @@ namespace StarfaceOutlookSync.Services
private Outlook.Application _outlookApp;
private bool _weStartedOutlook;
// Marshal.GetActiveObject existiert nicht in .NET 8, daher P/Invoke
[DllImport("oleaut32.dll", PreserveSig = false)]
private static extern void GetActiveObject([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk);
private static object GetActiveComObject(string progId)
{
var clsid = Type.GetTypeFromProgID(progId, true).GUID;
GetActiveObject(clsid, IntPtr.Zero, out var obj);
return obj;
}
private Outlook.Application GetOutlookApp()
{
if (_outlookApp != null) return _outlookApp;
@@ -18,7 +29,7 @@ namespace StarfaceOutlookSync.Services
try
{
// Versuche laufende Outlook-Instanz zu finden
_outlookApp = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
_outlookApp = (Outlook.Application)GetActiveComObject("Outlook.Application");
_weStartedOutlook = false;
}
catch
@@ -2,9 +2,8 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net4.8</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>Resources\app.ico</ApplicationIcon>
<AssemblyTitle>Starface Outlook Sync</AssemblyTitle>
<Company>HackerSoft - Hacker-Net Telekommunikation</Company>
<Product>Starface Outlook Sync</Product>
@@ -13,21 +12,14 @@
<FileVersion>0.0.0.1</FileVersion>
<Description>Synchronisiert Outlook-Kontakte mit Starface Telefonanlage</Description>
<Copyright>Stefan Hacker - HackerSoft</Copyright>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Office.Interop.Outlook">
<HintPath>$(ProgramFiles)\Microsoft Office\root\Office16\ADDINS\Microsoft.Office.Interop.Outlook.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\app.ico" />
<PackageReference Include="Microsoft.Office.Interop.Outlook" Version="15.0.4797.1004" />
</ItemGroup>
</Project>
+4 -3
View File
@@ -228,17 +228,17 @@ namespace StarfaceOutlookSync.UI
}
}
private async Task SyncSelectedProfile()
private Task SyncSelectedProfile()
{
if (_profileList.SelectedItems.Count == 0)
{
MessageBox.Show("Bitte ein Profil auswaehlen.", "Sync",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
return Task.CompletedTask;
}
var profile = _profileList.SelectedItems[0].Tag as SyncProfile;
if (profile == null) return;
if (profile == null) return Task.CompletedTask;
using (var syncForm = new SyncProgressForm(profile))
{
@@ -246,6 +246,7 @@ namespace StarfaceOutlookSync.UI
}
RefreshProfileList();
return Task.CompletedTask;
}
private async Task RunSync(SyncProfile profile)