Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using the Clipboard, Part I: Transferring Simple Text

0.00/5 (No votes)
6 May 2002 1  
In this first article of a four-part series on learning everything you ever wanted to know about programming the Windows Clipboard, you'll discover the basic steps of using the Clipboard API to transfer simple (ANSI) text to and from the Clipboard.

Sample image

With just a few lines of code, you can easily add Clipboard functionality to your application.

Introduction

In this first instalment of a four-part series of articles on programmatically transferring data to and from the Windows Clipboard, I'll explain the basic steps of using the Clipboard using the Clipboard API. After I've gone over the basics steps, which are used no matter what data format is on the Clipboard, I'll present a demo application that illustrates how to programmatically transfer simple (ANSI) text to and from the Clipboard.

Using the Windows Clipboard API

There are actually two distinct mechanisms for interfacing to the Clipboard. The first involves using the Windows Clipboard API and the second uses OLE. Since the Clipboard API is by far the most common method used, most of the demos in this little series will use this technique. If you're familiar with the Windows API - especially the means by which memory is allocated via the GlobalAlloc and GlobalLock functions - the steps needed to use the Clipboard will be all the easier to learn. Another thing to realize at this point is that regardless of the type of data being transferred to the clipboard, the same basic programmatic steps are taken any time you are transferring data to or from the Clipboard. Figure 1 shows these steps in a standard UML Sequence Diagram with the subsequent sections going into more detail about each step.

UML Sequence diagram

Figure 1: These are the standard steps used to transfer data to the Clipboard using the Windows Clipboard API.

Allocating Memory for Your Data

The verbiage "placing data on the Clipboard" is really a misnomer as the Clipboard is not some sort of global data buffer. Actually, the Clipboard is little more than a handle to a data buffer that is created and maintained by the application that is making this data available for other applications. Since the data must be accessible from all processes, the Windows API functions, GlobalAlloc and GlobalLock, are used.

As a quick refresher, here is the syntax for these two functions and how they work:

The GlobalAlloc function is used to allocate a global block of memory that will hold the entirety of the data being made available via the Clipboard.

HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes)

The uFlags parameter is used to specify to Windows how the memory is to be allocated. If you specify a value of 0 (or NULL), then a value of GMEM_FIXED is assumed. The valid values for this parameter are in the Table 1 and can be combined with the logical or operator.

Table 1 - GlobalAlloc flags

uFlag Value Description
GHND Same as GMEM_MOVEABLE | GMEM_ZEROINT
GMEM_FIXED The default value, this allocated a block of fixed (i.e., non-moveable) memory. The return value from GlobalAlloc when specifying GMEM_FIXED is a pointer.
GMEM_MOVEABLE In Windows, memory blocks are never moved in physical memory. However, the can be moved within the default heap. Therefore, the return value when specifying GMEM_MOVEABLE is a handle to the memory.
GPTR This value combines GMEM_FIXED and GMEM_ZEROINT, the later simply initializing the allocated memory to all zeroes.

Note - Since specifying a value of GMEM_FIXED for the uFlag parameter to the GlobalAlloc call will return a pointer while specifying GMEM_MOVEABLE will return a handle, these two values are mutually exclusive.

The parameter dwBytes is a double word that enables you to specify how large a buffer you wish to allocate.

The second function that you need to call to allocate the memory for your data is the Windows API function, GlobalLock.

LPVOID GlobalLock(HGLOBAL hMem)

This function is very straight-forward and takes as its only parameter a handle returned from the GlobalAlloc function.

Copy the Data into the Global Memory

Once you've allocated the global memory and have obtained a pointer to it, you can copy the desired data into that global memory buffer. How you do this will depend on what type of data you're transferring so I'll go into more detail about this step in the three demos that follow this article.

Unlock the Global Memory

This is a very important, yet often overlooked step in the process. According to the Windows documentation, once you've allocated the memory and inserted the data to be made public to other processes, you are not to touch this memory again. The reason is simple. Once you've made the Clipboard mechanism aware of the new data (next step), Windows will now have control over that memory and any further tampering with it on your end might very well invalidate the integrity of the data.

To unlock the global memory block, make a call to the GlobalUnlock API function. Here's the very simple syntax for this function where the hMem parameter is the handle returned from the GlobalAlloc function.

BOOL GlobalUnlock(HGLOBAL hMem)

Open the Clipboard

The OpenClipboard function enables you to lock the Clipboard so that no other processes can modify its contents as you are attempting to access that data. This function's syntax is as follows:

