CS-360
Fall, 2000
Class 13
R. Eckert

THE CLIPBOARD

The Windows Clipboard provides a common mechanism for getting information
(especially text and graphics) from one application to another.

Many programs have an "Edit" menu item with "Cut", "Copy", and "Paste"
items. "Cut" or "Copy" should cause a program to transfer data to the
clipboard; "Paste" can get data from the clipboard.

The clipboard is a movable global memory block that Windows maintains.
Its contents are available to any running application.

The clipboard's memory block can only be accessed through a HANDLE--
which means that we must use the Win16 GlobalAlloc(), GlobalLock(),
GlobalUnlock(), and GlobalFree() functions.

The clipboard can also be used for single-program cut and paste
operations.

We can use the Windows application CLIPBRD.EXE to view the contents of 
the clipboard.

Windows keeps track of type of data stored as a "clipboard format"
(e.g., CF_TEXT for text data, CF_BITMAP for bitmaps). Custom formats
can be registered.

An application sends data to the clipboard by copying it into a global
memory block and transferring it to the Windows clipboard, which takes
control of the block. The block is said to be "in the clipboard."


SUMMARY OF THE MOST RELEVANT WINDOWS GLOBAL MEMORY MANIPULATION 
FUNCTIONS; HOW TO ALLOCATE AND USE GLOBAL MEMORY BLOCKS--

1. Get a handle to the block (HANDLE hMem):

   hMem = GlobalAlloc(allocation_flags, numbytes_to_allocate);

     allocation_flags: Bitwise OR of GMEM_MOVEABLE, GMEM_ZEROINIT, and
     others. The most common is GMEM_MOVEABLE|GMEM_ZEROINT. Since this is
     so common, windows.h defines the GHND constant to be equal to it.

     Returns a handle to the block that can be used in subsequent calls
     to functions that send data to the clipboard. If it couldn't
     allocate the block, it returns a 0.

2. Fix the block in memory and get a pointer to it:

   pBlock = GlobalLock(hMem);

     Now we can use the returned pointer to read/write data from/to the
     block of memory.

3. After we're all done accessing the block of memory, we must make it
movable again.

   GlobalUnlock(hMem);

     The block still exists and its contents are intact, but the pointer
     is no longer valid. The handle (hMem) can still be used to gain
     future access to the block.

4. When we want to get rid of the block,

   GlobalFree(hMem);

     which releases it from memory.


CLIPBOARD FUNCTIONS--

OpenClipboard(hWnd)-- Opens the Clipboard for access by the program.  Only
one application can open the clipboard at any given time. The function
returns FALSE if the call was unsuccessful; e.g., the clipboard was not
available--probably because it's being accessed by another application.

EmptyClipboard()-- Empties the clipboard memory block and frees all data
currently in the clipboard. It returns FALSE if the call was unsuccessful.

GetClipboardData(uFormat)-- Gets a handle to read-only data in the
Clipboard. The uFormat parameter specifies the data format. The function
returns NULL if the call was unsuccessful; i.e., clipboard doesn't contain
data in the specified format. The handle returned doesn't belong to your
program, so you can't free the block or change its data. If you need to
manipulate the data, copy it into a new block.

SetClipboardData(uFormat, hData)-- Passes the memory block whose handle is
specified to the clipboard. Windows takes control of the block. It returns
a handle to the data if the call was successful. The calling program can read
the data, but must not free the handle to the memory block or leave it unlocked.
Usually EmptyClipboard() is called before using this function to pass data to
the clipboard.

CloseClipboard()-- Closes the clipboard so that other programs can access it.
It returns FALSE if the call was unsuccessful.

Sending Data to the Clipboard (e.g., in Cut and Copy Operations)--

  1. Allocate and lock a global memory block.

  2. Copy the data into the global memory block.

  3. Unlock the block.

  4. Open the clipboard with OpenClipboard().

  5. Empty the current contents of the clipboard with EmptyClipboard().

  6. Transfer the block to the Clipboard with SetClipboardData().
     (Windows now controls the block.)

  7. Close the clipboard with CloseClipboard().
     (So other programs can access it.)

