@@ -34,10 +34,44 @@ public enum TextDataFormat
34
34
}
35
35
36
36
/// <summary>
37
- /// Initializes and closes a session using the Clipboard calling <see cref="OpenClipboard"/> and then <see cref="CloseClipboard"/> on
38
- /// disposal. This can be called multiple times in nested calls and will ensure the Clipboard is only opened and closed at the highest scope.
37
+ /// Static class with methods to interact with the Clipboard. This implementation relies exclusively on COM clipboard methods and does not use those from USER32.
39
38
/// </summary>
40
- /// <seealso cref="System.IDisposable"/>
39
+ /// <example>
40
+ /// Below are two examples of a direct and indirect way to manipulate the clipboard.
41
+ /// <code title="Using the NativeClipboard class to set single items.">// Set/get simple text
42
+ /// NativeClipboard.SetText(txt, Vanara.Windows.Shell.TextDataFormat.UnicodeText);
43
+ /// string getText = NativeClipboard.GetText(Vanara.Windows.Shell.TextDataFormat.UnicodeText);
44
+ ///
45
+ /// // Set/get format as text
46
+ /// NativeClipboard.SetData(Shell32.ShellClipboardFormat.CFSTR_FILENAMEW, @"C:\file1.txt");
47
+ /// string getFile = (string)NativeClipboard.GetData(Shell32.ShellClipboardFormat.CFSTR_FILENAMEW);
48
+ ///
49
+ /// // Set/get text, html and rtf formats
50
+ /// NativeClipboard.SetText("Test", htmlFragment, rtfText); // sets text, html and rtf formats
51
+ /// string html = NativeClipboard.GetText(Vanara.Windows.Shell.TextDataFormat.Html);
52
+ ///
53
+ /// // Set/get text, url and html formats for a url
54
+ /// NativeClipboard.SetUrl("https://microsoft.com", "Microsoft Home"); // sets text, url and html formats
55
+ /// string url = (string)NativeClipboard.GetData(Shell32.ShellClipboardFormat.CFSTR_INETURLW);
56
+ ///
57
+ /// // Set/get string arrays
58
+ /// NativeClipboard.SetData(CLIPFORMAT.CF_HDROP, new[] { @"C:\file1.txt", @"C:\file2.txt" });
59
+ /// string[] getFiles = (string[])NativeClipboard.GetData(CLIPFORMAT.CF_HDROP);
60
+ ///
61
+ /// // Set/get structures
62
+ /// NativeClipboard.SetData("MyRect", new RECT(1, 2, 3, 4));
63
+ /// var rect = NativeClipboard.GetData<RECT>("MyRect");
64
+ ///
65
+ /// // Set/get shell items
66
+ /// NativeClipboard.SetShellItems(new[] { @"C:\file1.txt", @"C:\file2.txt" }.Select(ShellItem.Open));
67
+ /// ShellItemArray getArray = NativeClipboard.GetShellItemArray();</code>
68
+ /// <code title="Indirect manipulation">// This model let's you place multiple formats at once on the clipboard
69
+ /// IDataObject ido = NativeClipboard.CreateEmptyDataObject();
70
+ /// ido.SetData(CLIPFORMAT.CF_UNICODETEXT, txt);
71
+ /// ido.SetData(Shell32.ShellClipboardFormat.CF_HTML, htmlFragment);
72
+ /// ido.SetData("MyRectFormat", new RECT(1, 2, 3, 4));
73
+ /// NativeClipboard.SetDataObject(ido);</code></example>
74
+ /// <seealso cref="System.IDisposable" />
41
75
public static class NativeClipboard
42
76
{
43
77
private const int stdRetryCnt = 5 ;
@@ -46,7 +80,6 @@ public static class NativeClipboard
46
80
private static ListenerWindow listener ;
47
81
[ ThreadStatic ]
48
82
private static bool oleInit = false ;
49
- private static IComDataObject writableDataObj ;
50
83
51
84
/// <summary>Occurs when whenever the contents of the Clipboard have changed.</summary>
52
85
public static event EventHandler ClipboardUpdate
@@ -119,27 +152,29 @@ static IComDataObject ReadOnlyDataObject
119
152
}
120
153
}
121
154
122
- /// <summary>Gets the writable data object.</summary>
123
- /// <value>The writable data object.</value>
124
155
static IComDataObject WritableDataObj
125
156
{
126
157
get
127
158
{
128
- if ( writableDataObj is null )
129
- SHCreateDataObject ( ppv : out writableDataObj ) . ThrowIfFailed ( ) ;
159
+ SHCreateDataObject ( ppv : out var writableDataObj ) . ThrowIfFailed ( ) ;
130
160
return writableDataObj ;
131
161
}
132
162
set
133
163
{
134
164
Init ( ) ;
135
165
TryMultThenThrowIfFailed ( OleSetClipboard , value ) ;
166
+ Marshal . ReleaseComObject ( value ) ;
136
167
Flush ( ) ;
137
168
}
138
169
}
139
170
140
171
/// <summary>Clears the clipboard of any data or formatting.</summary>
141
172
public static void Clear ( ) => WritableDataObj = null ;
142
173
174
+ /// <summary>Creates an empty, writable data object.</summary>
175
+ /// <value>The data object.</value>
176
+ public static IComDataObject CreateEmptyDataObject ( ) => WritableDataObj ;
177
+
143
178
/// <summary>Enumerates the data formats currently available on the clipboard.</summary>
144
179
/// <returns>An enumeration of the data formats currently available on the clipboard.</returns>
145
180
/// <remarks>
@@ -157,7 +192,7 @@ static IComDataObject WritableDataObj
157
192
public static IEnumerable < uint > EnumAvailableFormats ( ) => ReadOnlyDataObject . EnumFormats ( ) . Select ( f => unchecked ( ( uint ) f . cfFormat ) ) ;
158
193
159
194
/// <summary>Carries out the clipboard shutdown sequence. It also releases any IDataObject instances that were placed on the clipboard.</summary>
160
- public static void Flush ( ) { Init ( ) ; TryMultThenThrowIfFailed ( OleFlushClipboard ) ; writableDataObj = null ; }
195
+ public static void Flush ( ) { Init ( ) ; TryMultThenThrowIfFailed ( OleFlushClipboard ) ; }
161
196
162
197
/// <summary>Retrieves the window handle of the current owner of the clipboard.</summary>
163
198
/// <returns>
@@ -474,6 +509,14 @@ public static void SetData(uint formatId, IEnumerable<string> values, StringList
474
509
public static void SetData ( string format , IEnumerable < string > values , StringListPackMethod packing = StringListPackMethod . Concatenated , CharSet charSet = CharSet . Auto ) =>
475
510
SetData ( RegisterFormat ( format ) , values , packing , charSet ) ;
476
511
512
+ /// <summary>
513
+ /// Places a specific data object onto the clipboard. This makes the data object accessible to the OleGetClipboard function.
514
+ /// </summary>
515
+ /// <param name="dataObj">
516
+ /// The IDataObject interface on the data object from which the data to be placed on the clipboard can be obtained.
517
+ /// </param>
518
+ public static void SetDataObject ( IComDataObject dataObj ) => WritableDataObj = dataObj ?? throw new ArgumentNullException ( nameof ( dataObj ) ) ;
519
+
477
520
/// <summary>Puts a list of shell items onto the clipboard.</summary>
478
521
/// <param name="shellItems">The sequence of shell items. The PIDL of each shell item must be absolute.</param>
479
522
public static void SetShellItems ( IEnumerable < ShellItem > shellItems ) => WritableDataObj = ( shellItems is ShellItemArray shia ? shia : new ShellItemArray ( shellItems ) ) . ToDataObject ( ) ;
0 commit comments