24 Commit-ok
v1.21 ... v1.22

Szerző SHA1 Üzenet Dátum
hariel1985
ddc5a70719 Merge remote README with screenshots, add Office 2016 info
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 23:36:05 +02:00
hariel1985
12b86e0707 v1.22 — Office 2016 MSI ISO telepítés támogatás
Office 2016 Standard és Professional Plus telepítése ISO letöltéssel
(soft.direct), ISO csatolással és a Microsoft MSI telepítő indításával.
A 2019/2021/2024 verziók továbbra is ODT-vel működnek.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 23:27:14 +02:00
hariel1985
813e08b7d4 Fix Office 2016 visibility with ScrollViewer, bump to v1.21
Version page now scrollable to fit all 4 Office versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:53:22 +02:00
hariel1985
292a5a093e Add Office 2016 support, bump to v1.20
Office 2016 Standard, Professional Plus, and Home & Business editions
added with PerpetualVL2019 channel for volume licenses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 12:47:44 +02:00
hariel1985
8e4ad331f1 v1.19 — Bug fixes, Hungarian accents, better error handling
- Fix: Back button was always visible (ternary always returned Visible)
- Fix: Missing Hungarian accents on EditionPage ("Válasszon kiadást")
- Fix: Better ODT download error messages (network/timeout distinguished)
- Signed with Azure Trusted Signing (Microsoft root CA, instant SmartScreen trust)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:04:11 +02:00
hariel1985
53ae21dd87 v1.17 — Signed with Certum OV code signing certificate
Signed by: InstaSoft Informatikai Zrt.
Issuer: Certum Code Signing 2021 CA
Valid until: 2027-04-02

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:50:30 +02:00
hariel1985
642b19274b README: add Hungarian diacritics
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:13:25 +02:00
hariel1985
fb7ce8b34e Add detailed internal README
Project documentation: features, tech specs, product IDs, build instructions,
version history, folder structure, signing and versioning guidelines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:11:41 +02:00
hariel1985
486589f9bc v1.16 — Remove PowerShell edition, restore flat project structure
PowerShell version removed — will use OV code signing certificate instead.
Files moved back from src/ to project root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:07:27 +02:00
hariel1985
ae4d7f82bc v1.15 — PowerShell edition + repo restructure
- New powershell/InstaSoftOfficeTool.ps1: single-file WPF GUI version
  - Same Fluent Design UI, no compilation needed
  - Runs on any Windows 7+ with PowerShell 5.1 (built-in)
  - Chrome won't flag .ps1 files as "rarely downloaded"
  - Auto-elevates to admin
- Moved C# source to src/ subfolder
- Updated .gitignore for nested bin/obj folders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 17:58:15 +02:00
hariel1985
0bc3bd2588 v1.14 — Reset window height on Back button navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:11:56 +02:00
hariel1985
ea8fa98bd6 v1.13 — Post-install activation, app launch, scrollable progress page
- Progress page now scrollable (activation + launch cards were clipped)
- Post-install activation card if no product key was provided during wizard
- App launch buttons (Word, Excel, PowerPoint, Outlook) after successful install
- Skipped apps not shown in launch buttons
- Install time hint: "akár 30-40 percet is igénybe vehet"
- Auto-refresh office list after removal
- MSI uninstall: only valid {GUID} product codes accepted

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 10:08:13 +02:00
hariel1985
9c835871ec v1.11 — Full app list, edition-specific availability
- All Office apps listed: Word, Excel, PowerPoint, Outlook, OneNote, Access, Publisher, Teams, Skype
- Access: only available in Professional Plus
- Publisher: available in Professional Plus and Standard, disabled for Home & Business
- Teams and Skype for Business: unchecked by default
- All core apps (Word, Excel, etc.) can be individually excluded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 08:43:14 +02:00
hariel1985
0e4253ba37 v1.10 — Activation with key dialog, auto-refresh, Access restriction, fixes
- Product key dialog: Fluent overlay with 5-field input + paste support
- Activate button on each license card asks for key first (/inpkey + /act)
- Auto-refresh lists after removal/activation on all pages
- Access checkbox disabled for Standard and Home & Business editions
- MSI uninstall: only accept {GUID} product codes (fix msiexec help popup)
- Window height properly resets when Details expander is collapsed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 08:38:08 +02:00
hariel1985
eac8813cc0 v1.09 — Fix ODT download, selective removal, Display Level Full
- Direct CDN download (officecdn.microsoft.com/pr/wsus/setup.exe) instead of broken fwlink redirect
- HttpClient with proper redirect handling, content-type check, file size validation
- Selective C2R removal: each product listed separately, only checked items removed
- OfficeDetector splits ProductReleaseIds into individual entries
- Display Level="Full" for removal (shows Microsoft progress UI)
- Confirmation dialog before removal on all pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 07:33:19 +02:00
hariel1985
f41b821d24 v1.08 — Custom Fluent confirmation dialog, replace all MessageBox
- New ConfirmDialog overlay with dark backdrop, rounded card, shadow
- Warning/Question/Error icon types with accent colors
- Replaced all MessageBox.Show calls (RemovePage, PreInstallCheck, Troubleshoot)
- Click outside dialog = cancel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:36:13 +02:00
hariel1985
c23865d5f5 v1.07 — Pre-install Office check before installation
- New PreInstallCheckPage between Summary and Progress
- Detects existing Office installs, offers removal before new install
- License cleanup option included
- Skip button to proceed without removal
- Auto-proceeds to install after removal completes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:25:48 +02:00
hariel1985
b412baaa5c v1.06 — Fix product key paste across all 5 fields
- Use DataObject.Pasting handler to intercept paste before MaxLength truncation
- Full key paste (e.g. XXXXX-XXXXX-XXXXX-XXXXX-XXXXX) distributes across all boxes
- Works when pasting into any of the 5 fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:20:29 +02:00
hariel1985
24b41b0e63 v1.05 — Fix primary button text contrast (white on blue)
- Removed Foreground from global TextBlock style (was overriding inherited colors)
- Set TextElement.Foreground on Window level for default text color
- PrimaryButton TextElement.Foreground now properly inherits white

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:15:24 +02:00
hariel1985
0401910711 v1.04 — Config layout, button contrast, Skype default, Win11 for 2019
- Arch + Language side by side on config page
- Removed redundant hint text under app checkboxes
- Primary button: white text on blue (TextElement.Foreground fix)
- Skype for Business unchecked by default
- Office 2019: added Windows 11 support, end-of-support note
- Version display synced to v1.04

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:12:51 +02:00
hariel1985
56d5c38ab1 v1.03 — Fluent UI controls, version card info, paste fix
- Version cards: release dates + supported OS (no LTSC/Version 16.0)
- Fluent ComboBox: rounded corners, shadow dropdown, chevron icon
- Fluent CheckBox: custom blue checkbox with MDL2 checkmark, hover states
- Fluent TextBox: rounded corners, blue bottom border on focus
- 64-bit labeled "(ajánlott)"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 06:04:10 +02:00
hariel1985
0794d40054 Wizard improvements: version info, 64-bit label, paste fix
- Version cards show technical info (Version 16.0 · LTSC · OS support)
- 64-bit option labeled as "(ajánlott)"
- Full product key paste distributes across all 5 input fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:57:34 +02:00
hariel1985
e8abb03eee v1.02 — License troubleshoot UI improvements
- Fix ospp.vbs path: add root\Office16 for Click-to-Run installs
- Individual key cards with per-key remove buttons
- "Remove all" only shown when 2+ keys found
- Collapsible "Details" section (ospp.vbs path + raw output)
- All log/output fields now selectable and copyable (TextBox)
- Parse license entries (name, status, error, key) from dstatus output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:51:26 +02:00
hariel1985
4937ac4b1c Initial release v1.01 — InstaSoft Office Tool
Office deployment wizard for InstaSoft customers:
- Install Office 2019/2021/2024 (Standard, Professional Plus, Home & Business)
- Auto-download ODT from Microsoft, generate config XML, run setup
- Remove existing Office installations (C2R + MSI)
- License troubleshooting via ospp.vbs (dstatus, unpkey)
- Fluent Design UI (WPF .NET Framework 4.8, Win7+ compatible)
- Hungarian interface, multi-language Office installation
- Product key input with auto-activation support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:40:50 +02:00
46 fájl változott, egészen pontosan 4281 új sor hozzáadva és 3 régi sor törölve

7
.gitignore vendored Normal file
Fájl megtekintése

@@ -0,0 +1,7 @@
**/bin/
**/obj/
*.user
*.suo
.vs/
*.DotSettings.user
packages/

14
App.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,14 @@
<Application x:Class="InstaSoftOfficeTool.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/FluentTheme.xaml"/>
<ResourceDictionary Source="Styles/ButtonStyles.xaml"/>
<ResourceDictionary Source="Styles/ControlStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

8
App.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,8 @@
using System.Windows;
namespace InstaSoftOfficeTool
{
public partial class App : Application
{
}
}

Fájl megtekintése

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net48</TargetFramework>
<UseWPF>true</UseWPF>
<RootNamespace>InstaSoftOfficeTool</RootNamespace>
<AssemblyName>InstaSoftOfficeTool</AssemblyName>
<ApplicationIcon>Resources\app.ico</ApplicationIcon>
<Company>InstaSoft Zrt.</Company>
<Product>InstaSoft Office Tool</Product>
<Copyright>Copyright (c) InstaSoft Zrt. 2026</Copyright>
<Version>1.22</Version>
<AssemblyVersion>1.22.0.0</AssemblyVersion>
<FileVersion>1.22.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\app.ico" />
</ItemGroup>
</Project>

83
MainWindow.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,83 @@
<Window x:Class="InstaSoftOfficeTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pages="clr-namespace:InstaSoftOfficeTool.Pages"
Title="InstaSoft Office Tool"
Width="800" Height="550"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="{StaticResource BackgroundBrush}"
TextElement.Foreground="{StaticResource TextPrimaryBrush}">
<Grid>
<!-- Main content -->
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="64"/>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<!-- Header bar -->
<Border Grid.Row="0" Background="{StaticResource HeaderBarBrush}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="0,0,0,1">
<Grid Margin="24,0">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<!-- Microsoft 4-color logo -->
<Grid Width="24" Height="24" Margin="0,0,12,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Row="0" Grid.Column="0" Fill="#F35325" Margin="0,0,1,1"/>
<Rectangle Grid.Row="0" Grid.Column="1" Fill="#81BC06" Margin="1,0,0,1"/>
<Rectangle Grid.Row="1" Grid.Column="0" Fill="#05A6F0" Margin="0,1,1,0"/>
<Rectangle Grid.Row="1" Grid.Column="1" Fill="#FFBA08" Margin="1,1,0,0"/>
</Grid>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="InstaSoft Office Tool" FontSize="16" FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"/>
<TextBlock Text="Microsoft Partner" FontSize="11"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,-2,0,0"/>
</StackPanel>
</StackPanel>
<TextBlock Text="v1.22" HorizontalAlignment="Right" VerticalAlignment="Center"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"/>
</Grid>
</Border>
<!-- Content area -->
<Frame x:Name="ContentFrame" Grid.Row="1" NavigationUIVisibility="Hidden"
Margin="0" Background="Transparent"/>
<!-- Bottom bar: step dots + navigation -->
<Border Grid.Row="2" Background="{StaticResource HeaderBarBrush}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="0,1,0,0">
<Grid Margin="24,0">
<!-- Step indicator dots -->
<StackPanel x:Name="StepIndicator" Orientation="Horizontal"
HorizontalAlignment="Left" VerticalAlignment="Center">
</StackPanel>
<!-- Navigation buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
VerticalAlignment="Center">
<Button x:Name="BtnBack" Content="&#x2190; Vissza" Style="{StaticResource SecondaryButton}"
Click="BtnBack_Click" Margin="0,0,8,0" Visibility="Collapsed"/>
<Button x:Name="BtnNext" Content="Tovább &#x2192;" Style="{StaticResource PrimaryButton}"
Click="BtnNext_Click" Visibility="Collapsed"/>
</StackPanel>
</Grid>
</Border>
</Grid>
<!-- Confirm dialog overlay -->
<pages:ConfirmDialog x:Name="Dialog"/>
<!-- Product key dialog overlay -->
<pages:ProductKeyDialog x:Name="KeyDialog"/>
</Grid>
</Window>

230
MainWindow.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,230 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using InstaSoftOfficeTool.Models;
using InstaSoftOfficeTool.Pages;
namespace InstaSoftOfficeTool
{
public partial class MainWindow : Window
{
private InstallConfig _config = new InstallConfig();
private List<Page> _wizardPages;
private int _currentPageIndex = -1;
private string _currentFlow; // "install", "remove", "license"
public MainWindow()
{
InitializeComponent();
NavigateToWelcome();
}
public void NavigateToWelcome()
{
_currentFlow = null;
_currentPageIndex = -1;
_config = new InstallConfig();
BtnBack.Visibility = Visibility.Collapsed;
BtnNext.Visibility = Visibility.Collapsed;
StepIndicator.Children.Clear();
ContentFrame.Navigate(new WelcomePage(this));
}
public void StartInstallFlow()
{
_currentFlow = "install";
_config = new InstallConfig();
_wizardPages = new List<Page>
{
new VersionPage(this, _config), // 0
new EditionPage(this, _config), // 1
new ConfigPage(this, _config), // 2
new ProductKeyPage(this, _config), // 3
new SummaryPage(this, _config), // 4
new PreInstallCheckPage(this), // 5 — remove old Office
new ProgressPage(this, _config) // 6
};
_currentPageIndex = 0;
ShowCurrentPage();
}
public void StartRemoveFlow()
{
_currentFlow = "remove";
_wizardPages = new List<Page>
{
new RemovePage(this)
};
_currentPageIndex = 0;
BtnNext.Visibility = Visibility.Collapsed;
BtnBack.Visibility = Visibility.Visible;
StepIndicator.Children.Clear();
ContentFrame.Navigate(_wizardPages[0]);
}
public void StartLicenseFlow()
{
_currentFlow = "license";
_wizardPages = new List<Page>
{
new TroubleshootPage(this)
};
_currentPageIndex = 0;
BtnNext.Visibility = Visibility.Collapsed;
BtnBack.Visibility = Visibility.Visible;
StepIndicator.Children.Clear();
ContentFrame.Navigate(_wizardPages[0]);
}
private void ShowCurrentPage()
{
if (_currentPageIndex < 0 || _currentPageIndex >= _wizardPages.Count) return;
ContentFrame.Navigate(_wizardPages[_currentPageIndex]);
UpdateStepIndicator();
UpdateButtons();
}
private void UpdateStepIndicator()
{
StepIndicator.Children.Clear();
if (_currentFlow != "install") return;
// Only show dots for install flow (exclude PreInstallCheck + Progress)
int totalDots = _wizardPages.Count - 2;
for (int i = 0; i < totalDots; i++)
{
var dot = new Ellipse
{
Margin = new Thickness(4, 0, 4, 0)
};
if (i <= _currentPageIndex)
{
dot.Width = 10;
dot.Height = 10;
dot.Fill = (SolidColorBrush)FindResource("AccentBrush");
}
else
{
dot.Width = 8;
dot.Height = 8;
dot.Fill = (SolidColorBrush)FindResource("BorderBrush");
}
StepIndicator.Children.Add(dot);
}
}
private void UpdateButtons()
{
BtnBack.Visibility = _currentPageIndex > 0 ? Visibility.Visible : Visibility.Collapsed;
BtnNext.Visibility = Visibility.Visible;
// On SummaryPage = "Tov\u00e1bb"
// On PreInstallCheckPage or ProgressPage = hide
if (_wizardPages[_currentPageIndex] is PreInstallCheckPage ||
_wizardPages[_currentPageIndex] is ProgressPage)
{
BtnNext.Visibility = Visibility.Collapsed;
BtnBack.Visibility = Visibility.Collapsed;
StepIndicator.Children.Clear();
}
else
{
BtnNext.Content = "Tov\u00e1bb \u2192";
}
}
private void BtnBack_Click(object sender, RoutedEventArgs e)
{
// Reset window height in case a page enlarged it
Height = 550;
if (_currentPageIndex > 0 && _currentFlow == "install")
{
_currentPageIndex--;
ShowCurrentPage();
}
else
{
NavigateToWelcome();
}
}
private void BtnNext_Click(object sender, RoutedEventArgs e)
{
if (_currentFlow != "install") return;
// Validate current page
var currentPage = _wizardPages[_currentPageIndex];
if (currentPage is IWizardPage wizardPage && !wizardPage.Validate())
return;
if (_currentPageIndex < _wizardPages.Count - 1)
{
_currentPageIndex++;
// Refresh edition page when version changes
if (_currentPageIndex == 1)
{
_wizardPages[1] = new EditionPage(this, _config);
}
// Refresh config page when edition changes (MSI/ODT mode may differ)
if (_currentPageIndex == 2)
{
_wizardPages[2] = new ConfigPage(this, _config);
}
ShowCurrentPage();
}
}
public void ProceedToInstall()
{
// Jump to ProgressPage (last page in the wizard)
_currentPageIndex = _wizardPages.Count - 1;
ShowCurrentPage();
if (_wizardPages[_currentPageIndex] is ProgressPage progressPage)
{
progressPage.StartInstallation();
}
}
public void ShowCloseButton()
{
BtnNext.Content = "Bez\u00e1r\u00e1s";
BtnNext.Visibility = Visibility.Visible;
BtnNext.Click -= BtnNext_Click;
BtnNext.Click += (s, e) => Close();
}
public Task<bool> ConfirmAsync(string title, string message,
string confirmText = "Igen", string cancelText = "M\u00e9gse",
DialogType type = DialogType.Warning)
{
return Dialog.ShowAsync(title, message, confirmText, cancelText, type);
}
public Task<string> AskProductKeyAsync()
{
return KeyDialog.ShowAsync();
}
public void ShowBackToHomeButton()
{
BtnBack.Content = "\u2190 F\u0151oldal";
BtnBack.Visibility = Visibility.Visible;
}
}
public interface IWizardPage
{
bool Validate();
}
}

