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>
This commit is contained in:
hariel1985
2026-03-31 08:38:08 +02:00
szülő eac8813cc0
commit 0e4253ba37
11 fájl változott, egészen pontosan 303 új sor hozzáadva és 22 régi sor törölve

Fájl megtekintése

@@ -9,9 +9,9 @@
<Company>InstaSoft Zrt.</Company>
<Product>InstaSoft Office Tool</Product>
<Copyright>Copyright (c) InstaSoft Zrt. 2026</Copyright>
<Version>1.0.9</Version>
<AssemblyVersion>1.0.9.0</AssemblyVersion>
<FileVersion>1.0.9.0</FileVersion>
<Version>1.1.0</Version>
<AssemblyVersion>1.1.0.0</AssemblyVersion>
<FileVersion>1.1.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
<LangVersion>latest</LangVersion>
</PropertyGroup>

Fájl megtekintése

@@ -45,7 +45,7 @@
Foreground="{StaticResource TextSecondaryBrush}" Margin="0,-2,0,0"/>
</StackPanel>
</StackPanel>
<TextBlock Text="v1.09" HorizontalAlignment="Right" VerticalAlignment="Center"
<TextBlock Text="v1.10" HorizontalAlignment="Right" VerticalAlignment="Center"
FontSize="12" Foreground="{StaticResource TextSecondaryBrush}"/>
</Grid>
</Border>
@@ -76,6 +76,8 @@
</Grid>
<!-- Confirm dialog overlay -->
<pages:ConfirmDialog x:Name="Dialog" Grid.RowSpan="3"/>
<pages:ConfirmDialog x:Name="Dialog"/>
<!-- Product key dialog overlay -->
<pages:ProductKeyDialog x:Name="KeyDialog"/>
</Grid>
</Window>

Fájl megtekintése

@@ -202,6 +202,11 @@ namespace InstaSoftOfficeTool
return Dialog.ShowAsync(title, message, confirmText, cancelText, type);
}
public Task<string> AskProductKeyAsync()
{
return KeyDialog.ShowAsync();
}
public void ShowBackToHomeButton()
{
BtnBack.Content = "\u2190 F\u0151oldal";

Fájl megtekintése

@@ -53,10 +53,15 @@ namespace InstaSoftOfficeTool.Pages
? !_config.ExcludedApps.Contains(app.Id)
: app.DefaultChecked;
bool isProPlus = _config.Edition != null &&
_config.Edition.ProductId.Contains("ProPlus");
bool accessOnly = app.Id == "Access";
var cb = new CheckBox
{
Content = app.DisplayName,
IsChecked = isChecked,
IsChecked = accessOnly && !isProPlus ? false : isChecked,
IsEnabled = !(accessOnly && !isProPlus),
Tag = app.Id,
Style = (Style)FindResource("FluentCheckBox"),
Margin = new Thickness(0, 4, 24, 4),
@@ -79,7 +84,7 @@ namespace InstaSoftOfficeTool.Pages
_config.ExcludedApps.Clear();
foreach (var cb in _appCheckBoxes)
{
if (cb.IsChecked != true)
if (cb.IsChecked != true || !cb.IsEnabled)
{
_config.ExcludedApps.Add((string)cb.Tag);
}

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

Fájl megtekintése

@@ -143,7 +143,13 @@ namespace InstaSoftOfficeTool.Pages
}
AppendLog("");
AppendLog("K\u00e9sz.");
AppendLog("K\u00e9sz. Lista friss\u00edt\u00e9se...");
DetectOffice();
if (_detected.Count == 0)
{
AppendLog("Nincs t\u00f6bb telep\u00edtett Office.");
}
}
catch (Exception ex)
{
@@ -151,6 +157,7 @@ namespace InstaSoftOfficeTool.Pages
AppendLog(ex.StackTrace);
}
BtnRemove.IsEnabled = _detected.Count > 0;
_main.ShowCloseButton();
}

Fájl megtekintése

@@ -14,7 +14,7 @@
<!-- 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 és termékkulcsok kezelése"
<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>

Fájl megtekintése

@@ -29,7 +29,6 @@ namespace InstaSoftOfficeTool.Pages
BtnRemoveAll.Visibility = Visibility.Collapsed;
BtnRefresh.IsEnabled = false;
// Loading indicator
var loadingText = new TextBlock
{
Text = "Keres\u00e9s folyamatban...",
@@ -164,18 +163,38 @@ namespace InstaSoftOfficeTool.Pages
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,
VerticalAlignment = VerticalAlignment.Center,
Tag = entry.Last5
Tag = entry.Last5,
Margin = new Thickness(6, 0, 0, 0)
};
removeBtn.Click += BtnRemoveSingle_Click;
Grid.SetColumn(removeBtn, 1);
grid.Children.Add(removeBtn);
btnPanel.Children.Add(removeBtn);
Grid.SetColumn(btnPanel, 1);
grid.Children.Add(btnPanel);
return new Border
{
@@ -189,6 +208,37 @@ namespace InstaSoftOfficeTool.Pages
};
}
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;
@@ -250,17 +300,12 @@ namespace InstaSoftOfficeTool.Pages
private void DetailsExpander_Expanded(object sender, RoutedEventArgs e)
{
// Grow window to fit details
var window = Window.GetWindow(this);
if (window != null && window.Height < 680)
window.Height = 680;
_main.Height = 680;
}
private void DetailsExpander_Collapsed(object sender, RoutedEventArgs e)
{
var window = Window.GetWindow(this);
if (window != null)
window.Height = 550;
_main.Height = 550;
}
}
}

Fájl megtekintése

@@ -161,5 +161,25 @@ namespace InstaSoftOfficeTool.Services
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");
}
}
}

Fájl megtekintése

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using InstaSoftOfficeTool.Models;
using Microsoft.Win32;
@@ -92,11 +93,14 @@ namespace InstaSoftOfficeTool.Services
!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 = subKeyName,
ProductCode = isGuid ? subKeyName : null,
IsClickToRun = false,
IsSelected = true
});