Skip to content

Commit 601cbfc

Browse files
committed
dded optional console + logging; attempted to fix crash in
ScreenPropertyChanged
1 parent 735c461 commit 601cbfc

File tree

6 files changed

+90
-6
lines changed

6 files changed

+90
-6
lines changed

src/App/App.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@
6868
<PackageReference Include="LostTech.VirtualDesktop" Version="0.0.8-pre0" />
6969
<PackageReference Include="MahApps.Metro" Version="1.6.5" />
7070
<PackageReference Include="ManagedShell" Version="0.0.196" />
71+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
72+
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.12.19" />
7173
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
74+
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.183">
75+
<PrivateAssets>all</PrivateAssets>
76+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
77+
</PackageReference>
7278
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
7379
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
7480
<PackageReference Include="PInvoke.User32" Version="0.7.124" />

src/App/App.xaml.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
namespace LostTech.Stack
22
{
3-
using System;
4-
using System.Collections.Generic;
53
using System.Collections.ObjectModel;
64
using System.Collections.Specialized;
75
using System.Drawing;
86
using System.Diagnostics;
97
using System.IO;
10-
using System.Linq;
118
using System.Reflection;
129
using System.Runtime.CompilerServices;
1310
using System.Runtime.InteropServices;
1411
using System.Threading;
15-
using System.Threading.Tasks;
1612
using System.Windows;
1713
using System.Windows.Forms;
1814
using System.Windows.Interop;
@@ -88,12 +84,26 @@ public partial class App : BoilerplateApp, ILayoutsViewModel, IServiceProvider
8884
int sessionLocked;
8985
bool SessionLocked => this.sessionLocked != 0;
9086
readonly Win32WindowFactory win32WindowFactory = new Win32WindowFactory();
87+
readonly Thread uiThread = Thread.CurrentThread;
88+
readonly Microsoft.Extensions.Hosting.IHost host;
89+
readonly ILogger<App> log;
9190

9291
public event EventHandler<EventArgs<ScreenLayout>> LayoutLoaded;
9392

9493
internal static readonly bool IsUwp = new DesktopBridge.Helpers().IsRunningAsUwp();
9594

9695
public App() {
96+
if (Environment.GetEnvironmentVariable("STACK_CONSOLE") == "1") {
97+
try {
98+
ConsoleWindow.Setup();
99+
} catch (Exception e) {
100+
Debug.WriteLine(e.ToString());
101+
}
102+
}
103+
104+
var builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder([]);
105+
this.host = builder.Build();
106+
this.log = this.host.Services.GetRequiredService<ILogger<App>>();
97107
this.screenProvider = new Win32ScreenProvider(a => this.Dispatcher.BeginInvoke(a));
98108
}
99109

@@ -594,9 +604,10 @@ async Task StartLayout(StackSettings settings)
594604
old.PropertyChanged -= ScreenPropertyChanged;
595605
@new.PropertyChanged += ScreenPropertyChanged;
596606
ScreenLayout layout = this.screenLayouts.FirstOrDefault(l => l.Screen?.ID == old.ID);
597-
if (layout != null)
607+
if (layout != null) {
608+
this.log.LogWarning("Old screen not found: {Old} -> {New}", old, @new);
598609
layout.ViewModel.Screen = @new;
599-
else {
610+
} else {
600611
RemoveLayoutForScreen(old);
601612
await AddLayoutForScreen(@new);
602613
}
@@ -655,6 +666,10 @@ async void LayoutBoundsChanged(object sender, EventArgs e) {
655666
}
656667

657668
async void ScreenPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
669+
await this.Dispatcher;
670+
671+
if (this.uiThread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
672+
throw new InvalidProgramException("not on UI thread");
658673
var screen = (Win32Screen)sender;
659674
switch (e.PropertyName) {
660675
case nameof(Win32Screen.WorkingArea):

src/App/GlobalUsings.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
global using System;
2+
global using System.Collections.Generic;
3+
global using System.Diagnostics;
4+
global using System.Linq;
5+
global using System.Threading.Tasks;
6+
7+
global using Microsoft.Extensions.DependencyInjection;
8+
global using Microsoft.Extensions.Logging;
9+
global using Microsoft.VisualStudio.Threading;
10+
11+
global using static System.FormattableString;

src/App/NativeMethods.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
AllocConsole
2+
ATTACH_PARENT_PROCESS
3+
AttachConsole
4+
WIN32_ERROR

src/App/Utils/ConsoleWindow.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace LostTech.Stack.Utils;
2+
3+
using System.ComponentModel;
4+
5+
using global::Windows.Win32.Foundation;
6+
7+
using static global::Windows.Win32.PInvoke;
8+
9+
static class ConsoleWindow {
10+
public static void Setup() {
11+
if (AttachConsole(ATTACH_PARENT_PROCESS))
12+
return;
13+
14+
var ex = new Win32Exception();
15+
var error = (WIN32_ERROR)ex.NativeErrorCode;
16+
17+
if (error is WIN32_ERROR.ERROR_ACCESS_DENIED
18+
or WIN32_ERROR.ERROR_INVALID_PARAMETER
19+
or WIN32_ERROR.ERROR_INVALID_HANDLE) {
20+
if (!AllocConsole())
21+
throw new Win32Exception();
22+
else
23+
return;
24+
}
25+
26+
throw ex;
27+
}
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace LostTech.Stack.Utils;
2+
using System.Runtime.CompilerServices;
3+
using System.Windows.Threading;
4+
using System;
5+
6+
static class DispatcherExtensions {
7+
public static DispatcherAwaiter GetAwaiter(this Dispatcher dispatcher) => new(dispatcher);
8+
9+
public class DispatcherAwaiter(Dispatcher dispatcher): INotifyCompletion {
10+
private readonly Dispatcher dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
11+
12+
public bool IsCompleted => this.dispatcher.CheckAccess();
13+
14+
public void GetResult() { }
15+
16+
public void OnCompleted(Action continuation) {
17+
this.dispatcher.BeginInvoke(continuation);
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)