94
Models/InstallConfig.cs Normal file
Fájl megtekintése

@@ -0,0 +1,94 @@
using System.Collections.Generic;
namespace InstaSoftOfficeTool.Models
{
public class InstallConfig
{
public OfficeVersion Version { get; set; }
public OfficeEdition Edition { get; set; }
public string Architecture { get; set; } = "64";
public string Language { get; set; } = "hu-hu";
public string ProductKey { get; set; }
public List<string> ExcludedApps { get; set; } = new List<string>();
public bool IsMsiInstall => Edition != null && Edition.IsMsiInstall;
public string GetIsoUrl()
{
return Edition?.GetIsoUrl(Architecture);
}
public string GetVersionDisplayName()
{
switch (Version)
{
case OfficeVersion.Office2024: return "Office 2024";
case OfficeVersion.Office2021: return "Office 2021";
case OfficeVersion.Office2019: return "Office 2019";
case OfficeVersion.Office2016: return "Office 2016";
default: return "";
}
}
public string GetLanguageDisplayName()
{
return LanguageList.GetDisplayName(Language);
}
}
public static class LanguageList
{
public static readonly (string Code, string Name)[] Languages = new[]
{
("hu-hu", "Magyar"),
("en-us", "English (US)"),
("de-de", "Deutsch"),
("fr-fr", "Fran\u00e7ais"),
("it-it", "Italiano"),
("es-es", "Espa\u00f1ol"),
("pt-pt", "Portugu\u00eas"),
("nl-nl", "Nederlands"),
("pl-pl", "Polski"),
("cs-cz", "\u010ce\u0161tina"),
("sk-sk", "Sloven\u010dina"),
("ro-ro", "Rom\u00e2n\u0103"),
("hr-hr", "Hrvatski"),
("sl-si", "Sloven\u0161\u010dina"),
("sr-latn-rs", "Srpski"),
("bg-bg", "\u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438"),
("uk-ua", "\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430"),
("ru-ru", "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"),
("tr-tr", "T\u00fcrk\u00e7e"),
("ja-jp", "\u65e5\u672c\u8a9e"),
("zh-cn", "\u4e2d\u6587 (\u7b80\u4f53)"),
("ko-kr", "\ud55c\uad6d\uc5b4"),
};
public static string GetDisplayName(string code)
{
foreach (var lang in Languages)
{
if (lang.Code == code) return lang.Name;
}
return code;
}
}
public static class ExcludableApps
{
// Id, DisplayName, DefaultChecked (true = telep\u00edt, false = kiz\u00e1r)
// MinEdition: "all", "standard+" (Standard \u00e9s ProPlus), "proplus" (csak ProPlus)
public static readonly (string Id, string DisplayName, bool DefaultChecked, string MinEdition)[] Apps = new[]
{
("Word", "Word", true, "all"),
("Excel", "Excel", true, "all"),
("PowerPoint", "PowerPoint", true, "all"),
("Outlook", "Outlook", true, "all"),
("OneNote", "OneNote", true, "all"),
("Access", "Access", true, "proplus"),
("Publisher", "Publisher", true, "standard+"),
("Teams", "Teams", false, "all"),
("Lync", "Skype for Business", false, "all"),
};
}
}

11
Models/InstalledOffice.cs Normal file
Fájl megtekintése

@@ -0,0 +1,11 @@
namespace InstaSoftOfficeTool.Models
{
public class InstalledOffice
{
public string DisplayName { get; set; }
public string Version { get; set; }
public string ProductCode { get; set; }
public bool IsClickToRun { get; set; }
public bool IsSelected { get; set; }
}
}

147
Models/OfficeEdition.cs Normal file
Fájl megtekintése

@@ -0,0 +1,147 @@
namespace InstaSoftOfficeTool.Models
{
public class OfficeEdition
{
public string DisplayName { get; set; }
public string Description { get; set; }
public string ProductId { get; set; }
public string Channel { get; set; }
public bool IsVolume { get; set; }
// MSI ISO telepítés (Office 2016)
public string IsoUrl32 { get; set; }
public string IsoUrl64 { get; set; }
public bool IsMsiInstall => IsoUrl64 != null || IsoUrl32 != null;
public string GetIsoUrl(string architecture)
{
return architecture == "32" ? IsoUrl32 : IsoUrl64;
}
public bool HasArchitecture(string architecture)
{
return architecture == "32" ? IsoUrl32 != null : IsoUrl64 != null;
}
public static OfficeEdition[] GetEditions(OfficeVersion version)
{
switch (version)
{
case OfficeVersion.Office2024:
return new[]
{
new OfficeEdition
{
DisplayName = "Standard",
Description = "Alapvet\u0151 irodai alkalmaz\u00e1sok: Word, Excel, PowerPoint, Outlook, OneNote",
ProductId = "Standard2024Volume",
Channel = "PerpetualVL2024",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Professional Plus",
Description = "Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote",
ProductId = "ProPlus2024Volume",
Channel = "PerpetualVL2024",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Otthoni \u00e9s kisv\u00e1llalati verzi\u00f3",
Description = "Word, Excel, PowerPoint, Outlook, OneNote \u2014 v\u00e1llalkoz\u00e1sokban is haszn\u00e1lhat\u00f3",
ProductId = "HomeBusiness2024Retail",
Channel = "Current",
IsVolume = false
}
};
case OfficeVersion.Office2021:
return new[]
{
new OfficeEdition
{
DisplayName = "Standard",
Description = "Alapvet\u0151 irodai alkalmaz\u00e1sok: Word, Excel, PowerPoint, Outlook, OneNote",
ProductId = "Standard2021Volume",
Channel = "PerpetualVL2021",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Professional Plus",
Description = "Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote",
ProductId = "ProPlus2021Volume",
Channel = "PerpetualVL2021",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Otthoni \u00e9s kisv\u00e1llalati verzi\u00f3",
Description = "Word, Excel, PowerPoint, Outlook, OneNote \u2014 v\u00e1llalkoz\u00e1sokban is haszn\u00e1lhat\u00f3",
ProductId = "HomeBusiness2021Retail",
Channel = "Current",
IsVolume = false
}
};
case OfficeVersion.Office2019:
return new[]
{
new OfficeEdition
{
DisplayName = "Standard",
Description = "Alapvet\u0151 irodai alkalmaz\u00e1sok: Word, Excel, PowerPoint, Outlook, OneNote",
ProductId = "Standard2019Volume",
Channel = "PerpetualVL2019",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Professional Plus",
Description = "Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote, Skype for Business",
ProductId = "ProPlus2019Volume",
Channel = "PerpetualVL2019",
IsVolume = true
},
new OfficeEdition
{
DisplayName = "Otthoni \u00e9s kisv\u00e1llalati verzi\u00f3",
Description = "Word, Excel, PowerPoint, Outlook, OneNote \u2014 v\u00e1llalkoz\u00e1sokban is haszn\u00e1lhat\u00f3",
ProductId = "HomeBusiness2019Retail",
Channel = "Current",
IsVolume = false
}
};
case OfficeVersion.Office2016:
return new[]
{
new OfficeEdition
{
DisplayName = "Standard",
Description = "Alapvető irodai alkalmazások: Word, Excel, PowerPoint, Outlook, OneNote",
ProductId = "Standard2016Volume",
Channel = "PerpetualVL2019",
IsVolume = true,
IsoUrl32 = "https://soft.direct/Install/SW_DVD5_Office_2016_W32_Hungarian_MLF_X20-41370.iso",
IsoUrl64 = "https://soft.direct/Install/SW_DVD5_Office_2016_W64_Hungarian_MLF_X20-41370.iso"
},
new OfficeEdition
{
DisplayName = "Professional Plus",
Description = "Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote, Skype for Business",
ProductId = "ProPlus2016Volume",
Channel = "PerpetualVL2019",
IsVolume = true,
IsoUrl64 = "https://soft.direct/Install/SW_DVD5_Office_Professional_Plus_2016_64Bit_Hungarian_MLF_X20-42439.ISO"
}
};
default:
return new OfficeEdition[0];
}
}
}
}

10
Models/OfficeVersion.cs Normal file
Fájl megtekintése

@@ -0,0 +1,10 @@
namespace InstaSoftOfficeTool.Models
{
public enum OfficeVersion
{
Office2024,
Office2021,
Office2019,
Office2016
}
}

53
Pages/ConfigPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,53 @@
<Page x:Class="InstaSoftOfficeTool.Pages.ConfigPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="40,30">
<StackPanel>
<TextBlock Text="Beállítások" FontSize="24" FontWeight="Light" Margin="0,0,0,20"/>
<!-- Arch + Language side by side -->
<Grid Margin="0,0,0,20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="0,0,16,0">
<TextBlock Text="Architektúra" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,8"/>
<StackPanel Orientation="Horizontal">
<RadioButton x:Name="Rb64" GroupName="Arch" IsChecked="True"
Style="{StaticResource CardRadioButton}" Margin="0,0,10,0" MinWidth="140">
<TextBlock Text="64-bit (ajánlott)" FontSize="14" Margin="6,0"/>
</RadioButton>
<RadioButton x:Name="Rb32" GroupName="Arch"
Style="{StaticResource CardRadioButton}" MinWidth="100">
<TextBlock Text="32-bit" FontSize="14" Margin="6,0"/>
</RadioButton>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock Text="Telepítési nyelv" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,8"/>
<ComboBox x:Name="CbLanguage" Style="{StaticResource FluentComboBox}"
HorizontalAlignment="Stretch"/>
<TextBlock x:Name="LanguageNote" Visibility="Collapsed"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,4,0,0" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
<TextBlock x:Name="ArchNote" Visibility="Collapsed"
FontSize="12" Foreground="#E65100" Margin="0,-12,0,16" TextWrapping="Wrap"/>
<TextBlock x:Name="AppTitle" Text="Telepítendő alkalmazások" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,10"/>
<WrapPanel x:Name="AppCheckBoxes" Orientation="Horizontal"/>
<TextBlock x:Name="AppNote" Visibility="Collapsed"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,8,0,0" TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer>
</Page>

142
Pages/ConfigPage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,142 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
namespace InstaSoftOfficeTool.Pages
{
public partial class ConfigPage : Page, IWizardPage
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
private readonly List<CheckBox> _appCheckBoxes = new List<CheckBox>();
public ConfigPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
bool isMsi = _config.IsMsiInstall;
// Restore arch
if (_config.Architecture == "32")
{
Rb32.IsChecked = true;
}
// MSI: handle architecture constraints
if (isMsi && _config.Edition != null && !_config.Edition.HasArchitecture("32"))
{
Rb32.IsEnabled = false;
Rb64.IsChecked = true;
ArchNote.Text = "A Professional Plus kiadáshoz csak 64-bites telepítő érhető el.";
ArchNote.Visibility = Visibility.Visible;
}
// Populate language combo
foreach (var lang in LanguageList.Languages)
{
CbLanguage.Items.Add(new ComboBoxItem
{
Content = lang.Name + " (" + lang.Code + ")",
Tag = lang.Code
});
}
// Select current language
for (int i = 0; i < CbLanguage.Items.Count; i++)
{
var item = (ComboBoxItem)CbLanguage.Items[i];
if ((string)item.Tag == _config.Language)
{
CbLanguage.SelectedIndex = i;
break;
}
}
if (CbLanguage.SelectedIndex < 0) CbLanguage.SelectedIndex = 0;
// MSI: language is baked into the ISO
if (isMsi)
{
CbLanguage.IsEnabled = false;
// Force Hungarian selection
for (int i = 0; i < CbLanguage.Items.Count; i++)
{
var item = (ComboBoxItem)CbLanguage.Items[i];
if ((string)item.Tag == "hu-hu")
{
CbLanguage.SelectedIndex = i;
break;
}
}
LanguageNote.Text = "Az Office 2016 telepítő ISO magyar nyelvű. A nyelv nem módosítható.";
LanguageNote.Visibility = Visibility.Visible;
}
// MSI: app exclusion not available through our tool
if (isMsi)
{
AppTitle.Visibility = Visibility.Collapsed;
AppCheckBoxes.Visibility = Visibility.Collapsed;
AppNote.Text = "Az alkalmazások kiválasztása a Microsoft telepítő felületén lehetséges.";
AppNote.Visibility = Visibility.Visible;
}
else
{
// Populate app checkboxes (ODT mode)
foreach (var app in ExcludableApps.Apps)
{
bool isChecked = _config.ExcludedApps.Count > 0
? !_config.ExcludedApps.Contains(app.Id)
: app.DefaultChecked;
bool isProPlus = _config.Edition != null &&
_config.Edition.ProductId.Contains("ProPlus");
bool isStandard = _config.Edition != null &&
_config.Edition.ProductId.Contains("Standard");
bool unavailable = false;
if (app.MinEdition == "proplus" && !isProPlus)
unavailable = true;
else if (app.MinEdition == "standard+" && !isProPlus && !isStandard)
unavailable = true;
var cb = new CheckBox
{
Content = app.DisplayName,
IsChecked = unavailable ? false : isChecked,
IsEnabled = !unavailable,
Tag = app.Id,
Style = (Style)FindResource("FluentCheckBox"),
Margin = new Thickness(0, 4, 24, 4),
MinWidth = 160
};
_appCheckBoxes.Add(cb);
AppCheckBoxes.Children.Add(cb);
}
}
}
public bool Validate()
{
_config.Architecture = Rb64.IsChecked == true ? "64" : "32";
if (CbLanguage.SelectedItem is ComboBoxItem selected)
{
_config.Language = (string)selected.Tag;
}
_config.ExcludedApps.Clear();
foreach (var cb in _appCheckBoxes)
{
if (cb.IsChecked != true || !cb.IsEnabled)
{
_config.ExcludedApps.Add((string)cb.Tag);
}
}
return true;
}
}
}

