Search Unity

Resolved UWP Clipboard support

Discussion in 'Windows' started by tkumpumaki, May 15, 2020.

  1. tkumpumaki

    tkumpumaki

    Joined:
    Sep 26, 2018
    Posts:
    18
    Hi,

    I have been trying to get the clipboard work on UWP platform. I'm running on Windows desktop configuration with IL2CPP. 2019.3.13f1 editor.

    The problem is that neither the old user32.dll SetClipboardData() through windowsapp.lib or by using the new Windows.ApplicationModel.DataTransfer.Clipboard.SetContent(dataPackage) is working.

    The user32.dll SetClipboardData() seems not to be available in desktop mode.

    I tried the Windows.ApplicationModel.DataTransfer.Clipboard.SetContent(dataPackage) with the following code inside C# plugin dll:

    Code (CSharp):
    1.        
    2. public static void UWPPngBytesToClipboard(byte[] png)
    3. {
    4.     var dataPackage = new DataPackage();
    5.     using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
    6.     {
    7.         using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
    8.         {
    9.             writer.WriteBytes(png);
    10.         }
    11.         dataPackage.SetBitmap(RandomAccessStreamReference.CreateFromStream(ms));
    12.         dataPackage.RequestedOperation = DataPackageOperation.Copy;
    13.     }
    14.     Clipboard.Clear();
    15.     Clipboard.SetContent(dataPackage);
    16. }
    17.  
    Clipboard.Clear() or Clipboard.SetContent() just give System.Exception.

    Any ideas what to try next or is this more or less not supported?
     
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,674
    Which thread are you accessing Windows.ApplicationModel.DataTransfer.Clipboard from? I believe you need to run that code on the UI thread (not the main Unity thread).
     
  3. tkumpumaki

    tkumpumaki

    Joined:
    Sep 26, 2018
    Posts:
    18
    Running on UI thread fixed that exception. However, I haven't found a way to get image to paste anywhere.
     
  4. tkumpumaki

    tkumpumaki

    Joined:
    Sep 26, 2018
    Posts:
    18
    Got it working by writing into a temporary file. No matter what I tried with the InMemoryRandomAccessStream and png bytes, it just won't work.

    Note, in the following file must be available as long as the data in on clipboard.
    Code (CSharp):
    1.  
    2. UnityEngine.WSA.Application.InvokeOnUIThread( async () =>
    3. {
    4.     DataPackage dataPackage = new DataPackage();
    5.  
    6.     StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder;
    7.  
    8.     StorageFile tempFile = await temporaryFolder.CreateFileAsync("clipboard.png",
    9.                                                             CreationCollisionOption.ReplaceExisting);
    10.     await FileIO.WriteBytesAsync(tempFile, data);
    11.  
    12.     dataPackage.SetBitmap(RandomAccessStreamReference.CreateFromFile(tempFile));
    13.     Clipboard.SetContent(dataPackage);
    14. }, false);
    15.  
     
  5. tkumpumaki

    tkumpumaki

    Joined:
    Sep 26, 2018
    Posts:
    18
    Finally, found some magic dust that works.

    Code (CSharp):
    1.  
    2. public static void UWPPngToClipboard(byte[] data)
    3. {
    4.     UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
    5.     {
    6.         MemoryStream ms = new MemoryStream(data);
    7.  
    8.         var imageDecoder = await BitmapDecoder.CreateAsync(ms.AsRandomAccessStream());
    9.         var inMemoryStream = new InMemoryRandomAccessStream();
    10.         var imageEncoder = await BitmapEncoder.CreateForTranscodingAsync(inMemoryStream, imageDecoder);
    11.         await imageEncoder.FlushAsync();
    12.  
    13.         DataPackage dataPackage = new DataPackage();
    14.  
    15.         dataPackage.RequestedOperation = DataPackageOperation.Copy;              
    16.         dataPackage.SetBitmap(RandomAccessStreamReference.CreateFromStream(inMemoryStream));
    17.  
    18.         Clipboard.SetContent(dataPackage);
    19.     }, false);
    20. }
    21.