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>
This commit is contained in:
hariel1985
2026-03-31 05:40:50 +02:00
commit 4937ac4b1c
38 fájl változott, egészen pontosan 2496 új sor hozzáadva és 0 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,26 @@
<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.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\app.ico" />
</ItemGroup>
</Project>

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

@@ -0,0 +1,73 @@
<Window x:Class="InstaSoftOfficeTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="InstaSoft Office Tool"
Width="800" Height="550"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Background="{StaticResource BackgroundBrush}">
<Grid>
<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.0" 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>
</Window>

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

@@ -0,0 +1,205 @@
using System.Collections.Generic;
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),
new EditionPage(this, _config),
new ConfigPage(this, _config),
new ProductKeyPage(this, _config),
new SummaryPage(this, _config),
new ProgressPage(this, _config)
};
_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 (6 steps, but last is progress - no dot)
int totalDots = _wizardPages.Count - 1; // exclude progress page
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.Visible;
BtnNext.Visibility = Visibility.Visible;
// Last step before progress = "Telep\u00edt\u00e9s ind\u00edt\u00e1sa"
if (_currentPageIndex == _wizardPages.Count - 2)
{
BtnNext.Content = "Telep\u00edt\u00e9s ind\u00edt\u00e1sa";
}
// On progress page, hide both
else if (_currentPageIndex == _wizardPages.Count - 1 &&
_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)
{
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);
}
ShowCurrentPage();
// Auto-start if we're on progress page
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 void ShowBackToHomeButton()
{
BtnBack.Content = "\u2190 F\u0151oldal";
BtnBack.Visibility = Visibility.Visible;
}
}
public interface IWizardPage
{
bool Validate();
}
}

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

@@ -0,0 +1,81 @@
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 string GetVersionDisplayName()
{
switch (Version)
{
case OfficeVersion.Office2024: return "Office 2024";
case OfficeVersion.Office2021: return "Office 2021";
case OfficeVersion.Office2019: return "Office 2019";
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
{
public static readonly (string Id, string DisplayName)[] Apps = new[]
{
("Access", "Access"),
("Teams", "Teams"),
("OneNote", "OneNote"),
("Publisher", "Publisher"),
("Outlook", "Outlook"),
("Lync", "Skype for Business"),
};
}
}

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; }
}
}

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

@@ -0,0 +1,107 @@
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; }
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
}
};
default:
return new OfficeEdition[0];
}
}
}
}

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

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

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

@@ -0,0 +1,33 @@
<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"/>
<TextBlock Text="Architektúra" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,8"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,20">
<RadioButton x:Name="Rb64" GroupName="Arch" IsChecked="True"
Style="{StaticResource CardRadioButton}" Margin="0,0,10,0" MinWidth="160">
<TextBlock Text="64-bit" FontSize="15" Margin="8,0"/>
</RadioButton>
<RadioButton x:Name="Rb32" GroupName="Arch"
Style="{StaticResource CardRadioButton}" MinWidth="160">
<TextBlock Text="32-bit" FontSize="15" Margin="8,0"/>
</RadioButton>
</StackPanel>
<TextBlock Text="Telepítési nyelv" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,8"/>
<ComboBox x:Name="CbLanguage" Style="{StaticResource FluentComboBox}"
Width="300" HorizontalAlignment="Left" Margin="0,0,0,20"/>
<TextBlock Text="Telepítendő alkalmazások" FontSize="15" FontWeight="SemiBold" Margin="0,0,0,4"/>
<TextBlock Text="Törölje a jelölést azon alkalmazásoknál, amelyeket nem szeretne telepíteni."
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,0,0,10"/>
<WrapPanel x:Name="AppCheckBoxes" Orientation="Horizontal"/>
</StackPanel>
</ScrollViewer>
</Page>

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

@@ -0,0 +1,86 @@
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;
// Restore arch
if (_config.Architecture == "32")
{
Rb32.IsChecked = true;
}
// 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;
// Populate app checkboxes
foreach (var app in ExcludableApps.Apps)
{
var cb = new CheckBox
{
Content = app.DisplayName,
IsChecked = !_config.ExcludedApps.Contains(app.Id),
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)
{
_config.ExcludedApps.Add((string)cb.Tag);
}
}
return true;
}
}
}

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="Valasszon kiadast" 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() + " — melyik kiadast szeretne?";
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;
}
}
}

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,112 @@
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];
}
}
}
private void KeyBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_suppressAutoTab) return;
var tb = (TextBox)sender;
var cleaned = Regex.Replace(tb.Text, "[^A-Za-z0-9]", "");
if (cleaned != tb.Text)
{
_suppressAutoTab = true;
tb.Text = cleaned;
tb.CaretIndex = cleaned.Length;
_suppressAutoTab = false;
}
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;
}
}
}

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