41
Pages/ConfirmDialog.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,41 @@
<UserControl x:Class="InstaSoftOfficeTool.Pages.ConfirmDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Visibility="Collapsed">
<!-- Backdrop overlay -->
<Grid>
<Border Background="#66000000" MouseDown="Backdrop_MouseDown"/>
<!-- Dialog card -->
<Border Background="{StaticResource CardBrush}" CornerRadius="12"
HorizontalAlignment="Center" VerticalAlignment="Center"
MinWidth="400" MaxWidth="500" Padding="28,24">
<Border.Effect>
<DropShadowEffect ShadowDepth="8" BlurRadius="32" Opacity="0.2" Color="Black"/>
</Border.Effect>
<StackPanel>
<!-- Icon + Title -->
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
<TextBlock x:Name="DialogIcon" FontFamily="Segoe MDL2 Assets" FontSize="22"
VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock x:Name="DialogTitle" FontSize="18" FontWeight="SemiBold"
VerticalAlignment="Center"/>
</StackPanel>
<!-- Message -->
<TextBlock x:Name="DialogMessage" FontSize="14" TextWrapping="Wrap"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,0,0,24"/>
<!-- Buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="BtnCancel" Style="{StaticResource SecondaryButton}"
Click="BtnCancel_Click" Margin="0,0,8,0"/>
<Button x:Name="BtnConfirm" Style="{StaticResource PrimaryButton}"
Click="BtnConfirm_Click"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</UserControl>

Fájl megtekintése

@@ -0,0 +1,75 @@
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace InstaSoftOfficeTool.Pages
{
public partial class ConfirmDialog : UserControl
{
private TaskCompletionSource<bool> _tcs;
public ConfirmDialog()
{
InitializeComponent();
}
public Task<bool> ShowAsync(string title, string message,
string confirmText = "Igen", string cancelText = "M\u00e9gse",
DialogType type = DialogType.Warning)
{
DialogTitle.Text = title;
DialogMessage.Text = message;
BtnConfirm.Content = confirmText;
BtnCancel.Content = cancelText;
switch (type)
{
case DialogType.Warning:
DialogIcon.Text = "\uE7BA";
DialogIcon.Foreground = (Brush)FindResource("WarningBrush");
break;
case DialogType.Question:
DialogIcon.Text = "\uE9CE";
DialogIcon.Foreground = (Brush)FindResource("AccentBrush");
break;
case DialogType.Error:
DialogIcon.Text = "\uE711";
DialogIcon.Foreground = (Brush)FindResource("ErrorBrush");
break;
}
Visibility = Visibility.Visible;
_tcs = new TaskCompletionSource<bool>();
return _tcs.Task;
}
private void BtnConfirm_Click(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(true);
}
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(false);
}
private void Backdrop_MouseDown(object sender, MouseButtonEventArgs e)
{
// click outside = cancel
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(false);
}
}
public enum DialogType
{
Warning,
Question,
Error
}
}

20
Pages/EditionPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,20 @@
<Page x:Class="InstaSoftOfficeTool.Pages.EditionPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,24">
<TextBlock x:Name="TitleText" Text="Válasszon kiadást" FontSize="24" FontWeight="Light"/>
<TextBlock x:Name="SubtitleText" FontSize="14"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<StackPanel x:Name="EditionPanel" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>
</Page>

80
Pages/EditionPage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,80 @@
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
namespace InstaSoftOfficeTool.Pages
{
public partial class EditionPage : Page, IWizardPage
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
private readonly OfficeEdition[] _editions;
public EditionPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
_editions = OfficeEdition.GetEditions(_config.Version);
SubtitleText.Text = _config.GetVersionDisplayName() + " \u2014 melyik kiad\u00e1st szeretn\u00e9?";
BuildEditionCards();
}
private void BuildEditionCards()
{
EditionPanel.Children.Clear();
for (int i = 0; i < _editions.Length; i++)
{
var edition = _editions[i];
var rb = new RadioButton
{
GroupName = "Edition",
IsChecked = i == 0 || (_config.Edition != null && _config.Edition.ProductId == edition.ProductId),
Style = (Style)FindResource("CardRadioButton"),
Margin = new Thickness(0, 0, 0, 10),
Tag = i
};
var sp = new StackPanel { Margin = new Thickness(8, 2, 8, 2) };
var titleBlock = new TextBlock
{
Text = edition.DisplayName,
FontSize = 18,
FontWeight = FontWeights.SemiBold
};
sp.Children.Add(titleBlock);
var descBlock = new TextBlock
{
Text = edition.Description,
FontSize = 12,
Foreground = (System.Windows.Media.Brush)FindResource("TextSecondaryBrush"),
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 2, 0, 0)
};
sp.Children.Add(descBlock);
rb.Content = sp;
EditionPanel.Children.Add(rb);
}
}
public bool Validate()
{
foreach (var child in EditionPanel.Children)
{
if (child is RadioButton rb && rb.IsChecked == true)
{
int idx = (int)rb.Tag;
_config.Edition = _editions[idx];
return true;
}
}
return false;
}
}
}

Fájl megtekintése

@@ -0,0 +1,67 @@
<Page x:Class="InstaSoftOfficeTool.Pages.PreInstallCheckPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,16">
<TextBlock Text="Meglévő Office ellenőrzése" FontSize="24" FontWeight="Light"/>
<TextBlock x:Name="SubtitleText" FontSize="14"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel>
<StackPanel x:Name="OfficeListPanel"/>
<!-- No office found card -->
<Border x:Name="NoOfficeCard" Visibility="Collapsed"
Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,14">
<StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="18"
Foreground="{StaticResource SuccessBrush}" VerticalAlignment="Center"
Margin="0,0,12,0"/>
<TextBlock Text="Nem található telepített Office. A telepítés indítható."
FontSize="14" VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- License cleanup -->
<Border x:Name="LicenseCleanupPanel" Margin="0,12,0,0" Visibility="Collapsed"
Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,12">
<CheckBox x:Name="CbCleanLicense" Style="{StaticResource FluentCheckBox}"
Content="Licenc-adatbázis tisztítása is (ajánlott)"
IsChecked="True"/>
</Border>
<!-- Log -->
<Border x:Name="LogPanel" Margin="0,12,0,0" Background="#F8F8F8"
CornerRadius="6" Padding="12" Visibility="Collapsed"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="LogText" FontFamily="Consolas" FontSize="11"
TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}"
IsReadOnly="True" Background="Transparent" BorderThickness="0"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True" MaxHeight="150"/>
</Border>
</StackPanel>
</ScrollViewer>
<!-- Buttons -->
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
<Button x:Name="BtnSkip" Content="Kihagyás, telepítés folytatása"
Style="{StaticResource SecondaryButton}" Click="BtnSkip_Click" Margin="0,0,8,0"/>
<Button x:Name="BtnRemove" Content="Eltávolítás, majd telepítés"
Style="{StaticResource PrimaryButton}" Click="BtnRemove_Click" Visibility="Collapsed"/>
</StackPanel>
</Grid>
</Page>

Fájl megtekintése

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
using InstaSoftOfficeTool.Services;
namespace InstaSoftOfficeTool.Pages
{
public partial class PreInstallCheckPage : Page
{
private readonly MainWindow _main;
private List<InstalledOffice> _detected;
public PreInstallCheckPage(MainWindow main)
{
InitializeComponent();
_main = main;
Loaded += (s, e) => DetectOffice();
}
private void DetectOffice()
{
_detected = OfficeDetector.Detect();
OfficeListPanel.Children.Clear();
if (_detected.Count == 0)
{
SubtitleText.Text = "Nincs kor\u00e1bbi Office telep\u00edt\u00e9s a g\u00e9pen.";
NoOfficeCard.Visibility = Visibility.Visible;
BtnRemove.Visibility = Visibility.Collapsed;
LicenseCleanupPanel.Visibility = Visibility.Collapsed;
BtnSkip.Content = "Tov\u00e1bb a telep\u00edt\u00e9shez \u2192";
return;
}
SubtitleText.Text = "A sz\u00e1m\u00edt\u00f3g\u00e9pen tal\u00e1lt Office telep\u00edt\u00e9sek. Az \u00faj Office telep\u00edt\u00e9se el\u0151tt aj\u00e1nlott elt\u00e1vol\u00edtani.";
BtnRemove.Visibility = Visibility.Visible;
LicenseCleanupPanel.Visibility = Visibility.Visible;
foreach (var office in _detected)
{
var cb = new CheckBox
{
Content = office.DisplayName +
(string.IsNullOrEmpty(office.Version) ? "" : " (" + office.Version + ")"),
IsChecked = true,
Style = (Style)FindResource("FluentCheckBox"),
Tag = office,
Margin = new Thickness(0, 4, 0, 4),
FontSize = 14
};
OfficeListPanel.Children.Add(cb);
}
}
private void BtnSkip_Click(object sender, RoutedEventArgs e)
{
_main.ProceedToInstall();
}
private async void BtnRemove_Click(object sender, RoutedEventArgs e)
{
bool confirmed = await _main.ConfirmAsync(
"Office elt\u00e1vol\u00edt\u00e1s",
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani a kiv\u00e1lasztott Office telep\u00edt\u00e9seket az \u00faj verzi\u00f3 telep\u00edt\u00e9se el\u0151tt?",
"Elt\u00e1vol\u00edt\u00e1s", "M\u00e9gse");
if (!confirmed) return;
BtnRemove.IsEnabled = false;
BtnSkip.IsEnabled = false;
LogPanel.Visibility = Visibility.Visible;
try
{
var c2rProducts = new System.Collections.Generic.List<string>();
foreach (UIElement child in OfficeListPanel.Children)
{
if (child is CheckBox cb && cb.IsChecked == true)
{
var office = (InstalledOffice)cb.Tag;
if (office.IsClickToRun)
{
c2rProducts.Add(office.ProductCode);
}
else if (!string.IsNullOrEmpty(office.ProductCode))
{
AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName);
var runner = new ProcessRunner();
runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg));
int code = await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb");
AppendLog("MSI exit code: " + code);
}
}
}
if (c2rProducts.Count > 0)
{
AppendLog("Click-to-Run term\u00e9kek elt\u00e1vol\u00edt\u00e1sa: " + string.Join(", ", c2rProducts));
var downloader = new OdtDownloader();
downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg));
bool ok = await downloader.DownloadAndExtractAsync();
if (!ok)
{
AppendLog("HIBA: Az ODT let\u00f6lt\u00e9se sikertelen.");
BtnRemove.IsEnabled = true;
BtnSkip.IsEnabled = true;
return;
}
string removeXml = OdtXmlGenerator.GenerateRemoveProducts(c2rProducts.ToArray());
string xmlPath = Path.Combine(downloader.OdtFolder, "remove.xml");
File.WriteAllText(xmlPath, removeXml);
AppendLog("Futtat\u00e1s: setup.exe /configure remove.xml");
AppendLog("Ez eltarthat n\u00e9h\u00e1ny percig...");
int exitCode = await downloader.RunRemoveAsync(xmlPath,
msg => Dispatcher.Invoke(() => AppendLog(msg)));
AppendLog("setup.exe exit code: " + exitCode);
AppendLog(exitCode == 0
? "Office sikeresen elt\u00e1vol\u00edtva."
: "FIGYELEM: Az elt\u00e1vol\u00edt\u00e1s nem siker\u00fclt (k\u00f3d: " + exitCode + ")");
}
if (CbCleanLicense.IsChecked == true)
{
AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa...");
var lm = new LicenseManager();
if (lm.FindOspp())
{
var cleanResult = await lm.RemoveAllKeysAsync();
AppendLog(cleanResult);
}
else
{
AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva.");
}
}
AppendLog("K\u00e9sz. Tov\u00e1bbl\u00e9p\u00e9s az \u00faj Office telep\u00edt\u00e9s\u00e9hez...");
}
catch (Exception ex)
{
AppendLog("V\u00e1ratlan hiba: " + ex.Message);
}
await System.Threading.Tasks.Task.Delay(2000);
_main.ProceedToInstall();
}
private void AppendLog(string text)
{
LogText.Text += DateTime.Now.ToString("HH:mm:ss") + " " + text + "\n";
LogText.ScrollToEnd();
}
}
}

Fájl megtekintése

@@ -0,0 +1,69 @@
<UserControl x:Class="InstaSoftOfficeTool.Pages.ProductKeyDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Visibility="Collapsed">
<Grid>
<Border Background="#66000000" MouseDown="Backdrop_MouseDown"/>
<Border Background="{StaticResource CardBrush}" CornerRadius="12"
HorizontalAlignment="Center" VerticalAlignment="Center"
MinWidth="480" Padding="28,24">
<Border.Effect>
<DropShadowEffect ShadowDepth="8" BlurRadius="32" Opacity="0.2" Color="Black"/>
</Border.Effect>
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
<TextBlock Text="&#xE8D7;" FontFamily="Segoe MDL2 Assets" FontSize="22"
Foreground="{StaticResource AccentBrush}"
VerticalAlignment="Center" Margin="0,0,12,0"/>
<TextBlock Text="Termékkulcs megadása" FontSize="18" FontWeight="SemiBold"
VerticalAlignment="Center"/>
</StackPanel>
<TextBlock Text="Adja meg a 25 karakteres termékkulcsot az aktiváláshoz."
FontSize="13" Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,0,0,16"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,20">
<TextBox x:Name="DKey1" Style="{StaticResource FluentTextBox}"
Width="76" MaxLength="5" CharacterCasing="Upper"
FontFamily="Consolas" FontSize="15" TextAlignment="Center"
TextChanged="KeyBox_TextChanged"/>
<TextBlock Text="-" FontSize="18" VerticalAlignment="Center" Margin="4,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="DKey2" Style="{StaticResource FluentTextBox}"
Width="76" MaxLength="5" CharacterCasing="Upper"
FontFamily="Consolas" FontSize="15" TextAlignment="Center"
TextChanged="KeyBox_TextChanged"/>
<TextBlock Text="-" FontSize="18" VerticalAlignment="Center" Margin="4,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="DKey3" Style="{StaticResource FluentTextBox}"
Width="76" MaxLength="5" CharacterCasing="Upper"
FontFamily="Consolas" FontSize="15" TextAlignment="Center"
TextChanged="KeyBox_TextChanged"/>
<TextBlock Text="-" FontSize="18" VerticalAlignment="Center" Margin="4,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="DKey4" Style="{StaticResource FluentTextBox}"
Width="76" MaxLength="5" CharacterCasing="Upper"
FontFamily="Consolas" FontSize="15" TextAlignment="Center"
TextChanged="KeyBox_TextChanged"/>
<TextBlock Text="-" FontSize="18" VerticalAlignment="Center" Margin="4,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="DKey5" Style="{StaticResource FluentTextBox}"
Width="76" MaxLength="5" CharacterCasing="Upper"
FontFamily="Consolas" FontSize="15" TextAlignment="Center"
TextChanged="KeyBox_TextChanged"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Mégse" Style="{StaticResource SecondaryButton}"
Click="BtnCancel_Click" Margin="0,0,8,0"/>
<Button x:Name="BtnOk" Content="Aktiválás" Style="{StaticResource PrimaryButton}"
Click="BtnOk_Click" IsEnabled="False"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</UserControl>

Fájl megtekintése

@@ -0,0 +1,124 @@
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace InstaSoftOfficeTool.Pages
{
public partial class ProductKeyDialog : UserControl
{
private TaskCompletionSource<string> _tcs;
private readonly TextBox[] _keyBoxes;
private bool _suppress;
public ProductKeyDialog()
{
InitializeComponent();
_keyBoxes = new[] { DKey1, DKey2, DKey3, DKey4, DKey5 };
foreach (var box in _keyBoxes)
{
DataObject.AddPastingHandler(box, OnPaste);
}
}
public Task<string> ShowAsync()
{
foreach (var box in _keyBoxes) box.Text = "";
BtnOk.IsEnabled = false;
Visibility = Visibility.Visible;
DKey1.Focus();
_tcs = new TaskCompletionSource<string>();
return _tcs.Task;
}
private string GetFullKey()
{
return string.Join("-", DKey1.Text, DKey2.Text, DKey3.Text, DKey4.Text, DKey5.Text).ToUpper();
}
private bool IsKeyComplete()
{
foreach (var box in _keyBoxes)
{
if (box.Text.Length != 5 || !Regex.IsMatch(box.Text, "^[A-Za-z0-9]{5}$"))
return false;
}
return true;
}
private void KeyBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_suppress) return;
var tb = (TextBox)sender;
var cleaned = Regex.Replace(tb.Text, "[^A-Za-z0-9]", "");
if (cleaned != tb.Text)
{
_suppress = true;
tb.Text = cleaned;
tb.CaretIndex = cleaned.Length;
_suppress = false;
}
if (tb.Text.Length == 5)
{
for (int i = 0; i < _keyBoxes.Length - 1; i++)
{
if (_keyBoxes[i] == tb)
{
_keyBoxes[i + 1].Focus();
break;
}
}
}
BtnOk.IsEnabled = IsKeyComplete();
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
if (!e.DataObject.GetDataPresent(typeof(string))) return;
var pasted = (string)e.DataObject.GetData(typeof(string));
var allAlphaNum = Regex.Replace(pasted, "[^A-Za-z0-9]", "");
if (allAlphaNum.Length <= 5) return;
e.CancelCommand();
_suppress = true;
for (int i = 0; i < 5; i++)
{
int start = i * 5;
if (start < allAlphaNum.Length)
{
int len = Math.Min(5, allAlphaNum.Length - start);
_keyBoxes[i].Text = allAlphaNum.Substring(start, len).ToUpper();
}
}
_suppress = false;
_keyBoxes[4].Focus();
_keyBoxes[4].CaretIndex = _keyBoxes[4].Text.Length;
BtnOk.IsEnabled = IsKeyComplete();
}
private void BtnOk_Click(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(GetFullKey());
}
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(null);
}
private void Backdrop_MouseDown(object sender, MouseButtonEventArgs e)
{
Visibility = Visibility.Collapsed;
_tcs?.TrySetResult(null);
}
}
}