BOOL OpenClipboard(HWND hWndNewOwner)

The hWndNewOwner simply allows you to associate the open Clipboard with a given window. If you don't need to do this (most don't), simply leave specify a value of NULL for this parameter, in which case, Windows will associate the open Clipboard with the current task. All of the demos in this book will use this latter technique as I've personally never seen too many situations where an association with a specific window was needed.

Empty the Clipboard

This step is needed to initialized the Clipboard and is accomplished via the EmptyClipboard function. When you call this function, Windows releases the global memory associated with the Clipboard. If you'll remember, earlier I said that Windows would be responsible for this task. Therefore, it is the responsibility of any application using the Clipboard to call this function in order to prevent memory leaks.

BOOL EmptyClipboard()

Note that you do not need to call a function to determine if any data exists prior to calling this function as this function will only return a nonzero value if the function fails. If it succeeds or if the Clipboard doesn't contain any data, the function returns zero (representing success).

Set the Clipboard Data

Finally, at this step, you set the Clipboard data. As mentioned earlier, the Clipboard really doesn't contain data, but simply maintains a global handle obtained (and populated) by your application. The function to perform this step is the SetClipboardData function. This is also the function that enables you to specify the format of the data being transferred (notice syntax below).

HANDLE SetClipboardData(UINT uFormat, HANDLE hMem)

The value you specify for the uFormat parameter must be either a standard Clipboard format (Table 2) or a registered format. Registered formats are user-defined formats that enable you to specify formats for application-specific data. We'll be getting into this format later on.

Table 2 - Standard Clipboard Formats

uFormat value hMem value
CF_BITMAP Handle to a bitmap (you'll see how to use this format in this article series' second demo)
CF_DIB Handle to a BITMAPINFO structure followed by the bits that constitute the bitmap
CF_DIBV5 Used in Windows 2000 only, this is also a handle to a BITMAPINFO structure where the subsequent bits represent the bitmap color information and the bitmap image.
CF_DIF Handle to a Software Arts' Data Interchange Format (SADIF) buffer
CF_DSPBITMAP Handle to a bitmap display format associated with an application-specific format. The data being pointed to must be data that can be displayed in bitmap format.
CF_DSPENHMETAFILE Handle to an enhanced metafile display format associated with a private format. In this case, the data must be displayable in enhanced metafile format in lieu of the privately formatted data.
CF_DSPMETAFILEPICT Handle to a metafile-picture display format associated with a private format. The data being pointed to must be displayable in metafile-picture format in lieu of the privately formatted data.
CF_DSPTEXT Handle to text display format associated with a private format. The data must be displayable in text format in lieu of the privately formatted data.
CF_ENHMETAFILE Handle to an enhanced metafile (HENHMETAFILE)
CF_GDIOBJFIRST through CF_GDIOBJLAST This range of integers represents application-defined GDI object clipboard formats. Note that the handles represented by these values are not automatically deleted using the GlobalFree function when the clipboard is emptied. Additionally, the hMem parameter is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_MOVEABLE flag.
CF_HDROP Handle to type HDROP that identifies a list of files being transferred via the Clipboard - typically used in drag & drop operations. The DragQueryFiles function is used to retrieve information about these files.
CF_LOCALE Handle to the locale identifier associated with the text in the clipboard
CF_METAFILEPICT Handle to a metafile picture format (METAFILEPICT) structure
CF_OEMTEXT Handle to a text format containing characters in the OEM character set. In this format, each line must be terminated with a carriage return/linefeed (CR/LF) combination. A null character represents end of data (EOD) using this format.
CF_OWNERDISPLAY If an application specifies a uFormat value of CF_OWNERDISPLAY, the hMem value must be NULL. In addition, the application is then responsible for displaying and updating the Clipboard viewer window and handling the following messages: WM_ASKCBFORMATNAME, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_SIZECLIPBOARD, WM_VSCROLLCLIPBOARD.
CF_PALETTE Handle to a color palette.
CF_PENDATA Handle to data representing pen extensions for the Microsoft Windows for Pen Computing.
CF_PRIVATEFIRST through CF_PRIVATELAST Much like using the CF_GDIOBJFIRST-CF_GDIOBJLAST range, these integers represent a series of value for private Clipboard formats. Note once again that the data associated with these handles is not freed automatically and as such it is the application's responsibility to do such.
CF_RIFF Handle to an audio data format that is more complex than can be represented with the standard (WAV) format where the uFormat parameter is set to CF_WAVE.
CF_SYLK Handle to Microsoft Symbolic Link (SYLK) formatted data.
CF_TEXT Handle to standard text. Using this format, each line must be terminated with a carriage return/linefeed (CR-LF) combination. A null character denotes end of data (EOD). This is used for ANSI text whereas CF_UNICODETEXT is used for UNICODE text.
CF_WAVE Handle to the audio data in one of the standard wave formats: such as 11 kHz or 22 kHz pulse code modulation (PCM).
CF_TIFF Handle to tagged-image file (TIFF) formatted data
CF_UNICODETEXT For use with Windows NT/2000 or later, this format is used for UNICODE data as opposed to ANSI text (which is represented by the CF_TEXT value).