Remember that the data in the clipboard belongs to Windows, so the block
is read-only once it's in the clipboard.

Getting Data from the Clipboard (e.g., in Paste Operations)--

  1. Open the clipboard with OpenClipboard().

  2. Get a handle to the clipboard data with GetClipboardData().

  3. Allocate and lock a memory block to hold the clipboard data.

  4. Lock the clipboard data block.

  5. Copy the data from the clipboard data block to the program's data block.
     (The data can now be manipulated by the application.)

  6. Unlock both memory blocks.

  7. Close the clipboard with CloseClipboard().

Some Precautions in Using the Clipboard--

  Close the clipboard as soon as possible after you open it.

  After getting data from the clipboard, an application must not leave the
  block locked.

  After calling SetClipboardData(), an application should not use the block,
  since it belongs to Windows. Treat its handle as invalid. Be sure the
  block is unlocked before closing the clipboard.

Clipboard Data Formats--

There are several predefined data types <See online help on Clipboard formats>.

Custom formats can be created using RegisterClipboardFormat().

Data can be saved to the clipboard in several formats. Only one memory
block at a time in the clipboard can have any given format, but there can
be many blocks as long as each has a different format.

IsClipboardFormatAvailable(uFormat)-- A function that determines if the
specified data format is currently in the clipboard. It returns TRUE if
the clipboard contains the type of data specified by uFormat. This is one
of the few clipboard functions that can be used without opening the
clipboard. Use of this function is an alternative to checking for a NULL
result on the call to GetClipboardData().

CLIP1 Example Program--

"Copy to Clipboard" ==> Send uppercase alphabet to the clipboard as text.

"Get clipboard Text" ==> Retrieve text data from clipboard, if available,
and output it to the window's client area.

"Clear Screen" ==> Clear the client area.

This program uses the Win16 memory manipulation functions and the clipboard
functions described above.

Multiple Clipboard Data Formats--

The clipboard can hold one block of data for each clipboard format.
Usually data passed to the clipboard with different formats would
represent different ways of saving the same basic data. (e.g., Microsoft
Word: text only, rich text format, Word format, Wordperfect format, HTML,
etc.)  The application that uses the clipboard can check each format stored
to see if the data is as expected or can choose the format it can work with
"best."

CLIP2: An Example that Uses Multiple Clipboard Data Formats--

"Clipboard / Copy to Clipboard" ==> Three types of data are sent to the
clipboard: some text using CF_TEXT format, a bitmap image using CF_BITMAP
format, and some custom-format data.

"Clipboard / Get clipboard Text" ==> Retrieves and displays the text from
the clipboard.

"Clipboard / Get clipboard BMP" ==> Retrieves and displays the bitmap
image from the clipboard.

"Clipboard / Get Special Data" ==> Retrieves and displays the custom-
format data.

After using CLIP2 to copy the three types of data to the clipboard try
the following:

  1. Use the Windows Notepad application and "Paste" ==> We get the text 
     since Notepad supports only the CF_TEXT format.

  2. Use the Windows Paint application and "Paste" ==> We get the bitmap 
     since Paint reads and writes the CF_BITMAP format.

  3. Use the Windows WordPad application and "Paste" ==> We get the text, 
     since Wordpad considers CF_TEXT to be "preferable" to CF_BITMAP. But 
     in Wordpad, you can also choose "Paste Special" to choose either the 
     text or the bitmap.

"Copy to clipboard": WM_COMMAND, IDM_SENDCLIP--

  1. Sends text to the clipboard as in CLIP1.
  2. Sends a bitmap to the clipboard:
      Loads it from the resources --> hBitmap, which can be used in
      SetClipboardData().
  3. Registers a new "DIGITS" format with RegisterClipboardFormat()
     and uses the return value as the uFormat value in the call to
     SetClipboardData(). The actual data is just a string of digits.

"Get clipboard text": WM_COMMAND, IDM_GETTEXT--

  Does the same thing as CLIP1.