62
Pages/ProductKeyPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,62 @@
<Page x:Class="InstaSoftOfficeTool.Pages.ProductKeyPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,24">
<TextBlock Text="Termékkulcs" FontSize="24" FontWeight="Light"/>
<TextBlock Text="Adja meg a 25 karakteres termékkulcsot, vagy hagyja üresen."
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<StackPanel Grid.Row="1" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBox x:Name="Key1" Style="{StaticResource FluentTextBox}"
Width="110" MaxLength="5" CharacterCasing="Upper"
TextChanged="KeyBox_TextChanged" FontFamily="Consolas" TextAlignment="Center"/>
<TextBlock Text="-" FontSize="20" VerticalAlignment="Center" Margin="6,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="Key2" Style="{StaticResource FluentTextBox}"
Width="110" MaxLength="5" CharacterCasing="Upper"
TextChanged="KeyBox_TextChanged" FontFamily="Consolas" TextAlignment="Center"/>
<TextBlock Text="-" FontSize="20" VerticalAlignment="Center" Margin="6,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="Key3" Style="{StaticResource FluentTextBox}"
Width="110" MaxLength="5" CharacterCasing="Upper"
TextChanged="KeyBox_TextChanged" FontFamily="Consolas" TextAlignment="Center"/>
<TextBlock Text="-" FontSize="20" VerticalAlignment="Center" Margin="6,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="Key4" Style="{StaticResource FluentTextBox}"
Width="110" MaxLength="5" CharacterCasing="Upper"
TextChanged="KeyBox_TextChanged" FontFamily="Consolas" TextAlignment="Center"/>
<TextBlock Text="-" FontSize="20" VerticalAlignment="Center" Margin="6,0"
Foreground="{StaticResource TextSecondaryBrush}"/>
<TextBox x:Name="Key5" Style="{StaticResource FluentTextBox}"
Width="110" MaxLength="5" CharacterCasing="Upper"
TextChanged="KeyBox_TextChanged" FontFamily="Consolas" TextAlignment="Center"/>
</StackPanel>
<CheckBox x:Name="CbSkipKey" Style="{StaticResource FluentCheckBox}"
Content="Később szeretném megadni"
Margin="0,20,0,0" Checked="CbSkipKey_Changed" Unchecked="CbSkipKey_Changed"/>
<Border Background="#FFF8E1" CornerRadius="6" Padding="16,12" Margin="0,24,0,0"
BorderBrush="#FFE082" BorderThickness="1" MaxWidth="600" HorizontalAlignment="Left">
<StackPanel>
<TextBlock Text="Tudnivaló" FontWeight="SemiBold" FontSize="13" Margin="0,0,0,4"/>
<TextBlock TextWrapping="Wrap" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
Text="Ha megadja a termékkulcsot, az Office automatikusan aktiválódik a telepítés után. Ha nem adja meg, későbbi időpontban is megadható az Office alkalmazáson belül (Fájl > Fiók > Termékkulcs módosítása)."/>
</StackPanel>
</Border>
<TextBlock x:Name="ValidationMessage" FontSize="12" Margin="0,12,0,0"
Foreground="{StaticResource ErrorBrush}" Visibility="Collapsed"/>
</StackPanel>
</Grid>
</Page>

Fájl megtekintése

@@ -0,0 +1,149 @@
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
namespace InstaSoftOfficeTool.Pages
{
public partial class ProductKeyPage : Page, IWizardPage
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
private readonly TextBox[] _keyBoxes;
private bool _suppressAutoTab;
public ProductKeyPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
_keyBoxes = new[] { Key1, Key2, Key3, Key4, Key5 };
if (!string.IsNullOrEmpty(_config.ProductKey))
{
var parts = _config.ProductKey.Split('-');
for (int i = 0; i < parts.Length && i < 5; i++)
{
_keyBoxes[i].Text = parts[i];
}
}
// Intercept paste on all boxes
foreach (var box in _keyBoxes)
{
DataObject.AddPastingHandler(box, OnPaste);
}
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
if (!e.DataObject.GetDataPresent(typeof(string))) return;
var pasted = (string)e.DataObject.GetData(typeof(string));
var allAlphaNum = Regex.Replace(pasted, "[^A-Za-z0-9]", "");
// Only intercept if it looks like a full key (more than 5 chars)
if (allAlphaNum.Length <= 5) return;
e.CancelCommand(); // prevent default paste
_suppressAutoTab = true;
for (int i = 0; i < 5; i++)
{
int start = i * 5;
if (start < allAlphaNum.Length)
{
int len = System.Math.Min(5, allAlphaNum.Length - start);
_keyBoxes[i].Text = allAlphaNum.Substring(start, len).ToUpper();
}
}
_suppressAutoTab = false;
_keyBoxes[4].Focus();
_keyBoxes[4].CaretIndex = _keyBoxes[4].Text.Length;
ValidationMessage.Visibility = Visibility.Collapsed;
}
private void KeyBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_suppressAutoTab) return;
var tb = (TextBox)sender;
var raw = tb.Text;
// Clean non-alphanumeric chars
var cleaned = Regex.Replace(raw, "[^A-Za-z0-9]", "");
if (cleaned != raw)
{
_suppressAutoTab = true;
tb.Text = cleaned;
tb.CaretIndex = cleaned.Length;
_suppressAutoTab = false;
}
// Auto-tab to next box when 5 chars entered
if (tb.Text.Length == 5)
{
for (int i = 0; i < _keyBoxes.Length - 1; i++)
{
if (_keyBoxes[i] == tb)
{
_keyBoxes[i + 1].Focus();
break;
}
}
}
ValidationMessage.Visibility = Visibility.Collapsed;
}
private void CbSkipKey_Changed(object sender, RoutedEventArgs e)
{
bool skip = CbSkipKey.IsChecked == true;
foreach (var box in _keyBoxes)
{
box.IsEnabled = !skip;
if (skip) box.Text = "";
}
ValidationMessage.Visibility = Visibility.Collapsed;
}
public bool Validate()
{
if (CbSkipKey.IsChecked == true)
{
_config.ProductKey = null;
return true;
}
bool allEmpty = true;
foreach (var box in _keyBoxes)
{
if (!string.IsNullOrEmpty(box.Text))
{
allEmpty = false;
break;
}
}
if (allEmpty)
{
_config.ProductKey = null;
return true;
}
foreach (var box in _keyBoxes)
{
if (box.Text.Length != 5 || !Regex.IsMatch(box.Text, "^[A-Za-z0-9]{5}$"))
{
ValidationMessage.Text = "A term\u00e9kkulcsnak 5 x 5 alfanumerikus karakterb\u0151l kell \u00e1llnia.";
ValidationMessage.Visibility = Visibility.Visible;
return false;
}
}
_config.ProductKey = string.Join("-",
Key1.Text, Key2.Text, Key3.Text, Key4.Text, Key5.Text).ToUpper();
return true;
}
}
}

90
Pages/ProgressPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,90 @@
<Page x:Class="InstaSoftOfficeTool.Pages.ProgressPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="40,30">
<StackPanel>
<TextBlock x:Name="TitleText" Text="Telepítés folyamatban..."
FontSize="24" FontWeight="Light" Margin="0,0,0,20"/>
<StackPanel Margin="0,0,0,16">
<StackPanel Orientation="Horizontal" Margin="0,4">
<TextBlock x:Name="Step1Icon" Text="&#xE73E;" FontFamily="Segoe MDL2 Assets"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Width="24"/>
<TextBlock x:Name="Step1Text" Text="Office Deployment Tool letöltése..."
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,4">
<TextBlock x:Name="Step2Icon" Text="&#xE73E;" FontFamily="Segoe MDL2 Assets"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Width="24"/>
<TextBlock x:Name="Step2Text" Text="Konfiguráció generálása..."
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,4">
<TextBlock x:Name="Step3Icon" Text="&#xE73E;" FontFamily="Segoe MDL2 Assets"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Width="24"/>
<TextBlock x:Name="Step3Text" Text="Office telepítése... (akár 30-40 percet is igénybe vehet)"
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
</StackPanel>
<ProgressBar x:Name="MainProgress" Style="{StaticResource FluentProgressBar}"
IsIndeterminate="True" Margin="0,0,0,0"/>
<TextBlock x:Name="DownloadInfo" FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,4,0,0" Visibility="Collapsed"/>
<Border Background="#F8F8F8" CornerRadius="6" Padding="12" Margin="0,12,0,0"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="LogText" FontFamily="Consolas" FontSize="11"
TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}"
IsReadOnly="True" Background="Transparent" BorderThickness="0"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>
</Border>
<!-- Done panel -->
<StackPanel x:Name="DonePanel" Margin="0,12,0,0" Visibility="Collapsed">
<!-- Status message -->
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
<TextBlock x:Name="DoneIcon" FontFamily="Segoe MDL2 Assets" FontSize="20"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock x:Name="DoneText" FontSize="15" FontWeight="SemiBold" VerticalAlignment="Center"/>
</StackPanel>
<!-- Activate card (only if no key was provided) -->
<Border x:Name="ActivateCard" Visibility="Collapsed"
Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,12" Margin="0,0,0,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="Termékkulcs megadása" FontSize="14" FontWeight="SemiBold"/>
<TextBlock Text="Az Office aktiválásához adja meg a termékkulcsot."
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
<Button x:Name="BtnActivateNow" Grid.Column="1" Content="Aktiválás"
Style="{StaticResource PrimaryButton}" Click="BtnActivateNow_Click"
VerticalAlignment="Center" Padding="18,8"/>
</Grid>
</Border>
<!-- Launch apps -->
<Border x:Name="LaunchCard" Visibility="Collapsed"
Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,12" Margin="0,0,0,8">
<StackPanel>
<TextBlock Text="Alkalmazás indítása" FontSize="14" FontWeight="SemiBold" Margin="0,0,0,10"/>
<WrapPanel x:Name="LaunchButtons" Orientation="Horizontal"/>
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Page>