@@ -0,0 +1,56 @@
<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">
<Grid Margin="40,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="TitleText" Grid.Row="0" Text="Telepítés folyamatban..."
FontSize="24" FontWeight="Light" Margin="0,0,0,20"/>
<StackPanel Grid.Row="1" 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..."
Foreground="{StaticResource TextSecondaryBrush}"/>
</StackPanel>
</StackPanel>
<ProgressBar x:Name="MainProgress" Grid.Row="1" Style="{StaticResource FluentProgressBar}"
IsIndeterminate="True" Margin="0,80,0,0"/>
<Border Grid.Row="2" 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>
<StackPanel x:Name="DonePanel" Grid.Row="3" Margin="0,12,0,0" Visibility="Collapsed"
Orientation="Horizontal">
<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>
</Grid>
</Page>

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

@@ -0,0 +1,140 @@
using System;
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
{
// Step 1: Download ODT
SetStepActive(Step1Icon, Step1Text);
AppendLog("ODT let\u00f6lt\u00e9se 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\u00f6lt\u00e9se sikertelen.");
return;
}
SetStepDone(Step1Icon, Step1Text);
// Step 2: Generate config XML
SetStepActive(Step2Icon, Step2Text);
AppendLog("Konfigur\u00e1ci\u00f3s XML gener\u00e1l\u00e1sa...");
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\u00edt\u00e9s ind\u00edt\u00e1sa...");
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\u00fclt!");
}
else
{
SetStepError(Step3Icon, Step3Text);
ShowDone(false, "A telep\u00edt\u00e9s hibak\u00f3ddal fejez\u0151d\u00f6tt be: " + exitCode);
}
}
catch (Exception ex)
{
AppendLog("HIBA: " + ex.Message);
ShowDone(false, "V\u00e1ratlan hiba t\u00f6rt\u00e9nt.");
}
}
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;
_main.ShowCloseButton();
});
}
}
}

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>

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

@@ -0,0 +1,131 @@
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)
{
var result = MessageBox.Show(
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani a kiv\u00e1lasztott Office telep\u00edt\u00e9seket?",
"Meger\u0151s\u00edt\u00e9s", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes) return;
BtnRemove.IsEnabled = false;
LogPanel.Visibility = Visibility.Visible;
bool hasC2R = false;
foreach (UIElement child in OfficeListPanel.Children)
{
if (child is CheckBox cb && cb.IsChecked == true)
{
var office = (InstalledOffice)cb.Tag;
if (office.IsClickToRun)
{
hasC2R = true;
}
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));
await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb");
}
}
}
if (hasC2R)
{
AppendLog("Click-to-Run Office elt\u00e1vol\u00edt\u00e1sa ODT-vel...");
var downloader = new OdtDownloader();
downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg));
bool ok = await downloader.DownloadAndExtractAsync();
if (ok)
{
string removeXml = OdtXmlGenerator.GenerateRemoveAll();
string xmlPath = Path.Combine(downloader.OdtFolder, "remove.xml");
File.WriteAllText(xmlPath, removeXml);
int exitCode = await downloader.RunRemoveAsync(xmlPath,
msg => Dispatcher.Invoke(() => AppendLog(msg)));
AppendLog(exitCode == 0
? "Office sikeresen elt\u00e1vol\u00edtva."
: "Elt\u00e1vol\u00edt\u00e1s befejez\u0151d\u00f6tt (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.");
_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>

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

@@ -0,0 +1,63 @@
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.ExcludedApps.Count > 0)
SumExcluded.Text = string.Join(", ", _config.ExcludedApps);
else
SumExcluded.Text = "Nincs (minden alkalmaz\u00e1s telep\u00fcl)";
_generatedXml = OdtXmlGenerator.Generate(_config);
XmlPreview.Text = _generatedXml;
}
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,45 @@
<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="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<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 és termékkulcsok kezelése"
FontSize="14" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,4,0,0"/>
</StackPanel>
<Border Grid.Row="1" Background="{StaticResource CardBrush}" CornerRadius="8"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
Padding="16,10" Margin="0,0,0,12">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="OsppStatusIcon" FontFamily="Segoe MDL2 Assets" FontSize="16"
VerticalAlignment="Center" Margin="0,0,8,0"/>
<TextBlock x:Name="OsppStatusText" FontSize="13" VerticalAlignment="Center"/>
</StackPanel>
</Border>
<Border Grid.Row="2" Background="#F8F8F8" CornerRadius="6" Padding="12"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1">
<TextBox x:Name="OutputText" FontFamily="Consolas" FontSize="12"
TextWrapping="Wrap" Foreground="{StaticResource TextSecondaryBrush}"
IsReadOnly="True" Background="Transparent" BorderThickness="0"
VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>
</Border>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,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"/>
</StackPanel>
</Grid>
</Page>

