-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathModernShareHelper.cs
More file actions
169 lines (153 loc) · 6.74 KB
/
Copy pathModernShareHelper.cs
File metadata and controls
169 lines (153 loc) · 6.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// ModernShareHelper.cs — Public API for showing the Windows 10+ modern Share dialog. SBNET-1858
// This file is compiled only when targeting net6.0-windows10.0.17763.0 or later.
// Consumers can call ModernShareHelper.ShowShareUI() from a BeforeCommandExecute event
// to handle the "Windows.ModernShare" context menu verb.
#if WINDOWS10_0_17763_0_OR_GREATER
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
namespace Jam.Shell
{
/// <summary>
/// COM interface for IDataTransferManagerInterop, used to show the modern share dialog
/// from Win32 desktop applications. SBNET-1858
/// </summary>
[ComImport]
[Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IDataTransferManagerInterop
{
[PreserveSig]
int GetForWindow(
IntPtr appWindow,
ref Guid riid,
out IntPtr dataTransferManager);
[PreserveSig]
int ShowShareUIForWindow(IntPtr appWindow);
}
/// <summary>
/// Provides the Windows 10+ modern Share dialog for Win32 desktop applications.
/// Use this class to handle the <c>Windows.ModernShare</c> context menu verb,
/// which fails via plain <c>IContextMenu::InvokeCommand</c> from desktop apps.
/// </summary>
/// <remarks>
/// This class is only available when targeting <c>net6.0-windows10.0.17763.0</c> or later.
/// </remarks>
/// <example>
/// Handling the Share verb in a <see cref="ShellContextMenuProvider.BeforeCommandExecute"/> event:
/// <code>
/// shellBrowser.BeforeShellCommand += (sender, e) =>
/// {
/// if (e.Verb.Verb == "Windows.ModernShare")
/// {
/// e.Cancel = true;
/// ModernShareHelper.ShowShareUI(this.Handle, e.Paths.ToList());
/// }
/// };
/// </code>
/// </example>
public static class ModernShareHelper
{
private static readonly Guid s_DataTransferManagerIid =
new Guid("A5CAEE9B-8708-49D1-8D36-67D25A8DA00C");
/// <summary>
/// Determines whether the given verb string is the modern share verb.
/// </summary>
/// <param name="verb">The context menu verb to check.</param>
/// <returns><c>true</c> if the verb is <c>Windows.ModernShare</c>; <c>false</c> otherwise.</returns>
public static bool IsModernShareVerb(string verb)
{
return string.Equals(verb, "Windows.ModernShare", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Shows the Windows 10+ modern Share dialog for the given window handle,
/// sharing the specified file system paths.
/// </summary>
/// <param name="hwnd">The window handle to associate the share dialog with.</param>
/// <param name="filePaths">The file system paths to share.</param>
/// <returns><c>true</c> if the share dialog was shown successfully; <c>false</c> otherwise.</returns>
public static bool ShowShareUI(IntPtr hwnd, IReadOnlyList<string> filePaths)
{
if (filePaths == null || filePaths.Count == 0)
return false;
try
{
// Get the IDataTransferManagerInterop COM interface from the activation factory.
var interop = DataTransferManager.As<IDataTransferManagerInterop>();
// Get the DataTransferManager for this window via raw COM.
Guid dtmIid = s_DataTransferManagerIid;
int hr = interop.GetForWindow(hwnd, ref dtmIid, out IntPtr dtmPtr);
if (hr < 0 || dtmPtr == IntPtr.Zero)
return false;
var dataTransferManager = DataTransferManager.FromAbi(dtmPtr);
Marshal.Release(dtmPtr);
// Subscribe to DataRequested to provide files when the share UI asks for them.
dataTransferManager.DataRequested += (sender, args) =>
{
var request = args.Request;
var data = request.Data;
data.Properties.Title = "Share";
var storageItems = new List<IStorageItem>();
foreach (string path in filePaths)
{
try
{
if (System.IO.Directory.Exists(path))
{
var folder = StorageFolder
.GetFolderFromPathAsync(path)
.AsTask().GetAwaiter().GetResult();
storageItems.Add(folder);
}
else if (System.IO.File.Exists(path))
{
var file = StorageFile
.GetFileFromPathAsync(path)
.AsTask().GetAwaiter().GetResult();
storageItems.Add(file);
}
}
catch (Exception ex)
{
Debug.WriteLine(
"ModernShareHelper: Could not add item '" + path + "': " + ex.Message);
}
}
if (storageItems.Count > 0)
{
data.SetStorageItems(storageItems);
}
else
{
request.FailWithDisplayText("No shareable files found.");
}
};
// Now show the share UI.
hr = interop.ShowShareUIForWindow(hwnd);
return hr >= 0;
}
catch (Exception ex)
{
Debug.WriteLine("ModernShareHelper.ShowShareUI failed: " + ex.Message);
return false;
}
}
/// <summary>
/// Shows the Windows 10+ modern Share dialog for the given window handle,
/// sharing the specified file system paths.
/// </summary>
/// <param name="hwnd">The window handle to associate the share dialog with.</param>
/// <param name="filePaths">The file system paths to share.</param>
/// <returns><c>true</c> if the share dialog was shown successfully; <c>false</c> otherwise.</returns>
public static bool ShowShareUI(IntPtr hwnd, params string[] filePaths)
{
return ShowShareUI(hwnd, (IReadOnlyList<string>)filePaths);
}
}
}
#endif