Close the Clipboard

When an application has finished examining or modifying the Clipboard data, the CloseClipboard function is called. This has the effect of unlocking the Clipboard so that other applications can have access to it.

BOOL CloseClipboard()

Demo to Transfer Simple Text

The first demo we'll start with will illustrate how to transfer text to and from the Clipboard. While this is not needed as much as it once was due to the Windows 2000/Me context menu (right-clicking over any edit control will result in a menu containing the standard Clipboard functions) there are still some very valid uses for this capability. One example is if you want to pass simple text-based data to another application. However, in order to keep the example as clean as possible, this demo will consist of a dialog with two edit controls. One edit control will enable you to type text into it and copy that text to the Clipboard while the second edit control will be a read-only control. A button will enable you to paste text from the Clipboard into this second control. By keeping the demo relatively simple, it's much easier for you to focus on the specifics of working with the Clipboard and it's also more convenient when you want to copy and paste the salient code from this demo into your own project files.

Creating the SimpleTextTransfer Demo Project

At this time, create a dialog-based application called SimpleTextTransfer. Once you've done that, modify the default dialog so that it looks like the one shown in Figure 2.

Figure 2

Figure 2: Simple dialog to test using the Clipboard to transfer standard ANSI text.

After you've modified the dialog, you'll need to make the following changes to the dialog's controls.

  • Set the Multiline property for both edit controls to True.
  • Set the AutoVScroll property for both edit controls to True.
  • Set the Vertical Scroll property for both edit controls to True.
  • Set the Readonly property for "from Clipboard" edit control to True.
  • Create a control member variable for each of the two edit controls. Name them m_edtToClipboard and m_edtFromClipboard, respectively.

Copying Text to the Clipboard

Once you've finished with the dialog controls' properties, add an event handler for the Copy button's BN_CLICKED message and modify it so that it looks like the following. I've placed comments throughout the code to make the code easy to understand.

void CSimpleTextTransferDlg::OnBnClickedBtncopy()
{
 if (UpdateData())
 {
  CString strData;
  m_edtToClipboard.GetWindowText(strData);

  // test to see if we can open the clipboard first before
  // wasting any cycles with the memory allocation
  if (OpenClipboard())
  {
   // Empty the Clipboard. This also has the effect
   // of allowing Windows to free the memory associated
   // with any data that is in the Clipboard
   EmptyClipboard();

   // Ok. We have the Clipboard locked and it's empty. 
   // Now let's allocate the global memory for our data.

   // Here I'm simply using the GlobalAlloc function to 
   // allocate a block of data equal to the text in the
   // "to clipboard" edit control plus one character for the
   // terminating null character required when sending
   // ANSI text to the Clipboard.
   HGLOBAL hClipboardData;
   hClipboardData = GlobalAlloc(GMEM_DDESHARE, 
                                strData.GetLength()+1);

   // Calling GlobalLock returns to me a pointer to the 
   // data associated with the handle returned from 
   // GlobalAlloc
   char * pchData;
   pchData = (char*)GlobalLock(hClipboardData);
		  
   // At this point, all I need to do is use the standard 
   // C/C++ strcpy function to copy the data from the local 
   // variable to the global memory.
   strcpy(pchData, LPCSTR(strData));
		  
   // Once done, I unlock the memory - remember you 
   // don't call GlobalFree because Windows will free the 
   // memory automatically when EmptyClipboard is next 
   // called. 
   GlobalUnlock(hClipboardData);
		  
   // Now, set the Clipboard data by specifying that 
   // ANSI text is being used and passing the handle to
   // the global memory.
   SetClipboardData(CF_TEXT,hClipboardData);
		  
   // Finally, when finished I simply close the Clipboard
   // which has the effect of unlocking it so that other
   // applications can examine or modify its contents.
   CloseClipboard();
  }
 }
}