386
Pages/ProgressPage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,386 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using InstaSoftOfficeTool.Models;
using InstaSoftOfficeTool.Services;
namespace InstaSoftOfficeTool.Pages
{
public partial class ProgressPage : Page
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
public ProgressPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
}
public async void StartInstallation()
{
try
{
if (_config.IsMsiInstall)
{
await StartMsiInstallation();
}
else
{
await StartOdtInstallation();
}
}
catch (Exception ex)
{
AppendLog("HIBA: " + ex.Message);
ShowDone(false, "Váratlan hiba történt.");
}
}
private async Task StartOdtInstallation()
{
// Step 1: Download ODT
SetStepActive(Step1Icon, Step1Text);
AppendLog("ODT letöltése indul...");
var downloader = new OdtDownloader();
downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg));
bool downloaded = await downloader.DownloadAndExtractAsync();
if (!downloaded)
{
SetStepError(Step1Icon, Step1Text);
ShowDone(false, "Az ODT letöltése sikertelen.");
return;
}
SetStepDone(Step1Icon, Step1Text);
// Step 2: Generate config XML
SetStepActive(Step2Icon, Step2Text);
AppendLog("Konfigurációs XML generálása...");
string xml = OdtXmlGenerator.Generate(_config);
string xmlPath = Path.Combine(downloader.OdtFolder, "configuration.xml");
File.WriteAllText(xmlPath, xml);
AppendLog("XML mentve: " + xmlPath);
SetStepDone(Step2Icon, Step2Text);
// Step 3: Run setup.exe /configure
SetStepActive(Step3Icon, Step3Text);
AppendLog("Office telepítés indítása...");
AppendLog("setup.exe /configure \"" + xmlPath + "\"");
int exitCode = await downloader.RunSetupAsync(xmlPath, msg =>
Dispatcher.Invoke(() => AppendLog(msg)));
if (exitCode == 0)
{
SetStepDone(Step3Icon, Step3Text);
ShowDone(true, "Az Office sikeresen települt!");
}
else
{
SetStepError(Step3Icon, Step3Text);
ShowDone(false, "A telepítés hibakóddal fejeződött be: " + exitCode);
}
}
private async Task StartMsiInstallation()
{
string isoUrl = _config.GetIsoUrl();
if (string.IsNullOrEmpty(isoUrl))
{
ShowDone(false, "Nincs elérhető ISO a kiválasztott architektúrához.");
return;
}
// Update step labels for MSI flow
Dispatcher.Invoke(() =>
{
Step1Text.Text = "Telepítő ISO letöltése...";
Step2Text.Text = "ISO csatolása...";
Step3Text.Text = "Office 2016 telepítése...";
});
var installer = new MsiInstaller();
installer.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg));
installer.DownloadProgress += (received, total) =>
{
Dispatcher.Invoke(() =>
{
long receivedMb = received / 1024 / 1024;
if (total > 0)
{
long totalMb = total / 1024 / 1024;
int percent = (int)(received * 100 / total);
DownloadInfo.Text = receivedMb + " MB / " + totalMb + " MB (" + percent + "%)";
MainProgress.IsIndeterminate = false;
MainProgress.Value = percent;
}
else
{
DownloadInfo.Text = receivedMb + " MB letöltve...";
}
DownloadInfo.Visibility = Visibility.Visible;
});
};
// Step 1: Download ISO
SetStepActive(Step1Icon, Step1Text);
AppendLog("ISO letöltése indul...");
bool downloaded = await installer.DownloadIsoAsync(isoUrl);
if (!downloaded)
{
SetStepError(Step1Icon, Step1Text);
ShowDone(false, "Az ISO letöltése sikertelen.");
return;
}
SetStepDone(Step1Icon, Step1Text);
// Hide download progress, reset progress bar
Dispatcher.Invoke(() =>
{
DownloadInfo.Visibility = Visibility.Collapsed;
MainProgress.IsIndeterminate = true;
});
// Step 2: Mount ISO
SetStepActive(Step2Icon, Step2Text);
bool mounted = await installer.MountIsoAsync();
if (!mounted)
{
SetStepError(Step2Icon, Step2Text);
ShowDone(false, "Az ISO csatolása sikertelen.");
return;
}
SetStepDone(Step2Icon, Step2Text);
// Step 3: Run setup.exe
SetStepActive(Step3Icon, Step3Text);
int exitCode = await installer.RunSetupAsync(msg =>
Dispatcher.Invoke(() => AppendLog(msg)));
// Dismount ISO regardless of result
await installer.DismountIsoAsync();
if (exitCode == 0)
{
SetStepDone(Step3Icon, Step3Text);
// Apply product key if provided
if (!string.IsNullOrEmpty(_config.ProductKey))
{
AppendLog("Termékkulcs telepítése...");
var lm = new LicenseManager();
if (lm.FindOspp())
{
string inpResult = await lm.InstallKeyAsync(_config.ProductKey);
AppendLog(inpResult);
AppendLog("Aktiválás...");
string actResult = await lm.ActivateAsync();
AppendLog(actResult);
}
else
{
AppendLog("Az ospp.vbs nem található — a kulcsot később a Licenc-kezelésben adhatja meg.");
}
}
ShowDone(true, "Az Office 2016 sikeresen települt!");
}
else
{
SetStepError(Step3Icon, Step3Text);
ShowDone(false, "A telepítés hibakóddal fejeződött be: " + exitCode);
}
}
private void AppendLog(string text)
{
LogText.Text += DateTime.Now.ToString("HH:mm:ss") + " " + text + "\n";
LogText.ScrollToEnd();
}
private void SetStepActive(TextBlock icon, TextBlock text)
{
Dispatcher.Invoke(() =>
{
icon.Text = "\uE72A";
icon.Foreground = (Brush)FindResource("AccentBrush");
text.Foreground = (Brush)FindResource("TextPrimaryBrush");
text.FontWeight = FontWeights.SemiBold;
});
}
private void SetStepDone(TextBlock icon, TextBlock text)
{
Dispatcher.Invoke(() =>
{
icon.Text = "\uE73E";
icon.Foreground = (Brush)FindResource("SuccessBrush");
text.Foreground = (Brush)FindResource("SuccessBrush");
text.FontWeight = FontWeights.Normal;
});
}
private void SetStepError(TextBlock icon, TextBlock text)
{
Dispatcher.Invoke(() =>
{
icon.Text = "\uE711";
icon.Foreground = (Brush)FindResource("ErrorBrush");
text.Foreground = (Brush)FindResource("ErrorBrush");
text.FontWeight = FontWeights.Normal;
});
}
private void ShowDone(bool success, string message)
{
Dispatcher.Invoke(() =>
{
MainProgress.IsIndeterminate = false;
MainProgress.Value = 100;
TitleText.Text = success ? "Telep\u00edt\u00e9s befejezve" : "Telep\u00edt\u00e9s sikertelen";
DoneIcon.Text = success ? "\uE73E" : "\uE711";
DoneIcon.Foreground = success
? (Brush)FindResource("SuccessBrush")
: (Brush)FindResource("ErrorBrush");
DoneText.Text = message;
DoneText.Foreground = DoneIcon.Foreground;
DonePanel.Visibility = Visibility.Visible;
if (success)
{
// Show activate card if no product key was provided
if (string.IsNullOrEmpty(_config.ProductKey))
{
ActivateCard.Visibility = Visibility.Visible;
}
// Show launch buttons
BuildLaunchButtons();
LaunchCard.Visibility = Visibility.Visible;
}
_main.ShowCloseButton();
});
}
private void BuildLaunchButtons()
{
LaunchButtons.Children.Clear();
var apps = new[]
{
("Word", "WINWORD.EXE"),
("Excel", "EXCEL.EXE"),
("PowerPoint", "POWERPNT.EXE"),
("Outlook", "OUTLOOK.EXE"),
};
foreach (var (name, exe) in apps)
{
// Skip if excluded
if (_config.ExcludedApps.Contains(name == "Word" ? "Word" :
name == "Excel" ? "Excel" :
name == "PowerPoint" ? "PowerPoint" :
name == "Outlook" ? "Outlook" : ""))
continue;
var btn = new Button
{
Content = name,
Style = (Style)FindResource("SecondaryButton"),
Padding = new Thickness(18, 8, 18, 8),
FontSize = 13,
Margin = new Thickness(0, 0, 8, 0),
Tag = exe
};
btn.Click += LaunchApp_Click;
LaunchButtons.Children.Add(btn);
}
}
private void LaunchApp_Click(object sender, RoutedEventArgs e)
{
var btn = (Button)sender;
var exe = (string)btn.Tag;
try
{
// Try common Office paths
var paths = new[]
{
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"Microsoft Office", "root", "Office16", exe),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
"Microsoft Office", "root", "Office16", exe),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"Microsoft Office", "Office16", exe),
};
foreach (var path in paths)
{
if (File.Exists(path))
{
Process.Start(path);
return;
}
}
// Fallback: let Windows find it
Process.Start(exe);
}
catch
{
AppendLog("Nem siker\u00fclt elind\u00edtani: " + exe);
}
}
private async void BtnActivateNow_Click(object sender, RoutedEventArgs e)
{
string key = await _main.AskProductKeyAsync();
if (string.IsNullOrEmpty(key)) return;
BtnActivateNow.IsEnabled = false;
BtnActivateNow.Content = "Aktiv\u00e1l\u00e1s...";
var lm = new LicenseManager();
if (!lm.FindOspp())
{
AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3.");
BtnActivateNow.IsEnabled = true;
BtnActivateNow.Content = "Aktiv\u00e1l\u00e1s";
return;
}
AppendLog("Term\u00e9kkulcs telep\u00edt\u00e9se: " + key);
string inpResult = await lm.InstallKeyAsync(key);
AppendLog(inpResult);
AppendLog("Aktiv\u00e1l\u00e1s...");
string actResult = await lm.ActivateAsync();
AppendLog(actResult);
if (actResult.Contains("successful") || actResult.Contains("sikeres"))
{
BtnActivateNow.Content = "Aktiv\u00e1lva \u2713";
AppendLog("Az Office sikeresen aktiv\u00e1lva!");
}
else
{
BtnActivateNow.IsEnabled = true;
BtnActivateNow.Content = "Aktiv\u00e1l\u00e1s";
AppendLog("Az aktiv\u00e1l\u00e1s eredm\u00e9ny\u00e9t ellen\u0151rizze a kimenetben.");
}
}
}
}

52
Pages/RemovePage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,52 @@
<Page x:Class="InstaSoftOfficeTool.Pages.RemovePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,20">
<TextBlock Text="Office eltávolítás" FontSize="24" FontWeight="Light"/>
<TextBlock Text="A számítógépen talált Office telepítések:"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel>
<StackPanel x:Name="OfficeListPanel"/>
<TextBlock x:Name="NoOfficeText" Text="Nem található telepített Office."
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}"
Margin="0,20,0,0" Visibility="Collapsed"/>
<Border x:Name="LicenseCleanupPanel" Margin="0,20,0,0"
Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,12">
<CheckBox x:Name="CbCleanLicense" Style="{StaticResource FluentCheckBox}"
Content="Licenc-adatbázis tisztítása is (ajánlott)"
IsChecked="True"/>
</Border>
<Border x:Name="LogPanel" Margin="0,16,0,0" Background="#F8F8F8"
CornerRadius="6" Padding="12" Visibility="Collapsed"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="LogText" FontFamily="Consolas" FontSize="11"
TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}"
IsReadOnly="True" Background="Transparent" BorderThickness="0"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True" MaxHeight="200"/>
</Border>
</StackPanel>
</ScrollViewer>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
<Button x:Name="BtnRemove" Content="Eltávolítás" Style="{StaticResource PrimaryButton}"
Click="BtnRemove_Click"/>
</StackPanel>
</Grid>
</Page>

170
Pages/RemovePage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
using InstaSoftOfficeTool.Services;
namespace InstaSoftOfficeTool.Pages
{
public partial class RemovePage : Page
{
private readonly MainWindow _main;
private List<InstalledOffice> _detected;
public RemovePage(MainWindow main)
{
InitializeComponent();
_main = main;
Loaded += (s, e) => DetectOffice();
}
private void DetectOffice()
{
_detected = OfficeDetector.Detect();
OfficeListPanel.Children.Clear();
if (_detected.Count == 0)
{
NoOfficeText.Visibility = Visibility.Visible;
LicenseCleanupPanel.Visibility = Visibility.Collapsed;
BtnRemove.IsEnabled = false;
return;
}
foreach (var office in _detected)
{
var cb = new CheckBox
{
Content = office.DisplayName + (string.IsNullOrEmpty(office.Version) ? "" : " (" + office.Version + ")"),
IsChecked = true,
Style = (Style)FindResource("FluentCheckBox"),
Tag = office,
Margin = new Thickness(0, 4, 0, 4),
FontSize = 14
};
OfficeListPanel.Children.Add(cb);
}
}
private async void BtnRemove_Click(object sender, RoutedEventArgs e)
{
bool confirmed = await _main.ConfirmAsync(
"Office elt\u00e1vol\u00edt\u00e1s",
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani a kiv\u00e1lasztott Office telep\u00edt\u00e9seket?",
"Elt\u00e1vol\u00edt\u00e1s", "M\u00e9gse");
if (!confirmed) return;
BtnRemove.IsEnabled = false;
LogPanel.Visibility = Visibility.Visible;
try
{
var c2rProducts = new System.Collections.Generic.List<string>();
foreach (UIElement child in OfficeListPanel.Children)
{
if (child is CheckBox cb && cb.IsChecked == true)
{
var office = (InstalledOffice)cb.Tag;
if (office.IsClickToRun)
{
c2rProducts.Add(office.ProductCode);
}
else if (!string.IsNullOrEmpty(office.ProductCode))
{
AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName);
var runner = new ProcessRunner();
runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg));
int code = await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb");
AppendLog("MSI exit code: " + code);
}
}
}
if (c2rProducts.Count > 0)
{
AppendLog("Click-to-Run term\u00e9kek elt\u00e1vol\u00edt\u00e1sa: " + string.Join(", ", c2rProducts));
var downloader = new OdtDownloader();
downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg));
bool ok = await downloader.DownloadAndExtractAsync();
if (!ok)
{
AppendLog("HIBA: Az ODT let\u00f6lt\u00e9se sikertelen.");
BtnRemove.IsEnabled = true;
return;
}
string removeXml = OdtXmlGenerator.GenerateRemoveProducts(c2rProducts.ToArray());
string xmlPath = Path.Combine(downloader.OdtFolder, "remove.xml");
File.WriteAllText(xmlPath, removeXml);
AppendLog("Remove XML:");
AppendLog(removeXml);
AppendLog("");
AppendLog("Futtat\u00e1s: setup.exe /configure remove.xml");
AppendLog("Ez eltarthat n\u00e9h\u00e1ny percig...");
int exitCode = await downloader.RunRemoveAsync(xmlPath,
msg => Dispatcher.Invoke(() => AppendLog(msg)));
AppendLog("setup.exe exit code: " + exitCode);
if (exitCode == 0)
{
AppendLog("Office sikeresen elt\u00e1vol\u00edtva.");
}
else
{
AppendLog("FIGYELEM: Az elt\u00e1vol\u00edt\u00e1s nem siker\u00fclt (k\u00f3d: " + exitCode + ")");
AppendLog("Pr\u00f3b\u00e1lja meg manu\u00e1lisan: Vez\u00e9rl\u0151pult > Programok elt\u00e1vol\u00edt\u00e1sa");
}
}
if (CbCleanLicense.IsChecked == true)
{
AppendLog("");
AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa...");
var lm = new LicenseManager();
if (lm.FindOspp())
{
var cleanResult = await lm.RemoveAllKeysAsync();
AppendLog(cleanResult);
}
else
{
AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva.");
}
}
AppendLog("");
AppendLog("K\u00e9sz. Lista friss\u00edt\u00e9se...");
DetectOffice();
if (_detected.Count == 0)
{
AppendLog("Nincs t\u00f6bb telep\u00edtett Office.");
}
}
catch (Exception ex)
{
AppendLog("V\u00e1ratlan hiba: " + ex.Message);
AppendLog(ex.StackTrace);
}
BtnRemove.IsEnabled = _detected.Count > 0;
_main.ShowCloseButton();
}
private void AppendLog(string text)
{
LogText.Text += DateTime.Now.ToString("HH:mm:ss") + " " + text + "\n";
LogText.ScrollToEnd();
}
}
}

63
Pages/SummaryPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,63 @@
<Page x:Class="InstaSoftOfficeTool.Pages.SummaryPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="40,30">
<StackPanel>
<TextBlock Text="Összegzés" FontSize="24" FontWeight="Light" Margin="0,0,0,20"/>
<TextBlock Text="Ellenőrizze a beállításokat a telepítés indítása előtt."
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,0,0,16"/>
<Border Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="20,16" Margin="0,0,0,16">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Verzió:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="SumVersion" Margin="0,4"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Kiadás:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="SumEdition" Margin="0,4"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Architektúra:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="2" Grid.Column="1" x:Name="SumArch" Margin="0,4"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Nyelv:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="3" Grid.Column="1" x:Name="SumLanguage" Margin="0,4"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Termékkulcs:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="4" Grid.Column="1" x:Name="SumKey" Margin="0,4"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Kizárt alkalmazások:" FontWeight="SemiBold" Margin="0,4"/>
<TextBlock Grid.Row="5" Grid.Column="1" x:Name="SumExcluded" Margin="0,4" TextWrapping="Wrap"/>
</Grid>
</Border>
<Expander Header="Konfigurációs XML megtekintése" FontSize="13" Margin="0,0,0,10">
<Border Background="#F8F8F8" CornerRadius="4" Padding="12" Margin="0,8,0,0"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="XmlPreview" IsReadOnly="True" TextWrapping="Wrap"
FontFamily="Consolas" FontSize="12" BorderThickness="0"
Background="Transparent" VerticalScrollBarVisibility="Auto"
MaxHeight="200"/>
</Border>
</Expander>
<Button x:Name="BtnSaveXml" Content="XML mentése fájlba..." Style="{StaticResource SecondaryButton}"
HorizontalAlignment="Left" Click="BtnSaveXml_Click" Margin="0,4,0,0"/>
</StackPanel>
</ScrollViewer>
</Page>

80
Pages/SummaryPage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,80 @@
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
using InstaSoftOfficeTool.Services;
using Microsoft.Win32;
namespace InstaSoftOfficeTool.Pages
{
public partial class SummaryPage : Page, IWizardPage
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
private string _generatedXml;
public SummaryPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
Loaded += (s, e) => RefreshSummary();
}
private void RefreshSummary()
{
SumVersion.Text = _config.GetVersionDisplayName();
SumEdition.Text = _config.Edition?.DisplayName ?? "-";
SumArch.Text = _config.Architecture + "-bit";
SumLanguage.Text = _config.GetLanguageDisplayName() + " (" + _config.Language + ")";
SumKey.Text = string.IsNullOrEmpty(_config.ProductKey) ? "Nincs megadva" : _config.ProductKey;
if (_config.IsMsiInstall)
{
// MSI mode: no app exclusion, show ISO info instead of XML
SumExcluded.Text = "(a Microsoft telepítőben választható)";
string isoUrl = _config.GetIsoUrl();
XmlPreview.Text = "Telepítési mód: ISO letöltés + MSI telepítő\n" +
"ISO URL: " + (isoUrl ?? "Nem elérhető") + "\n\n" +
"A telepítő ISO fájl letöltése után a Microsoft Office\n" +
"saját telepítője indul el automatikusan.";
BtnSaveXml.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
if (_config.ExcludedApps.Count > 0)
SumExcluded.Text = string.Join(", ", _config.ExcludedApps);
else
SumExcluded.Text = "Nincs (minden alkalmazás települ)";
_generatedXml = OdtXmlGenerator.Generate(_config);
XmlPreview.Text = _generatedXml;
BtnSaveXml.Visibility = System.Windows.Visibility.Visible;
}
}
private void BtnSaveXml_Click(object sender, RoutedEventArgs e)
{
var dlg = new SaveFileDialog
{
Filter = "XML f\u00e1jl (*.xml)|*.xml",
FileName = "configuration.xml"
};
if (dlg.ShowDialog() == true)
{
System.IO.File.WriteAllText(dlg.FileName, _generatedXml);
MessageBox.Show("XML sikeresen mentve:\n" + dlg.FileName,
"Ment\u00e9s", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
public bool Validate()
{
return true;
}
}
}

Fájl megtekintése

@@ -0,0 +1,51 @@
<Page x:Class="InstaSoftOfficeTool.Pages.TroubleshootPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Title -->
<StackPanel Grid.Row="0" Margin="0,0,0,16">
<TextBlock Text="Licenc-kezelés" FontSize="24" FontWeight="Light"/>
<TextBlock Text="Office licenc állapot lekérdezése, aktiválás és termékkulcsok kezelése"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<!-- Key cards (scrollable) -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Margin="0,0,0,8">
<StackPanel x:Name="KeyCardsPanel"/>
</ScrollViewer>
<!-- Details expander -->
<Expander x:Name="DetailsExpander" Grid.Row="2" Header="Részletek" FontSize="13"
Margin="0,0,0,8" Expanded="DetailsExpander_Expanded" Collapsed="DetailsExpander_Collapsed">
<StackPanel Margin="0,8,0,0">
<TextBlock x:Name="OsppPathText" FontSize="12"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,0,0,6"/>
<Border Background="#F8F8F8" CornerRadius="4" Padding="10"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="OutputText" FontFamily="Consolas" FontSize="11"
TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}"
IsReadOnly="True" Background="Transparent" BorderThickness="0"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True"
Height="85"/>
</Border>
</StackPanel>
</Expander>
<!-- Buttons -->
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,4,0,0">
<Button x:Name="BtnRefresh" Content="Állapot frissítése" Style="{StaticResource SecondaryButton}"
Click="BtnRefresh_Click" Margin="0,0,8,0"/>
<Button x:Name="BtnRemoveAll" Content="Összes kulcs eltávolítása" Style="{StaticResource PrimaryButton}"
Click="BtnRemoveAll_Click" IsEnabled="False" Visibility="Collapsed"/>
</StackPanel>
</Grid>
</Page>

