diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj
index 0769a926a..85d3f19f9 100644
--- a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj
+++ b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj
@@ -11,8 +11,10 @@
PreserveNewest
+
+
diff --git a/GreenshotWin10Plugin/MemoryRandomAccessStream.cs b/GreenshotWin10Plugin/MemoryRandomAccessStream.cs
index 4b3476a04..7b18328ca 100644
--- a/GreenshotWin10Plugin/MemoryRandomAccessStream.cs
+++ b/GreenshotWin10Plugin/MemoryRandomAccessStream.cs
@@ -1,66 +1,106 @@
-using System.IO;
+/*
+ * Greenshot - a free and open source screenshot tool
+ * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom
+ *
+ * For more information see: http://getgreenshot.org/
+ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using System.IO;
using Windows.Storage.Streams;
namespace GreenshotWin10Plugin
{
+ ///
+ /// This is an IRandomAccessStream implementation which uses a MemoryStream
+ ///
public sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream
{
+ ///
+ /// Default constructor
+ ///
public MemoryRandomAccessStream()
{
}
+ ///
+ /// Constructor where also bytes are already passed
+ ///
+ /// byte array
public MemoryRandomAccessStream(byte[] bytes)
{
Write(bytes, 0, bytes.Length);
}
- public IInputStream GetInputStreamAt(ulong position)
+ ///
+ public IInputStream GetInputStreamAt(ulong position)
{
Seek((long)position, SeekOrigin.Begin);
return this.AsInputStream();
}
- public IOutputStream GetOutputStreamAt(ulong position)
+ ///
+ public IOutputStream GetOutputStreamAt(ulong position)
{
Seek((long)position, SeekOrigin.Begin);
return this.AsOutputStream();
}
- ulong IRandomAccessStream.Position => (ulong)Position;
+ ///
+ ulong IRandomAccessStream.Position => (ulong)Position;
- public ulong Size
+ ///
+ public ulong Size
{
get { return (ulong)Length; }
set { SetLength((long)value); }
}
- public IRandomAccessStream CloneStream()
+ ///
+ public IRandomAccessStream CloneStream()
{
var cloned = new MemoryRandomAccessStream();
CopyTo(cloned);
return cloned;
}
- public void Seek(ulong position)
+ ///
+ public void Seek(ulong position)
{
Seek((long)position, SeekOrigin.Begin);
}
- public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
+ ///
+ public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
{
var inputStream = GetInputStreamAt(0);
return inputStream.ReadAsync(buffer, count, options);
}
- Windows.Foundation.IAsyncOperation IOutputStream.FlushAsync()
+ ///
+ Windows.Foundation.IAsyncOperation IOutputStream.FlushAsync()
{
var outputStream = GetOutputStreamAt(0);
return outputStream.FlushAsync();
}
- public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer)
+ ///
+ public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer)
{
var outputStream = GetOutputStreamAt(0);
return outputStream.WriteAsync(buffer);
diff --git a/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs b/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs
index b20725bf5..734d5f73f 100644
--- a/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs
+++ b/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs
@@ -1,20 +1,20 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom
- *
+ *
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
@@ -36,12 +36,18 @@ namespace GreenshotWin10Plugin.Native
private readonly IDataTransferManagerInterOp _dataTransferManagerInterOp;
private readonly IntPtr _windowHandle;
+ ///
+ /// The DataTransferManager
+ ///
public DataTransferManager DataTransferManager
{
get;
private set;
}
-
+ ///
+ /// Constructor which takes a handle to initialize
+ ///
+ ///
public DataTransferManagerHelper(IntPtr handle)
{
//TODO: Add a check for failure here. This will fail for versions of Windows below Windows 10
@@ -52,8 +58,8 @@ namespace GreenshotWin10Plugin.Native
_windowHandle = handle;
var riid = new Guid(DataTransferManagerId);
- var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager);
- if (hresult != 0)
+ var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager);
+ if (hresult.Failed())
{
Log.WarnFormat("HResult for GetForWindow: {0}", hresult);
}
@@ -66,9 +72,9 @@ namespace GreenshotWin10Plugin.Native
public void ShowShareUi()
{
var hresult = _dataTransferManagerInterOp.ShowShareUIForWindow(_windowHandle);
- if (hresult != 0)
- {
- Log.WarnFormat("HResult for ShowShareUIForWindow: {0}", hresult);
+ if (hresult.Failed())
+ {
+ Log.WarnFormat("HResult for ShowShareUIForWindow: {0}", hresult);
}
else
{
diff --git a/GreenshotWin10Plugin/Native/HResult.cs b/GreenshotWin10Plugin/Native/HResult.cs
new file mode 100644
index 000000000..9a36be173
--- /dev/null
+++ b/GreenshotWin10Plugin/Native/HResult.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GreenshotWin10Plugin.Native
+{
+ ///
+ /// The HRESULT represents Windows error codes
+ /// See wikipedia
+ ///
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum HResult
+ {
+#pragma warning disable 1591
+ S_OK = 0,
+ S_FALSE = 1,
+ E_FAIL = unchecked((int)0x80004005),
+ E_INVALIDARG = unchecked((int)0x80070057),
+ E_NOTIMPL = unchecked((int)0x80004001),
+ E_POINTER = unchecked((int)0x80004003),
+ E_PENDING = unchecked((int)0x8000000A),
+ E_NOINTERFACE = unchecked((int)0x80004002),
+ E_ABORT = unchecked((int)0x80004004),
+ E_ACCESSDENIED = unchecked((int)0x80070006),
+ E_HANDLE = unchecked((int)0x80070006),
+ E_UNEXPECTED = unchecked((int)0x8000FFFF),
+ E_FILENOTFOUND = unchecked((int)0x80070002),
+ E_PATHNOTFOUND = unchecked((int)0x80070003),
+ E_INVALID_DATA = unchecked((int)0x8007000D),
+ E_OUTOFMEMORY = unchecked((int)0x8007000E),
+ E_INSUFFICIENT_BUFFER = unchecked((int)0x8007007A),
+ WSAECONNABORTED = unchecked((int)0x80072745),
+ WSAECONNRESET = unchecked((int)0x80072746),
+ ERROR_TOO_MANY_CMDS = unchecked((int)0x80070038),
+ ERROR_NOT_SUPPORTED = unchecked((int)0x80070032),
+ TYPE_E_ELEMENTNOTFOUND = unchecked((int)0x8002802B)
+#pragma warning restore 1591
+ }
+}
diff --git a/GreenshotWin10Plugin/Native/HResultExtensions.cs b/GreenshotWin10Plugin/Native/HResultExtensions.cs
new file mode 100644
index 000000000..55ec38073
--- /dev/null
+++ b/GreenshotWin10Plugin/Native/HResultExtensions.cs
@@ -0,0 +1,64 @@
+// Greenshot - a free and open source screenshot tool
+// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
+//
+// For more information see: http://getgreenshot.org/
+// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 1 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+
+namespace GreenshotWin10Plugin.Native
+{
+ ///
+ /// Extensions to handle the HResult
+ ///
+ public static class HResultExtensions
+ {
+ ///
+ /// Test if the HResult respresents a fail
+ ///
+ /// HResult
+ /// bool
+ [Pure]
+ public static bool Failed(this HResult hResult)
+ {
+ return hResult < 0;
+ }
+
+ ///
+ /// Test if the HResult respresents a success
+ ///
+ /// HResult
+ /// bool
+ [Pure]
+ public static bool Succeeded(this HResult hResult)
+ {
+ return hResult >= HResult.S_OK;
+ }
+
+ ///
+ /// Throw an exception on Failure
+ ///
+ /// HResult
+ public static void ThrowOnFailure(this HResult hResult)
+ {
+ if (Failed(hResult))
+ {
+ throw Marshal.GetExceptionForHR((int)hResult);
+ }
+ }
+ }
+}
diff --git a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs b/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs
index f350e7372..470c03f6b 100644
--- a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs
+++ b/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs
@@ -1,23 +1,21 @@
-/*
- * Greenshot - a free and open source screenshot tool
- * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom
- *
- * For more information see: http://getgreenshot.org/
- * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
+// Greenshot - a free and open source screenshot tool
+// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
+//
+// For more information see: http://getgreenshot.org/
+// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 1 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
using System;
using System.Runtime.InteropServices;
@@ -43,7 +41,7 @@ namespace GreenshotWin10Plugin.Native
/// The DataTransferManager instance for this window handle
/// HRESULT
[PreserveSig]
- uint GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager);
+ HResult GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager);
///
/// Show the share flyout for the window identified by a window handle
@@ -51,7 +49,7 @@ namespace GreenshotWin10Plugin.Native
/// The window handle
/// HRESULT
[PreserveSig]
- uint ShowShareUIForWindow(IntPtr appWindow);
+ HResult ShowShareUIForWindow(IntPtr appWindow);
}
}
diff --git a/GreenshotWin10Plugin/Native/WindowMessageInfo.cs b/GreenshotWin10Plugin/Native/WindowMessageInfo.cs
new file mode 100644
index 000000000..231e3ec14
--- /dev/null
+++ b/GreenshotWin10Plugin/Native/WindowMessageInfo.cs
@@ -0,0 +1,70 @@
+// Greenshot - a free and open source screenshot tool
+// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
+//
+// For more information see: http://getgreenshot.org/
+// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 1 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using GreenshotPlugin.UnmanagedHelpers;
+using System;
+
+namespace Greenshot.Addon.Win10.Native
+{
+ ///
+ /// Container for the windows messages
+ ///
+ public class WindowMessageInfo
+ {
+ ///
+ /// IntPtr with the Handle of the window
+ ///
+ public IntPtr Handle { get; private set; }
+
+ ///
+ /// WindowsMessages which is the actual message
+ ///
+ public WindowsMessages Message { get; private set; }
+
+ ///
+ /// IntPtr with the word-param
+ ///
+ public IntPtr WordParam { get; private set; }
+
+ ///
+ /// IntPtr with the long-param
+ ///
+ public IntPtr LongParam { get; private set; }
+
+ ///
+ /// Factory method for the Window Message Info
+ ///
+ /// IntPtr with the Handle of the window
+ /// WindowsMessages which is the actual message
+ /// IntPtr with the word-param
+ /// IntPtr with the long-param
+ ///
+ /// WindowMessageInfo
+ public static WindowMessageInfo Create(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ return new WindowMessageInfo
+ {
+ Handle = hwnd,
+ Message = (WindowsMessages)msg,
+ WordParam = wParam,
+ LongParam = lParam
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/GreenshotWin10Plugin/Native/WindowMessageMonitor.cs b/GreenshotWin10Plugin/Native/WindowMessageMonitor.cs
new file mode 100644
index 000000000..81e40ec66
--- /dev/null
+++ b/GreenshotWin10Plugin/Native/WindowMessageMonitor.cs
@@ -0,0 +1,137 @@
+// Greenshot - a free and open source screenshot tool
+// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
+//
+// For more information see: http://getgreenshot.org/
+// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 1 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using System.Windows;
+using System.Windows.Interop;
+
+namespace Greenshot.Addon.Win10.Native
+{
+
+ ///
+ /// A monitor for window messages
+ ///
+ public static class WindowMessageMonitor
+ {
+ ///
+ /// Create a HwndSource for the specified Window
+ ///
+ /// Window
+ /// HwndSource
+ private static HwndSource ToHwndSource(this Window window)
+ {
+ IntPtr windowHandle = new WindowInteropHelper(window).Handle;
+ if (windowHandle == IntPtr.Zero)
+ {
+ return null;
+ }
+ return HwndSource.FromHwnd(windowHandle);
+ }
+
+ ///
+ /// Create an observable for the specified window
+ ///
+ public static IObservable WindowMessages(this Window window)
+ {
+ return WindowMessages(window, null);
+ }
+
+ ///
+ /// Create an observable for the specified HwndSource
+ ///
+ public static IObservable WindowMessages(this HwndSource hwndSource)
+ {
+ return WindowMessages(null, hwndSource);
+ }
+
+ ///
+ /// Create an observable for the specified window or HwndSource
+ ///
+ /// Window
+ /// HwndSource
+ /// IObservable
+ private static IObservable WindowMessages(Window window, HwndSource hwndSource)
+ {
+ if (window == null && hwndSource == null)
+ {
+ throw new NotSupportedException("One of Window or HwndSource must be supplied");
+ }
+ if (window != null && hwndSource != null)
+ {
+ throw new NotSupportedException("Either Window or HwndSource must be supplied");
+ }
+
+ return Observable.Create(observer =>
+ {
+ // This handles the message, and generates the observable OnNext
+ IntPtr WindowMessageHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ observer.OnNext(WindowMessageInfo.Create(hwnd, msg, wParam, lParam, ref handled));
+ // ReSharper disable once AccessToDisposedClosure
+ if (hwndSource.IsDisposed)
+ {
+ observer.OnCompleted();
+ }
+ return IntPtr.Zero;
+ }
+
+ void HwndSourceDisposedHandle(object sender, EventArgs e)
+ {
+ observer.OnCompleted();
+ }
+
+ void RegisterHwndSource()
+ {
+ hwndSource.Disposed += HwndSourceDisposedHandle;
+ hwndSource.AddHook(WindowMessageHandler);
+ }
+
+ if (window != null)
+ {
+ hwndSource = window.ToHwndSource();
+ }
+ if (hwndSource != null)
+ {
+ RegisterHwndSource();
+ }
+ else
+ {
+ // No, try to get it later
+ window.SourceInitialized += (sender, args) =>
+ {
+ hwndSource = window.ToHwndSource();
+ RegisterHwndSource();
+ };
+ }
+
+ return Disposable.Create(() =>
+ {
+ hwndSource.Disposed -= HwndSourceDisposedHandle;
+ hwndSource.RemoveHook(WindowMessageHandler);
+ hwndSource.Dispose();
+ });
+ })
+ // Make sure there is always a value produced when connecting
+ .Publish()
+ .RefCount();
+ }
+ }
+}
diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs
index 5f440ea38..815ebc787 100644
--- a/GreenshotWin10Plugin/Win10Plugin.cs
+++ b/GreenshotWin10Plugin/Win10Plugin.cs
@@ -1,20 +1,20 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
- *
+ *
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
@@ -31,7 +31,6 @@ namespace GreenshotWin10Plugin
///
public class Win10Plugin : IGreenshotPlugin
{
-
public void Dispose()
{
Dispose(true);
@@ -67,7 +66,7 @@ namespace GreenshotWin10Plugin
{
yield break;
}
-
+
///
/// Implementation of the IGreenshotPlugin.Initialize
///
diff --git a/GreenshotWin10Plugin/Win10ShareDestination.cs b/GreenshotWin10Plugin/Win10ShareDestination.cs
index da8191fba..cb6d3f3cc 100644
--- a/GreenshotWin10Plugin/Win10ShareDestination.cs
+++ b/GreenshotWin10Plugin/Win10ShareDestination.cs
@@ -1,178 +1,261 @@
/*
* Greenshot - a free and open source screenshot tool
* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom
- *
+ *
* For more information see: http://getgreenshot.org/
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 1 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
using System;
using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Interop;
+using Windows.ApplicationModel.DataTransfer;
+using Windows.Storage;
using Windows.Storage.Streams;
+using Greenshot.Addon.Win10.Native;
+using Color = Windows.UI.Color;
+using System.Reactive.Linq;
+using GreenshotPlugin.UnmanagedHelpers;
using Greenshot.Plugin;
using GreenshotPlugin.Core;
-using GreenshotWin10Plugin.Native;
-using System.Threading.Tasks;
-using Windows.Storage;
-using Color = Windows.UI.Color;
-using System.Collections.Generic;
using System.Drawing;
+using GreenshotWin10Plugin.Native;
namespace GreenshotWin10Plugin
{
- ///
- /// This uses the Share from Windows 10 to make the capture available to apps.
- ///
- public class Win10ShareDestination : AbstractDestination
- {
- private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10ShareDestination));
+ ///
+ /// This uses the Share from Windows 10 to make the capture available to apps.
+ ///
+ public class Win10ShareDestination : AbstractDestination
+ {
+ private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10ShareDestination));
- public override string Designation { get; } = "WIN10Share";
- public override string Description { get; } = "Windows 10 share";
+ public override string Designation { get; } = "WIN10Share";
+ public override string Description { get; } = "Windows 10 share";
- ///
- /// Icon for the App-share, the icon was found via: http://help4windows.com/windows_8_shell32_dll.shtml
- ///
- public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\shell32.dll"), 238);
+ ///
+ /// Icon for the App-share, the icon was found via: http://help4windows.com/windows_8_shell32_dll.shtml
+ ///
+ public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\shell32.dll"), 238);
- ///
- /// Share the screenshot with a windows app
- ///
- ///
- ///
- ///
- /// ExportInformation
+ private class ShareInfo
+ {
+ public string ApplicationName { get; set; }
+ public bool AreShareProvidersRequested { get; set; }
+ public bool IsDeferredFileCreated { get; set; }
+ public DataPackageOperation CompletedWithOperation { get; set; }
+ public string AcceptedFormat { get; set; }
+ public bool IsDestroyed { get; set; }
+ public bool IsShareCompleted { get; set; }
+
+ public TaskCompletionSource ShareTask { get; } = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ public bool IsDataRequested { get; set; }
+ }
+
+ ///
+ /// Share the screenshot with a windows app
+ ///
+ ///
+ ///
+ ///
+ /// ExportInformation
public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails)
- {
- var exportInformation = new ExportInformation(Designation, Description);
- try
- {
- var handle = PluginUtils.Host.GreenshotForm.Handle;
+ {
+ var exportInformation = new ExportInformation(Designation, Description);
+ try
+ {
+ var triggerWindow = new Window
+ {
+ WindowState = WindowState.Normal,
+ WindowStartupLocation = WindowStartupLocation.CenterScreen,
+ Width = 400,
+ Height = 400
+ };
- var exportTarget = Task.Run(async () =>
- {
- var taskCompletionSource = new TaskCompletionSource();
+ triggerWindow.Show();
+ var shareInfo = new ShareInfo();
- using var imageStream = new MemoryRandomAccessStream();
- using var logoStream = new MemoryRandomAccessStream();
- using var thumbnailStream = new MemoryRandomAccessStream();
- var outputSettings = new SurfaceOutputSettings();
- outputSettings.PreventGreenshotFormat();
-
- // Create capture for export
- ImageOutput.SaveToStream(surface, imageStream, outputSettings);
- imageStream.Position = 0;
- Log.Info("Created RandomAccessStreamReference for the image");
- var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream);
- RandomAccessStreamReference thumbnailRandomAccessStreamReference;
- RandomAccessStreamReference logoRandomAccessStreamReference;
-
- // Create thumbnail
- using (var tmpImageForThumbnail = surface.GetImageForExport())
+ // This is a bad trick, but don't know how else to do it.
+ // Wait for the focus to return, and depending on the state close the window!
+ triggerWindow.WindowMessages()
+ .Where(m => m.Message == WindowsMessages.WM_SETFOCUS).Delay(TimeSpan.FromSeconds(1))
+ .Subscribe(info =>
{
- using var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160);
- ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
- thumbnailStream.Position = 0;
- thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream);
- Log.Info("Created RandomAccessStreamReference for the thumbnail");
- }
- // Create logo
- using (var logo = GreenshotResources.getGreenshotIcon().ToBitmap())
- {
- using var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30);
- ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
- logoStream.Position = 0;
- logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream);
- Log.Info("Created RandomAccessStreamReference for the logo");
- }
- string applicationName = null;
- var dataTransferManagerHelper = new DataTransferManagerHelper(handle);
- dataTransferManagerHelper.DataTransferManager.TargetApplicationChosen += (dtm, args) =>
- {
- Log.InfoFormat("Trying to share with {0}", args.ApplicationName);
- applicationName = args.ApplicationName;
- };
- var filename = FilenameHelper.GetFilename(OutputFormat.png, captureDetails);
- var storageFile = await StorageFile.CreateStreamedFileAsync(filename, async streamedFileDataRequest =>
- {
- // Information on how was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/
- Log.DebugFormat("Creating deferred file {0}", filename);
- try
+ if (shareInfo.ApplicationName != null)
{
- using (var deferredStream = streamedFileDataRequest.AsStreamForWrite())
- {
- await imageStream.CopyToAsync(deferredStream).ConfigureAwait(false);
- await imageStream.FlushAsync().ConfigureAwait(false);
- }
- // Signal that the stream is ready
- streamedFileDataRequest.Dispose();
+ return;
}
- catch (Exception)
- {
- streamedFileDataRequest.FailAndClose(StreamedFileFailureMode.Incomplete);
- }
- // Signal transfer ready to the await down below
- taskCompletionSource.TrySetResult(applicationName);
- }, imageRandomAccessStreamReference).AsTask().ConfigureAwait(false);
-
- dataTransferManagerHelper.DataTransferManager.DataRequested += (sender, args) =>
+
+ shareInfo.ShareTask.TrySetResult(false);
+ });
+ var windowHandle = new WindowInteropHelper(triggerWindow).Handle;
+
+ Share(shareInfo, windowHandle, surface, captureDetails).GetAwaiter().GetResult();
+ Log.Debug("Sharing finished, closing window.");
+ triggerWindow.Close();
+ if (string.IsNullOrWhiteSpace(shareInfo.ApplicationName))
+ {
+ exportInformation.ExportMade = false;
+ }
+ else
+ {
+ exportInformation.ExportMade = true;
+ exportInformation.DestinationDescription = shareInfo.ApplicationName;
+ }
+ }
+ catch (Exception ex)
+ {
+ exportInformation.ExportMade = false;
+ exportInformation.ErrorMessage = ex.Message;
+ }
+
+ ProcessExport(exportInformation, surface);
+ return exportInformation;
+
+ }
+ ///
+ /// Share the surface by using the Share-UI of Windows 10
+ ///
+ /// ShareInfo
+ /// IntPtr with the handle for the hosting window
+ /// ISurface with the bitmap to share
+ /// ICaptureDetails
+ /// Task with string, which describes the application which was used to share with
+ private async Task Share(ShareInfo shareInfo, IntPtr handle, ISurface surface, ICaptureDetails captureDetails)
+ {
+ using (var imageStream = new MemoryRandomAccessStream())
+ using (var logoStream = new MemoryRandomAccessStream())
+ using (var thumbnailStream = new MemoryRandomAccessStream())
+ {
+ var outputSettings = new SurfaceOutputSettings();
+ outputSettings.PreventGreenshotFormat();
+
+ // Create capture for export
+ ImageOutput.SaveToStream(surface, imageStream, outputSettings);
+ imageStream.Position = 0;
+ Log.Debug("Created RandomAccessStreamReference for the image");
+ var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream);
+
+ // Create thumbnail
+ RandomAccessStreamReference thumbnailRandomAccessStreamReference;
+ using (var tmpImageForThumbnail = surface.GetImageForExport())
+ using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160))
+ {
+ ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings);
+ thumbnailStream.Position = 0;
+ thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream);
+ Log.Debug("Created RandomAccessStreamReference for the thumbnail");
+ }
+
+ // Create logo
+ RandomAccessStreamReference logoRandomAccessStreamReference;
+ using (var logo = GreenshotResources.getGreenshotIcon().ToBitmap())
+ using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30))
+ {
+ ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings);
+ logoStream.Position = 0;
+ logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream);
+ Log.Info("Created RandomAccessStreamReference for the logo");
+ }
+
+ var dataTransferManagerHelper = new DataTransferManagerHelper(handle);
+ dataTransferManagerHelper.DataTransferManager.ShareProvidersRequested += (sender, args) =>
+ {
+ shareInfo.AreShareProvidersRequested = true;
+ Log.DebugFormat("Share providers requested: {0}", string.Join(",", args.Providers.Select(p => p.Title)));
+ };
+ dataTransferManagerHelper.DataTransferManager.TargetApplicationChosen += (dtm, args) =>
+ {
+ shareInfo.ApplicationName = args.ApplicationName;
+ Log.DebugFormat("TargetApplicationChosen: {0}", args.ApplicationName);
+ };
+ var filename = FilenameHelper.GetFilename(OutputFormat.png, captureDetails);
+ var storageFile = await StorageFile.CreateStreamedFileAsync(filename, async streamedFileDataRequest =>
+ {
+ shareInfo.IsDeferredFileCreated = true;
+ // Information on the "how" was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/
+ Log.DebugFormat("Creating deferred file {0}", filename);
+ try
{
- var deferral = args.Request.GetDeferral();
- args.Request.Data.OperationCompleted += (dp, eventArgs) =>
+ using (var deferredStream = streamedFileDataRequest.AsStreamForWrite())
+ {
+ await imageStream.CopyToAsync(deferredStream).ConfigureAwait(false);
+ await imageStream.FlushAsync().ConfigureAwait(false);
+ }
+ // Signal that the stream is ready
+ streamedFileDataRequest.Dispose();
+ // Signal that the action is ready, bitmap was exported
+ shareInfo.ShareTask.TrySetResult(true);
+ }
+ catch (Exception)
+ {
+ streamedFileDataRequest.FailAndClose(StreamedFileFailureMode.Incomplete);
+ }
+ }, imageRandomAccessStreamReference).AsTask().ConfigureAwait(false);
+
+ dataTransferManagerHelper.DataTransferManager.DataRequested += (dataTransferManager, dataRequestedEventArgs) =>
+ {
+ var deferral = dataRequestedEventArgs.Request.GetDeferral();
+ try
+ {
+ shareInfo.IsDataRequested = true;
+ Log.DebugFormat("DataRequested with operation {0}", dataRequestedEventArgs.Request.Data.RequestedOperation);
+ var dataPackage = dataRequestedEventArgs.Request.Data;
+ dataPackage.OperationCompleted += (dp, eventArgs) =>
{
Log.DebugFormat("OperationCompleted: {0}, shared with", eventArgs.Operation);
- taskCompletionSource.TrySetResult(applicationName);
+ shareInfo.CompletedWithOperation = eventArgs.Operation;
+ shareInfo.AcceptedFormat = eventArgs.AcceptedFormatId;
+
+ shareInfo.ShareTask.TrySetResult(true);
+ };
+ dataPackage.Destroyed += (dp, o) =>
+ {
+ shareInfo.IsDestroyed = true;
+ Log.Debug("Destroyed");
+ shareInfo.ShareTask.TrySetResult(true);
+ };
+ dataPackage.ShareCompleted += (dp, shareCompletedEventArgs) =>
+ {
+ shareInfo.IsShareCompleted = true;
+ Log.Debug("ShareCompleted");
+ shareInfo.ShareTask.TrySetResult(true);
};
- var dataPackage = args.Request.Data;
dataPackage.Properties.Title = captureDetails.Title;
dataPackage.Properties.ApplicationName = "Greenshot";
dataPackage.Properties.Description = "Share a screenshot";
dataPackage.Properties.Thumbnail = thumbnailRandomAccessStreamReference;
dataPackage.Properties.Square30x30Logo = logoRandomAccessStreamReference;
dataPackage.Properties.LogoBackgroundColor = Color.FromArgb(0xff, 0x3d, 0x3d, 0x3d);
- dataPackage.SetStorageItems(new List { storageFile });
+ dataPackage.SetStorageItems(new[] {storageFile});
dataPackage.SetBitmap(imageRandomAccessStreamReference);
- dataPackage.Destroyed += (dp, o) =>
- {
- Log.Debug("Destroyed.");
- };
+ }
+ finally
+ {
deferral.Complete();
- };
- dataTransferManagerHelper.ShowShareUi();
- return await taskCompletionSource.Task.ConfigureAwait(false);
- }).Result;
- if (string.IsNullOrWhiteSpace(exportTarget))
- {
- exportInformation.ExportMade = false;
- }
- else
- {
- exportInformation.ExportMade = true;
- exportInformation.DestinationDescription = exportTarget;
- }
- }
- catch (Exception ex)
- {
- exportInformation.ExportMade = false;
- exportInformation.ErrorMessage = ex.Message;
- }
-
- ProcessExport(exportInformation, surface);
- return exportInformation;
-
- }
- }
+ Log.Debug("Called deferral.Complete()");
+ }
+ };
+ dataTransferManagerHelper.ShowShareUi();
+ Log.Debug("ShowShareUi finished.");
+ await shareInfo.ShareTask.Task.ConfigureAwait(false);
+ }
+ }
+ }
}