"Get clipboard bitmap": WM_COMMAND, IDM_GETBMP--

  1. Gets a handle to the clipboard bitmap.
  2. Creates a compatible memory DC and selects the bitmap into it.
  3. Uses GetObject(hClipMem, sizeof(BITMAP), &bm) to copy the bitmap
     data into a BITMAP structure (bm), which will contain width and height
     fields.
  4. Uses BitBlt() to copy the memory DC to the screen DC using the size
     information contained in the bm structure.

"Get Special data": WM_COMMAND, IDM_GETSPECIAL--

  This is similar to getting the text data--only we use the new uFormat
  value that was returned when the custom format was registered
  (wClipFormat).

Delayed Rendering of Clipboard Data--

There are many clipboard data formats, so lots of memory space could be
wasted if all formats are sent to the clipboard with each "Copy" or "Cut".

An application can "send" data without including the data by just sending
the format. To do this, pass NULL as the handle to the data block when
SetClipboardData() is called. Windows will "remember" the handle of the
window that was active when the clipboard was opened. The application's
WndProc() will have to provide the data of the specified type when an
application subsequently tries to read the clipboard. For example, the
data supplier program could do the following:

OpenClipboard (hWnd);
EmptyClipboard ();
SetClipboardData (CF_TEXT, 0)  // delayed rendering of CF_TEXT data
CloseClipboard();

When any application subsequently tries to read the clipboard, the following
sequence occurs:

  1. The application requests CF_TEXT data with GetClipboardData().

  2. Windows recognizes that CF_TEXT data must be loaded.

  3. Windows sends a WM_RENDERFORMAT message to the data supplier program
     (wParam = clipboard format code).

  4. That program's WndProc() calls SetClipboardData() again, this time
     sending the data (handle).

  5. Windows passes the handle to the application requesting the data.

But what if the program supplying the clipboard data terminates before the
data is requested?

  Windows sends the supplying program a WM_RENDERALLFORMATS message before
  it terminates. The program should respond by sending memory blocks with
  data of all formats it supports.

Using the Clipboard with an Edit Control--

Windows has built-in cut-and-paste capability for text selected in an edit
control. The user selects text in an edit control by dragging the mouse
cursor over the text (or by using the <Shift>-arrow keys). The selected
text is highlighted. Once the text has been selected, it can be cut or
copied to the clipboard. All that needs to be done is to send the edit
control a WM_CUT or WM_COPY message. For example, to copy the currently
selected text in the edit control whose handle is hEdWin:

    SendMessage (hEditWin, WM_COPY, 0, 0);

Notice the wParam and lParam are not not used. When the edit control 
receives this message, the selected text is copied to the clipboard using 
the CF_TEXT format.

Pasting text from the clipboard to an edit control is very similar. Send
the edit control a WM_PASTE message. If there's text in the clipboard, its
text is inserted at the position of the blinking caret in the edit control:

    SendMessage (hEditWin, WM_PASTE, 0, 0);

Cutting text (removing it) from an edit control to the clipboard. Send the
edit control a WM_CUT message:

    SendMessage (hEditWin, WM_CUT, 0, 0);

We can also delete text from an edit control by cutting it and then
emptying the clipboard:

    SendMessage (hEditWin, WM_CUT, 0, 0);
    if (OpenClipboard (hWnd)
    {
       EmptyClipboard ();
       CloseClipboard ();
    }

EDITCCPD EXAMPLE-- 

This application adds "Copy", "Cut", "Paste", and "Delete" capability to 
the FILECOMD example--

"Edit" popup menu --> "Cut", "Copy", "Paste" & "Delete" menu items.

These make use of the clipboard as described above.

"File" popup menu --> "Open File, "Close File", "About", & "Exit" --
Works just like in FILECOMD. Note also that we have added an accelerator
table to the program's resources so that the "feel" of this mini-editor
will be similar to that in other standard Windows applications.

The result is a fairly sophisticated program with many of the capabilities
of the Windows Notepad application.