Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Installed (Velopack) builds crashed on launch with a blank window — the published app
was missing its resource index (`resources.pri`), so the first screen failed with a
XAML parsing error. The published build now ships the app's resources correctly, and
launches as expected. Running from Visual Studio was unaffected.
- The system tray menu's "Show Snipdeck" and "Exit" entries did nothing when clicked.
They now work.

## [1.0.2] - 2026-06-08

### Added
Expand Down
15 changes: 9 additions & 6 deletions src/Snipdeck.App/CrashLog.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -88,11 +87,8 @@ private static void AppendException(StringBuilder sb, Exception ex, int depth)
var indent = new string(' ', depth * 2);

_ = sb.Append(indent).Append("Type: ").AppendLine(ex.GetType().FullName ?? ex.GetType().Name);
if (ex is COMException)
{
_ = sb.Append(indent).Append("HRESULT: 0x")
.AppendLine(ex.HResult.ToString("X8", CultureInfo.InvariantCulture));
}
_ = sb.Append(indent).Append("HRESULT: 0x")
.AppendLine(ex.HResult.ToString("X8", CultureInfo.InvariantCulture));
_ = sb.Append(indent).Append("Message: ").AppendLine(ex.Message);
if (!string.IsNullOrEmpty(ex.Source))
{
Expand All @@ -106,6 +102,13 @@ private static void AppendException(StringBuilder sb, Exception ex, int depth)
_ = sb.Append(indent).Append(" ").AppendLine(line.TrimEnd('\r'));
}
}
// WinRT-sourced exceptions (e.g. XamlParseException) carry the real
// detail here, not in Message — the RestrictedDescription is what
// names the missing resource / failing element.
foreach (System.Collections.DictionaryEntry entry in ex.Data)
{
_ = sb.Append(indent).Append("Data[").Append(entry.Key).Append("]: ").AppendLine(entry.Value?.ToString());
}
if (ex.InnerException is not null)
{
_ = sb.Append(indent).AppendLine("Inner:");
Expand Down
34 changes: 18 additions & 16 deletions src/Snipdeck.App/Services/HNotifyIconTrayService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,38 +57,40 @@ public void Dispose()

private MenuFlyout BuildContextMenu()
{
var showItem = new MenuFlyoutItem { Text = "Show Snipdeck" };
showItem.Click += OnShowItemClick;

var exitItem = new MenuFlyoutItem { Text = "Exit" };
exitItem.Click += OnExitItemClick;

// In an unpackaged app H.NotifyIcon's default context menu is a native
// Win32 PopupMenu, built from this MenuFlyout by invoking each item's
// Command — it does NOT raise the WinUI routed Click event. So the menu
// items must use Command (like LeftClickCommand does), not Click, or
// they silently do nothing.
return new MenuFlyout
{
Items =
{
showItem,
new MenuFlyoutItem
{
Text = "Show Snipdeck",
Command = new RelayCommand(RaiseShowRequested),
},
new MenuFlyoutSeparator(),
exitItem,
new MenuFlyoutItem
{
Text = "Exit",
Command = new RelayCommand(RaiseExitRequested),
},
},
};
}

private void OnShowItemClick(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
private void RaiseShowRequested()
{
RaiseShowRequested();
ShowRequested?.Invoke(this, EventArgs.Empty);
}

private void OnExitItemClick(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
private void RaiseExitRequested()
{
ExitRequested?.Invoke(this, EventArgs.Empty);
}

private void RaiseShowRequested()
{
ShowRequested?.Invoke(this, EventArgs.Empty);
}

private sealed partial class RelayCommand(Action execute) : System.Windows.Input.ICommand
{
#pragma warning disable CS0067 // 'CanExecuteChanged' is never used — relay never changes.
Expand Down
12 changes: 12 additions & 0 deletions src/Snipdeck.App/Snipdeck.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
<WinUISDKReferences>false</WinUISDKReferences>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<!-- Imports the WinUI PRI/packaging targets. Without it the app's PRI is
generated into bin but never copied to the publish output, so a
published build ships with no app resources.pri at all. Required for
unpackaged self-contained WinUI per the Windows App SDK docs. -->
<EnableMsixTooling>true</EnableMsixTooling>
<!-- Unpackaged + self-contained WinUI auto-loads only "resources.pri" from
the exe directory; the build otherwise names the app's PRI after the
assembly (Snipdeck.App.pri), which the runtime never loads — so every
ms-appx:/// lookup for the app's own XAML/Assets fails and the first
app-specific page throws XamlParseException ("Cannot locate resource").
Forcing the conventional name fixes it. See microsoft-ui-xaml#10856. -->
<ProjectPriFileName>resources.pri</ProjectPriFileName>
<Platforms>x64</Platforms>
<!-- Use the explicit entry point in Program.cs instead of the
XAML-generated Main, so Velopack + single-instance run first.
Expand Down
Loading