Skip to content

Commit cc6d0c3

Browse files
committed
msauth: replace WinForms dummy window with Avn window
1 parent 07d08f0 commit cc6d0c3

File tree

4 files changed

+59
-84
lines changed

4 files changed

+59
-84
lines changed

src/shared/Core/Authentication/MicrosoftAuthentication.cs

+27-83
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
using Microsoft.Identity.Client;
88
using Microsoft.Identity.Client.Extensions.Msal;
99
using System.Threading;
10-
using System.Runtime.InteropServices;
10+
using Avalonia.Controls;
11+
using GitCredentialManager.UI;
12+
using GitCredentialManager.UI.Views;
1113

1214
#if NETFRAMEWORK
13-
using System.Drawing;
14-
using System.Windows.Forms;
1515
using Microsoft.Identity.Client.Broker;
1616
#endif
1717

@@ -46,9 +46,7 @@ public class MicrosoftAuthentication : AuthenticationBase, IMicrosoftAuthenticat
4646
"live", "liveconnect", "liveid",
4747
};
4848

49-
#if NETFRAMEWORK
50-
private DummyWindow _dummyWindow;
51-
#endif
49+
private readonly CancellationTokenSource _progressWindowCts = new();
5250

5351
public MicrosoftAuthentication(ICommandContext context)
5452
: base(context) { }
@@ -166,10 +164,8 @@ public async Task<IMicrosoftAuthenticationResult> GetTokenAsync(
166164
}
167165
finally
168166
{
169-
#if NETFRAMEWORK
170-
// If we created a dummy window during authentication we should dispose of it now that we're done
171-
_dummyWindow?.Dispose();
172-
#endif
167+
// If we created a progress window during authentication we should close it now that we're done
168+
_progressWindowCts.Cancel();
173169
}
174170
}
175171

@@ -266,11 +262,27 @@ private async Task<IPublicClientApplication> CreatePublicClientApplicationAsync(
266262
}
267263
else if (enableBroker) // Only actually need to set a parent window when using the Windows broker
268264
{
269-
#if NETFRAMEWORK
270-
Context.Trace.WriteLine($"Using dummy parent window for MSAL authentication dialogs.");
271-
_dummyWindow = new DummyWindow();
272-
appBuilder.WithParentActivityOrWindow(_dummyWindow.ShowAndGetHandle);
273-
#endif
265+
IntPtr ShowAndGetProgressWindowHandle()
266+
{
267+
var windowShown = new TaskCompletionSource<IntPtr>();
268+
269+
Window CreateWindow()
270+
{
271+
var window = new ProgressWindow();
272+
window.Loaded += (s, e) =>
273+
windowShown.SetResult(window.PlatformImpl?.Handle.Handle ?? IntPtr.Zero);
274+
return window;
275+
}
276+
277+
// Do not wait for the window to be closed, but instead wait for the window to be shown
278+
// and return the window handle immediately.
279+
Task _ = AvaloniaUi.ShowWindowAsync(CreateWindow, IntPtr.Zero, _progressWindowCts.Token);
280+
281+
return windowShown.Task.GetAwaiter().GetResult();
282+
}
283+
284+
Context.Trace.WriteLine("Using progress window for MSAL authentication dialogs.");
285+
appBuilder.WithParentActivityOrWindow(ShowAndGetProgressWindowHandle);
274286
}
275287
}
276288
}
@@ -545,73 +557,5 @@ public MsalResult(AuthenticationResult msalResult)
545557
public string AccessToken => _msalResult.AccessToken;
546558
public string AccountUpn => _msalResult.Account.Username;
547559
}
548-
549-
#if NETFRAMEWORK
550-
private class DummyWindow : IDisposable
551-
{
552-
private readonly Thread _staThread;
553-
private readonly ManualResetEventSlim _readyEvent;
554-
private Form _window;
555-
private IntPtr _handle;
556-
557-
public DummyWindow()
558-
{
559-
_staThread = new Thread(ThreadProc);
560-
_staThread.SetApartmentState(ApartmentState.STA);
561-
_readyEvent = new ManualResetEventSlim();
562-
}
563-
564-
public IntPtr ShowAndGetHandle()
565-
{
566-
_staThread.Start();
567-
_readyEvent.Wait();
568-
return _handle;
569-
}
570-
571-
public void Dispose()
572-
{
573-
_window?.Invoke(() => _window.Close());
574-
575-
if (_staThread.IsAlive)
576-
{
577-
_staThread.Join();
578-
}
579-
}
580-
581-
private void ThreadProc()
582-
{
583-
System.Windows.Forms.Application.EnableVisualStyles();
584-
_window = new Form
585-
{
586-
TopMost = true,
587-
ControlBox = false,
588-
MaximizeBox = false,
589-
MinimizeBox = false,
590-
ClientSize = new Size(182, 46),
591-
FormBorderStyle = FormBorderStyle.None,
592-
StartPosition = FormStartPosition.CenterScreen,
593-
};
594-
595-
var progress = new ProgressBar
596-
{
597-
Style = ProgressBarStyle.Marquee,
598-
Location = new Point(12, 12),
599-
Size = new Size(158, 23),
600-
MarqueeAnimationSpeed = 30,
601-
};
602-
603-
_window.Controls.Add(progress);
604-
_window.Shown += (s, e) =>
605-
{
606-
_handle = _window.Handle;
607-
_readyEvent.Set();
608-
};
609-
610-
_window.ShowDialog();
611-
_window.Dispose();
612-
_window = null;
613-
}
614-
}
615-
#endif
616560
}
617561
}

src/shared/Core/Core.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<Reference Include="System.Net.Http" />
1515
<Reference Include="System.Web" />
1616
<PackageReference Include="Microsoft.Identity.Client.Broker" Version="4.52.0" />
17-
<PackageReference Include="Avalonia.Win32" Version="11.0.0-preview6"/>
17+
<PackageReference Include="Avalonia.Win32" Version="11.0.0-preview6" />
1818
</ItemGroup>
1919

2020
<ItemGroup Condition="'$(TargetFramework)' != 'net472'">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
SizeToContent="WidthAndHeight"
4+
x:Class="GitCredentialManager.UI.Views.ProgressWindow"
5+
Title="ProgressWindow"
6+
WindowStartupLocation="CenterScreen"
7+
ShowInTaskbar="False"
8+
SystemDecorations="BorderOnly">
9+
<ProgressBar Margin="10" IsIndeterminate="True" Height="20" Width="80"/>
10+
</Window>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
using Avalonia.Markup.Xaml;
4+
5+
namespace GitCredentialManager.UI.Views;
6+
7+
public partial class ProgressWindow : Window
8+
{
9+
public ProgressWindow()
10+
{
11+
InitializeComponent();
12+
#if DEBUG
13+
this.AttachDevTools();
14+
#endif
15+
}
16+
17+
private void InitializeComponent()
18+
{
19+
AvaloniaXamlLoader.Load(this);
20+
}
21+
}

0 commit comments

Comments
 (0)