12
12
using System . Runtime . InteropServices ;
13
13
using System . Text . Json ;
14
14
using System . Windows . Forms . Primitives ;
15
+ using System . Windows . Forms . TestUtilities ;
15
16
using Windows . Win32 . System . Ole ;
16
17
using static System . Windows . Forms . Tests . BinaryFormatUtilitiesTests ;
17
18
using static System . Windows . Forms . TestUtilities . DataObjectTestHelpers ;
@@ -23,7 +24,8 @@ namespace System.Windows.Forms.Tests;
23
24
// Note: each registered Clipboard format is an OS singleton
24
25
// and we should not run this test at the same time as other tests using the same format.
25
26
[ Collection ( "Sequential" ) ]
26
- [ UISettings ( MaxAttempts = 3 ) ] // Try up to 3 times before failing.
27
+ // Try up to 3 times before failing.
28
+ [ UISettings ( MaxAttempts = 3 ) ]
27
29
public class ClipboardTests
28
30
{
29
31
#pragma warning disable WFDEV005 // Type or member is obsolete
@@ -1110,14 +1112,19 @@ public void Clipboard_CustomDataObject_AvoidBinaryFormatter(bool copy)
1110
1112
// Pasting in different process has been simulated. Manual Json deserialization will need to occur.
1111
1113
IDataObject received = Clipboard . GetDataObject ( ) . Should ( ) . BeAssignableTo < IDataObject > ( ) . Subject ;
1112
1114
received . Should ( ) . NotBe ( jsonDataObject ) ;
1115
+ received . Should ( ) . BeAssignableTo < ITypedDataObject > ( ) ;
1113
1116
byte [ ] jsonBytes = Clipboard . GetData ( format ) . Should ( ) . BeOfType < byte [ ] > ( ) . Subject ;
1114
1117
JsonSerializer . Deserialize ( jsonBytes , typeof ( SimpleTestData ) ) . Should ( ) . BeEquivalentTo ( data ) ;
1118
+ received . TryGetData ( format , out byte [ ] ? jsonBytes1 ) . Should ( ) . BeTrue ( ) ;
1119
+ jsonBytes1 . Should ( ) . BeEquivalentTo ( jsonBytes ) ;
1115
1120
}
1116
1121
else
1117
1122
{
1118
1123
JsonDataObject received = Clipboard . GetDataObject ( ) . Should ( ) . BeOfType < JsonDataObject > ( ) . Subject ;
1119
1124
received . Should ( ) . Be ( jsonDataObject ) ;
1120
1125
received . Deserialize < SimpleTestData > ( format ) . Should ( ) . BeEquivalentTo ( data ) ;
1126
+ Action tryGetData = ( ) => received . TryGetData ( format , out byte [ ] ? _ ) ;
1127
+ tryGetData . Should ( ) . Throw < NotSupportedException > ( ) ;
1121
1128
}
1122
1129
}
1123
1130
@@ -1288,4 +1295,90 @@ public class SomeDataObject : DataObject
1288
1295
public override bool GetDataPresent ( string format , bool autoConvert )
1289
1296
=> format == Format || base . GetDataPresent ( format , autoConvert ) ;
1290
1297
}
1298
+
1299
+ [ WinFormsTheory ]
1300
+ [ BoolData ]
1301
+ public void Clipboard_RoundTrip_DataObject_SupportsTypedInterface ( bool copy ) =>
1302
+ CustomDataObject_RoundTrip_SupportsTypedInterface < DataObject > ( copy ) ;
1303
+
1304
+ [ WinFormsTheory ]
1305
+ [ BoolData ]
1306
+ public void Clipboard_RoundTrip_ManagedAndRuntimeDataObject_SupportsTypedInterface ( bool copy ) =>
1307
+ CustomDataObject_RoundTrip_SupportsTypedInterface < ManagedAndRuntimeDataObject > ( copy ) ;
1308
+
1309
+ [ WinFormsTheory ]
1310
+ [ BoolData ]
1311
+ public void Clipboard_RoundTrip_TypedAndRuntimeDataObject_SupportsTypedInterface ( bool copy ) =>
1312
+ CustomDataObject_RoundTrip_SupportsTypedInterface < TypedAndRuntimeDataObject > ( copy ) ;
1313
+
1314
+ [ WinFormsTheory ]
1315
+ [ BoolData ]
1316
+ public void Clipboard_RoundTrip_TypedDataObject_SupportsTypedInterface ( bool copy ) =>
1317
+ CustomDataObject_RoundTrip_SupportsTypedInterface < TypedDataObject > ( copy ) ;
1318
+
1319
+ [ WinFormsTheory ]
1320
+ [ BoolData ]
1321
+ public void Clipboard_RoundTrip_ManagedDataObject_SupportsTypedInterface ( bool copy ) =>
1322
+ CustomDataObject_RoundTrip_SupportsTypedInterface < ManagedDataObject > ( copy ) ;
1323
+
1324
+ [ WinFormsTheory ]
1325
+ [ BoolData ]
1326
+ public void Clipboard_RoundTrip_Object_SupportsTypedInterface ( bool copy )
1327
+ {
1328
+ SerializableTestData data = new ( ) ;
1329
+ string format = typeof ( SerializableTestData ) . FullName ! ;
1330
+
1331
+ // Opt-in into access to the binary formatted stream.
1332
+ using BinaryFormatterInClipboardDragDropScope clipboardScope = new ( enable : true ) ;
1333
+ // We need the BinaryFormatter to flush the data from the managed object to the HGLOBAL
1334
+ // and to write data to HGLOBAL as a binary formatted stream now if it hadn't been flushed.
1335
+ using BinaryFormatterScope scope = new ( enable : true ) ;
1336
+
1337
+ Clipboard . SetDataObject ( data , copy ) ;
1338
+
1339
+ DataObject received = Clipboard . GetDataObject ( ) . Should ( ) . BeOfType < DataObject > ( ) . Subject ;
1340
+
1341
+ received . TryGetData ( format , out SerializableTestData ? result ) . Should ( ) . BeTrue ( ) ;
1342
+ result . Should ( ) . BeEquivalentTo ( data ) ;
1343
+
1344
+ Clipboard . TryGetData ( format , out result ) . Should ( ) . BeTrue ( ) ;
1345
+ result . Should ( ) . BeEquivalentTo ( data ) ;
1346
+ }
1347
+
1348
+ private static void CustomDataObject_RoundTrip_SupportsTypedInterface < T > ( bool copy ) where T : IDataObject , new ( )
1349
+ {
1350
+ SerializableTestData data = new ( ) ;
1351
+ T testDataObject = new ( ) ;
1352
+ string format = ManagedDataObject . s_format ;
1353
+ testDataObject . SetData ( format , data ) ;
1354
+
1355
+ // Opt-in into access the binary formatted stream.
1356
+ using BinaryFormatterInClipboardDragDropScope clipboardScope = new ( enable : copy ) ;
1357
+ // We need the BinaryFormatter to flush the data from the managed object to the HGLOBAL.
1358
+ using ( BinaryFormatterScope scope = new ( enable : copy ) )
1359
+ {
1360
+ Clipboard . SetDataObject ( testDataObject , copy ) ;
1361
+ }
1362
+
1363
+ // copy == true => data was flushed to HGLOBAL and we read it with a WinForms DataObject.
1364
+ // Otherwise this is the user-implemented ITypedDataObject or the WinForms wrapper.
1365
+ if ( copy || typeof ( T ) . IsAssignableTo ( typeof ( ITypedDataObject ) ) )
1366
+ {
1367
+ ITypedDataObject received = Clipboard . GetDataObject ( ) . Should ( ) . BeAssignableTo < ITypedDataObject > ( ) . Subject ;
1368
+
1369
+ received . TryGetData ( format , out SerializableTestData ? result ) . Should ( ) . BeTrue ( ) ;
1370
+ result . Should ( ) . BeEquivalentTo ( data ) ;
1371
+
1372
+ Clipboard . TryGetData ( format , out result ) . Should ( ) . BeTrue ( ) ;
1373
+ result . Should ( ) . BeEquivalentTo ( data ) ;
1374
+ }
1375
+ else
1376
+ {
1377
+ T received = Clipboard . GetDataObject ( ) . Should ( ) . BeOfType < T > ( ) . Subject ;
1378
+ received . Should ( ) . Be ( testDataObject ) ;
1379
+ // When we are not flushing the data to the HGLOBAL, we are reading from our DataStore or the managed test data object.
1380
+ Action tryGetData = ( ) => received . TryGetData ( format , out SerializableTestData ? result ) ;
1381
+ tryGetData . Should ( ) . Throw < NotSupportedException > ( ) ;
1382
+ }
1383
+ }
1291
1384
}
0 commit comments