Fájl megtekintése

@@ -0,0 +1,311 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using InstaSoftOfficeTool.Services;
namespace InstaSoftOfficeTool.Pages
{
public partial class TroubleshootPage : Page
{
private readonly MainWindow _main;
private readonly LicenseManager _licenseManager = new LicenseManager();
private List<LicenseEntry> _entries = new List<LicenseEntry>();
public TroubleshootPage(MainWindow main)
{
InitializeComponent();
_main = main;
Loaded += async (s, e) => await RefreshStatus();
}
private async System.Threading.Tasks.Task RefreshStatus()
{
OutputText.Text = "";
OsppPathText.Text = "";
KeyCardsPanel.Children.Clear();
BtnRemoveAll.IsEnabled = false;
BtnRemoveAll.Visibility = Visibility.Collapsed;
BtnRefresh.IsEnabled = false;
var loadingText = new TextBlock
{
Text = "Keres\u00e9s folyamatban...",
FontSize = 13,
Foreground = (Brush)FindResource("TextSecondaryBrush"),
Margin = new Thickness(0, 8, 0, 8)
};
KeyCardsPanel.Children.Add(loadingText);
bool found = _licenseManager.FindOspp();
if (!found)
{
KeyCardsPanel.Children.Clear();
var errorCard = new Border
{
Background = (Brush)FindResource("CardBrush"),
BorderBrush = (Brush)FindResource("BorderBrush"),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Padding = new Thickness(16, 14, 16, 14),
Margin = new Thickness(0, 0, 0, 6)
};
var errorPanel = new StackPanel();
errorPanel.Children.Add(new TextBlock
{
Text = "Az ospp.vbs nem tal\u00e1lhat\u00f3",
FontSize = 14, FontWeight = FontWeights.SemiBold,
Foreground = (Brush)FindResource("ErrorBrush")
});
errorPanel.Children.Add(new TextBlock
{
Text = "Nincs telep\u00edtett Microsoft Office, vagy nem a szok\u00e1sos helyre lett telep\u00edtve.",
FontSize = 12, Foreground = (Brush)FindResource("TextSecondaryBrush"),
TextWrapping = TextWrapping.Wrap, Margin = new Thickness(0, 4, 0, 0)
});
errorCard.Child = errorPanel;
KeyCardsPanel.Children.Add(errorCard);
BtnRefresh.IsEnabled = true;
return;
}
OsppPathText.Text = "ospp.vbs helye: " + _licenseManager.OsppPath;
try
{
string status = await _licenseManager.GetStatusAsync();
OutputText.Text = status;
_entries = _licenseManager.ParseLicenseEntries(status);
BuildKeyCards();
}
catch (Exception ex)
{
KeyCardsPanel.Children.Clear();
OutputText.Text = "Hiba a lek\u00e9rdez\u00e9s sor\u00e1n: " + ex.Message;
}
BtnRefresh.IsEnabled = true;
}
private void BuildKeyCards()
{
KeyCardsPanel.Children.Clear();
if (_entries.Count == 0)
{
var noKeyCard = new Border
{
Background = (Brush)FindResource("CardBrush"),
BorderBrush = (Brush)FindResource("BorderBrush"),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Padding = new Thickness(16, 14, 16, 14)
};
noKeyCard.Child = new TextBlock
{
Text = "Nincs telep\u00edtett term\u00e9kkulcs.",
FontSize = 13,
Foreground = (Brush)FindResource("TextSecondaryBrush")
};
KeyCardsPanel.Children.Add(noKeyCard);
return;
}
if (_entries.Count > 1)
{
BtnRemoveAll.Visibility = Visibility.Visible;
BtnRemoveAll.IsEnabled = true;
}
foreach (var entry in _entries)
{
KeyCardsPanel.Children.Add(CreateKeyCard(entry));
}
}
private Border CreateKeyCard(LicenseEntry entry)
{
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
var infoPanel = new StackPanel { VerticalAlignment = VerticalAlignment.Center };
infoPanel.Children.Add(new TextBlock
{
Text = string.IsNullOrEmpty(entry.LicenseName) ? "Ismeretlen licenc" : entry.LicenseName,
FontSize = 13, FontWeight = FontWeights.SemiBold,
TextTrimming = TextTrimming.CharacterEllipsis
});
var statusLine = !string.IsNullOrEmpty(entry.ErrorDescription)
? entry.ErrorDescription
: (!string.IsNullOrEmpty(entry.Status) ? entry.Status : entry.Description);
infoPanel.Children.Add(new TextBlock
{
Text = statusLine,
FontSize = 11, Foreground = (Brush)FindResource("TextSecondaryBrush"),
TextTrimming = TextTrimming.CharacterEllipsis
});
infoPanel.Children.Add(new TextBlock
{
Text = "Kulcs: *****-" + entry.Last5,
FontSize = 11, FontFamily = new FontFamily("Consolas"),
Foreground = (Brush)FindResource("TextSecondaryBrush"),
Margin = new Thickness(0, 2, 0, 0)
});
Grid.SetColumn(infoPanel, 0);
grid.Children.Add(infoPanel);
// Right side: Activate + Remove buttons
var btnPanel = new StackPanel
{
Orientation = Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center
};
var activateBtn = new Button
{
Content = "Aktiv\u00e1l\u00e1s",
Style = (Style)FindResource("PrimaryButton"),
Padding = new Thickness(14, 6, 14, 6),
FontSize = 12,
Tag = entry.Last5
};
activateBtn.Click += BtnActivateSingle_Click;
btnPanel.Children.Add(activateBtn);
var removeBtn = new Button
{
Content = "Elt\u00e1vol\u00edt\u00e1s",
Style = (Style)FindResource("SecondaryButton"),
Padding = new Thickness(14, 6, 14, 6),
FontSize = 12,
Tag = entry.Last5,
Margin = new Thickness(6, 0, 0, 0)
};
removeBtn.Click += BtnRemoveSingle_Click;
btnPanel.Children.Add(removeBtn);
Grid.SetColumn(btnPanel, 1);
grid.Children.Add(btnPanel);
return new Border
{
Background = (Brush)FindResource("CardBrush"),
BorderBrush = (Brush)FindResource("BorderBrush"),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Padding = new Thickness(16, 10, 16, 10),
Margin = new Thickness(0, 0, 0, 6),
Child = grid
};
}
private async void BtnActivateSingle_Click(object sender, RoutedEventArgs e)
{
string key = await _main.AskProductKeyAsync();
if (string.IsNullOrEmpty(key)) return;
var btn = (Button)sender;
btn.IsEnabled = false;
btn.Content = "...";
DetailsExpander.IsExpanded = true;
OutputText.Text = "Term\u00e9kkulcs telep\u00edt\u00e9se: " + key + "\n";
try
{
string inpResult = await _licenseManager.InstallKeyAsync(key);
OutputText.Text += inpResult + "\n";
OutputText.Text += "Aktiv\u00e1l\u00e1s...\n";
string actResult = await _licenseManager.ActivateAsync();
OutputText.Text += actResult;
await RefreshStatus();
}
catch (Exception ex)
{
OutputText.Text += "\nHiba: " + ex.Message;
btn.IsEnabled = true;
btn.Content = "Aktiv\u00e1l\u00e1s";
}
}
private async void BtnRemoveSingle_Click(object sender, RoutedEventArgs e)
{
var btn = (Button)sender;
var last5 = (string)btn.Tag;
bool confirmed = await _main.ConfirmAsync(
"Kulcs elt\u00e1vol\u00edt\u00e1sa",
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani a *****-" + last5 + " kulcsot?",
"Elt\u00e1vol\u00edt\u00e1s", "M\u00e9gse", DialogType.Question);
if (!confirmed) return;
btn.IsEnabled = false;
btn.Content = "...";
try
{
await _licenseManager.RemoveKeyAsync(last5);
await RefreshStatus();
}
catch (Exception ex)
{
OutputText.Text += "\nHiba: " + ex.Message;
btn.IsEnabled = true;
btn.Content = "Elt\u00e1vol\u00edt\u00e1s";
}
}
private async void BtnRefresh_Click(object sender, RoutedEventArgs e)
{
await RefreshStatus();
}
private async void BtnRemoveAll_Click(object sender, RoutedEventArgs e)
{
bool confirmed = await _main.ConfirmAsync(
"\u00d6sszes kulcs elt\u00e1vol\u00edt\u00e1sa",
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani az \u00f6sszes telep\u00edtett term\u00e9kkulcsot (" + _entries.Count + " db)?\n\n" +
"Ez nem t\u00f6r\u00f6l adatot, csak az aktiv\u00e1ci\u00f3s \u00e1llapotot \u00e1ll\u00edtja vissza.",
"\u00d6sszes elt\u00e1vol\u00edt\u00e1sa", "M\u00e9gse");
if (!confirmed) return;
BtnRemoveAll.IsEnabled = false;
BtnRefresh.IsEnabled = false;
try
{
await _licenseManager.RemoveAllKeysAsync();
await RefreshStatus();
}
catch (Exception ex)
{
OutputText.Text += "\nHiba: " + ex.Message;
}
BtnRefresh.IsEnabled = true;
}
private void DetailsExpander_Expanded(object sender, RoutedEventArgs e)
{
_main.Height = 680;
}
private void DetailsExpander_Collapsed(object sender, RoutedEventArgs e)
{
_main.Height = 550;
}
}
}

58
Pages/VersionPage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,58 @@
<Page x:Class="InstaSoftOfficeTool.Pages.VersionPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,24">
<TextBlock Text="Válasszon Office verziót" FontSize="24" FontWeight="Light"/>
<TextBlock Text="Melyik évjáratot szeretné telepíteni?" FontSize="14"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Padding="0,0,4,0">
<StackPanel VerticalAlignment="Top">
<RadioButton x:Name="Rb2024" Style="{StaticResource CardRadioButton}"
GroupName="Version" IsChecked="True" Margin="0,0,0,10">
<StackPanel Margin="8,2">
<TextBlock Text="Office 2024" FontSize="18" FontWeight="SemiBold"/>
<TextBlock Text="2024. októberi kiadás · Windows 10 / 11"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,2,0,0"/>
</StackPanel>
</RadioButton>
<RadioButton x:Name="Rb2021" Style="{StaticResource CardRadioButton}"
GroupName="Version" Margin="0,0,0,10">
<StackPanel Margin="8,2">
<TextBlock Text="Office 2021" FontSize="18" FontWeight="SemiBold"/>
<TextBlock Text="2021. októberi kiadás · Windows 10 / 11"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,2,0,0"/>
</StackPanel>
</RadioButton>
<RadioButton x:Name="Rb2019" Style="{StaticResource CardRadioButton}"
GroupName="Version" Margin="0,0,0,10">
<StackPanel Margin="8,2">
<TextBlock Text="Office 2019" FontSize="18" FontWeight="SemiBold"/>
<TextBlock Text="2019. szeptemberi kiadás · Windows 7 / 8.1 / 10 / 11 · Támogatás lejárt: 2025.10."
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,2,0,0"/>
</StackPanel>
</RadioButton>
<RadioButton x:Name="Rb2016" Style="{StaticResource CardRadioButton}"
GroupName="Version" Margin="0,0,0,10">
<StackPanel Margin="8,2">
<TextBlock Text="Office 2016" FontSize="18" FontWeight="SemiBold"/>
<TextBlock Text="2016. szeptemberi kiadás · Windows 7 / 8.1 / 10 · Támogatás lejárt: 2025.10."
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,2,0,0"/>
</StackPanel>
</RadioButton>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

36
Pages/VersionPage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,36 @@
using System.Windows.Controls;
using InstaSoftOfficeTool.Models;
namespace InstaSoftOfficeTool.Pages
{
public partial class VersionPage : Page, IWizardPage
{
private readonly MainWindow _main;
private readonly InstallConfig _config;
public VersionPage(MainWindow main, InstallConfig config)
{
InitializeComponent();
_main = main;
_config = config;
// Restore selection
switch (_config.Version)
{
case OfficeVersion.Office2024: Rb2024.IsChecked = true; break;
case OfficeVersion.Office2021: Rb2021.IsChecked = true; break;
case OfficeVersion.Office2019: Rb2019.IsChecked = true; break;
case OfficeVersion.Office2016: Rb2016.IsChecked = true; break;
}
}
public bool Validate()
{
if (Rb2024.IsChecked == true) _config.Version = OfficeVersion.Office2024;
else if (Rb2021.IsChecked == true) _config.Version = OfficeVersion.Office2021;
else if (Rb2019.IsChecked == true) _config.Version = OfficeVersion.Office2019;
else if (Rb2016.IsChecked == true) _config.Version = OfficeVersion.Office2016;
return true;
}
}
}

59
Pages/WelcomePage.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,59 @@
<Page x:Class="InstaSoftOfficeTool.Pages.WelcomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Transparent">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,30">
<TextBlock Text="Üdvözöljük!" FontSize="28" FontWeight="Light"
Foreground="{StaticResource TextPrimaryBrush}"/>
<TextBlock Text="Válassza ki a kívánt műveletet:" FontSize="15"
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<UniformGrid Grid.Row="1" Columns="3" Margin="0,0,0,0">
<Button Style="{StaticResource CardButton}" Margin="0,0,10,0"
Click="InstallClick">
<StackPanel>
<TextBlock FontSize="28" Text="&#xE710;" FontFamily="Segoe MDL2 Assets"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,12"/>
<TextBlock Text="Office telepítés" FontSize="16" FontWeight="SemiBold"/>
<TextBlock Text="Új Microsoft Office telepítése a számítógépre"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
TextWrapping="Wrap" Margin="0,6,0,0"/>
</StackPanel>
</Button>
<Button Style="{StaticResource CardButton}" Margin="5,0,5,0"
Click="RemoveClick">
<StackPanel>
<TextBlock FontSize="28" Text="&#xE74D;" FontFamily="Segoe MDL2 Assets"
Foreground="{StaticResource WarningBrush}" Margin="0,0,0,12"/>
<TextBlock Text="Office eltávolítás" FontSize="16" FontWeight="SemiBold"/>
<TextBlock Text="Meglévő Microsoft Office eltávolítása"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
TextWrapping="Wrap" Margin="0,6,0,0"/>
</StackPanel>
</Button>
<Button Style="{StaticResource CardButton}" Margin="10,0,0,0"
Click="LicenseClick">
<StackPanel>
<TextBlock FontSize="28" Text="&#xE8D7;" FontFamily="Segoe MDL2 Assets"
Foreground="{StaticResource SuccessBrush}" Margin="0,0,0,12"/>
<TextBlock Text="Licenc-kezelés" FontSize="16" FontWeight="SemiBold"/>
<TextBlock Text="Licenc állapot lekérdezése, termékkulcsok törlése"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"
TextWrapping="Wrap" Margin="0,6,0,0"/>
</StackPanel>
</Button>
</UniformGrid>
</Grid>
</Page>

31
Pages/WelcomePage.xaml.cs Normal file
Fájl megtekintése