Fájl megtekintése

@@ -0,0 +1,106 @@
using System;
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();
public TroubleshootPage(MainWindow main)
{
InitializeComponent();
_main = main;
Loaded += async (s, e) => await RefreshStatus();
}
private async System.Threading.Tasks.Task RefreshStatus()
{
OutputText.Text = "Keres\u00e9s folyamatban...\n";
BtnRemoveAll.IsEnabled = false;
BtnRefresh.IsEnabled = false;
bool found = _licenseManager.FindOspp();
if (!found)
{
OsppStatusIcon.Text = "\uE711";
OsppStatusIcon.Foreground = (Brush)FindResource("ErrorBrush");
OsppStatusText.Text = "Az ospp.vbs nem tal\u00e1lhat\u00f3. Nincs telep\u00edtett Office?";
OutputText.Text = "Az ospp.vbs f\u00e1jl nem tal\u00e1lhat\u00f3 a sz\u00e1m\u00edt\u00f3g\u00e9pen.\n\n" +
"Lehets\u00e9ges okok:\n" +
"- Nincs telep\u00edtett Microsoft Office\n" +
"- Az Office nem a szok\u00e1sos helyre lett telep\u00edtve";
BtnRefresh.IsEnabled = true;
return;
}
OsppStatusIcon.Text = "\uE73E";
OsppStatusIcon.Foreground = (Brush)FindResource("SuccessBrush");
OsppStatusText.Text = "ospp.vbs megtal\u00e1lva: " + _licenseManager.OsppPath;
OutputText.Text = "Licenc-\u00e1llapot lek\u00e9rdez\u00e9se...\n";
try
{
string status = await _licenseManager.GetStatusAsync();
OutputText.Text = status;
var keys = _licenseManager.ParseLicenseKeys(status);
BtnRemoveAll.IsEnabled = keys.Count > 0;
if (keys.Count > 0)
{
OutputText.Text += "\n--- " + keys.Count + " term\u00e9kkulcs tal\u00e1lhat\u00f3 ---";
}
else
{
OutputText.Text += "\n--- Nincs telep\u00edtett term\u00e9kkulcs ---";
}
}
catch (Exception ex)
{
OutputText.Text = "Hiba a lek\u00e9rdez\u00e9s sor\u00e1n: " + ex.Message;
}
BtnRefresh.IsEnabled = true;
}
private async void BtnRefresh_Click(object sender, RoutedEventArgs e)
{
await RefreshStatus();
}
private async void BtnRemoveAll_Click(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show(
"Biztosan el szeretn\u00e9 t\u00e1vol\u00edtani az \u00f6sszes telep\u00edtett term\u00e9kkulcsot?\n\n" +
"Ez nem t\u00f6r\u00f6l adatot, csak az aktiv\u00e1ci\u00f3s \u00e1llapotot \u00e1ll\u00edtja vissza.",
"Meger\u0151s\u00edt\u00e9s", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes) return;
BtnRemoveAll.IsEnabled = false;
BtnRefresh.IsEnabled = false;
OutputText.Text += "\n\nTerm\u00e9kkulcsok elt\u00e1vol\u00edt\u00e1sa...\n";
try
{
string cleanResult = await _licenseManager.RemoveAllKeysAsync();
OutputText.Text += cleanResult + "\n";
OutputText.Text += "\nK\u00e9sz. Kattintson az '\u00c1llapot friss\u00edt\u00e9se' gombra az eredm\u00e9ny ellen\u0151rz\u00e9s\u00e9hez.";
}
catch (Exception ex)
{
OutputText.Text += "Hiba: " + ex.Message;
}
BtnRefresh.IsEnabled = true;
}
}
}

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

