diff --git a/ScreenCast.Core/Services/FileTransferService.cs b/ScreenCast.Core/Services/FileTransferService.cs index 68779ed0f..ab074506c 100644 --- a/ScreenCast.Core/Services/FileTransferService.cs +++ b/ScreenCast.Core/Services/FileTransferService.cs @@ -11,6 +11,7 @@ using System.Threading; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; +using Remotely.Shared.Win32; namespace Remotely.ScreenCast.Core.Services { @@ -23,9 +24,10 @@ public interface IFileTransferService public class FileTransferService : IFileTransferService { - private static readonly ConcurrentDictionary _partialTransfers = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary partialTransfers = new ConcurrentDictionary(); - private static readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1); + private static readonly SemaphoreSlim writeLock = new SemaphoreSlim(1); + private static volatile bool messageBoxPending; public string GetBaseDirectory() { @@ -48,7 +50,7 @@ public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, { try { - await _writeLock.WaitAsync(); + await writeLock.WaitAsync(); var baseDir = GetBaseDirectory(); @@ -71,10 +73,10 @@ public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, File.Create(filePath).Close(); SetFileOrFolderPermissions(filePath); var fs = new FileStream(filePath, FileMode.OpenOrCreate); - _partialTransfers.AddOrUpdate(messageId, fs, (k,v) => fs); + partialTransfers.AddOrUpdate(messageId, fs, (k,v) => fs); } - var fileStream = _partialTransfers[messageId]; + var fileStream = partialTransfers[messageId]; if (buffer?.Length > 0) { @@ -85,7 +87,7 @@ public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, if (endOfFile) { fileStream.Close(); - _partialTransfers.Remove(messageId, out _); + partialTransfers.Remove(messageId, out _); if (EnvironmentHelper.IsWindows) { Process.Start("explorer.exe", baseDir); @@ -98,7 +100,12 @@ public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, } finally { - _writeLock.Release(); + writeLock.Release(); + + if (endOfFile) + { + await Task.Run(ShowTransferComplete); + } } } @@ -149,5 +156,29 @@ private void SetFileOrFolderPermissions(string path) } } } + + private void ShowTransferComplete() + { + // Prevent multiple dialogs from popping up. + if (!messageBoxPending) + { + if (EnvironmentHelper.IsWindows) + { + messageBoxPending = true; + var result = Win32Interop.ShowMessageBox(IntPtr.Zero, + "File transfer complete. Show folder?", + "Transfer Complete", + User32.MessageBoxType.MB_YESNO | + User32.MessageBoxType.MB_ICONINFORMATION | + User32.MessageBoxType.MB_TOPMOST); + + if (result == User32.MessageBoxResult.IDYES) + { + Process.Start("explorer.exe", GetBaseDirectory()); + } + messageBoxPending = false; + } + } + } } } diff --git a/Shared/Win32/User32.cs b/Shared/Win32/User32.cs index df23acd9a..90e3ab32d 100644 --- a/Shared/Win32/User32.cs +++ b/Shared/Win32/User32.cs @@ -1000,6 +1000,51 @@ public enum InputType : uint KEYBOARD = 1, HARDWARE = 2 } + public enum MessageBoxType : long + { + MB_ABORTRETRYIGNORE = 0x00000002L, + MB_CANCELTRYCONTINUE = 0x00000006L, + MB_HELP = 0x00004000L, + MB_OK = 0x00000000L, + MB_OKCANCEL = 0x00000001L, + MB_RETRYCANCEL = 0x00000005L, + MB_YESNO = 0x00000004L, + MB_YESNOCANCEL = 0x00000003L, + MB_ICONEXCLAMATION = 0x00000030L, + MB_ICONWARNING = 0x00000030L, + MB_ICONINFORMATION = 0x00000040L, + MB_ICONASTERISK = 0x00000040L, + MB_ICONQUESTION = 0x00000020L, + MB_ICONSTOP = 0x00000010L, + MB_ICONERROR = 0x00000010L, + MB_ICONHAND = 0x00000010L, + MB_DEFBUTTON1 = 0x00000000L, + MB_DEFBUTTON2 = 0x00000100L, + MB_DEFBUTTON3 = 0x00000200L, + MB_DEFBUTTON4 = 0x00000300L, + MB_APPLMODAL = 0x00000000L, + MB_SYSTEMMODAL = 0x00001000L, + MB_TASKMODAL = 0x00002000L, + MB_DEFAULT_DESKTOP_ONLY = 0x00020000L, + MB_RIGHT = 0x00080000L, + MB_RTLREADING = 0x00100000L, + MB_SETFOREGROUND = 0x00010000L, + MB_TOPMOST = 0x00040000L, + MB_SERVICE_NOTIFICATION = 0x00200000L + } + + public enum MessageBoxResult : int + { + IDABORT = 3, + IDCANCEL = 2, + IDCONTINUE = 11, + IDIGNORE = 5, + IDNO = 7, + IDOK = 1, + IDRETRY = 4, + IDTRYAGAIN = 10, + IDYES = 6, + } #endregion #region Structs @@ -1249,6 +1294,8 @@ public static extern int SystemParametersInfo( [return: MarshalAs(UnmanagedType.Bool)] public static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern int MessageBox(IntPtr hWnd, string text, string caption, long type); #endregion } diff --git a/Shared/Win32/Win32Interop.cs b/Shared/Win32/Win32Interop.cs index 66fc87383..2c8984a07 100644 --- a/Shared/Win32/Win32Interop.cs +++ b/Shared/Win32/Win32Interop.cs @@ -177,6 +177,13 @@ public static void SetMonitorState(MonitorState state) SendMessage(0xFFFF, 0x112, 0xF170, (int)state); } + public static MessageBoxResult ShowMessageBox(IntPtr owner, + string message, + string caption, + MessageBoxType messageBoxType) + { + return (MessageBoxResult)MessageBox(owner, message, caption, (long)messageBoxType); + } public static bool SwitchToInputDesktop() { var inputDesktop = OpenInputDesktop();