@@ -0,0 +1,31 @@
using System.Windows;
using System.Windows.Controls;
namespace InstaSoftOfficeTool.Pages
{
public partial class WelcomePage : Page
{
private readonly MainWindow _main;
public WelcomePage(MainWindow main)
{
InitializeComponent();
_main = main;
}
private void InstallClick(object sender, RoutedEventArgs e)
{
_main.StartInstallFlow();
}
private void RemoveClick(object sender, RoutedEventArgs e)
{
_main.StartRemoveFlow();
}
private void LicenseClick(object sender, RoutedEventArgs e)
{
_main.StartLicenseFlow();
}
}
}

Fájl megtekintése

@@ -8,7 +8,7 @@ Fejlesztő: **InstaSoft Informatikai Zrt.** | Microsoft Partner
## Letöltés
### [Legfrissebb verzió letöltése](https://github.com/InstaSoft-hu/OfficeTool/releases/latest)
A legfrissebb verzió a **Releases** oldalon érhető el.
> Az alkalmazás futtatásához **.NET Framework 4.8** szükséges (Windows 10/11 rendszereken alapértelmezetten telepítve van).
> A program rendszergazdai jogosultságot kér induláskor.
@@ -36,7 +36,7 @@ Első futtatáskor a Windows SmartScreen figyelmeztetést jeleníthet meg, mivel
## Funkciók
### Office telepítés
- Támogatott verziók: **Office 2024**, **Office 2021**, **Office 2019**
- Támogatott verziók: **Office 2024**, **Office 2021**, **Office 2019**, **Office 2016**
- Kiadások: **Standard**, **Professional Plus**, **Otthoni és kisvállalati verzió**
- Architektúra választás (64-bit / 32-bit)
- 22 telepítési nyelv
@@ -45,6 +45,8 @@ Első futtatáskor a Windows SmartScreen figyelmeztetést jeleníthet meg, mivel
- Meglévő Office automatikus felismerése és eltávolítási lehetőség telepítés előtt
- A telepítés végén alkalmazások közvetlen indítása
> **Office 2016** telepítése ISO letöltéssel történik (a Microsoft CDN már nem szolgálja ki a 2016-os Click-to-Run fájlokat). A Standard kiadás 32-bit és 64-bit, a Professional Plus kiadás 64-bit változatban érhető el, magyar nyelven.
### Office eltávolítás
- Telepített Office verziók automatikus felismerése (Click-to-Run és MSI)
- Szelektív eltávolítás — minden termék külön kiválasztható
@@ -93,7 +95,7 @@ Első futtatáskor a Windows SmartScreen figyelmeztetést jeleníthet meg, mivel
## Verziótörténet
A részletes verziótörténet a [Releases](https://github.com/InstaSoft-hu/OfficeTool/releases) oldalon érhető el.
A részletes verziótörténet a Releases oldalon érhető el.
---

BINáris
Resources/app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Méret: 2.4 KiB

185
Services/LicenseManager.cs Normal file
Fájl megtekintése

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
public class LicenseEntry
{
public string LicenseName { get; set; } = "";
public string Description { get; set; } = "";
public string Status { get; set; } = "";
public string ErrorDescription { get; set; } = "";
public string Last5 { get; set; } = "";
}
public class LicenseManager
{
public string OsppPath { get; private set; }
public bool FindOspp()
{
var searchPaths = new[]
{
// Click-to-Run (leggyakoribb — Office 365, 2019, 2021, 2024)
@"C:\Program Files\Microsoft Office\root\Office16\OSPP.VBS",
@"C:\Program Files (x86)\Microsoft Office\root\Office16\OSPP.VBS",
// Hagyományos MSI
@"C:\Program Files\Microsoft Office\Office16\ospp.vbs",
@"C:\Program Files (x86)\Microsoft Office\Office16\ospp.vbs",
@"C:\Program Files\Microsoft Office\Office15\ospp.vbs",
@"C:\Program Files (x86)\Microsoft Office\Office15\ospp.vbs",
@"C:\Program Files\Microsoft Office\Office14\ospp.vbs",
@"C:\Program Files (x86)\Microsoft Office\Office14\ospp.vbs",
};
foreach (var path in searchPaths)
{
if (File.Exists(path))
{
OsppPath = path;
return true;
}
}
try
{
var c2rPath = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Office\ClickToRun\Configuration")
?.GetValue("InstallationPath") as string;
if (!string.IsNullOrEmpty(c2rPath))
{
// C2R: root\Office16 vagy sima Office16
var candidates = new[]
{
Path.Combine(c2rPath, "root", "Office16", "OSPP.VBS"),
Path.Combine(c2rPath, "Office16", "OSPP.VBS"),
};
foreach (var candidate in candidates)
{
if (File.Exists(candidate))
{
OsppPath = candidate;
return true;
}
}
}
}
catch { }
return false;
}
public async Task<string> GetStatusAsync()
{
if (string.IsNullOrEmpty(OsppPath))
return "Az ospp.vbs nem tal\u00e1lhat\u00f3.";
var runner = new ProcessRunner();
return await runner.RunAndCaptureAsync("cscript",
"//Nologo \"" + OsppPath + "\" /dstatus");
}
public List<string> ParseLicenseKeys(string dstatusOutput)
{
var keys = new List<string>();
var regex = new Regex(@"Last 5 characters of installed product key:\s*(\S+)",
RegexOptions.IgnoreCase);
foreach (Match match in regex.Matches(dstatusOutput))
{
keys.Add(match.Groups[1].Value);
}
return keys;
}
public List<LicenseEntry> ParseLicenseEntries(string dstatusOutput)
{
var entries = new List<LicenseEntry>();
// Split by "-------" separator blocks
var blocks = Regex.Split(dstatusOutput, @"-{10,}");
foreach (var block in blocks)
{
var trimmed = block.Trim();
if (string.IsNullOrEmpty(trimmed)) continue;
if (trimmed.StartsWith("---Processing") || trimmed.StartsWith("---Exiting")) continue;
var entry = new LicenseEntry();
var nameMatch = Regex.Match(trimmed, @"LICENSE NAME:\s*(.+)", RegexOptions.IgnoreCase);
if (nameMatch.Success) entry.LicenseName = nameMatch.Groups[1].Value.Trim();
var descMatch = Regex.Match(trimmed, @"LICENSE DESCRIPTION:\s*(.+)", RegexOptions.IgnoreCase);
if (descMatch.Success) entry.Description = descMatch.Groups[1].Value.Trim();
var statusMatch = Regex.Match(trimmed, @"LICENSE STATUS:\s*(.+)", RegexOptions.IgnoreCase);
if (statusMatch.Success) entry.Status = statusMatch.Groups[1].Value.Trim();
var errorMatch = Regex.Match(trimmed, @"ERROR DESCRIPTION:\s*(.+)", RegexOptions.IgnoreCase);
if (errorMatch.Success) entry.ErrorDescription = errorMatch.Groups[1].Value.Trim();
var keyMatch = Regex.Match(trimmed, @"Last 5 characters of installed product key:\s*(\S+)", RegexOptions.IgnoreCase);
if (keyMatch.Success) entry.Last5 = keyMatch.Groups[1].Value.Trim();
if (!string.IsNullOrEmpty(entry.Last5))
entries.Add(entry);
}
return entries;
}
public async Task<string> RemoveKeyAsync(string last5Chars)
{
if (string.IsNullOrEmpty(OsppPath))
return "Az ospp.vbs nem tal\u00e1lhat\u00f3.";
var runner = new ProcessRunner();
return await runner.RunAndCaptureAsync("cscript",
"//Nologo \"" + OsppPath + "\" /unpkey:" + last5Chars);
}
public async Task<string> RemoveAllKeysAsync()
{
var status = await GetStatusAsync();
var keys = ParseLicenseKeys(status);
if (keys.Count == 0)
return "Nem tal\u00e1lhat\u00f3 telep\u00edtett term\u00e9kkulcs.";
var results = new List<string>();
foreach (var key in keys)
{
var result = await RemoveKeyAsync(key);
results.Add(key + ": " + result.Trim());
}
return string.Join("\n", results);
}
public async Task<string> InstallKeyAsync(string productKey)
{
if (string.IsNullOrEmpty(OsppPath))
return "Az ospp.vbs nem tal\u00e1lhat\u00f3.";
var runner = new ProcessRunner();
return await runner.RunAndCaptureAsync("cscript",
"//Nologo \"" + OsppPath + "\" /inpkey:" + productKey);
}
public async Task<string> ActivateAsync()
{
if (string.IsNullOrEmpty(OsppPath))
return "Az ospp.vbs nem tal\u00e1lhat\u00f3.";
var runner = new ProcessRunner();
return await runner.RunAndCaptureAsync("cscript",
"//Nologo \"" + OsppPath + "\" /act");
}
}
}

192
Services/MsiInstaller.cs Normal file
Fájl megtekintése

@@ -0,0 +1,192 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
public class MsiInstaller
{
public event Action<string> StatusChanged;
public event Action<long, long> DownloadProgress;
private string _isoPath;
private string _mountedDrive;
public string WorkFolder { get; private set; }
public MsiInstaller()
{
WorkFolder = Path.Combine(Path.GetTempPath(), "InstaSoftODT");
Directory.CreateDirectory(WorkFolder);
}
public async Task<bool> DownloadIsoAsync(string url)
{
try
{
string fileName = Path.GetFileName(new Uri(url).AbsolutePath);
_isoPath = Path.Combine(WorkFolder, fileName);
// Check if already downloaded
if (File.Exists(_isoPath))
{
var fi = new FileInfo(_isoPath);
if (fi.Length > 100_000_000)
{
StatusChanged?.Invoke("ISO már letöltve: " + fileName + " (" + (fi.Length / 1024 / 1024) + " MB)");
return true;
}
File.Delete(_isoPath);
}
StatusChanged?.Invoke("ISO letöltése: " + fileName);
StatusChanged?.Invoke("URL: " + url);
using (var handler = new HttpClientHandler { AllowAutoRedirect = true })
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Add("User-Agent", "InstaSoftOfficeTool/1.0");
client.Timeout = TimeSpan.FromMinutes(30);
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
long totalBytes = response.Content.Headers.ContentLength ?? -1;
using (var stream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(_isoPath, FileMode.Create, FileAccess.Write, FileShare.None, 65536))
{
var buffer = new byte[65536];
long totalRead = 0;
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalRead += bytesRead;
DownloadProgress?.Invoke(totalRead, totalBytes);
}
}
var downloadedSize = new FileInfo(_isoPath).Length;
StatusChanged?.Invoke("ISO letöltve: " + (downloadedSize / 1024 / 1024) + " MB");
}
return true;
}
catch (HttpRequestException ex)
{
StatusChanged?.Invoke("Hálózati hiba: " + ex.Message);
return false;
}
catch (TaskCanceledException)
{
StatusChanged?.Invoke("Időtúllépés: A letöltés túl sokáig tartott.");
return false;
}
catch (Exception ex)
{
StatusChanged?.Invoke("ISO letöltési hiba: " + ex.Message);
return false;
}
}
public async Task<bool> MountIsoAsync()
{
try
{
StatusChanged?.Invoke("ISO csatolása...");
var psi = new ProcessStartInfo
{
FileName = "powershell",
Arguments = "-NoProfile -Command \"" +
"$result = Mount-DiskImage -ImagePath '" + _isoPath + "' -PassThru; " +
"$vol = $result | Get-Volume; " +
"Write-Output $vol.DriveLetter\"",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using (var process = Process.Start(psi))
{
string output = await Task.Run(() => process.StandardOutput.ReadToEnd());
await Task.Run(() => process.WaitForExit());
string driveLetter = output.Trim();
if (process.ExitCode != 0 || driveLetter.Length != 1 || !char.IsLetter(driveLetter[0]))
{
string error = await Task.Run(() => process.StandardError.ReadToEnd());
StatusChanged?.Invoke("Hiba: Az ISO csatolása sikertelen.");
if (!string.IsNullOrEmpty(error))
StatusChanged?.Invoke(error.Trim());
return false;
}
_mountedDrive = driveLetter + ":\\";
StatusChanged?.Invoke("ISO csatolva: " + _mountedDrive);
return true;
}
}
catch (Exception ex)
{
StatusChanged?.Invoke("ISO csatolási hiba: " + ex.Message);
return false;
}
}
public async Task<int> RunSetupAsync(Action<string> outputCallback)
{
string setupExe = Path.Combine(_mountedDrive, "setup.exe");
if (!File.Exists(setupExe))
{
StatusChanged?.Invoke("Hiba: setup.exe nem található: " + setupExe);
return -1;
}
StatusChanged?.Invoke("Office 2016 telepítő indítása: " + setupExe);
outputCallback?.Invoke("A Microsoft Office telepítő ablaka megjelenik...");
outputCallback?.Invoke("Kérjük, kövesse a telepítő utasításait.");
var psi = new ProcessStartInfo
{
FileName = setupExe,
UseShellExecute = true
};
using (var process = Process.Start(psi))
{
await Task.Run(() => process.WaitForExit());
return process.ExitCode;
}
}
public async Task DismountIsoAsync()
{
try
{
if (string.IsNullOrEmpty(_isoPath) || !File.Exists(_isoPath)) return;
StatusChanged?.Invoke("ISO leválasztása...");
var psi = new ProcessStartInfo
{
FileName = "powershell",
Arguments = "-NoProfile -Command \"Dismount-DiskImage -ImagePath '" + _isoPath + "'\"",
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = Process.Start(psi))
{
await Task.Run(() => process.WaitForExit());
}
StatusChanged?.Invoke("ISO leválasztva.");
}
catch { }
}
}
}

124
Services/OdtDownloader.cs Normal file
Fájl megtekintése

@@ -0,0 +1,124 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
public class OdtDownloader
{
// Direct CDN link to ODT setup.exe (no self-extractor needed)
private const string OdtDownloadUrl = "https://officecdn.microsoft.com/pr/wsus/setup.exe";
public event Action<string> StatusChanged;
public string OdtFolder { get; private set; }
public string SetupExePath { get; private set; }
public OdtDownloader()
{
OdtFolder = Path.Combine(Path.GetTempPath(), "InstaSoftODT");
}
public async Task<bool> DownloadAndExtractAsync()
{
try
{
SetupExePath = Path.Combine(OdtFolder, "setup.exe");
// Check if valid setup.exe already exists
if (File.Exists(SetupExePath))
{
var existingSize = new FileInfo(SetupExePath).Length;
if (existingSize > 1000000) // valid setup.exe is ~7MB
{
StatusChanged?.Invoke("Az ODT setup.exe m\u00e1r el\u00e9rhet\u0151 (" +
(existingSize / 1024 / 1024) + " MB).");
return true;
}
// Delete corrupted file
StatusChanged?.Invoke("S\u00e9r\u00fclt setup.exe t\u00f6rl\u00e9se...");
File.Delete(SetupExePath);
}
Directory.CreateDirectory(OdtFolder);
// Download setup.exe directly from CDN
StatusChanged?.Invoke("Office Deployment Tool let\u00f6lt\u00e9se...");
StatusChanged?.Invoke("URL: " + OdtDownloadUrl);
using (var handler = new HttpClientHandler { AllowAutoRedirect = true })
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Add("User-Agent", "InstaSoftOfficeTool/1.0");
client.Timeout = TimeSpan.FromMinutes(5);
var response = await client.GetAsync(OdtDownloadUrl);
if (!response.IsSuccessStatusCode)
{
StatusChanged?.Invoke("Hiba: HTTP " + (int)response.StatusCode + " " + response.StatusCode);
return false;
}
var contentType = response.Content.Headers.ContentType?.MediaType ?? "";
if (contentType.Contains("text/html"))
{
StatusChanged?.Invoke("Hiba: HTML oldal \u00e9rkezett exe helyett.");
StatusChanged?.Invoke("T\u00f6ltse le manu\u00e1lisan: https://www.microsoft.com/en-us/download/details.aspx?id=49117");
return false;
}
var bytes = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes(SetupExePath, bytes);
StatusChanged?.Invoke("Let\u00f6ltve: " + (bytes.Length / 1024) + " KB");
}
if (!File.Exists(SetupExePath) || new FileInfo(SetupExePath).Length < 1000000)
{
StatusChanged?.Invoke("Hiba: A let\u00f6lt\u00f6tt f\u00e1jl s\u00e9r\u00fclt vagy t\u00fal kicsi.");
return false;
}
StatusChanged?.Invoke("ODT setup.exe k\u00e9sz.");
return true;
}
catch (System.Net.Http.HttpRequestException ex)
{
StatusChanged?.Invoke("H\u00e1l\u00f3zati hiba: Nincs internetkapcsolat vagy a szerver nem el\u00e9rhet\u0151.");
StatusChanged?.Invoke("R\u00e9szletek: " + ex.Message);
return false;
}
catch (TaskCanceledException)
{
StatusChanged?.Invoke("Id\u0151t\u00fall\u00e9p\u00e9s: A let\u00f6lt\u00e9s t\u00fal sok\u00e1ig tartott. Ellen\u0151rizze az internetkapcsolatot.");
return false;
}
catch (Exception ex)
{
StatusChanged?.Invoke("Hiba: " + ex.GetType().Name + ": " + ex.Message);
return false;
}
}
public async Task<int> RunSetupAsync(string configXmlPath, Action<string> outputCallback)
{
var runner = new ProcessRunner();
runner.OutputReceived += line => outputCallback?.Invoke(line);
StatusChanged?.Invoke("Office telep\u00edt\u00e9s ind\u00edt\u00e1sa...");
return await runner.RunAsync(SetupExePath, "/configure \"" + configXmlPath + "\"");
}
public async Task<int> RunRemoveAsync(string configXmlPath, Action<string> outputCallback)
{
var runner = new ProcessRunner();
runner.OutputReceived += line => outputCallback?.Invoke(line);
StatusChanged?.Invoke("Office elt\u00e1vol\u00edt\u00e1s ind\u00edt\u00e1sa...");
return await runner.RunAsync(SetupExePath, "/configure \"" + configXmlPath + "\"");
}
}
}