@@ -0,0 +1,47 @@
<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>
<StackPanel Grid.Row="1" 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="Legújabb változat — Word, Excel, PowerPoint, Outlook és más alkalmazások"
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="Stabil, bevált változat — széleskörű kompatibilitás"
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="Régebbi változat — Windows 7, 8.1 és 10 támogatás"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}" Margin="0,2,0,0"/>
</StackPanel>
</RadioButton>
</StackPanel>
</Grid>
</Page>

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

@@ -0,0 +1,34 @@
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;
}
}
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;
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();
}
}
}

BINáris
Resources/app.ico Normal file

Binary file not shown.

After

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

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

@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
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 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);
}
}
}

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

@@ -0,0 +1,96 @@
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace InstaSoftOfficeTool.Services
{
public class OdtDownloader
{
private const string OdtDownloadUrl = "https://go.microsoft.com/fwlink/p/?LinkID=626065";
public event Action<string> StatusChanged;
public event Action<int> ProgressChanged;
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
{
Directory.CreateDirectory(OdtFolder);
var odtExePath = Path.Combine(OdtFolder, "officedeploymenttool.exe");
SetupExePath = Path.Combine(OdtFolder, "setup.exe");
if (File.Exists(SetupExePath))
{
StatusChanged?.Invoke("Az ODT setup.exe m\u00e1r el\u00e9rhet\u0151, let\u00f6lt\u00e9s kihagyva.");
return true;
}
StatusChanged?.Invoke("Office Deployment Tool let\u00f6lt\u00e9se...");
using (var client = new WebClient())
{
client.DownloadProgressChanged += (s, e) =>
{
ProgressChanged?.Invoke(e.ProgressPercentage);
};
await client.DownloadFileTaskAsync(new Uri(OdtDownloadUrl), odtExePath);
}
StatusChanged?.Invoke("ODT kicsomagol\u00e1sa...");
var runner = new ProcessRunner();
var exitCode = await runner.RunAsync(odtExePath,
"/extract:\"" + OdtFolder + "\" /quiet");
if (exitCode != 0)
{
StatusChanged?.Invoke("Hiba: Az ODT kicsomagol\u00e1sa sikertelen (k\u00f3d: " + exitCode + ")");
return false;
}
if (!File.Exists(SetupExePath))
{
StatusChanged?.Invoke("Hiba: A setup.exe nem tal\u00e1lhat\u00f3 a kicsomagol\u00e1s ut\u00e1n.");
return false;
}
StatusChanged?.Invoke("ODT sikeresen let\u00f6ltve \u00e9s kicsomagolva.");
return true;
}
catch (Exception ex)
{
StatusChanged?.Invoke("Hiba a let\u00f6lt\u00e9s sor\u00e1n: " + 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,55 @@
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")));
var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration);
return doc.Declaration + "\n" + doc.Root;
}
}
}

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

@@ -0,0 +1,104 @@
using System.Collections.Generic;
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))
{
results.Add(new InstalledOffice
{
DisplayName = "Microsoft Office Click-to-Run (" + productIds + ")",
Version = versionToReport ?? "",
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;
results.Add(new InstalledOffice
{
DisplayName = displayName,
Version = version,
ProductCode = subKeyName,
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();
}
}
}

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

@@ -0,0 +1,119 @@
<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">
<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>

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

@@ -0,0 +1,104 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Fluent ComboBox -->
<Style x:Key="FluentComboBox" TargetType="ComboBox">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Background" Value="{StaticResource CardBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
</Style>
<!-- Fluent TextBox -->
<Style x:Key="FluentTextBox" TargetType="TextBox">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="Padding" Value="10,8"/>
<Setter Property="Background" Value="{StaticResource CardBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<Setter Property="CaretBrush" Value="{StaticResource AccentBrush}"/>
<Setter Property="SelectionBrush" Value="{StaticResource AccentBrush}"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
</Trigger>
</Style.Triggers>
</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 -->
<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="Padding" Value="8,4"/>
</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>

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

@@ -0,0 +1,49 @@
<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 -->
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI Variable Display, Segoe UI, Arial"/>
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}"/>
<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>