Nov 18, 2009

Silverlight Clipboard API

Clipboard API in Silverlight

Silverlight 4 adds Clipboard support. Check out the amazing demos by Scott Guthrie and Brian Goldfarb today at PDC that showcase scenarios enabled by Silveilght4 Clipboard support.

Silverlight’s Clipboard API is a subset of WPF’s Clipboard API: 

public static class Clipboard
{
public static bool ContainsText();
public static string GetText();
public static void SetText(string text);
}
It allows copy/paste Unicode strings to/from system clipboard. GetText and SetText require either of following to succeed:
  1. the calling Silverlight application is an elevated trust application, or
  2. it is user initiated and user grants clipboard access
For the second case, when GetText or SetText is first called in an user initiated event handling, Silverlight pops up a dialog like the one below (UI may change at RTW):
    Clipboard Prompt
    If user clicks yes, Silverlight will allow this and later GetText/SetText calls to succeed for this application during this session; if user clicks no, the default, Silverlight will throw a SecurityException. In another word, the setting is per application, per session, for both get and set access to system clipboard, and it is not persisted.

Clipboard API in JavaScript and WPF

We need to consider many factors while designing Clipboard API for Silverlight. Among them, the Clipboard APIs of JavaScript and WPF are particularly interesting, because we need to study the security lessons in JavaScript and try to be compatible with WPF.

There is no cross browser, cross platform JavaScript API for clipboard access. IE provides clipboardData object that allows get/set/clear strings in system clipboard:

bResult = window.clipboardData.setData(sDataFormat, sData);
sData = window.clipboardData.getData(sDataFormat);
bResult = window.clipboardData.clearData([sDataFormat]);

where sDataFormat is a string constant of "Text" or "URL", sData is a string, and bResult is a Boolean.

The first time the clipboadData object is accessed, IE will prompt user to allow the script to access clipboard, and the setting is valid for the session only.

WPF’s Clipboard API supports more and extensible data format via IDataObject, and has helper functions for common formats like text, image, audio, and filedrop.

public static class Clipboard
{
// Methods
[SecurityCritical]
public static void Clear();
public static bool ContainsAudio();
public static bool ContainsData(string format);
public static bool ContainsFileDropList();
public static bool ContainsImage();
public static bool ContainsText();
public static bool ContainsText(TextDataFormat format);
public static Stream GetAudioStream();
public static object GetData(string format);
[SecurityCritical]
public static IDataObject GetDataObject();
public static StringCollection GetFileDropList();
public static BitmapSource GetImage();
public static string GetText();
public static string GetText(TextDataFormat format);
public static bool IsCurrent(IDataObject data);
public static void SetAudio(byte[] audioBytes);
public static void SetAudio(Stream audioStream);
public static void SetData(string format, object data);
[SecurityCritical]
public static void SetDataObject(object data);
[SecurityCritical]
public static void SetDataObject(object data, bool copy);
public static void SetFileDropList(StringCollection fileDropList);
public static void SetImage(BitmapSource image);
public static void SetText(string text);
public static void SetText(string text, TextDataFormat format);
}

Clipboard API in Windows and Mac OS X

Silverlight’s clipboard API is ultimately implemented on top of the clipboard APIs of the underlying operating system. Windows’ clipboard APIs are documented at MSDN, below excerpt gives an overview on how to set/get clipboard data:

Cut and Copy Operations

To place information on the clipboard, a window first clears any previous clipboard content by using the EmptyClipboard function. This function sends the WM_DESTROYCLIPBOARD message to the previous clipboard owner, frees resources associated with data on the clipboard, and assigns clipboard ownership to the window that has the clipboard open. To find out which window owns the clipboard, call the GetClipboardOwner function.

After emptying the clipboard, the window places data on the clipboard in as many clipboard formats as possible, ordered from the most descriptive clipboard format to the least descriptive. For each format, the window calls the SetClipboardData function, specifying the format identifier and a global memory handle. The memory handle can be NULL, indicating that the window renders the data on request. For more information, see Delayed Rendering.

Paste Operations

To retrieve paste information from the clipboard, a window first determines the clipboard format to retrieve. Typically, a window enumerates the available clipboard formats by using the EnumClipboardFormats function and uses the first format it recognizes. This method selects the best available format according to the priority set when the data was placed on the clipboard.

Alternatively, a window can use the GetPriorityClipboardFormat function. This function identifies the best available clipboard format according to a specified priority. A window that recognizes only one clipboard format can simply determine whether that format is available by using the IsClipboardFormatAvailable function.

After determining the clipboard format to use, a window calls the GetClipboardData function. This function returns the handle to a global memory object containing data in the specified format. A window can briefly lock the memory object in order to examine or copy the data. However, a window should not free the object or leave it locked for a long period of time.

For now, Silverlight Clipboard API only supports CF_UNICODETEXT format for copy/paste Unicode text to/from clipboard.

Mac OS X uses Pasteboard Manager. It is documented at Mac Dev Center. Below excerpt (with APIs added) gives an overview:

The copying application is responsible for placing copied or cut data onto the pasteboard:

  1. The user selects some data and invokes the Copy (or Cut) menu item.

  2. If the application doesn’t already have a reference to the Clipboard pasteboard, it creates one (PasteboardCreate).

  3. The application then takes ownership of the pasteboard and clears the current contents (PasteboardClear).

  4. The application assigns item IDs to the selected data.

  5. If any data is to be promised, the application must register a promise keeper callback function to supply the promised data (PasteboardSetPromiseKeeper).

  6. The application adds one or more flavors of each item to the pasteboard, including either the actual flavor data or a promise with each flavor (PasteboardPutItemFlavor).

The receiving application has a slightly different set of tasks to handle the Paste action:

  1. When the application becomes active, it checks to see if the pasteboard has been modified (PasteboardSynchronize). If so, it obtains a listing of the flavors on the pasteboard. If there are any flavors the application supports, it can enable its Paste menu item.

  2. The user invokes the Paste menu item.

  3. The application requests the item (or items) on the pasteboard in the flavors that it supports (PasteboardGetItemCount, PasteboardGetItemIdentifier, PasteboardCopyItemFlavors, PasteboardCopyItemFlavorData).

  4. If the pasted data is to be stored as a file, the receiving application needs to set a paste location before requesting any flavor data. In any other case, the receiving application doesn’t need to worry about whether the paste data was promised or not.

If the copying application’s promise keeper is called, the callback must do the following:

  • If the data is to be stored as a file, determine the paste location specified by the receiving application.

  • Generate or otherwise prepare the promised data for transfer.

  • If the promised data is not be stored as a file, add the flavor and data to the pasteboard. Otherwise, transfer the promised data to the specified file location.

Some time later, when the application quits, or when it no longer needs the pasteboard, the application can release the pasteboard reference.

As on Windows, Silverlight Clipboard API only uses kPasteboardClipboard and kUTTypeUTF16PlainText flavor to support copy/paste Unicode text to/from clipboard.

Feedback

We are excited to add clipboard support to Silverlight, and see all the important scenarios enabled by this simple API. I am interested in hearing your feedbacks, especially:

  • any security concerns over Silverlight clipboard API design and implementation
  • how important it is to add support for other data type/format, and in what priority order
  • how important it is to make the API extensible, like supporting IDataObject, allowing custom format/flavor and delayed rendering/promised data

Thanks!

-Ning

Technorati Tags: ,