Fájl megtekintése

@@ -0,0 +1,79 @@
using System.Xml.Linq;
using InstaSoftOfficeTool.Models;
namespace InstaSoftOfficeTool.Services
{
public static class OdtXmlGenerator
{
public static string Generate(InstallConfig config)
{
var product = new XElement("Product",
new XAttribute("ID", config.Edition.ProductId));
if (!string.IsNullOrWhiteSpace(config.ProductKey))
{
product.Add(new XAttribute("PIDKEY", config.ProductKey.Replace("-", "").Trim()));
}
product.Add(new XElement("Language", new XAttribute("ID", config.Language)));
foreach (var app in config.ExcludedApps)
{
product.Add(new XElement("ExcludeApp", new XAttribute("ID", app)));
}
var add = new XElement("Add",
new XAttribute("OfficeClientEdition", config.Architecture),
new XAttribute("Channel", config.Edition.Channel),
product);
var configuration = new XElement("Configuration",
add,
new XElement("Display",
new XAttribute("Level", "Full"),
new XAttribute("AcceptEULA", "TRUE")),
new XElement("Property",
new XAttribute("Name", "FORCEAPPSHUTDOWN"),
new XAttribute("Value", "TRUE")));
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration);
return doc.Declaration + "\n" + doc.Root;
}
public static string GenerateRemoveAll()
{
var configuration = new XElement("Configuration",
new XElement("Remove", new XAttribute("All", "TRUE")),
new XElement("Display",
new XAttribute("Level", "Full"),
new XAttribute("AcceptEULA", "TRUE")),
new XElement("Property",
new XAttribute("Name", "FORCEAPPSHUTDOWN"),
new XAttribute("Value", "TRUE")));
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration);
return doc.Declaration + "\n" + doc.Root;
}
public static string GenerateRemoveProducts(string[] productIds)
{
var remove = new XElement("Remove");
foreach (var id in productIds)
{
remove.Add(new XElement("Product", new XAttribute("ID", id)));
}
var configuration = new XElement("Configuration",
remove,
new XElement("Display",
new XAttribute("Level", "Full"),
new XAttribute("AcceptEULA", "TRUE")),
new XElement("Property",
new XAttribute("Name", "FORCEAPPSHUTDOWN"),
new XAttribute("Value", "TRUE")));
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration);
return doc.Declaration + "\n" + doc.Root;
}
}
}

116
Services/OfficeDetector.cs Normal file
Fájl megtekintése

@@ -0,0 +1,116 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using InstaSoftOfficeTool.Models;
using Microsoft.Win32;
namespace InstaSoftOfficeTool.Services
{
public static class OfficeDetector
{
public static List<InstalledOffice> Detect()
{
var results = new List<InstalledOffice>();
// Check Click-to-Run
DetectClickToRun(results);
// Check MSI-based installs
DetectMsi(results);
return results;
}
private static void DetectClickToRun(List<InstalledOffice> results)
{
try
{
using (var key = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Office\ClickToRun\Configuration"))
{
if (key == null) return;
var productIds = key.GetValue("ProductReleaseIds") as string;
var versionToReport = key.GetValue("VersionToReport") as string;
if (string.IsNullOrEmpty(productIds)) return;
// Split into individual products (e.g. "O365BusinessRetail,VisioProRetail")
var ids = productIds.Split(',');
foreach (var id in ids)
{
var trimmedId = id.Trim();
if (string.IsNullOrEmpty(trimmedId)) continue;
results.Add(new InstalledOffice
{
DisplayName = "Microsoft Office Click-to-Run (" + trimmedId + ")",
Version = versionToReport ?? "",
ProductCode = trimmedId,
IsClickToRun = true,
IsSelected = true
});
}
}
}
catch { }
}
private static void DetectMsi(List<InstalledOffice> results)
{
var uninstallPaths = new[]
{
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};
foreach (var path in uninstallPaths)
{
try
{
using (var key = Registry.LocalMachine.OpenSubKey(path))
{
if (key == null) continue;
foreach (var subKeyName in key.GetSubKeyNames())
{
using (var subKey = key.OpenSubKey(subKeyName))
{
if (subKey == null) continue;
var displayName = subKey.GetValue("DisplayName") as string;
var publisher = subKey.GetValue("Publisher") as string;
if (displayName != null &&
publisher != null &&
publisher.Contains("Microsoft") &&
(displayName.Contains("Microsoft Office") ||
displayName.Contains("Microsoft 365")))
{
var version = subKey.GetValue("DisplayVersion") as string ?? "";
// Skip Click-to-Run updater entries
if (displayName.Contains("Click-to-Run") &&
!displayName.Contains("Microsoft Office"))
continue;
// Only accept {GUID} product codes for MSI uninstall
bool isGuid = Regex.IsMatch(subKeyName, @"^\{[0-9A-Fa-f\-]+\}$");
results.Add(new InstalledOffice
{
DisplayName = displayName,
Version = version,
ProductCode = isGuid ? subKeyName : null,
IsClickToRun = false,
IsSelected = true
});
}
}
}
}
}
catch { }
}
}
}
}

63
Services/ProcessRunner.cs Normal file
Fájl megtekintése

@@ -0,0 +1,63 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
public class ProcessRunner
{
public event Action<string> OutputReceived;
public async Task<int> RunAsync(string fileName, string arguments, bool redirectOutput = true)
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = redirectOutput,
RedirectStandardError = redirectOutput,
StandardOutputEncoding = redirectOutput ? Encoding.UTF8 : null,
StandardErrorEncoding = redirectOutput ? Encoding.UTF8 : null
};
using (var process = new Process { StartInfo = psi })
{
if (redirectOutput)
{
process.OutputDataReceived += (s, e) =>
{
if (e.Data != null)
OutputReceived?.Invoke(e.Data);
};
process.ErrorDataReceived += (s, e) =>
{
if (e.Data != null)
OutputReceived?.Invoke("[HIBA] " + e.Data);
};
}
process.Start();
if (redirectOutput)
{
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
await Task.Run(() => process.WaitForExit());
return process.ExitCode;
}
}
public async Task<string> RunAndCaptureAsync(string fileName, string arguments)
{
var sb = new StringBuilder();
OutputReceived += line => sb.AppendLine(line);
await RunAsync(fileName, arguments);
return sb.ToString();
}
}
}

120
Styles/ButtonStyles.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,120 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Primary (accent) button -->
<Style x:Key="PrimaryButton" TargetType="Button">
<Setter Property="Background" Value="{StaticResource AccentBrush}"/>
<Setter Property="Foreground" Value="{StaticResource TextOnAccentBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Padding" Value="24,10"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True"
TextElement.Foreground="{StaticResource TextOnAccentBrush}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource AccentHoverBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource AccentPressedBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Opacity" Value="0.4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Secondary (outline) button -->
<Style x:Key="SecondaryButton" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="24,10"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource CardHoverBrush}"/>
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource BorderBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Opacity" Value="0.4"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Card button (for WelcomePage action cards) -->
<Style x:Key="CardButton" TargetType="Button">
<Setter Property="Background" Value="{StaticResource CardBrush}"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="20,24"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="8"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect ShadowDepth="1" BlurRadius="8" Opacity="0.08" Color="Black"/>
</Border.Effect>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="border" Property="Background" Value="#FAFCFF"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="#F0F4FA"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

259
Styles/ControlStyles.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,259 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Fluent ComboBox with rounded corners and custom dropdown -->
<Style x:Key="FluentComboBox" TargetType="ComboBox">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="Background" Value="{StaticResource CardBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="12,9"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="itemBorder" Background="Transparent"
Padding="{TemplateBinding Padding}" CornerRadius="4" Margin="2,1">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="itemBorder" Property="Background" Value="#E8E8E8"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="itemBorder" Property="Background" Value="#DCE8F8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton x:Name="ToggleButton" Focusable="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="toggleBorder"
Background="{StaticResource CardBrush}"
BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1" CornerRadius="6"
SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="36"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="1">
<TextBlock Text="&#xE70D;" FontFamily="Segoe MDL2 Assets"
FontSize="10" HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{StaticResource TextSecondaryBrush}"/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="toggleBorder" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="toggleBorder" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="toggleBorder" Property="BorderThickness" Value="1,1,1,2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter x:Name="ContentSite" IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
Margin="14,9,36,9"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Popup x:Name="Popup" Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True" Focusable="False"
PopupAnimation="Slide">
<Border x:Name="DropDownBorder" Background="{StaticResource CardBrush}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
CornerRadius="8" Padding="4"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
Margin="0,2,0,0"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect ShadowDepth="4" BlurRadius="16" Opacity="0.14" Color="Black"/>
</Border.Effect>
<ScrollViewer SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Fluent TextBox with rounded corners -->
<Style x:Key="FluentTextBox" TargetType="TextBox">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="CaretBrush" Value="{StaticResource AccentBrush}"/>
<Setter Property="SelectionBrush" Value="{StaticResource AccentBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="border" Background="{StaticResource CardBrush}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
CornerRadius="6" Padding="10,8" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="False"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#BBBBBB"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="border" Property="BorderThickness" Value="1,1,1,2"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Background" Value="#F0F0F0"/>
<Setter Property="Foreground" Value="#999999"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Card-style RadioButton -->
<Style x:Key="CardRadioButton" TargetType="RadioButton">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="16,14"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border x:Name="border"
Background="{StaticResource CardBrush}"
BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect ShadowDepth="1" BlurRadius="6" Opacity="0.06" Color="Black"/>
</Border.Effect>
<ContentPresenter VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="border" Property="Background" Value="#FAFCFF"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="border" Property="BorderThickness" Value="2"/>
<Setter TargetName="border" Property="Background" Value="#F0F6FF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Fluent CheckBox with custom box -->
<Style x:Key="FluentCheckBox" TargetType="CheckBox">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border x:Name="rootBorder" Background="Transparent" Padding="6,8" CornerRadius="6"
SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<Border x:Name="checkBorder" Width="20" Height="20"
CornerRadius="4" BorderThickness="2"
BorderBrush="{StaticResource BorderBrush}"
Background="{StaticResource CardBrush}"
VerticalAlignment="Center" Margin="0,0,10,0">
<TextBlock x:Name="checkMark" Text="&#xE73E;"
FontFamily="Segoe MDL2 Assets" FontSize="12"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="White" Visibility="Collapsed"/>
</Border>
<ContentPresenter VerticalAlignment="Center" RecognizesAccessKey="True"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="rootBorder" Property="Background" Value="#F5F5F5"/>
<Setter TargetName="checkBorder" Property="BorderBrush" Value="#999"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="checkBorder" Property="Background" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="checkBorder" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
<Setter TargetName="checkMark" Property="Visibility" Value="Visible"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="checkBorder" Property="Background" Value="{StaticResource AccentHoverBrush}"/>
<Setter TargetName="checkBorder" Property="BorderBrush" Value="{StaticResource AccentHoverBrush}"/>
<Setter TargetName="rootBorder" Property="Background" Value="#F5F5F5"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="rootBorder" Property="Opacity" Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Step indicator dot (active) -->
<Style x:Key="StepDotActive" TargetType="Ellipse">
<Setter Property="Width" Value="10"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Fill" Value="{StaticResource AccentBrush}"/>
<Setter Property="Margin" Value="4,0"/>
</Style>
<!-- Step indicator dot (inactive) -->
<Style x:Key="StepDotInactive" TargetType="Ellipse">
<Setter Property="Width" Value="8"/>
<Setter Property="Height" Value="8"/>
<Setter Property="Fill" Value="{StaticResource BorderBrush}"/>
<Setter Property="Margin" Value="4,0"/>
</Style>
<!-- Progress bar -->
<Style x:Key="FluentProgressBar" TargetType="ProgressBar">
<Setter Property="Height" Value="4"/>
<Setter Property="Background" Value="{StaticResource BorderBrush}"/>
<Setter Property="Foreground" Value="{StaticResource AccentBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
</ResourceDictionary>

48
Styles/FluentTheme.xaml Normal file
Fájl megtekintése

@@ -0,0 +1,48 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Colors -->
<Color x:Key="AccentColor">#0078D4</Color>
<Color x:Key="AccentHoverColor">#106EBE</Color>
<Color x:Key="AccentPressedColor">#005A9E</Color>
<Color x:Key="BackgroundColor">#F3F3F3</Color>
<Color x:Key="CardColor">#FFFFFF</Color>
<Color x:Key="CardHoverColor">#F8F8F8</Color>
<Color x:Key="BorderColor">#E0E0E0</Color>
<Color x:Key="TextPrimaryColor">#1A1A1A</Color>
<Color x:Key="TextSecondaryColor">#666666</Color>
<Color x:Key="TextOnAccentColor">#FFFFFF</Color>
<Color x:Key="SuccessColor">#107C10</Color>
<Color x:Key="ErrorColor">#D13438</Color>
<Color x:Key="WarningColor">#CA5010</Color>
<Color x:Key="HeaderBarColor">#FAFAFA</Color>
<!-- Brushes -->
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}"/>
<SolidColorBrush x:Key="AccentHoverBrush" Color="{StaticResource AccentHoverColor}"/>
<SolidColorBrush x:Key="AccentPressedBrush" Color="{StaticResource AccentPressedColor}"/>
<SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}"/>
<SolidColorBrush x:Key="CardBrush" Color="{StaticResource CardColor}"/>
<SolidColorBrush x:Key="CardHoverBrush" Color="{StaticResource CardHoverColor}"/>
<SolidColorBrush x:Key="BorderBrush" Color="{StaticResource BorderColor}"/>
<SolidColorBrush x:Key="TextPrimaryBrush" Color="{StaticResource TextPrimaryColor}"/>
<SolidColorBrush x:Key="TextSecondaryBrush" Color="{StaticResource TextSecondaryColor}"/>
<SolidColorBrush x:Key="TextOnAccentBrush" Color="{StaticResource TextOnAccentColor}"/>
<SolidColorBrush x:Key="SuccessBrush" Color="{StaticResource SuccessColor}"/>
<SolidColorBrush x:Key="ErrorBrush" Color="{StaticResource ErrorColor}"/>
<SolidColorBrush x:Key="WarningBrush" Color="{StaticResource WarningColor}"/>
<SolidColorBrush x:Key="HeaderBarBrush" Color="{StaticResource HeaderBarColor}"/>
<!-- Global font — no Foreground here, it breaks inherited colors in buttons -->
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<Style TargetType="Label">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</ResourceDictionary>

26
app.manifest Normal file
Fájl megtekintése

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="InstaSoftOfficeTool"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>