Delayed Rendering of Clipboard Data

Programs such as Word use multiple Clipboard formats and copying them all to the Clipboard whenever copy or cut options are selected will be a waste as it's unlikely that all of them would be used at once.

Windows provides an intelligent alternative to simply copy all the data on the Clipboard. An application sending data to the Clipboard can register the Clipboard format without passing any data. This is done by passing null as the handle to the data block when SetClipboardData () is called. The effect of passing a null handle is that the Clipboard doesn't recieve any data but it records that it will be provided with the data when it's needed.

For an example, you can set the null data handle for a CF_TEXT clipboard format:

OpenClipboard ();
EmptyClipboard ();
SetClipboardData (CF_TEXT, NULL);
CloseClipboard ();

When you need to paste that data into, say, Notepad, Windows recognizes that the CF_TEXT data needs to be loaded and it sends a WM_RENDERFORMAT message to the window that called SetClipboardData () with a null handle. The program then calls SetClipboardData () again, but this time passes a handle to a memory block containing the data. And then, Windows pastes the data into Notepad.

There is one situation that pops up when an application uses delayed rendering. That is what will happen when the application that's to supply the data is terminated before the Clipboard data is requested. In such a situation, the supplying program recieves a WM_RENDERALLFORMATS message before it terminates. The result is that the data is put in the Clipboard before the program terminates and is available to all other programs.

In the included project, the application displays a message when the Clipboard asks for the data to be copied to it. To see it, type some text in the edit box on the dialog box then click copy to Clipboard. Then, open Notepad and press Ctrl + V; at this time, the application will display a message.

The following code from the included project will make things clearer.

void CDelayedrenderingDlg::OnCopy() 
{
   //Open the Clipboard and then clear its contents
   OpenClipboard ();
   EmptyClipboard ();

   //Now, instead of the memory handle we pass NULL;
   //this indicates that the data will be made available
   //when the user requests it.
   SetClipboardData (CF_TEXT, NULL);
   CloseClipboard ();
}

void CDelayedrenderingDlg::OnRenderFormat (UINT nFormat)
{
   //Check whether the requested data is of type text
   if (nFormat == CF_TEXT)
   {
      //Get the data from the edit control and put it on the
      //Clipboard because the user has requested it
      CString strEditText;
      HANDLE hClipboard;
      LPTSTR lpszBuffer;

      (GetDlgItem (IDC_EDIT))->GetWindowText (strEditText);

      hClipboard = GlobalAlloc (GPTR, strEditText.GetLength () + 1);
      lpszBuffer = (LPTSTR) GlobalLock (hClipboard);
      _tcscpy (lpszBuffer, strEditText);
      GlobalUnlock (hClipboard);

      //Note that we don't open the Clipboard here because it's
      //already opened by the application that needs the data
      SetClipboardData (CF_TEXT, hClipboard);
      CloseClipboard ();
   }
   AfxMessageBox (_T("Data send to the clipboard"));
}

void CDelayedrenderingDlg::OnRenderAllFormats ()
{
   //The application recieves this message before it quits so
   //that the data could be put on the Clipboard

   //Get the data from the edit control and put it on the
   //Clipboard because the user has requested it
   CString strEditText;
   HANDLE hClipboard;
   LPTSTR lpszBuffer;

   //This time we need to open the Clipboard
   OpenClipboard ();
   EmptyClipboard ();

   (GetDlgItem (IDC_EDIT))->GetWindowText (strEditText);

   hClipboard = GlobalAlloc (GPTR, strEditText.GetLength () + 1);
   lpszBuffer = (LPTSTR) GlobalLock (hClipboard);
   _tcscpy (lpszBuffer, strEditText);
   GlobalUnlock (hClipboard);

   //Set the text on the Clipboard and then close it
   SetClipboardData (CF_TEXT, hClipboard);
   CloseClipboard ();
   AfxMessageBox (_T("Application terminating, so data copied to
                      Clipboard."));
}


Downloads

Comments

  • Why OnRenderFormat( ) be done when I copy string.

    Posted by bo60503 on 01/07/2006 02:26am

    When I copy string to the edit. The Message of 'Data send to the clipboard' apear. In the message_map have two function, I cann't understand. ON_WM_RENDERFORMAT() ON_WM_RENDERALLFORMATS()

    • Why OnRenderFormat( ) be done when I copy string

      Posted by logan on 01/07/2006 02:15pm

      When Windows sees that data needs to be pasted into notepad it sends a WM_RENDERFORMAT message to the application which called SetClipboardData () with a NULL handle. The program shows the message box to display this.
      
      When the application is about to quit Windows sends it a WM_RENDERALLFORMATS message so that it can set the data on the clipboard before it terminates.

      Reply
    Reply
  • BE CAREFUL WITH THIS CODE

    Posted by hollebeek on 01/04/2006 04:24pm

    This is *not* the way delayed rendering should be implemented, as it has a serious race condition. Image the sequence (1) copy, (2) modify edit box, (3) paste old copied text into notepad. A correct implementation will paste the copied text, but this version will paste the modified text. Beware of "optimizations" that break your application's behavior. WHENEVER you are using caching or delayed computation, ALWAYS think about race conditions and make sure your debug version has ASSERTs that guarantee the results are the same as the "straightforward" implementation.

    Reply
  • Nice one

    Posted by kirants on 01/03/2006 03:07pm

    first off, it's a nice article and it reveals how some applications could be doing storing multiple clipboard data ( read MS office ). 
    
    Some small things I wanted to mention:
    1. If one does Ctrl-C and assumes that this is the data copied, goes on to type more and then presses ctrl-v, the data used on renderformat will be the latest data and not data present at the time of doing a Ctrl-V. 
    
    2. Code:
    
    _tcscpy (lpszBuffer, strEditText);
    //Set the text on the clipboard and then close it
    SetClipboardData (CF_TEXT, hClipboard);
    is not good if using UNICODE build, since format specified is CF_TEXT, but data is unicode. It should be 
    
    Code:
    
    #ifdef _UNICODE
    _tcscpy (lpszBuffer, strEditText);
    //Set the text on the clipboard and then close it
    SetClipboardData (CF_UNICODETEXT, hClipboard);
    #else
    _tcscpy (lpszBuffer, strEditText);
    //Set the text on the clipboard and then close it
    SetClipboardData (CF_TEXT, hClipboard);
    #endif

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date