Cutting Text to the Clipboard

As you might have guessed, the only difference between copying data to the Clipboard and cutting it to the Clipboard is that in the latter case, the data is removed after the transfer takes place. Therefore, at this point, add an event handler for the Cut button's BN_CLICKED message. Once you've done that, modify that handler so that it looks as follows:

void CSimpleTextTransferDlg::OnBnClickedBtncut()
{
 OnBnClickedBtncopy();
 m_edtToClipboard.SetWindowText("");
}

Pasting Text from the Clipboard

At this point, the application can place data on the clipboard, but it doesn't yet allow for the pasting of that data to the dialog. Therefore, we'll take care of that now.

As with the Copy and Cut buttons, add an event handler for the Paste button's BN_CLICKED message.

void CSimpleTextTransferDlg::OnBnClickedBtnpaste()
{
 // Test to see if we can open the clipboard first.
 if (OpenClipboard()) 
 {
  // Retrieve the Clipboard data (specifying that 
  // we want ANSI text (via the CF_TEXT value).
  HANDLE hClipboardData = GetClipboardData(CF_TEXT);

  // Call GlobalLock so that to retrieve a pointer
  // to the data associated with the handle returned
  // from GetClipboardData.
  char *pchData = (char*)GlobalLock(hClipboardData);

  // Set a local CString variable to the data
  // and then update the dialog with the Clipboard data
  CString strFromClipboard = pchData;
  m_edtFromClipboard.SetWindowText(strFromClipboard);

  // Unlock the global memory.
  GlobalUnlock(hClipboardData);

  // Finally, when finished I simply close the Clipboard
  // which has the effect of unlocking it so that other
  // applications can examine or modify its contents.
  CloseClipboard();
 }
}

Testing the SimpleTextTransfer Demo

At this point, compile and test the application. Your results should be similar to what you see in Figure 3.

Figure 3

Figure 3: With just a few lines of code, you can easily add Clipboard functionality to your application.

However, there is just one problem with our little test. If you click the <Alt><Print Screen> key combination, this copies a bitmap of the current window to the Clipboard. You can test this by opening the PaintBrush application and pasting the image into a new bitmap image. However, if you copy an image to the Clipboard and then click the Paste button on the demo application, the text in the "to clipboard" edit control is wiped out and nothing appears! This is because the demo is attempting to use the data on the Clipboard without first determining if the data is valid for this application.

In order to check as to the format of the data on the Clipboard, simply use the IsClipboardAvailable function.

BOOL IsClipboardFormatAvailable(UINT format)

The format parameter can be any value listed in Table 1. Here's the modified BN_CLICKED handler for the dialog's Paste button. I've bolded the lines that have changed from the previous incarnation of this function.

void CSimpleTextTransferDlg::OnBnClickedBtnpaste()
{
 // Test to see if we can open the clipboard first.
 if (OpenClipboard()) 
 {
  if (::IsClipboardFormatAvailable(CF_TEXT)
  || ::IsClipboardFormatAvailable(CF_OEMTEXT))
  {
    // Retrieve the Clipboard data (specifying that 
    // we want ANSI text (via the CF_TEXT value).
    HANDLE hClipboardData = GetClipboardData(CF_TEXT);

    // Call GlobalLock so that to retrieve a pointer
    // to the data associated with the handle returned
    // from GetClipboardData.
    char *pchData = (char*)GlobalLock(hClipboardData);

    // Set a local CString variable to the data
    // and then update the dialog with the Clipboard data
    CString strFromClipboard = pchData;
    m_edtFromClipboard.SetWindowText(strFromClipboard);

    // Unlock the global memory.
    GlobalUnlock(hClipboardData);
  }
  else
  { 
    AfxMessageBox("There is no text data (ANSI) on the Clipboard.");
  }

  // Finally, when finished I simply close the Clipboard
  // which has the effect of unlocking it so that other
  // applications can examine or modify its contents.
  CloseClipboard();
 }
}

Now, if you run this application, copy a bitmap (or any data that is not defined as CF_TEXT or CF_OEMTEXT) and press the demo's Paste button, you will see the message shown in Figure 4.

Figure 4

Figure 4: You should always check the format of the data on the Clipboard before attempting to use it.

Summary

In this first of a four-part series on programming the Windows Clipboard, you learned the basics of using the Windows API to transfer data to and from the Clipboard. You then put that new-found knowledge to work with a demo application using simple ANSI text. In the next instalment of this series, I'll go into sending and receiving bitmap images from and to the Clipboard.

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here